Impedance Control

This example demonstrates a simple PD-style impedance controller that commands actuator torque to maintain a particular position. It shows how to initialize an ActuatorGroup, zero the encoder, read position, compute PD torque, and send torque commands at a fixed control frequency.

Demo Video

Code

"""
This script will control the output shaft to a set position using the input positional and velocity gains.
"""

from epicallypowerful.actuation import ActuatorGroup
from epicallypowerful.toolbox import TimedLoop


##################################################################
# SET CLOCK SPECIFICATIONS
##################################################################

# Set control loop frequency
OPERATING_FREQ = 200 # [Hz]
clocking_loop = TimedLoop(rate=OPERATING_FREQ)

##################################################################
# INITIALIZE DEVICES & VISUALIZER
##################################################################

# Determine number of connected actuators. This assumes a uniform actuator type (i.e. all are AK80-9)
actuator_type = input(
    "\nSpecify actuator type (see actuation.motor_data for possible types): "
)

# Get actuator IDs
actuator_id = input("Specify actuator id: ")
actuator_id = int(actuator_id)
initialization_dict = {actuator_id:actuator_type}

# Initialize actuator object from dictionary
acts = ActuatorGroup.from_dict(initialization_dict)

##################################################################
# SET CONTROLLER PARAMETERS (PLAY AROUND WITH THESE!)
##################################################################

GAIN_KP = 2 # proportional gain
GAIN_KD = 0.1 # derivative gain
error_current = 0 # initialize, will change in loop
prev_error = 0 # initialize, will change in loop
position_desired = 0 # [rad]

##################################################################
# MAIN OPERATING LOOP
##################################################################

# Zero actuator encoder
acts.zero_encoder(actuator_id)

# Run control loop at set frequency
while clocking_loop():
    print('\033[A\033[A\033[A')
    print(f'| Actuator | Position [rad] | Velocity [rad/s] | Torque [Nm] |')

    # Get data from actuator
    act_data = acts.get_data(ACT_ID)

    # Update position error
    position_current = acts.get_position(can_id=ACT_ID, degrees=False)
    prev_error = error_current
    error_current = position_desired - position_current
    errordot_right = (error_current - prev_error) / (1 / OPERATING_FREQ)

    # Update torques
    torque_desired = GAIN_KP*error_current + GAIN_KD*errordot_right
    acts.set_torque(can_id=ACT_ID, torque=torque_desired)

    print(f'| {int(ACT_ID):^5} | {act_data.current_position:^14.2f} | {act_data.current_velocity:^16.2f} | {act_data.current_torque:^11.2f} |')

Code is available here