Skip to content

Peregrine2

Markus Grönholm edited this page Jun 15, 2026 · 5 revisions

Peregrine2 motion controller

Install required packages

python -mpip install pyserial alshain

Quick start

import alshain
import serial
import sys

# Serial port as first command line parameter
com = serial.Serial( sys.argv[1], alshain.BAUDRATE, timeout = 0.25 )

dev = alshain.Peregrine2( com, address = 1 )

Parameters

dev.read( alshain.Peregrine2.Parameters.ENCODER_A ) # Current encode value, axis A
dev.read( alshain.Peregrine2.Parameters.ENCODER_B ) # Current encode value, axis B
dev.read( alshain.Peregrine2.Parameters.POSITION_A ) # Current position in encoder steps, axis A
dev.read( alshain.Peregrine2.Parameters.POSITION_B ) # Current position in encoder steps, axis B

dev.read( alshain.Peregrine2.Parameters.TARGET_A ) # Target position, axis A [encoder steps]
dev.read( alshain.Peregrine2.Parameters.TARGET_B ) # Target position, axis B [encoder steps]

dev.read( alshain.Peregrine2.Parameters.STEPRATE_A ) # Current steprate, axis A [steps/s]
dev.read( alshain.Peregrine2.Parameters.STEPRATE_B ) # Current steprate, axis A [steps/s]

dev.read( alshain.Peregrine2.Parameters.ENABLED_A ) # Is axis A enabled [0 -> no, 1 -> yes]
dev.read( alshain.Peregrine2.Parameters.ENABLED_B ) # Is axis B enabled [0 -> no, 1 -> yes]

# Path parameters
dev.read( alshain.Peregrine2.Parameters.PATH_A_T ) # Current path time, axis A [s]
dev.read( alshain.Peregrine2.Parameters.PATH_A_T0 ) # End of acceleration phase, axis A [s]
dev.read( alshain.Peregrine2.Parameters.PATH_A_T1 ) # End of constant velocity phase, axis A [s]
dev.read( alshain.Peregrine2.Parameters.PATH_A_T2 ) # End of deacceleration phase, axis A [s]

dev.read( alshain.Peregrine2.Parameters.PATH_B_T ) # Current path time, axis B [s]
dev.read( alshain.Peregrine2.Parameters.PATH_B_T0 ) # End of acceleration phase, axis B [s]
dev.read( alshain.Peregrine2.Parameters.PATH_B_T1 ) # End of constant velocity phase, axis B [s]
dev.read( alshain.Peregrine2.Parameters.PATH_B_T2 ) # End of deacceleration phase, axis B [s]

dev.read( alshain.Peregrine2.Parameters.PATH_A_X0 ) # Path starting position, axis A [steps]
dev.read( alshain.Peregrine2.Parameters.PATH_A_X1 ) # Path end position, axis A [steps]
dev.read( alshain.Peregrine2.Parameters.PATH_B_X0 ) # Path starting position, axis B [steps]
dev.read( alshain.Peregrine2.Parameters.PATH_B_X1 ) # Path end position, axis B [steps]

# Limit switches
dev.read( alshain.Peregrine2.Parameters.LIMIT_A_MINUS ) # Limit- state, axis A [0/1]
dev.read( alshain.Peregrine2.Parameters.LIMIT_A_PLUS ) # Limit+ state, axis A [0/1]
dev.read( alshain.Peregrine2.Parameters.LIMIT_B_MINUS ) # Limit- state, axis B [0/1]
dev.read( alshain.Peregrine2.Parameters.LIMIT_B_PLUS ) # Limit+ state, axis B [0/1]

# Limit switch mode, options:
# LIMIT_SWITCH_DISABLED -> limit switch disabled
# LIMIT_SWITCH_ENABLED -> limit switch enabled (state change will stop movement)
# LIMIT_SWITCH_INVERTED -> limit switch enabled, polarity inverted

dev.write( alshain.Peregrine2.Parameters.LIMIT_A_MINUS_MODE, alshain.Peregrine.Options.LIMIT_SWITCH_ENABLED )
dev.write( alshain.Peregrine2.Parameters.LIMIT_A_PLUS_MODE, alshain.Peregrine.Options.LIMIT_SWITCH_ENABLED  )
dev.write( alshain.Peregrine2.Parameters.LIMIT_B_MINUS_MODE, alshain.Peregrine.Options.LIMIT_SWITCH_ENABLED  )
dev.write( alshain.Peregrine2.Parameters.LIMIT_B_PLUS_MODE, alshain.Peregrine.Options.LIMIT_SWITCH_ENABLED  )

# Per-axis driver module configuration
# MODULE_UNKNOWN -> no driver module present, movement halted
# MODULE_STEPPER -> stepper driver present, using step/dir to control movement
# MODULE_HBRIDGE -> H-bridge driver (for DC motors) present, using pwm/dir to control movement

dev.write( alshain.Peregrine2.Parameters.MODULE_A, alshain.Peregrine2.Options.MODULE_STEPPER )
dev.write( alshain.Peregrine2.Parameters.MODULE_B, alshain.Peregrine2.Options.MODULE_STEPPER )

# Set driver config pins
# Value = 0..7, 3bit config
# For stepper motor modules with TMC2209:
# 0 (000) -> 1/8  microstepping, stealthChop
# 1 (001) -> 1/32 microstepping, stealthChop
# 2 (010) -> 1/64 microstepping, stealthChop
# 3 (011) -> 1/16 microstepping, stealthChop
# 4 (100) -> 1/8  microstepping, spreadCycle
# 5 (101) -> 1/32 microstepping, spreadCycle
# 6 (110) -> 1/64 microstepping, spreadCycle
# 7 (111) -> 1/8  microstepping, spreadCycle

dev.write( alshain.Peregrine2.Parameters.DRIVE_CFG_A, 0x02 )
dev.write( alshain.Peregrine2.Parameters.DRIVE_CFG_B, 0x02 )

# Motor rotation direction compared to encoder, -1 or 1
dev.write( alshain.Peregrine2.Parameters.MOTOR_DIR_A, 1 )
dev.write( alshain.Peregrine2.Parameters.MOTOR_DIR_B, -1 )

# Servo loop parameters, Peregrine2 uses a LQR for control
dev.write( alshain.Peregrine2.Parameters.ERROR_GAIN_A )
dev.write( alshain.Peregrine2.Parameters.LQR_K0_A )
dev.write( alshain.Peregrine2.Parameters.LQR_K1_A )
dev.write( alshain.Peregrine2.Parameters.DEADZONE_A )
dev.write( alshain.Peregrine2.Parameters.SLEWRATE_A )

dev.write( alshain.Peregrine2.Parameters.ERROR_GAIN_B )
dev.write( alshain.Peregrine2.Parameters.LQR_K0_B )
dev.write( alshain.Peregrine2.Parameters.LQR_K1_B )
dev.write( alshain.Peregrine2.Parameters.DEADZONE_B )
dev.write( alshain.Peregrine2.Parameters.SLEWRATE_B )

dev.read( alshain.Peregrine2.Parameters.EMG_STOP )
# Peregrine sets EMG_STOP_LATCH to 1 when emergency stop activated. User must clear it manually.
# Clears also in power loss
dev.read( alshain.Peregrine2.Parameters.EMG_STOP_LATCH )
dev.write( alshain.Peregrine2.Parameters.EMG_STOP_LATCH, 0 ) # Clear latch value


# Current and voltage monitoring
dev.read( alshain.Peregrine2.Parameters.IMON0 ) # Axis A, driver current [A]
dev.read( alshain.Peregrine2.Parameters.IMON1 ) # Axis B, driver current [A]
dev.read( alshain.Peregrine2.Parameters.A0 ) # Voltage at analog input 0
dev.read( alshain.Peregrine2.Parameters.A1 ) # Voltage at analog input 0
dev.read( alshain.Peregrine2.Parameters.A2 ) # Voltage at analog input 0
dev.read( alshain.Peregrine2.Parameters.VMON ) # Power supply voltage [V]

# Status of GPIO inputs
dev.read( alshain.Peregrine2.Parameters.GPIO0 )
dev.read( alshain.Peregrine2.Parameters.GPIO1 )

# Analog outputs are current DACs, range 0..50mA (0 .. 50e-3 amps)
dev.write( alshain.Peregrine2.Parameters.IDAC1, 0.0 ) # IDAC1 at 0mA
dev.write( alshain.Peregrine2.Parameters.IDAC2, 10e-3 ) # IDAC2 set to 10mA

# If driver module is H-bridge, set PWM override (0..100% -> 0..1000)
dev.write( alshain.Peregrine2.Parameters.HBRIDGE_PWM_A, 500 ) # set to 50% duty cycle
dev.write( alshain.Peregrine2.Parameters.HBRIDGE_PWM_B, 0 ) # 0% duty cycle

# Fault detection, isolation and recovery (FDIR) subsystem parameters
# FDIR system tries to detect stalls and similar situations by monitoring rotational speed from encoder
# and comparing it to target step rate
dev.write( alshain.Peregrine2.Parameters.FDIR_MAX_ERROR_A )
dev.read( alshain.Peregrine2.Parameters.FDIR_STATE_A )

dev.write( alshain.Peregrine2.Parameters.FDIR_MAX_ERROR_B )
dev.read( alshain.Peregrine2.Parameters.FDIR_STATE_B )

# Peregrine2 features an analog triggering feature, stores positions on both rising and falling edge
# Works for analog input channels A0 and A1

# Analog input channel A0
dev.write( alshain.Peregrine2.Parameters.ANALOG_THRESHOLD_0, 0.5 ) # Set trigger threshold for channel A0 to 0.5V
dev.write( alshain.Peregrine2.Parameters.ANALOG_TH_0_HYST, 0.01 ) # Set hysteresis for trigger threshold to 0.01V
dev.read( alshain.Peregrine2.Parameters.ANALOG_TH_0_POS_A ) # Last position for axis A stored when triggered
dev.read( alshain.Peregrine2.Parameters.ANALOG_TH_0_POS_B ) # Last position for axis B stored when triggered
dev.read( alshain.Peregrine2.Parameters.ANALOG_TH_0_STATE ) # State of the trigger comparator, channel A0

# Analog input channel A1
dev.write( alshain.Peregrine2.Parameters.ANALOG_THRESHOLD_1, 1.0 ) # Set trigger threshold for channel A1 to 1.0V
dev.write( alshain.Peregrine2.Parameters.ANALOG_TH_1_HYST, 0.2 ) # Set hysteresis for trigger threshold to 0.2V
dev.read( alshain.Peregrine2.Parameters.ANALOG_TH_1_POS_A )
dev.read( alshain.Peregrine2.Parameters.ANALOG_TH_1_POS_B )
dev.read( alshain.Peregrine2.Parameters.ANALOG_TH_1_STATE )

# Is servo loop enabled (default: yes)
dev.write( alshain.Peregrine2.Parameters.SERVO_LOOP_ENABLED_A, 1 ) # 0 -> disabled, 1 -> enabled
dev.write( alshain.Peregrine2.Parameters.SERVO_LOOP_ENABLED_B, 1 )

Clone this wiki locally