Galil Axis Agent

The Galil Axis Agent provides motion control and telemetry readout for the Galil DMC motor controller. When used in the Simons Observatory SAT Coupling Optics system, the agent controls four axes—two linear and two angular—that move the hardware as needed to perform detector passband measurements.

usage: python3 agent.py [-h] [--ip IP] [--port PORT] [--configfile CONFIGFILE]
                        [--input_config INPUT_CONFIG] [--mode {init,acq}]

Agent Options

--ip
--port

Default: 23

--configfile
--input_config
--mode

Possible choices: init, acq

Configuration File Examples

Below are configuration examples for the ocs config file and for running the Agent in a docker container.

OCS Site Config

To configure your Galil axis motor controller for use with OCS you need to add a GalilAxisAgent block to your ocs configuration file. Here is an example configuration block:

{'agent-class': 'GalilAxisAgent',
 'instance-id': 'satcouplingoptics',
               ['--ip', '10.120.1.6',
                '--configfile', 'axes_config.yaml',
                '--input_config', True,
                '--mode', 'acq']}

Each device requires configuration under ‘agent-instances’. See the OCS site configs documentation for more details.

Note

The input_config argument is a boolean flag. When True, the init task loads and applies all motor-controller settings from the agent’s configuration file (see Galil Motor Axis Config below) to bring the controller and its axes into the desired state.

Galil Axis Config

A Galil axis configuration file defines the motion settings, motor parameters, and brake mappings for each controlled axis. This allows the user to easily adapt to different hardware configurations or coordinate multiple axes (e.g., A, B, C, D) during operation:

galil:
  motorsettings:
    countspermm: 4000
    countsperdeg: 2000
  limitsetting:
    polarity: '1'
    disable_limits:
      B: '3'
      D: '3'
  brakes:
    output_map:
      A: '1'
      B: '2'
      C: '3'
      D: '4'
  motorconfigparams:
    A:              # linear axis
      MT: '1'
      OE: '1'
      AG: '2'
      TL: '5'
      AU: '9'
    B:              # linear axis
      MT: '1'
      OE: '1'
      AG: '2'
      TL: '5'
      AU: '9'
    C:              # rotary axis
      MT: '1'
      OE: '1'
      AG: '2'
      TL: '5'
      AU: '9'
    D:              # rotary axis
      MT: '1'
      OE: '1'
      AG: '2'
      TL: '5'
      AU: '9'
  initaxisparams:
    BA: 'True'          # if True, will drive motors for each axis at 3V (BZ) for prepping for servo'd motion
    BM: '3276.8'
    BZ: '3'
  dwell_times:
    first_ms: '1000'
    second_ms: '1500'

Docker Compose

The Galil Axis Agent should be configured to run in a Docker container. An example configuration is:

ocs-galil-agent:
  image: simonsobs/socs:latest
  hostname: ocs-docker
  network_mode: "host"
  environment:
    - INSTANCE_ID=satcouplingoptics
    - SITE_HUB=ws://127.0.0.1:8001/ws
    - SITE_HTTP=http://127.0.0.1:8001/call
  volumes:
    - ${OCS_CONFIG_DIR}:/config:ro

Example Clients

Below are some example use cases for using this agent.

Note

The examples below assume the Galil motor controller has sinusoidal amplifers, limit switches, and brakes (i.e., the Galil motor controllers used for the SAT coupling optics system)

Updating the config file

Though the agent can be configured to initialize the axes via the input_config boolean parameter in the OCS site config file, any changes made to the configuration file after agent startup will require reloading it. The following client command is used to update the motor controller settings accordingly:

client.input_configfile(configfile='axes_config.yaml')

Note

It is important to call the input_configfile task even if the only update to the configuration file is a change to countspermm or countsperdeg, since these calibration values are necessary for commanding axis motion in physical units (mm/deg) rather than raw encoder counts.

Homing Procedure

The SAT coupling optics Galil axes are equipped with limit switches, so the chosen homing procedure is to move each axis continuously until it is stopped by its limit switch. When the axis is forced to stop at the switch, that raw encoder position should then be defined as 0.

To continuously move an axis, we use set_jog_speed to define the speed at which the axis will jog:

client.set_jog_speed(axis='A', speed=5000.0)

Here, 5000.0 is in units of counts/sec. Note that the speed set through set_jog_speed is always specified in counts/sec, unlike other tasks that alow motion in physical units of millimeter or degrees (e.g., set_relative_position or set_absolute_position).

To begin motion:

client.begin_axis_motion(axis='A')

After the axis stops at the limit switch, we define that position using:

client.define_position(axis='A', val=0.00)

Gearing Settings

The following tasks are used to define leader–follower relationships between axes. For the SAT coupling optics system, axes A and B are the linear pair, and axes C and D are the angular pair. In this configuration, A is the leader for B, and C is the leader for D.

The gearing ratio determines the velocity at which each follower axis moves relative to its leader. For example, a ratio of 1 means that B will follow A at the exact same speed defined for A. A ratio of -1 means the follower moves at the same speed scale but in the opposite direction.

Once the leader–follower mapping and gearing ratios are set, commanding motion on the leader (e.g., A) will cause both A and B to move. If this does not occur, stop motion and query the gearing ratio for the relevant axes.

When querying the ratio, the expected response for a leader axis is 0, since leaders do not follow any other axis. The follower axis should return the ratio you set (e.g., 1 for B).

Occasionally, the Galil motor controller may lose the gearing ratio values while still correctly remembering the leader/follower assignments. If a gearing-ratio query for the follower axis returns 0, reapply the gearing ratio.

Example usage of defining leader/follower axes and the gearing ratio:

# configure A and C as the leader axes
client.set_gearing(order=',A,C')
client.set_gearing_ratio(order=',-1,1')

Here, the second field corresponds to B and the fourth field corresponds to D.

Another example using axes E and F for a 6-axis Galil motor controller system:

# using axes E and F
client.set_gearing(order=',,,,,E')
client.set_gearing_ratio(order=',,,,,1')

In this case, F (the sixth position) follows E with a ratio of 1.

Note

The order argument encodes leader–follower relationships—each comma-delimited field corresponds to one axis in alphabetical order. An empty field means the axis is independent (i.e., not following another axis), while a non-empty field specifies which axis it should follow.

To query the gearing ratio:

>>> response = client.get_gearing_ratio(axis='F')
>>> print(response)
OCSReply: OK : Operation "get_gearing_ratio" is currently not running (SUCCEEDED).
get_gearing_ratio[session=5]; status=done without error 0.006998 s ago, took 0.545369 s
messages (4 of 4):
  1762986294.032 Status is now "starting".
  1762986294.032 Status is now "running".
  1762986294.576 Gearing ratio for axis F is: 1.0.
  1762986294.577 Status is now "done".
other keys in .session: op_code, degraded, data

Here, the agent states that the gearing ratio for axis F is 1, which also indirectly confirms that the set_gearing task was successful.

Examples of sets and gets

Below are 2 examples of setting and querying a specific state for a Galil axis:

>>> client.set_motor_state(axis='F', state='disable')
>>> response = client.get_motor_state(axis='F')
>>> OCSReply: OK : Operation "get_motor_state" is currently not running (SUCCEEDED).
get_motor_state[session=3]; status=done without error 0.007853 s ago, took 1.4 s
messages (4 of 4):
  1762987023.477 Status is now "starting".
  1762987023.477 Status is now "running".
  1762987024.889 Motor F state: off (raw=1)
  1762987024.889 Status is now "done".
other keys in .session: op_code, degraded, data

Here, get_motor_state reports that axis F is disabled. The raw value shown as (raw=1) reflects how the Galil command works internally: the controller returns a value of 1 when the axis is off.

Another set/get example below:

>>> client.set_torque_limit(axis='E', val=2.0)
>>> print(client.get_torque_limit(axis='E'))
>>> OCSReply: OK : Operation "get_torque_limit" is currently not running (SUCCEEDED).
get_torque_limit[session=4]; status=done without error 0.006350 s ago, took 2.8 s
messages (4 of 4):
  1762987510.209 Status is now "starting".
  1762987510.209 Status is now "running".
  1762987512.988 Torque limit for axis E is  2.0000.
  1762987512.988 Status is now "done".
other keys in .session: op_code, degraded, data

Agent API

class socs.agents.galil_axis.agent.GalilAxisAgent(agent, ip, configfile, port=23)[source]

Agent for controlling Galil axis motors used in SAT coupling optics instrument for passband measurements on-site.

Parameters:
  • ip (str) – IP address for the Galil axis motor controller

  • configfile (str) – Path to .yaml config file containing axis and motor settings

  • port (int, optional) – TCP port for controller communication. Default is 23

init(input_config=False, auto_acquire=False)[source]

Task - Initalize connection to Galil axis controller.

Parameters:
  • input_config (bool, optional) – If True, init task will also run input_configfile task as part of agent initialization. Defaults to False.

  • auto_acquire (bool) – If True, start acquisition immediately after initialization. Defaults to False.

acq()[source]

Process - Starts acquisition of data from the Galil Stage Controller.

Parameters:

test_mode (bool, optional) – Run the process loop only once. This is meant only for testing. Default is False.

Notes

The data collected is stored in session data in the structure:

>> response.session['data']
{'fields':
    {'A_position': -1129.0, 'A_velocity': 0.0, 'A_torque': 0.0, 'A_position_error': 7.0,
     'B_position': -542.0, 'B_velocity': 0.0, 'B_torque': 0.0, 'B_position_error': 14.0,
     'C_position': 810637.0, 'C_velocity': -14983.0, 'C_torque': -1.0501, 'C_position_error': -558.0,
     'D_position': 810711.0, 'D_velocity': -15240.0, 'D_torque': -1.0421, 'D_position_error': -580.0},
     'timestamp': 1764009732.0866072}
set_relative_position(axis, distance, movetype)[source]

Task - Set the relative position location for a specified axis.

Parameters:
  • axis (str) – Axis to command position. Ex: ‘A’

  • distance (float) – Relative distance value, in millimeter, degrees, or raw counts, depending on movetype.

  • movetype (str) – ‘linear’ (mm) or ‘angular’ (deg), or ‘encoder’ for raw encoder counts.

Notes

The conversion from millimeters to encoder counts is defined in the configuration file under galil.motorsettings.countspermm or galil.motorsettings.countsperdeg

set_absolute_position(axis, position, movetype)[source]

Task - Set the absolute position location for a specified axis.

Parameters:
  • axis (str) – Axis to command position. Example: ‘A’

  • position (float) – Absolute position distance value in mm, deg, or raw encoder counts.

  • movetype (str) – ‘linear’ (mm) or ‘angular’ (deg), or ‘encoder’ for raw encoder counts.

Notes

The conversion from millimeters to encoder counts is defined in the configuration file under galil.motorsettings.countspermm or galil.motorsettings.countsperdeg

get_brake_status(axis)[source]

Task - Get brake status for a given axis.

Parameters:

axis (str) – Axis to query (e.g. ‘A’, ‘B’).

set_axis_brake(axis, state)[source]

Task - Engages or releases the brake for the specified axis.

Parameters:
  • axis (str) – Axis to control brake for. Ex. ‘A’

  • state (str) – Desired brake state: ‘engage’ or ‘release’.

get_thermistor_voltage(axis)[source]

Task - Returns a given motor’s thermistor reading in volts.

Parameters:

axis (str) – Axis/motor to query (e.g. ‘A’)

begin_axis_motion(axis)[source]

Task - Moves the specified axis.

Parameters:

axis (str) – Specified axis. Ex. ‘A’

set_motor_type(axis)[source]

Task - Sets motor type for each axis, depending on servo motor features

Parameters:

axis (str) – Specified axis. Ex. ‘A’

get_motor_type(axis)[source]

Task - Queries the motor type for a given axis.

Parameters:

axis (str) – Axis to query (e.g. ‘A’, ‘B’).

set_off_on_error(axis)[source]

Task - Configure the off-on-error behavior for a specified axis.

This task enables or disables the Galil controller’s off-on-error function, which determines whether the motor power is shut off when a position error occurs.

Parameters:
  • axis (str) – Axis to configure. Ex. ‘A’

  • errtype (int) – Error handling mode, as defined by the controller’s disable/enable settings.

get_off_on_error(axis)[source]

Task - Query the Off-On-Error (OE) state for a given axis.

Parameters:

axis (str) – Axis to query (e.g. ‘A’, ‘B’, ‘E’).

set_amp_gain(axis, val)[source]

Task - Set amplifier gain for internal amplifier per axis.

Parameters:
  • axis (str) – Specified axis. Ex. ‘A’

  • val (int) – Amplifier gain value to apply, as defined by controller’s internal gain settings

get_amp_gain(axis)[source]

Task - Query the amplifier gain value for a given axis.

Parameters:

axis (str) – Axis to query (e.g. ‘A’, ‘B’, ‘E’).

get_amp_currentloop_gain(axis)[source]

Task - Query the amplifier current loop gain value for a given axis.

Parameters:

axis (str) – Axis to query (e.g. ‘A’).

set_amp_currentloop_gain(axis, val)[source]

Task - Set amplifier current loop gain for a given axis.

Parameters:
  • axis (str) – Specified axis. Ex. ‘A’

  • val (int) – Current-loop gain value to apply.

set_torque_limit(axis, val)[source]

Task - Set motor torque limit per axis.

Parameters:
  • axis (str) – Specified axis. Ex. ‘A’

  • val (float) – Torque limit value in volts. Defines max

  • current (allowable motor)

  • controller's (as specifiied by)

  • settings. (internal)

get_torque_limit(axis)[source]

Task - Query motor torque limit for specified axis.

Parameters:

axis (str) – Axis to query (e.g. ‘A’).

set_motor_state(axis, state)[source]

Task - Enable or disable axis motor, and query its state.

Parameters:
  • axis (str) – Axis to set motor state for (e.g. ‘A’, ‘B’, ‘E’).

  • state (str) – Desired motor state — ‘enable’ or ‘disable’.

get_motor_state(axis)[source]

Task - Query and interpret whether a motor is ON or OFF for a given axis.

Parameters:

axis (str) – Axis to query (e.g. ‘A’).

set_magnetic_cycle(axis, val)[source]

Task - Set magnetic cycle value for motors with sinusoidal amplifiers for specific axis.

Defines the length of the motor’s magnetic cycle in encoder units.

Parameters:
  • axis (str) – Specified axis. Ex. ‘A’

  • val (float) – Magnetic cycle value to apply.

set_dwell_times(t_first, t_second)[source]

Task - Define dwell times for the initialization task.

This task defines the time between driving each axis motor to 2 different locations.

Parameters:
  • t_first (int) – timing in milliseconds for driviing the motor to the first location. Ex: 1500

  • t_second (int) – timing in milliseconds for driving the motor to the second location. Ex: 1000

initialize_axis(axis, val)[source]

Task - Initialize axes configured with sinusoidal amplifiers.

During this procedure, each motor is driven to two magnetic positions to establish the commutation angle required for motion.

Parameters:
  • axis (str) – Specified axis. Ex. ‘A’

  • val (float) – Torque command voltage to be applied during initialization. Ex: 3.0

Notes

To run this task, you must run the enable_sin_commutation, set_magnetic_cycle, and set_dwell_times tasks first.

define_position(axis, val)[source]

Task - Resets the position of an axis encoder to a specifically set value.

Parameters:
  • axis (str) – Specified axis. Ex. ‘A’

  • val (float) – The value to set the current motor position as specified by user. (i.e., 0.00 if homing)

set_jog_speed(axis, speed)[source]

Task - Defines the jog speed for the specified axis.

This task will set the speed to move the axis continuously when ready to begin motion, but does not begin motion.

Parameters:
  • axis (str) – Specified axis. Ex. ‘A’

  • speed (float) – The value of the speed in raw encoder units

Notes

The speed value here is not defined in terms of millimeters or degrees. User will have to define in encoder counts (i.e., 4000 for 4000 counts/sec).

set_speed(axis, speed)[source]

Task - Sets the speed for a subsequent motion/move-to command (such as relative or absolute position motion).

Parameters:
  • axis (str) – Specified axis. Ex. ‘A’

  • speed (float) – Specified speed value in raw encoder units

Notes

The speed value here is not defined in terms of millimeters or degrees. User will have to define in encoder counts (i.e., 4000 for 4000 counts/sec).

get_speed(axis)[source]

Task - Return the set speed for a given axis.

Parameters:

axis (str) – Axis to query (e.g. ‘A’)

set_acceleration(axis, acc)[source]

Task - Sets the acceleration for a subsequent motion/move-to command.

Parameters:
  • axis (str) – Specified axis. Ex. ‘A’

  • acc (float) – Specified acceleration value in raw encoder units.

Notes

The acceleration value here is not defined in terms of millimters or degrees. User will have to define in encoder counts that are powers of 2. (i.e., ‘4096’ for 4096 counts/sec^2).

get_acceleration(axis)[source]

Task - Query acceleration for a given axis.

Parameters:

axis (str) – Axis to query (e.g. ‘A’)

set_deceleration(axis, decel)[source]

Task - Sets the deceleration for a subsequent motion/move-to command.

Parameters:
  • axis (str) – Specified axis. Ex. ‘A’

  • decel (float) – Deceleration in encoder units (counts/s^2)

Notes

User will have to define in encoder counts/s^2 in powers of 2, (e.g. 8192).

get_deceleration(axis)[source]

Task - Returns the deceleration for a given axis.

Parameters:

axis (str) – Axis to query (e.g. ‘A’)

enable_sin_commutation(axis)[source]

Task - Enable sinusoidal commutation for a specified brushless axis.

Parameters:

axis (str) – Specified axis. Ex. ‘A’

set_limitswitch_mode(axis, val)[source]

Task - Enable or disable limit switch for a specified axis.

Parameters:
  • axis (str) – Specified axis. Ex. ‘A’

  • val (int) – 0 = both enabled; 1 = forward disabled; 2 = reverse disabled; 3 = both disabled

get_limitswitch_mode(axis)[source]

Task - Get the limit switch enable/disable setting for a given axis.

Parameters:

axis (str) – Specified axis. Ex. ‘A’

set_limitswitch_polarity(polarity)[source]

Task - Configure the limit switch polarity for all axes.

Parameters:

polarity (int) – Limit switch polarity value. 0 is active-low (limit triggers when input goes low), 1 is active-high (limit triggers when input goes high).

get_limitswitch_polarity()[source]

Task - Query limit switch polarity setting.

stop_axis_motion(axis)[source]

Task - Stop motion for specified axis.

Parameters:

axis (str) – Specified axis. Ex. ‘A’

set_gearing(order)[source]

Task - Configure electronic gearing relationships between follower and leader axes.

Parameters:

order (str) – Comma-separated axis assignment string defining the leader/follower mapping (e.g., ‘,,,,,E’ assigns E as the leader for F axis).

set_gearing_ratio(order)[source]

Task - Set electronic gearing ratio between leader and follower axes.

A ratio of 1 means the follower axis moves at the same speed as its leader axis.

Parameters:

order (str) – Comma-separated string of gearing ratios for each axis, similar in format as set_gearing task. (e.g., ‘,,,,,1’)

get_gearing_ratio(axis)[source]

Task - Query the current electronic gearing ratio for a specified axis

Parameters:

axis (str) – Axis to query (e.g., ‘A’)

get_gearing_lead(axis)[source]

Task - Query the leader axis for a given follower axis.

Parameters:

axis (str) – Axis to query (e.g., ‘A’)

input_configfile(configfile=None)[source]

Task - Upload Galil Axis Controller configuration file to initialize device and axes on device

Parameters:

configfile (str, optional) – name of .yaml config file. Defaults to the file set in the site config.