diff --git a/docker/Dockerfile.user b/docker/Dockerfile.user index 4cfbb437a..bcd067637 100644 --- a/docker/Dockerfile.user +++ b/docker/Dockerfile.user @@ -29,7 +29,7 @@ ENV DEBIAN_FRONTEND=noninteractive \ # Install system dependencies and uv (as root) RUN apt-get update && apt-get install -y --no-install-recommends \ - build-essential git curl libglib2.0-0 libegl1-mesa ffmpeg \ + build-essential git curl libglib2.0-0 libegl1-mesa-dev ffmpeg \ libusb-1.0-0-dev speech-dispatcher libgeos-dev portaudio19-dev \ && curl -LsSf https://astral.sh/uv/install.sh | sh \ && mv /root/.local/bin/uv /usr/local/bin/uv \ diff --git a/docs/source/_toctree.yml b/docs/source/_toctree.yml index 1af96d79d..af44c512b 100644 --- a/docs/source/_toctree.yml +++ b/docs/source/_toctree.yml @@ -39,6 +39,8 @@ - sections: - local: notebooks title: Notebooks + - local: feetech + title: Updating Feetech Firmware title: "Resources" - sections: - local: contributing diff --git a/docs/source/feetech.mdx b/docs/source/feetech.mdx new file mode 100644 index 000000000..bba60e4cc --- /dev/null +++ b/docs/source/feetech.mdx @@ -0,0 +1,71 @@ +# Feetech Motor Firmware Update + +This tutorial guides you through updating the firmware of Feetech motors using the official Feetech software. + +## Prerequisites + +- Windows computer (Feetech software is only available for Windows) +- Feetech motor control board +- USB cable to connect the control board to your computer +- Feetech motors connected to the control board + +## Step 1: Download Feetech Software + +1. Visit the official Feetech software download page: [https://www.feetechrc.com/software.html](https://www.feetechrc.com/software.html) +2. Download the latest version of the Feetech debugging software (FD) +3. Install the software on your Windows computer + +## Step 2: Hardware Setup + +1. Connect your Feetech motors to the motor control board +2. Connect the motor control board to your Windows computer via USB cable +3. Ensure power is supplied to the motors + +## Step 3: Configure Connection + +1. Launch the Feetech debugging software +2. Select the correct COM port from the port dropdown menu + - If unsure which port to use, check Windows Device Manager under "Ports (COM & LPT)" +3. Set the appropriate baud rate (typically 1000000 for most Feetech motors) +4. Click "Open" to establish communication with the control board + +## Step 4: Scan for Motors + +1. Once connected, click the "Search" button to detect all connected motors +2. The software will automatically discover and list all motors on the bus +3. Each motor will appear with its ID number + +## Step 5: Update Firmware + +For each motor you want to update: + +1. **Select the motor** from the list by clicking on it +2. **Click on Upgrade tab**: +3. **Click on Online button**: + - If an potential firmware update is found, it will be displayed in the box +4. **Click on Upgrade button**: + - The update progress will be displayed + +## Step 6: Verify Update + +1. After the update completes, the software should automatically refresh the motor information +2. Verify that the firmware version has been updated to the expected version + +## Important Notes + +⚠️ **Warning**: Do not disconnect power or USB during firmware updates, it will potentially brick the motor. + +## Bonus: Motor Debugging on Linux/macOS + +For debugging purposes only, you can use the open-source Feetech Debug Tool: + +- **Repository**: [FT_SCServo_Debug_Qt](https://github.com/CarolinePascal/FT_SCServo_Debug_Qt/tree/fix/port-search-timer) + +### Installation Instructions + +Follow the instructions in the repository to install the tool, for Ubuntu you can directly install it, for MacOS you need to build it from source. + +**Limitations:** + +- This tool is for debugging and parameter adjustment only +- Firmware updates must still be done on Windows with official Feetech software diff --git a/src/lerobot/datasets/lerobot_dataset.py b/src/lerobot/datasets/lerobot_dataset.py index 617ac297f..a869cb920 100644 --- a/src/lerobot/datasets/lerobot_dataset.py +++ b/src/lerobot/datasets/lerobot_dataset.py @@ -825,6 +825,8 @@ class LeRobotDataset(torch.utils.data.Dataset): """ if not episode_data: episode_buffer = self.episode_buffer + else: + episode_buffer = episode_data validate_episode_buffer(episode_buffer, self.meta.total_episodes, self.features) diff --git a/src/lerobot/motors/dynamixel/tables.py b/src/lerobot/motors/dynamixel/tables.py index 8b67bbf38..5417d8cee 100644 --- a/src/lerobot/motors/dynamixel/tables.py +++ b/src/lerobot/motors/dynamixel/tables.py @@ -107,6 +107,8 @@ X_SERIES_ENCODINGS_TABLE = { "Goal_PWM": X_SERIES_CONTROL_TABLE["Goal_PWM"][1], "Goal_Current": X_SERIES_CONTROL_TABLE["Goal_Current"][1], "Goal_Velocity": X_SERIES_CONTROL_TABLE["Goal_Velocity"][1], + "Goal_Position": X_SERIES_CONTROL_TABLE["Goal_Position"][1], + "Present_Position": X_SERIES_CONTROL_TABLE["Present_Position"][1], "Present_PWM": X_SERIES_CONTROL_TABLE["Present_PWM"][1], "Present_Current": X_SERIES_CONTROL_TABLE["Present_Current"][1], "Present_Velocity": X_SERIES_CONTROL_TABLE["Present_Velocity"][1], diff --git a/src/lerobot/robots/so100_follower/so100_follower.py b/src/lerobot/robots/so100_follower/so100_follower.py index ac52293ff..1e117e80b 100644 --- a/src/lerobot/robots/so100_follower/so100_follower.py +++ b/src/lerobot/robots/so100_follower/so100_follower.py @@ -161,6 +161,11 @@ class SO100Follower(Robot): self.bus.write("I_Coefficient", motor, 0) self.bus.write("D_Coefficient", motor, 32) + if motor == "gripper": + self.bus.write("Max_Torque_Limit", motor, 500) # 50% of max torque to avoid burnout + self.bus.write("Protection_Current", motor, 250) # 50% of max current to avoid burnout + self.bus.write("Overload_Torque", motor, 25) # 25% torque when overloaded + def setup_motors(self) -> None: for motor in reversed(self.bus.motors): input(f"Connect the controller board to the '{motor}' motor only and press enter.") diff --git a/src/lerobot/robots/so101_follower/so101_follower.py b/src/lerobot/robots/so101_follower/so101_follower.py index 3ef66d702..31b06c2fd 100644 --- a/src/lerobot/robots/so101_follower/so101_follower.py +++ b/src/lerobot/robots/so101_follower/so101_follower.py @@ -157,6 +157,13 @@ class SO101Follower(Robot): self.bus.write("I_Coefficient", motor, 0) self.bus.write("D_Coefficient", motor, 32) + if motor == "gripper": + self.bus.write( + "Max_Torque_Limit", motor, 500 + ) # 50% of the max torque limit to avoid burnout + self.bus.write("Protection_Current", motor, 250) # 50% of max current to avoid burnout + self.bus.write("Overload_Torque", motor, 25) # 25% torque when overloaded + def setup_motors(self) -> None: for motor in reversed(self.bus.motors): input(f"Connect the controller board to the '{motor}' motor only and press enter.") diff --git a/src/lerobot/scripts/server/robot_client.py b/src/lerobot/scripts/server/robot_client.py index 0599e068e..939d5cea8 100644 --- a/src/lerobot/scripts/server/robot_client.py +++ b/src/lerobot/scripts/server/robot_client.py @@ -302,11 +302,6 @@ class RobotClient: self.logger.debug(f"Current latest action: {latest_action}") - # Get queue state before changes - old_size, old_timesteps = self._inspect_action_queue() - if not old_timesteps: - old_timesteps = [latest_action] # queue was empty - # Get queue state before changes old_size, old_timesteps = self._inspect_action_queue() if not old_timesteps: