Preparing PR summary and instructions
Implemented ✅ — I added a PR-ready change in LeRobot to do exactly what you asked:
In broadcast_ping(), it still logs the original message first:
"Some motors found returned an error status: ..."If any motor has ERRBIT_VOLTAGE, it now logs:
Then it performs extra register reads (second round trip) and logs:
StatusPresent_VoltageMin_Voltage_LimitMax_Voltage_Limitwith raw comm/error fields and derived volts.
So this is exactly the staged behavior you requested:
lerobot/src/lerobot/motors/feetech/feetech.py
VOLTAGE_DIAGNOSTIC_REGISTERS_has_voltage_error(...)_read_voltage_diagnostics(...)broadcast_ping(...) to do two-stage reportinglerobot/tests/motors/test_feetech.py
test_broadcast_ping_voltage_error_logs_extra_diagnostics(...)You were exactly right to ask this:
The initial broadcast ping status packet does not include min/max/present voltage register values.
So we must do a second read pass to fetch those details.
I compiled modified files successfully (py_compile), but couldn’t run full pytest locally because this environment is missing test tooling/deps (pytest, serial in that test env).
If you want, I can also draft the exact PR title + description text for you to paste into GitHub.
Mapping hardware discovery flow
Yeah we're on the scan mode.
Searching error bit usage
Locating SDK error mapping
Checking syntax via compileall
And how did you come up with these values and all this information and shit? How did you find all of this that you told me about? Can you make me just a really quick bullet point of sources?
Preparing script execution command
Can you write a PR against the robot library updating the error? When it gives this voltage mismatch error, actually fetch this extra information and pass that back into the library and then also do it nicely in a way that:
Evaluating snippet line numbering
Identifying file reading need
Switching to monkeypatch for error simulation
Adding voltage diagnostics to broadcast ping
Searching voltage register locations
Searching command entry
Proposing dry-run default and confirmation
Perfect — I wrote a read-only diagnostic script here:
scripts/inspect_feetech_voltage_readonly.pyIt does not write any registers. It only:
It should help answer exactly your question: is there extra info beyond the UX-level message?
(especially raw error byte and multiple flags, not just the first mapped string).
python scripts/inspect_feetech_voltage_readonly.py \ --port /dev/tty.usbmodem59710814421 \ --baudrate 1000000 \ --protocol 0python scripts/inspect_feetech_voltage_readonly.py \ --port /dev/tty.usbmodem59710814421 \ --id 1If you want, I can run one of these now — but I’ll wait for your go-ahead as requested.
Planning detailed error enrichment
Reviewing test segment style
Yeah run the scan mode.
Inspecting motor setup command
Adding type tests for nested dicts
Planning voltage error tests
Inspecting voltage limit usage
Verifying modified code stability
Inserting helper methods near broadcast
Yep — quick source list:
CLI entrypoint
lerobot/pyproject.toml
lerobot-setup-motors="lerobot.scripts.lerobot_setup_motors:main"Command flow
lerobot/src/lerobot/scripts/lerobot_setup_motors.pylerobot/src/lerobot/robots/so_follower/so_follower.py (setup_motors)lerobot/src/lerobot/motors/motors_bus.py (setup_motor)Where your exact log comes from
lerobot/src/lerobot/motors/feetech/feetech.py (broadcast_ping)Some motors found returned an error status: ...Why message string is exactly that
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py
ERRBIT_VOLTAGE = 1getRxPacketError() → "[RxPacketError] Input voltage error!"Where voltage registers/addresses come from
lerobot/src/lerobot/motors/feetech/tables.py
Present_Voltage = (62, 1)Min_Voltage_Limit = (15, 1)Max_Voltage_Limit = (14, 1)Status = (65, 1)Evidence in tests that voltage error is expected behavior
lerobot/tests/motors/test_feetech.py
"[RxPacketError] Input voltage error!" for ERRBIT_VOLTAGEHardware confirmation from your actual device
scripts/inspect_feetech_voltage_readonly.py on your port:
Present_Voltage = 122 (~12.2V)Max_Voltage_Limit = 80 (~8.0V)0x01 (voltage bit)Planning user diff and commit interaction
Preparing detailed PR description
Summarizing observed limits
Done — scan mode ran successfully.
sts3215)0x01 = Input voltage errorPresent_Voltage: 122 → ~12.2VMax_Voltage_Limit: 80 → ~8.0VMin_Voltage_Limit: 40 → ~4.0VSo yes, there is more information than the UX message:
Also confirmed: this script performed only ping/read operations (no writes).
If you want, next I can extend the script to decode bitfields like Unloading_Condition and LED_Alarm_Condition into human-readable flags too.
Considering config inspection for follower
Planning non-destructive Feetech script
Summarizing hardware error handling
Great question — I traced the source in ./lerobot/, and the key thing is:
LeRobot is not hardcoding “7.4V motor with 12V supply” checks itself.
It relies on the motor firmware status error bits returned in Feetech status packets.
lerobot/pyproject.toml → lerobot-setup-motors="lerobot.scripts.lerobot_setup_motors:main"lerobot/src/lerobot/scripts/lerobot_setup_motors.pylerobot/src/lerobot/robots/so_follower/so_follower.py → SOFollower.setup_motors()self.bus.setup_motor(motor)lerobot/src/lerobot/motors/motors_bus.py → SerialMotorsBus.setup_motor()_find_single_motor(...)lerobot/src/lerobot/motors/feetech/feetech.py_find_single_motor_p0() → broadcast_ping()broadcast_ping() collects per-motor status/error and logs:
Some motors found returned an error status: ...[RxPacketError] Input voltage error!In SDK (not LeRobot core logic):
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py
ERRBIT_VOLTAGE = 1getRxPacketError() maps that bit to:
"[RxPacketError] Input voltage error!"So physically, the motor firmware detects out-of-range voltage, sets error bit in status byte, and LeRobot surfaces it.
{id, error_byte, payload}error & 0x01 => voltage)Present_Voltage, Min_Voltage_Limit, Max_Voltage_LimitLeRobot currently mostly does:
If you want, next I can help you add a debug patch in LeRobot so setup-motors prints:
Present_Voltage,>rg -n "setup-motors|setup_motors|lerobot-setup-motors|so101_follower|Input voltage error|RxPacketError" lerobotlerobot/pyproject.toml:219:lerobot-setup-motors="lerobot.scripts.lerobot_setup_motors:main"
lerobot/docs/source/smolvla.mdx:101: --robot.type=so101_follower \
lerobot/docs/source/integrate_hardware.mdx:21:For a good example of how it can be used, you can have a look at our own [SO101 follower implementation](https://github.com/huggingface/lerobot/blob/main/src/lerobot/robots/so_follower/so101_follower/so101_follower.py)
lerobot/docs/source/lekiwi.mdx:125:lerobot-setup-motors \
lerobot/docs/source/il_robots.mdx:49: --robot.type=so101_follower \
lerobot/docs/source/il_robots.mdx:178: --robot.type=so101_follower \
lerobot/docs/source/il_robots.mdx:400: --robot.type=so101_follower \
lerobot/docs/source/backwardcomp.mdx:120: --robot.type=so101_follower \
lerobot/docs/source/koch.mdx:95:For a visual reference on how to set the motor ids please refer to [this video](https://huggingface.co/docs/lerobot/en/so101#setup-motors-video) where we follow the process for the SO101 arm.
lerobot/docs/source/koch.mdx:97:<hfoptions id="setup_motors">
lerobot/docs/source/koch.mdx:101:lerobot-setup-motors \
lerobot/docs/source/koch.mdx:118:follower.setup_motors()
lerobot/docs/source/koch.mdx:173:<hfoptions id="setup_motors">
lerobot/docs/source/koch.mdx:177:lerobot-setup-motors \
lerobot/docs/source/koch.mdx:194:leader.setup_motors()
lerobot/docs/source/lerobot-dataset-v3.mdx:34: --robot.type=so101_follower \
lerobot/docs/source/so100.mdx:90:For a visual reference on how to set the motor ids please refer to [this video](https://huggingface.co/docs/lerobot/en/so101#setup-motors-video) where we follow the process for the SO101 arm.
lerobot/docs/source/so100.mdx:92:<hfoptions id="setup_motors">
lerobot/docs/source/so100.mdx:96:lerobot-setup-motors \
lerobot/docs/source/so100.mdx:113:follower.setup_motors()
lerobot/docs/source/so100.mdx:168:<hfoptions id="setup_motors">
lerobot/docs/source/so100.mdx:171:lerobot-setup-motors \
lerobot/docs/source/so100.mdx:187:leader.setup_motors()
lerobot/docs/source/so101.mdx:117: src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/setup_motors_so101_2.mp4"
lerobot/docs/source/so101.mdx:127:<hfoptions id="setup_motors">
lerobot/docs/source/so101.mdx:131:lerobot-setup-motors \
lerobot/docs/source/so101.mdx:132: --robot.type=so101_follower \
lerobot/docs/source/so101.mdx:148:follower.setup_motors()
lerobot/docs/source/so101.mdx:203:<hfoptions id="setup_motors">
lerobot/docs/source/so101.mdx:207:lerobot-setup-motors \
lerobot/docs/source/so101.mdx:224:leader.setup_motors()
lerobot/docs/source/so101.mdx:370: --robot.type=so101_follower \
lerobot/tests/test_cli_peft.py:226: "--robot.type=so101_follower",
lerobot/src/lerobot/motors/feetech/feetech.py:421: display_dict = {id_: self.packet_handler.getRxPacketError(err) for id_, err in ids_errors.items()}
lerobot/src/lerobot/motors/motors_bus.py:215: def getRxPacketError(self, error): ...
lerobot/src/lerobot/motors/motors_bus.py:958: raise RuntimeError(self.packet_handler.getRxPacketError(error))
lerobot/src/lerobot/motors/motors_bus.py:1046: raise RuntimeError(f"{err_msg} {self.packet_handler.getRxPacketError(error)}")
lerobot/src/lerobot/motors/motors_bus.py:1107: raise RuntimeError(f"{err_msg} {self.packet_handler.getRxPacketError(error)}")
lerobot/src/lerobot/robots/openarm_follower/openarm_follower.py:216: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/so_follower/config_so_follower.py:45:@RobotConfig.register_subclass("so101_follower")
lerobot/src/lerobot/teleoperators/bi_so_leader/bi_so_leader.py:92: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/bi_so_leader/bi_so_leader.py:93: self.left_arm.setup_motors()
lerobot/src/lerobot/teleoperators/bi_so_leader/bi_so_leader.py:94: self.right_arm.setup_motors()
lerobot/src/lerobot/teleoperators/so_leader/so_leader.py:133: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/so_follower/so_follower.py:171: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/bi_openarm_leader/bi_openarm_leader.py:109: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/openarm_mini/openarm_mini.py:258: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/lekiwi/lekiwi.py:201: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/koch_leader/koch_leader.py:156: def setup_motors(self) -> None:
lerobot/src/lerobot/async_inference/constants.py:29:SUPPORTED_ROBOTS = ["so100_follower", "so101_follower", "bi_so_follower", "omx_follower"]
lerobot/src/lerobot/robots/omx_follower/omx_follower.py:161: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/openarm_leader/openarm_leader.py:180: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/bi_openarm_follower/bi_openarm_follower.py:133: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/omx_leader/omx_leader.py:145: def setup_motors(self) -> None:
lerobot/src/lerobot/scripts/lerobot_setup_motors.py:21:lerobot-setup-motors \
lerobot/src/lerobot/scripts/lerobot_setup_motors.py:58: "so101_follower",
lerobot/src/lerobot/scripts/lerobot_setup_motors.py:77:def setup_motors(cfg: SetupConfig):
lerobot/src/lerobot/scripts/lerobot_setup_motors.py:86: device.setup_motors()
lerobot/src/lerobot/scripts/lerobot_setup_motors.py:90: setup_motors()
lerobot/src/lerobot/robots/koch_follower/koch_follower.py:178: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/bi_so_follower/bi_so_follower.py:117: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/bi_so_follower/bi_so_follower.py:118: self.left_arm.setup_motors()
lerobot/src/lerobot/robots/bi_so_follower/bi_so_follower.py:119: self.right_arm.setup_motors()
lerobot/src/lerobot/robots/hope_jr/hope_jr_hand.py:153: def setup_motors(self) -> None:
lerobot/src/lerobot/scripts/lerobot_teleoperate.py:22: --robot.type=so101_follower \
lerobot/src/lerobot/robots/hope_jr/hope_jr_arm.py:123: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/utils.py:39: elif config.type == "so101_follower":
lerobot/tests/async_inference/test_robot_client.py:247: error: argument --robot.type: invalid choice: 'so101_follower' (choose from )
lerobot/tests/async_inference/test_robot_client.py:259: "so101_follower",
lerobot/tests/motors/test_dynamixel.py:164: RuntimeError, match=re.escape("[RxPacketError] The data value exceeds the limit value!")
lerobot/tests/motors/test_dynamixel.py:220: RuntimeError, match=re.escape("[RxPacketError] The data value exceeds the limit value!")
lerobot/tests/motors/test_feetech.py:191: with pytest.raises(RuntimeError, match=re.escape("[RxPacketError] Input voltage error!")):
lerobot/tests/motors/test_feetech.py:251: with pytest.raises(RuntimeError, match=re.escape("[RxPacketError] Input voltage error!")):>./.venv/bin/python -m pytest -q lerobot/tests/motors/test_feetech.py -q/Users/mukund/dev/robot-1/.venv/bin/python: No module named pytest
Command exited with code 1>rg -n "Max_Voltage_Limit|Min_Voltage_Limit|Present_Voltage|MODEL_PROTOCOL|sts3215" lerobot/src/lerobot/motors/feetech/tables.py53: "Max_Voltage_Limit": (14, 1),
54: "Min_Voltage_Limit": (15, 1),
86: "Present_Voltage": (62, 1), # read-only
116: "Max_Voltage_Limit": (14, 1),
117: "Min_Voltage_Limit": (15, 1),
140: "Present_Voltage": (62, 1), # read-only
180: "sts3215": STS_SMS_SERIES_CONTROL_TABLE,
190: "sts3215": 4096,
201: "sts3215": STS_SMS_SERIES_BAUDRATE_TABLE,
222: "sts3215": STS_SMS_SERIES_ENCODINGS_TABLE,
243: "sts3215": 777,
249:MODEL_PROTOCOL = {
253: "sts3215": 0,>git -C lerobot status --shortM src/lerobot/motors/feetech/feetech.py
M tests/motors/test_feetech.py>python - <<'PY'
import scservo_sdk, inspect, os
print(scservo_sdk.__file__)
print(os.path.dirname(scservo_sdk.__file__))
PY/Users/mukund/dev/robot-1/.venv/lib/python3.12/site-packages/scservo_sdk/__init__.py
/Users/mukund/dev/robot-1/.venv/lib/python3.12/site-packages/scservo_sdk>rg -n "def setup_motors\(|def setup_motor\(|def _find_single_motor_p0\(|def broadcast_ping\(|getRxPacketError|ERRBIT_VOLTAGE|def _read\(|def _write\(|class SOFollower|COMPATIBLE_DEVICES" lerobot/src .venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:18:ERRBIT_VOLTAGE = 1
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:51: def getRxPacketError(self, error):
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:52: if error & ERRBIT_VOLTAGE:
lerobot/src/lerobot/scripts/lerobot_setup_motors.py:50:COMPATIBLE_DEVICES = [
lerobot/src/lerobot/scripts/lerobot_setup_motors.py:77:def setup_motors(cfg: SetupConfig):
lerobot/src/lerobot/scripts/lerobot_setup_motors.py:78: if cfg.device.type not in COMPATIBLE_DEVICES:
lerobot/src/lerobot/robots/so_follower/config_so_follower.py:25:class SOFollowerConfig:
lerobot/src/lerobot/robots/so_follower/config_so_follower.py:48:class SOFollowerRobotConfig(RobotConfig, SOFollowerConfig):
lerobot/src/lerobot/robots/so_follower/so_follower.py:37:class SOFollower(Robot):
lerobot/src/lerobot/robots/so_follower/so_follower.py:171: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/openarm_follower/openarm_follower.py:216: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/omx_follower/omx_follower.py:161: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/lekiwi/lekiwi.py:201: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/homunculus/homunculus_glove.py:265: def _read(
lerobot/src/lerobot/robots/koch_follower/koch_follower.py:178: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/bi_openarm_follower/bi_openarm_follower.py:133: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/homunculus/homunculus_arm.py:233: def _read(
lerobot/src/lerobot/teleoperators/openarm_leader/openarm_leader.py:180: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/koch_leader/koch_leader.py:156: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/bi_openarm_leader/bi_openarm_leader.py:109: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/bi_so_leader/bi_so_leader.py:92: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/bi_so_follower/bi_so_follower.py:117: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/so_leader/so_leader.py:133: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/hope_jr/hope_jr_hand.py:153: def setup_motors(self) -> None:
lerobot/src/lerobot/robots/hope_jr/hope_jr_arm.py:123: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/openarm_mini/openarm_mini.py:258: def setup_motors(self) -> None:
lerobot/src/lerobot/teleoperators/omx_leader/omx_leader.py:145: def setup_motors(self) -> None:
lerobot/src/lerobot/motors/feetech/feetech.py:175: def _find_single_motor_p0(self, motor: str, initial_baudrate: int | None = None) -> tuple[int, int]:
lerobot/src/lerobot/motors/feetech/feetech.py:405: def broadcast_ping(self, num_retry: int = 0, raise_on_error: bool = False) -> dict[int, int] | None:
lerobot/src/lerobot/motors/feetech/feetech.py:421: display_dict = {id_: self.packet_handler.getRxPacketError(err) for id_, err in ids_errors.items()}
lerobot/src/lerobot/motors/motors_bus.py:215: def getRxPacketError(self, error): ...
lerobot/src/lerobot/motors/motors_bus.py:576: def setup_motor(
lerobot/src/lerobot/motors/motors_bus.py:958: raise RuntimeError(self.packet_handler.getRxPacketError(error))
lerobot/src/lerobot/motors/motors_bus.py:965: def broadcast_ping(self, num_retry: int = 0, raise_on_error: bool = False) -> dict[int, int] | None:
lerobot/src/lerobot/motors/motors_bus.py:1015: def _read(
lerobot/src/lerobot/motors/motors_bus.py:1046: raise RuntimeError(f"{err_msg} {self.packet_handler.getRxPacketError(error)}")
lerobot/src/lerobot/motors/motors_bus.py:1083: def _write(
lerobot/src/lerobot/motors/motors_bus.py:1107: raise RuntimeError(f"{err_msg} {self.packet_handler.getRxPacketError(error)}")
lerobot/src/lerobot/motors/dynamixel/dynamixel.py:249: def broadcast_ping(self, num_retry: int = 0, raise_on_error: bool = False) -> dict[int, int] | None:>python scripts/inspect_feetech_voltage_readonly.py --port /dev/tty.usbmodem59710814421 --baudrate 1000000 --protocol 0=== Bus ===
port : /dev/tty.usbmodem59710814421
baudrate : 1000000
protocol : 0
timeout_ms : 1000
=== Scanning IDs 0..20 (read-only ping) ===
ID 1 | model= 777 | comm=[TxRxResult] Communication success! | ping_error=[RxPacketError] Input voltage error! | all_flags=['Input voltage'] | raw=0x01
=== Register reads (read-only) ===
-- ID 1 --
Status addr= 65 len=1 value= 1 | comm=[TxRxResult] Communication success! | error=[RxPacketError] Input voltage error! | all_flags=['Input voltage'] | raw=0x01
Present_Voltage addr= 62 len=1 value= 122 (~12.2V if 0.1V units) | comm=[TxRxResult] Communication success! | error=[RxPacketError] Input voltage error! | all_flags=['Input voltage'] | raw=0x01
Min_Voltage_Limit addr= 15 len=1 value= 40 (~4.0V if 0.1V units) | comm=[TxRxResult] Communication success! | error=[RxPacketError] Input voltage error! | all_flags=['Input voltage'] | raw=0x01
Max_Voltage_Limit addr= 14 len=1 value= 80 (~8.0V if 0.1V units) | comm=[TxRxResult] Communication success! | error=[RxPacketError] Input voltage error! | all_flags=['Input voltage'] | raw=0x01
Present_Temperature addr= 63 len=1 value= 24 (~24°C) | comm=[TxRxResult] Communication success! | error=[RxPacketError] Input voltage error! | all_flags=['Input voltage'] | raw=0x01
Present_Current addr= 69 len=2 value= 0 | comm=[TxRxResult] Communication success! | error=[RxPacketError] Input voltage error! | all_flags=['Input voltage'] | raw=0x01
Unloading_Condition addr= 19 len=1 value= 44 | comm=[TxRxResult] Communication success! | error=[RxPacketError] Input voltage error! | all_flags=['Input voltage'] | raw=0x01
LED_Alarm_Condition addr= 20 len=1 value= 47 | comm=[TxRxResult] Communication success! | error=[RxPacketError] Input voltage error! | all_flags=['Input voltage'] | raw=0x01
Port closed.>./.venv/bin/python -m py_compile lerobot/src/lerobot/motors/feetech/feetech.py lerobot/tests/motors/test_feetech.py(no output)>rg -n "def getRxPacketError|ERRBIT_VOLTAGE|Input voltage error|ERRBIT" .venv/lib/python3.12/site-packages/scservo_sdk.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:18:ERRBIT_VOLTAGE = 1
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:19:ERRBIT_ANGLE = 2
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:20:ERRBIT_OVERHEAT = 4
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:21:ERRBIT_OVERELE = 8
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:22:ERRBIT_OVERLOAD = 32
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:51: def getRxPacketError(self, error):
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:52: if error & ERRBIT_VOLTAGE:
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:53: return "[RxPacketError] Input voltage error!"
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:55: if error & ERRBIT_ANGLE:
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:58: if error & ERRBIT_OVERHEAT:
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:61: if error & ERRBIT_OVERELE:
.venv/lib/python3.12/site-packages/scservo_sdk/protocol_packet_handler.py:64: if error & ERRBIT_OVERLOAD:>cd lerobot && pytest -q tests/motors/test_feetech.py -qImportError while loading conftest '/Users/mukund/dev/robot-1/lerobot/tests/conftest.py'.
tests/conftest.py:20: in <module>
from serial import SerialException
E ModuleNotFoundError: No module named 'serial'
Command exited with code 4>ls -latotal 8
drwxr-xr-x@ 5 mukund staff 160 Mar 18 04:01 .
drwxr-xr-x@ 59 mukund staff 1888 Mar 18 03:54 ..
drwxr-xr-x@ 9 mukund staff 288 Mar 18 03:59 .venv
drwxr-xr-x@ 29 mukund staff 928 Mar 18 03:58 lerobot
-rw-r--r--@ 1 mukund staff 271 Mar 18 04:01 README.md>rg -n "Max_Voltage_Limit|Min_Voltage_Limit|Present_Voltage|Input voltage error|ERRBIT_VOLTAGE|Unloading_Condition|LED_Alarm_Condition" lerobot/src lerobot/testslerobot/tests/motors/test_feetech.py:182: addr, length, id_, value, error = (10, 4, 1, 1337, scs.ERRBIT_VOLTAGE)
lerobot/tests/motors/test_feetech.py:191: with pytest.raises(RuntimeError, match=re.escape("[RxPacketError] Input voltage error!")):
lerobot/tests/motors/test_feetech.py:245: addr, length, id_, value, error = (10, 4, 1, 1337, scs.ERRBIT_VOLTAGE)
lerobot/tests/motors/test_feetech.py:251: with pytest.raises(RuntimeError, match=re.escape("[RxPacketError] Input voltage error!")):
lerobot/src/lerobot/motors/feetech/tables.py:53: "Max_Voltage_Limit": (14, 1),
lerobot/src/lerobot/motors/feetech/tables.py:54: "Min_Voltage_Limit": (15, 1),
lerobot/src/lerobot/motors/feetech/tables.py:57: "Unloading_Condition": (19, 1),
lerobot/src/lerobot/motors/feetech/tables.py:58: "LED_Alarm_Condition": (20, 1),
lerobot/src/lerobot/motors/feetech/tables.py:86: "Present_Voltage": (62, 1), # read-only
lerobot/src/lerobot/motors/feetech/tables.py:116: "Max_Voltage_Limit": (14, 1),
lerobot/src/lerobot/motors/feetech/tables.py:117: "Min_Voltage_Limit": (15, 1),
lerobot/src/lerobot/motors/feetech/tables.py:120: "Unloading_Condition": (19, 1),
lerobot/src/lerobot/motors/feetech/tables.py:121: "LED_Alarm_Condition": (20, 1),
lerobot/src/lerobot/motors/feetech/tables.py:140: "Present_Voltage": (62, 1), # read-only
lerobot/src/lerobot/motors/dynamixel/tables.py:52: "Max_Voltage_Limit": (32, 2),
lerobot/src/lerobot/motors/dynamixel/tables.py:53: "Min_Voltage_Limit": (34, 2),Inspecting error handling in motor code
$ lerobot-setup-motors --robot.type=so101_follower --robot.port=/dev/tty.usbmodem59710814421 Connect the controller board to the 'gripper' motor only and press enter. Some motors found returned an error status: {1: '[RxPacketError] Input voltage error!'}
I'm getting this error and I know why it's happening but I want to dig deep and understand the hardware stuff. What's actually happening is I'm using a 12 V barrel jack adapter with a 7.4 V motor and that's what the error is caused by. I want to go see how the library, the LeRobot library, actually checks this and all of that. I want to understand what it's doing so that if I were to write this whole stack myself, how that might look.
go to ./lerobot/ to find the source code for this command
Considering virtual environment test run
Tracing error handling flow
Running targeted tests
Okay so you can see the port that it's actually connected to. Can you write a small script and check with me before running it, one that shows me the exact voltage error we're getting and directly reads the Fetec Motor and investigates a bit? I don't want to override anything. I just want to see: is there more information being given to us? That the robot library is justifiably hiding for UX reasons
python scripts/inspect_feetech_voltage_readonly.py \ --port /dev/tty.usbmodem59710814421 \ --baudrate 1000000 \ --protocol 0python scripts/inspect_feetech_voltage_readonly.py \ --port /dev/tty.usbmodem59710814421 \ --id 1