from pcp_api import PCP_over_USB, PulsarActuator
from time import sleep
Instantiate the adapter¶
Pulsar devices understand the PCP protocol, which can be transmitted over USB or CAN. The devices have a built-in USB interface, so you can connect directly to the actuator via USB. Alternatively, you can use a CAN to USB adapter to connect to the actuator over a CAN bus. This adapter is connected to the host computer via USB, so in both cases, you will use the PCP_over_USB class to create the adapter.
port = PCP_over_USB.get_port() # The serial port or the device (Actuator or CAN adapter) will be auto-detected
# port = "COM1" # you can specify a port if there is multiple devices
print(f"Connecting to {port}")
adapter = PCP_over_USB(port)
Instantiate the actuator¶
You can instantiate as many actuators as you want with the same CAN adapter. In this example we are going to control only one actuator, connected directly via USB. If you are using a CAN adapter, you need to specify the PCP address of the actuator. The PCP address must be unique for each actuator. You can find this address with the CLI scan command. If you are connecting directly via USB, use 0 as the address.
ACTUATOR_ADDRESS = 0 # 0 for direct USB connection, or use the actuator address if using CAN adapter
actuator = PulsarActuator(adapter, ACTUATOR_ADDRESS)
actuator.connect()
print(f"Connected to the actuator {actuator.address} (model: {actuator.model}, firmware: {actuator.firmware_version})")
Configure feedback¶
First, define a function to handle the feedback from the actuator. This function will be called whenever new feedback is received from the actuator.
def actuator_feedback(address: int, feedback: dict):
print(feedback)
Set up the feedback, the feedback loop is intended for high frequency feedback like speed, position, torque, ...
You can set the feedback items you want to receive. The items are defined in PulsarActuator.PCP_Items. The rates are defined in PulsarActuator.Rates, and you can choose from RATE_1HZ, RATE_10HZ, RATE_100HZ, RATE_1KHZ, or DISABLED to disable the feedback. Integer values can also be used to set custom rates in Hz, for example, 5 for 5 Hz.
actuator.setFeedbackItems([
PulsarActuator.PCP_Items.SPEED_FB,
PulsarActuator.PCP_Items.POSITION_FB,
PulsarActuator.PCP_Items.TORQUE_FB,
# You can add more items as needed
])
actuator.setFeedbackRate(actuator.Rates.RATE_10HZ)
# Set the feedback callback function to handle the feedback data
actuator.set_feedback_callback(actuator_feedback)
# feedback_callback can be set to None to disable it
# and read the feedback manually with actuator.get_feedback()
Other type of feedback, like temperatures or bus voltage can be requested asynchronously when needed
other_feedback = actuator.getItemsBlocking([
PulsarActuator.PCP_Items.VBUS,
PulsarActuator.PCP_Items.TEMP_PCB,
PulsarActuator.PCP_Items.TEMP_MOTOR,
])
print(other_feedback)
Configure control settings¶
You can choose from different control modes, such as SPEED, POSITION, or TORQUE. These are defined in PulsarActuator.Mode. Run only one of the following code blocks to test each control mode. The units are in SI: speed in rad/s, position in radians, and torque in Nm.
actuator.change_mode(PulsarActuator.Mode.SPEED)
actuator.change_setpoint(1.0) # rad/s
actuator.change_mode(PulsarActuator.Mode.TORQUE)
actuator.change_setpoint(2.0) # Nm
actuator.change_mode(PulsarActuator.Mode.POSITION)
actuator.set_home_position() # Sets the current position as the zero reference
actuator.change_setpoint(3.1416) # (rad) target position at about 180 degrees from home
Start the actuator¶
Start the actuator with the start() method. The actuator will begin following the setpoint you defined and feedback will be received at the configured rates. It is advisable to wrap the control loop in a try/finally block to ensure the actuator is properly disconnected when the program is interrupted.
try:
actuator.start()
print("Actuator started. Press Stop to interrupt.")
while True:
sleep(0.1) # actuator_feedback() should be triggered
except KeyboardInterrupt:
pass
finally:
actuator.disconnect() # also stops the actuator
sleep(0.1)
adapter.close()