Serve LeRobot supported SO-ARM 101 servo driver board over WebSocket server with nice looking GUI integrated on M5Stack Cardputer mini screen. Supported board & device:
- M5Stack Cardputer
- M5StickC Plus2
The WebSocket server will start listening on port 81 by default.
Servo commands can be issued through WebSocket messages over ws://<device-ip>:81.
The server accepts both the legacy flat JSON payload and a typed message. Typed messages are recommended for new clients.
Event index:
servo:move- Command a servo to move to an absolute or relative position.servo:move:ack- Acknowledges aservo:movecommand with applied values.telemetry:servos- Periodic full-state telemetry for all servos.servos:torque:enable- Enable torque for all servos.servos:torque:disable- Disable torque for all servos.servos:torque:enable:ack- Ack for enabling torque on all servos.servos:torque:disable:ack- Ack for disabling torque on all servos.servo:torque:enable- Enable torque for one servo.servo:torque:disable- Disable torque for one servo.servo:torque:enable:ack- Ack for enabling torque on one servo.servo:torque:disable:ack- Ack for disabling torque on one servo.servo:read- Read a servo register by address/length.servo:read:ack- Ack for reading a servo register.servo:write- Write a servo register by address/length.servo:write:ack- Ack for writing a servo register.servo:eprom:unlock- Unlock EEPROM for a servo.servo:eprom:unlock:ack- Ack for EEPROM unlock.servo:eprom:lock- Lock EEPROM for a servo.servo:eprom:lock:ack- Ack for EEPROM lock.error- Error response for typed messages.
Send a command to move a servo. clamp is optional and limits the allowed
range for this command only.
{
"type": "servo:move",
"data": {
"id": 1,
"pos": 1000,
"delta": 0,
"speed": 1500,
"clamp": { "min": 0, "max": 4095 }
}
}Ack:
{
"type": "servo:move:ack",
"data": {
"id": 1,
"pos": 1000,
"speed": 1500,
"requested": 1200,
"clamped": true,
"clamp": { "min": 0, "max": 1000 }
}
}Notes:
posordeltacan be used; ifposis omitted,deltais applied to the current servo position.requested,clamped, andclampappear only when clamping is used and the requested value differs from the applied value.
Emitted periodically with full servo telemetry.
Note
You can implement force feedback on the client by using load and/or
current as a proxy for resistance. For example, compare the latest load
or current to a threshold and slow down or stop user motion when it rises,
or scale the input by (1 - load/load_max) to soften motion under higher
load.
{
"type": "telemetry:servos",
"data": {
"ts": 123456,
"joints": [
{
"id": 1,
"pos": 960,
"speed": 0,
"load": 12,
"current": 45,
"move": 0,
"voltage": 74,
"temp": 32
}
]
}
}Enable or disable torque for all servos:
{
"type": "servos:torque:enable"
}{
"type": "servos:torque:disable"
}Ack:
{
"type": "servos:torque:enable:ack",
"data": {
"ids": [1, 2, 3, 4, 5, 6],
"enabled": true,
"ok": true
}
}Enable or disable torque for a specific servo:
{
"type": "servo:torque:disable",
"data": { "id": 1 }
}Ack:
{
"type": "servo:torque:disable:ack",
"data": {
"id": 1,
"enabled": false,
"ok": true
}
}Read a register (1 or 2 bytes):
{
"type": "servo:read",
"data": { "id": 1, "addr": 31, "len": 2 }
}Ack:
{
"type": "servo:read:ack",
"data": { "id": 1, "addr": 31, "len": 2, "value": 123 }
}Write a register (1 or 2 bytes):
{
"type": "servo:write",
"data": { "id": 1, "addr": 31, "len": 2, "value": 123 }
}Ack:
{
"type": "servo:write:ack",
"data": { "id": 1, "addr": 31, "len": 2, "value": 123, "ok": true }
}Unlock/lock EEPROM for register writes:
{ "type": "servo:eprom:unlock", "data": { "id": 1 } }{ "type": "servo:eprom:lock", "data": { "id": 1 } }Ack:
{
"type": "servo:eprom:unlock:ack",
"data": { "id": 1, "locked": false, "ok": true }
}The Rust mock server listens on port 81 and accepts the same WebSocket
payloads.
cargo run --bin mock-serverUse ws://localhost:81 for local testing.
