GuidesDrive an actuator
Drive a single actuator
Talk to one MAKIINA drive over CAN without a server: find it, read its state, move it, tune it and stream its state at a high rate.
makiina.actuator talks straight to one MAKIINA drive over a USB CAN adapter, with no robot server in between. Use it when you build your own machine around MAKIINA actuators, for bench tests, or to look at one drive closely. This guide goes from finding the drive to smooth, tuned motion.
All values are in SI units at the output shaft: radians, rad/s, amperes, N m, and degrees Celsius. Only one program can hold the adapter, so close the Robot Console's session first.
Find the drive
Every drive answers on its own CAN id. Sweep the adapter to list them:
from makiina.actuator import list_channels
from makiina.calibration.discovery import discover_bus
list_channels() # your adapters
for board in discover_bus("candle", "207137C04845500F2:0"):
print(board.id, board.version, board.part, board.label)
# 1454 (2, 5) right_arm J1The sweep only reads: it asks every possible id for its position and notes which ones answer, then asks each drive what it is. It takes about a second. The Robot Console's On this PC page shows the same ids on each board of an arm.
Connect
from makiina.actuator import Actuator
act = Actuator(1454, interface="candle", channel="207137C04845500F2:0")Several Actuator objects can share one adapter. In a script, prefer the with form so the bus is released however the script ends:
with Actuator(1454, interface="candle", channel="207137C04845500F2:0") as act:
print(act.get_states())With exactly one adapter plugged in you can leave out interface and channel.
Read its state
frame = act.get_states()
frame.position # rad, multi-turn
frame.velocity # rad/s
frame.current # A, the torque-producing current
frame.torque # N m, an estimate (NaN on classic CAN frames)
frame.temperature # degrees C (NaN on classic CAN frames)Set the limits
act.max_current = 3.0 # A: the safety knob; weak enough to stop by hand
act.max_velocity = 20.0 # rad/s while it tracks a position target
act.output_ramp = 1000.0 # lower is a softer start
act.set_position_mode()With a low current limit the drive cannot hurt you or itself. Raise it only when you need the torque.
Move it
act.target_pos = act.current_pos + 1.0 # one radian from where it isThe drive runs to the target at up to max_velocity and holds it. For a smooth back and forth, stream targets on a cosine, so the velocity is zero at both ends of the stroke:
import math, time
center = act.current_pos
t0 = time.time()
while time.time() - t0 < 12:
phase = (time.time() - t0) / 4.0 * 2 * math.pi # 4 s per cycle
act.target_pos = center + 3.0 * (1 - math.cos(phase)) / 2 # 3 rad stroke
time.sleep(0.01)
act.target_pos = centerInterrupt it whenever you like; the drive holds the last target it got.
Choose a control mode
| Mode | Set it with | Then command |
|---|---|---|
| position | set_position_mode() | target_pos, rad |
| velocity | set_velocity_mode() | target_velocity, rad/s |
| current | set_current_mode() | target_current, A |
| torque | set_torque_mode() | target_torque, N m |
| free | set_free_mode(True) | nothing: the shaft turns by hand, with cogging compensation |
Tune it
Gains are properties; set them and read them back from the drive:
act.kp_angle = 20.0 # position stiffness
act.configure_adaptive_vpid(enabled=True, p_min=0.1, p_max=0.4,
i_min=0.2, i_max=0.6,
vel_min_rad_s=0.0, vel_max_rad_s=30.0)
act.position_filter_amount = 0.06 # light smoothing of targets
act.kp_angle # 20.0, read from the drive
act.read_settings(["kp_angle", "max_current"])
act.read_settings() # every setting, as a dictEvery read is one round trip on the bus, so read when you want to look, not inside a control loop. Reading settings needs firmware 2.04 or later. Tune the joints live explains what the gains do.
Stream state at a high rate
Asking for the state costs a round trip each time. In broadcast mode the drive sends its state on its own, at the rate you choose:
act.start_broadcast(500.0) # frames per second
frame = act.get_next_broadcast_frame(timeout_s=0.1) # every frame, in order
act.get_latest_velocity() # the newest value, no waiting
act.stop_broadcast()Use get_next_broadcast_frame() to record every frame, and the latest readers in a control loop that only needs the newest value. A robot uses the same mechanism at 60 Hz per drive.
Let go
act.stop_broadcast()
act.set_free_mode(True) # optional: let the shaft turn freely
act.close()close() releases the bus and sends nothing to the drive: while powered, it keeps holding its last target unless you put it in free mode first.
Go further
makiina.actuator.protocol documents the CAN wire format, if you want to talk to the drive from your own stack. The full list of functions and properties is in the makiina.actuator reference.