The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

$Lab::Moose::Instrument::Lakeshore340::VERSION = '3.930';
#ABSTRACT: Lakeshore Model 340 Temperature Controller
use v5.20;
use Moose;
validated_getter validated_setter setter_params /;
use Carp;
#use POSIX qw/log10 ceil floor/;
with qw(
);
has input_channel => (
is => 'ro',
isa => enum( [qw/A B C D/] ),
default => 'A',
);
has default_loop => (
is => 'ro',
isa => enum( [ 1 .. 2 ] ),
default => 1,
);
sub BUILD {
my $self = shift;
$self->clear();
$self->cls();
}
my %channel_arg
= ( channel => { isa => enum( [qw/A B C D/] ), optional => 1 } );
my %loop_arg = ( loop => { isa => enum( [qw/1 2/] ), optional => 1 } );
sub get_T {
my ( $self, %args ) = validated_getter(
\@_,
%channel_arg
);
my $channel = delete $args{channel} // $self->input_channel();
return $self->query( command => "KRDG? $channel", %args );
}
sub get_value {
my $self = shift;
return $self->get_T(@_);
}
sub get_sensor_units_reading {
my ( $self, %args ) = validated_getter(
\@_,
%channel_arg
);
my $channel = delete $args{channel} // $self->input_channel();
return $self->query( command => "SRDG? $channel", %args );
}
sub get_setpoint {
my ( $self, %args ) = validated_getter(
\@_,
%loop_arg
);
my $loop = delete $args{loop} // $self->default_loop;
return $self->query( command => "SETP? $loop", %args );
}
sub set_setpoint {
my ( $self, $value, %args ) = validated_setter(
\@_,
%loop_arg
);
my $loop = delete $args{loop} // $self->default_loop;
# Device bug. The 340 cannot parse values with too many digits.
$value = sprintf( "%.6G", $value );
$self->write( command => "SETP $loop,$value", %args );
}
sub set_T {
my $self = shift;
$self->set_setpoint(@_);
}
sub set_heater_range {
my ( $self, $value, %args ) = validated_setter(
\@_,
value => { isa => enum( [qw/0 1 2 3 4 5/] ) }
);
$self->write( command => "RANGE $value", %args );
}
sub get_heater_range {
my ( $self, %args ) = validated_getter( \@_ );
return $self->query( command => "RANGE?", %args );
}
sub set_control_mode {
my ( $self, $value, %args ) = validated_setter(
\@_,
value => { isa => enum( [ ( 1 .. 6 ) ] ) },
%loop_arg
);
my $loop = delete $args{loop} // $self->default_loop;
return $self->write( command => "CMODE $loop,$value", %args );
}
sub get_control_mode {
my ( $self, %args ) = validated_getter(
\@_,
%loop_arg
);
my $loop = delete $args{loop} // $self->default_loop;
return $self->query( command => "CMODE? $loop", %args );
}
sub set_mout {
my ( $self, $value, %args ) = validated_setter(
\@_,
value => { isa => 'Num' },
%loop_arg
);
my $loop = delete $args{loop} // $self->default_loop;
return $self->write( command => "MOUT $loop,$value", %args );
}
sub get_mout {
my ( $self, %args ) = validated_getter(
\@_,
%loop_arg
);
my $loop = delete $args{loop} // $self->default_loop;
return $self->query( command => "MOUT? $loop", %args );
}
sub set_control_parameters {
my ( $self, %args ) = validated_getter(
\@_,
%loop_arg,
%channel_arg,
units => { isa => enum( [qw/1 2 3/] ) },
state => { isa => enum( [qw/0 1/] ) },
powerup_enable => { isa => enum( [qw/0 1/] ), default => 1 },
);
my $channel = delete $args{channel} // $self->input_channel();
my ( $loop, $units, $state, $powerup_enable )
= delete @args{qw/loop units state powerup_enable/};
$loop = $loop // $self->default_loop;
$self->write( command => "CSET $loop, $channel, $units, $state,"
. "$powerup_enable", %args );
}
sub get_control_parameters {
my ( $self, %args ) = validated_getter(
\@_,
%loop_arg
);
my $loop = delete $args{loop} // $self->default_loop();
my $rv = $self->query( command => "CSET? $loop", %args );
my @rv = split /,/, $rv;
return (
channel => $rv[0], units => $rv[1], state => $rv[2],
powerup_enable => $rv[3]
);
}
sub set_input_curve {
my ( $self, $value, %args ) = validated_setter(
\@_,
%channel_arg,
value => { isa => enum( [ 0 .. 60 ] ) },
);
my $channel = delete $args{channel} // $self->input_channel();
$self->write( command => "INCRV $channel,$value", %args );
}
sub get_input_curve {
my ( $self, %args ) = validated_getter(
\@_,
%channel_arg,
);
my $channel = delete $args{channel} // $self->input_channel();
return $self->query( command => "INCRV $channel", %args );
}
sub set_remote_mode {
my ( $self, $value, %args )
= validated_setter( \@_, value => { isa => enum( [ 1 .. 3 ] ) } );
$self->write( command => "MODE $value", %args );
}
sub get_remote_mode {
my ( $self, %args ) = validated_getter( \@_ );
return $self->query( command => "MODE?", %args );
}
sub set_pid {
my ( $self, %args ) = validated_getter(
\@_,
%loop_arg,
P => { isa => 'Lab::Moose::PosNum' },
I => { isa => 'Lab::Moose::PosNum' },
D => { isa => 'Lab::Moose::PosNum' }
);
my ( $loop, $P, $I, $D ) = delete @args{qw/loop P I D/};
$loop = $loop // $self->default_loop();
$self->write(
command => sprintf( "PID $loop, %.1f, %.1f, %d", $P, $I, $D ),
%args
);
}
sub get_pid {
my ( $self, %args ) = validated_getter(
\@_,
%loop_arg
);
my $loop = delete $args{loop} // $self->default_loop;
my $pid = $self->query( command => "PID? $loop", %args );
my %pid;
@pid{qw/P I D/} = split /,/, $pid;
return %pid;
}
sub set_zone {
my ( $self, %args ) = validated_getter(
\@_,
%loop_arg,
zone => { isa => enum( [ 1 .. 10 ] ) },
top => { isa => 'Lab::Moose::PosNum' },
P => { isa => 'Lab::Moose::PosNum' },
I => { isa => 'Lab::Moose::PosNum' },
D => { isa => 'Lab::Moose::PosNum' },
mout => { isa => 'Lab::Moose::PosNum', optional => 1 },
range => { isa => enum( [ 0 .. 5 ] ) },
);
my ( $loop, $zone, $top, $P, $I, $D, $mout, $range )
= delete @args{qw/loop zone top P I D mout range/};
$loop = $loop // $self->default_loop;
if ( defined $mout ) {
$mout = sprintf( "%.1f", $mout );
}
else {
$mout = ' ';
}
$self->write(
command => sprintf(
"ZONE $loop, $zone, %.6G, %.1f, %.1f, %d, $mout, $range", $top,
$P, $I, $D
),
%args
);
}
sub get_zone {
my ( $self, %args ) = validated_getter(
\@_,
%loop_arg,
zone => { isa => enum( [ 1 .. 10 ] ) }
);
my ( $loop, $zone ) = delete @args{qw/loop zone/};
$loop = $loop // $self->default_loop;
my $result = $self->query( command => "ZONE? $loop, $zone", %args );
my %zone;
@zone{qw/top P I D mout range/} = split /,/, $result;
return %zone;
}
sub set_analog_out {
my ( $self, %args ) = validated_getter(
\@_,
output => { isa => enum( [ 1, 2 ] ) },
bipolar_enable => { isa => enum( [ 0, 1 ] ), default => 0 },
mode => { isa => enum( [ 0, 1, 2, 3 ] ) },
input => { isa => enum( [qw/A B C D/] ), default => '' },
source => { isa => enum( [ 1, 2, 3, 4 ] ), default => '' },
high_value => { isa => 'Num', default => '' },
low_value => { isa => 'Num', default => '' },
manual_value => { isa => 'Num', default => '' },
);
my (
$output, $bipolar_enable, $mode, $input, $source, $high_value,
$low_value, $manual_value
)
= delete @args{
qw/output bipolar_enable mode input source high_value low_value manual_value/
};
$self->write(
command =>
"ANALOG $output, $bipolar_enable, $mode, $input, $source, $high_value, $low_value, $manual_value",
%args
);
}
sub get_analog_out {
my ( $self, %args ) = validated_getter(
\@_,
output => { isa => enum( [ 1, 2 ] ) },
);
my $output = delete $args{'output'};
my $result = $self->query( command => "ANALOG? $output", %args );
my %analog_out;
@analog_out{
qw/output bipolar_enable mode input source high_value low_value manual_value/
} = split /,/, $result;
return %analog_out;
}
__PACKAGE__->meta()->make_immutable();
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Lab::Moose::Instrument::Lakeshore340 - Lakeshore Model 340 Temperature Controller
=head1 VERSION
version 3.930
=head1 SYNOPSIS
use Lab::Moose;
# Constructor
my $lakeshore = instrument(
type => 'Lakeshore340',
connection_type => 'LinuxGPIB',
connection_options => {pad => 22},
input_channel => 'B', # set default input channel for all method calls
);
my $temp_B = $lakeshore->get_T(); # Get temp for input 'B' set as default in constructor.
my $temp_A = $lakeshore->get_T(channel => 'A'); # Get temp for input 'A'.
=head1 METHODS
=head2 get_T
my $temp = $lakeshore->get_T(channel => $channel);
C<$channel> can be 'A' or 'B'. The default can be set in the constructor.
=head2 get_value
alias for C<get_T>.
=head2 get_sensor_units_reading
my $reading = $lakeshore->get_sensor_units_reading(channel => $channel);
Get sensor units reading (like resistance) of an input channel.
=head2 set_setpoint/get_setpoint
Set/get setpoint for loop 1 in whatever units the setpoint is using
$lakeshore->set_setpoint(value => 10, loop => 1);
my $setpoint1 = $lakeshore->get_setpoint(loop => 1);
=head2 set_T
alias for C<set_setpoint>
=head2 set_heater_range/get_heater_range
$lakeshore->set_heater_range(value => 1);
my $range = $lakeshore->get_heater_range();
Value is one of 0 (OFF),1,...,5 (MAX)
=head2 set_control_mode/get_control_mode
Specifies the control mode. Valid entries: 1 = Manual PID, 2 = Zone,
3 = Open Loop 4 = AutoTune PID, 5 = AutoTune PI, 6 = AutoTune P.
# Set loop 1 to manual PID
$lakeshore->set_control_mode(value => 1, loop => 1);
my $cmode = $lakeshore->get_control_mode(loop => 1);
=head2 set_mout/get_mout
$lakeshore->set_mout(
loop => 1,
value => 22.45, # percent of range
);
my $mout = $lakeshore->get_mout(loop => 1);
Set/get manual output. Only works if output is configured for open
loop control.
=head2 set_control_parameters/get_control_parameters
$lakeshore->set_control_parameters(
loop => 1,
input => 'A',
units => 1, # 1 = Kelvin, 2 = Celsius, 3 = sensor units
state => 1, # 0 = off, 1 = on
powerup_enable => 1, # 0 = off, 1 = on, optional with default = off
);
my %args = $lakeshore->get_control_parameters(loop => 1);
=head2 set_input_curve/get_input_curve
# Set channel 'B' to use curve 25
$lakeshore->set_input_curve(channel => 'B', value => 25);
my $curve = $lakeshore->get_input_curve(channel => 'B');
=head2 set_remote_mode/get_remote_mode
$lakeshore->set_remote_mode(value => 1);
my $mode = $lakeshore->get_remote_mode();
Valid entries: 1 = local, 2 = remote, 3 = remote with local lockout.
=head2 set_pid/get_pid
$lakeshore->set_pid(loop => 1, P => 1, I => 50, D => 50)
my %PID = $lakeshore->get_pid(loop => 1);
# %PID = (P => $P, I => $I, D => $D);
=head2 set_zone/get_zone
$lakeshore->set_zone(
loop => 1,
zone => 1,
top => 10,
P => 25,
I => 10,
D => 20,
range => 1
);
my %zone = $lakeshore->get_zone(loop => 1, zone => 1);
=head2 set_analog_out/get_analog_out
$lakeshore->set_analog_out
output => 1,
bipolar_enable => 1, # default: 0
mode => 2, # 0 = off, 1 = input, 2 = manual, 3 = loop. Loop is only valid for output 2
manual_value => -30, # -30 percent output (-3V)
);
my %analog_out = $lakeshore->get_analog_out();
=head2 Consumed Roles
This driver consumes the following roles:
=over
=item L<Lab::Moose::Instrument::Common>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2025 by the Lab::Measurement team; in detail:
Copyright 2018 Simon Reinhardt
2020 Andreas K. Huettel, Simon Reinhardt
2021-2022 Simon Reinhardt
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut