Skip to content
Software

Arduino library

3 min readFirmware v2 · protocol v2

The same protocol for microcontrollers: TercioBridge.h and .cpp, no dynamic allocation, talking to the Tercio FD over any Arduino Stream.

The Tercio FD is a USB device. To use it from a microcontroller, the board must be a USB host that exposes the adapter as a serial Stream:

  • Teensy 4.1 or 4.0With the USBHost_t36 library’s USBSerial.
  • Any other USB-host boardWith a CDC (ACM) serial class that is an Arduino Stream.

Copy TercioBridge.h and TercioBridge.cpp from the repository into your sketch folder.

#include <USBHost_t36.h>
#include "TercioBridge.h"
USBHost usb;
USBSerial fd(usb); // the Tercio FD
Tercio::Bus bus(fd);
Tercio::Stepper motor(bus, 1, Tercio::Unit::Degrees);
void onFault(uint8_t node, uint16_t faults, uint16_t warnings, Tercio::AxisState state) {
Serial.printf("node %u fault 0x%04x\n", node, faults);
}
void setup() {
Serial.begin(115200);
usb.begin();
fd.begin(115200); // any baud: it is USB
while (!fd) usb.Task(); // wait for the adapter
bus.onFault(onFault);
if (motor.enable() != Tercio::Status::Ok) Serial.println("enable refused");
motor.moveTo(90.0);
}
void loop() {
usb.Task();
bus.poll(); // every iteration
Tercio::Telemetry t;
if (motor.telemetry(t) && t.state == Tercio::AxisState::Holding && (t.flags & Tercio::flag::Settled)) {
static bool back = false;
motor.moveTo(back ? 0.0 : 90.0);
back = !back;
}
}
Bus(Stream& io, uint32_t timeoutMs = 200) timeoutMs: how long request waits for a reply.
poll() Parses everything received. Call it every loop iteration.
request(node, cmd, payload, length, reply, replyLength) Sends a command and waits for its reply (polling). Returns the Status, or Status::Timeout.
command(node, cmd, payload, length) Fire and forget: the node only answers if it refuses.
send(canId, opcode, payload, length) Raw frame.
stopAll(), emergencyStopAll(), sync() Broadcasts.
telemetry(node, out) Latest telemetry; false if none yet. Tracks up to 16 nodes.
onFault(callback) void (*)(uint8_t node, uint16_t faults, uint16_t warnings, AxisState state)
adapterStatus(out), framingErrors() Adapter bus health and damaged frames.

Stepper(bus, nodeId, Unit::Degrees), with Unit::Turns, Unit::Degrees or Unit::Radians. Every call returns a Status.

Method Does
enable(), disable(), stop(), emergencyStop() As in the protocol.
moveTo(pos, velocity = 0, acceleration = 0, deferred = false, ack = true) Absolute move in the stepper’s unit. 0 = use the limits. ack = false streams.
moveBy(delta, …) Relative move.
setVelocity(v, acceleration = 0) Continuous rotation.
setZero(pos = 0) The current position becomes pos.
calibrate(), home(), autoTune(min, max) Start a procedure; watch telemetry().state.
getParam(Param, float&), getParam(Param, uint32_t&), setParam(Param, value) Parameters in wire units (turns).
setNodeId(id), save(), clearFaults(), reboot() System commands.
telemetry(out), position(out) Latest state; position in the stepper’s unit.

Telemetry has state, flags, faults, warnings, position, target (turns), velocity, followingError, temperatureC, supplyV, procedureStep, sequence, controlLoadPct and receivedMs.

Tercio::Imu imu(bus); // node 100
imu.zero(); // or imu.zero(true): heading only
Tercio::ImuTelemetry t;
if (imu.telemetry(t)) {
Serial.printf("roll %.1f pitch %.1f yaw %.1f\n", t.roll, t.pitch, t.yaw);
if (t.flags & Tercio::imu_flag::Calibrated) imu.saveCalibration();
}

ImuTelemetry has state, flags, faults, warnings, calSystem/calGyro/calAccel/calMag (0–3), quaternion[4], roll, pitch, yaw, acceleration[3], rate[3], temperatureC and receivedMs. Imu also has clearZero(), save(), clearFaults(), reboot(), getParam() and setParam() with ImuParam. The bus tracks up to 4 IMUs.

  • request blocks until the reply arrives (a few milliseconds) or the timeout. In a fast loop, stream moves with ack = false.
  • Set Stop if host is silent for on each motor, so a crashed sketch stops the axes.