Repository navigation
docs: Bus/ServoDefinition as the higher-level API for LeRobot - #146
Closed
pierre-rouanet wants to merge 6 commits into
Closed
pierre-rouanet wants to merge 6 commits into
pierre-rouanet wants to merge 6 commits into
Conversation
Finding the motors on a port meant reading the model number of every id in turn, under a short timeout so that 254 absent ids do not take minutes. That timeout has to be short (5 ms) for the sweep to stay usable, and a USB adapter with a 16 ms latency timer, such as the FTDI chip of a U2D2, can hold a healthy motor's answer longer than that. A broadcast ping reaches every motor with one instruction; each one that hears it answers in turn. The handler listens for one window, sized like the vendor SDKs size it: the status packets of every possible id, 3 ms of turn per id and 16 ms of adapter latency, about 0.8 s at 1 Mbps. A status packet that does not parse is skipped; the port's timeout is put back. Checked on two SO-101 arms (six STS3215 each): the six ids at 1 Mbps, none at 500 kbps or 115.2 kbps, in 790 ms.
ServoDefinition::scan read the model number of every id asked, each under a 5 ms timeout. Behind a USB adapter that holds short answers for its 16 ms latency timer, a motor that is there reads as absent, and a full sweep at one baud rate costs 254 timeouts. A definition now states whether its firmware answers a broadcast ping: the protocol v2 Dynamixel (XL320, XL330, XL430) and the Feetech STS3215 do, the protocol v1 Dynamixel and the Feetech SCS do not. For those that do, scan pings once and reads the model number of the motors that answered only, under the port's own timeout, so the adapter's latency is covered once for the whole bus. The others keep the sweep. On two SO-101 arms, scan_all through the STS3215 definition finds the six motors (777) in 0.8 s, where the sweep takes 1.3 s.
Setting up a new motor means giving it its id and the bus's baud rate. Both live in EEPROM: a Dynamixel only writes it with the torque off, a Feetech also needs its lock register open, and the baud rate register takes a code, not a rate. Every caller has to know all three, and LeRobot does it by hand for each family. change_id and change_baudrate on ServoDefinition and Bus do it: torque off, lock open where the servo has one (writing 0 is harmless on the AX and MX, whose lock only clears at power-up), then the write; the baud rate is looked up in the definition's baudrates, and a rate it does not list fails as a RegisterError before anything is sent. Like scan, they take the definition and reach motors the bus does not have, since a new motor answers at its factory id. Checked on an SO-101 leader: its gripper motor taken from id 6 to 7 and back, then to 500 kbps and back to 1 Mbps, each step confirmed by a scan.
Both static methods built their dict from a HashMap, so its order changed from one process to the next. A caller trying each baud rate in turn to find a motor (LeRobot's setup does) tried them in a different order on every run, and took a different time to find the same motor. They now come from a BTreeMap: baud rates slowest first, models by name. The return type is still a dict.
The README listed two APIs, the protocol handler and the controllers. Bus and ServoDefinition have become a third one: they work across servo families, reach registers by name and cover motor setup, and some of their choices are LeRobot conventions (change_id leaves the torque off and the Feetech lock open). Say so in the README, the bus and definition module docs and the Python Bus docstring, so other users pick the controllers when they want typed access to one servo family. Refs #145 Assisted-by: Claude:claude-opus-5-5
Refs #145 Assisted-by: Claude:claude-opus-5-5
pierre-rouanet
marked this pull request as ready for review
October 5, 2026 13:14
nicolas-rabault
force-pushed
the
feat/motor-setup
branch
2 times, most recently
from
October 5, 2026 13:41
dbfeffa to
cf861c5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #145.
Says explicitly that
Bus/ServoDefinitionare a higher-level API, designed mostly for LeRobot:DynamixelProtocolHandler(protocol), the controllers and typed module functions (general purpose, one servo family), andServoDefinition/Bus(works across families, registers by name, motor setup, built mostly for LeRobot and carrying some of its conventions).src/bus.rs: the module doc and the PythonBusdocstring say the same, withchange_id/change_baudrateleaving the torque off and the lock open as the example of a convention.src/servo/definition.rs: the module doc points to the bus doc.This is based on #142 (
feat/motor-setup) and should merge after it. Once #143 has landed, the convention list can also mention the lock following the torque inset_torque, andfind_modeland the servo facts.Docs only:
cargo docshows no new warnings, and the doc tests pass.🤖 Generated with Claude Code