Protocol v2 is how hosts and Tercio S1 drivers talk on the bus. It is small on purpose: an 11-bit ID says who and what, the first data byte says which command, and everything after is little-endian.
CAN-FD frames come in fixed lengths (0–8, 12, 16, 20, 24, 32, 48, 64 bytes), so a payload is padded up to the next one. Ignore bytes after the fields you expect, and accept frames longer than the minimum.
The ID’s upper four bits are the function, the lower seven the node ID (1–127).
ID
Function
Direction
0x000
Broadcast
Host → every node
0x080 + node
Event (faults)
Node → host
0x100 + node
Command
Host → node
0x180 + node
Reply
Node → host
0x200 + node
Telemetry
Node → host
Node 1 listens on 0x101 and 0x000, answers on 0x181, streams telemetry on 0x201 and reports faults on 0x081. Other Tercio nodes, such as the Tercio IMU, use the same scheme and share the 1–127 range; GetInfo’s last byte tells them apart.
Replies. Every command addressed to one node gets a reply on 0x180 + node, with the same opcode and a status. Set the top bit of the opcode (opcode | 0x80) and the node only replies if the command fails: use it to stream moves without doubling the traffic.
Broadcasts (ID 0x000) are not answered, except GetInfo and AssignNodeId. Only these commands act on a broadcast: GetInfo, AssignNodeId, Enable, Stop, EmergencyStop and Sync.
Identity: protocol and firmware version, hardware revision, encoder, node ID and the 12-byte unique ID. Broadcast, every node answers within 64 ms, staggered by unique ID.
Arguments
—
Reply data
Info (20 bytes)
Python
motor.info()
0x01
SaveConfig
Writes every parameter to flash. The step output pauses for the few milliseconds the write takes.
Arguments
—
Reply data
—
Refused with
Busy while moving or during a procedure. StorageError if the flash write failed.
Python
motor.save()
0x02
FactoryReset
Restores the factory defaults in RAM, keeping the node ID. Send SaveConfig to make it stick.
Arguments
—
Reply data
—
Refused with
Busy unless the motor is disabled.
Python
motor.factory_reset()
0x03
Reboot
Restarts the driver 20 ms after replying.
Arguments
—
Reply data
—
Python
motor.reboot()
0x04
ClearFaults
Clears latched faults. Hard faults stay if their cause is still there.
Arguments
—
Reply data
—
Refused with
Faulted if the driver is still hot, shorted or silent, the board is within 5 °C of the shutdown temperature, or the encoder still cannot be read.
Python
motor.clear_faults()
0x05
AssignNodeId
Broadcast only
Gives a new node ID to the driver with this unique ID, even when several drivers share an ID. It answers from its new ID. Applied immediately; send SaveConfig to keep it.
Arguments
u8[12] uid u8 id
Reply data
—
Refused with
Sent to a single node instead of broadcast: BadValue.
Python
bus.assign_node_id(uid, id)
0x08
GetParam
Reads one parameter.
Arguments
u8 param
Reply data
[u8 param][4-byte value]
Refused with
UnknownParam.
Python
motor.get_param(Param.param)
0x09
SetParam
Writes one parameter (RAM; SaveConfig persists). The reply carries the value as applied.
Arguments
u8 param f32 value
Reply data
[u8 param][4-byte value]
Refused with
UnknownParam, ReadOnly, BadValue (out of range) or Busy (the parameter can only change when stopped or disabled).
Turns the motor a quarter turn each way to learn the encoder direction and check the scale, then sets zero here and saves. Enables the motor itself.
Arguments
—
Reply data
— (the procedure runs on; watch the state)
Refused with
Faulted without encoder readings, Busy during another procedure.
Python
motor.calibrate()
0x21
Home
Finds the reference with the homing parameters (a switch or a hard stop), backs off and sets zero there.
Arguments
—
Reply data
— (the procedure runs on; watch the state)
Refused with
As MoveTo.
Python
motor.home()
0x22
AutoTune
Runs back and forth between two positions, faster each pass, and keeps the fastest velocity and acceleration that pass three times. Saved automatically.
Arguments
f32 min f32 max
Reply data
— (the procedure runs on; watch the state)
Refused with
BadValue if the range is under 5/6 turn (0.8333 turns); otherwise as MoveTo.
Python
motor.auto_tune(min, max)
A procedure command replies as soon as the procedure starts. Follow it in telemetry: the state is Calibrating, Homing or Tuning while it runs, and the procedure step field says which phase. When it ends, the state returns to Holding; a failure also sets the matching fault.
GetParam and SetParam carry one parameter as [u8 id] [4-byte value]: integers zero-extended to 32 bits, booleans 0 or 1, floats as IEEE 754 single precision, all little-endian. SetParam’s reply returns the value as the driver applied it.
Discover: broadcast GetInfo. Each node replies from its own ID after a delay of 0–63 ms derived from its unique ID, so several nodes sharing an ID still answer one by one, each with its unique ID.
Assign: broadcast AssignNodeId with [uid 12 bytes] [u8 new id]. Only the node with that unique ID takes the new ID and replies from it. Send SaveConfig to the new ID to keep it.
SetParam NodeId to a single node works too: its reply still comes from the old ID, then it switches.
MoveTo and MoveBy with flag bit 0 set are queued: the node checks and stores the move, replies Ok and sets the move pending flag. A broadcast Sync starts every queued move on every node at the same moment. Stop, Enable 0 and EmergencyStop discard a queued move.