Add damiao motors and open arm robot

This commit is contained in:
Pepijn
2025-10-27 16:40:05 +01:00
parent 1cf768e17a
commit 6288439d48
14 changed files with 2194 additions and 397 deletions
+541
View File
@@ -0,0 +1,541 @@
# OpenArms Robot
OpenArms is a 7 DOF robotic arm with a gripper, designed by [Enactic, Inc.](https://www.enactic.com/) It uses Damiao motors controlled via CAN bus communication and MIT control mode for smooth, precise motion.
## Hardware Overview
- **7 DOF per arm** (14 DOF total for dual arm setup)
- **1 gripper per arm** (2 grippers total)
- **Damiao motors** with 4 different types:
- **DM8009** (DM-J8009P-2EC) for shoulders (J1, J2) - high torque
- **DM4340** for shoulder rotation and elbow (J3, J4)
- **DM4310** (DM-J4310-2EC V1.1) for wrist (J5, J6, J7) and gripper (J8)
- **24V power supply** required
- **CAN interface device**:
- **Linux**: Any SocketCAN-compatible adapter
- **macOS**: CANable, PEAK PCAN-USB, or Kvaser USBcan
- Proper CAN wiring (CANH, CANL, 120Ω termination)
## Motor Configuration
Each arm has the following motor configuration based on the [OpenArm setup guide](https://docs.openarm.dev/software/setup/):
| Joint | Motor | Motor Type | Sender CAN ID | Receiver ID | Description |
|-------|-------|------------|---------------|-------------|-------------|
| J1 | joint_1 | DM8009 | 0x01 | 0x11 | Shoulder pan |
| J2 | joint_2 | DM8009 | 0x02 | 0x12 | Shoulder lift |
| J3 | joint_3 | DM4340 | 0x03 | 0x13 | Shoulder rotation |
| J4 | joint_4 | DM4340 | 0x04 | 0x14 | Elbow flex |
| J5 | joint_5 | DM4310 | 0x05 | 0x15 | Wrist roll |
| J6 | joint_6 | DM4310 | 0x06 | 0x16 | Wrist pitch |
| J7 | joint_7 | DM4310 | 0x07 | 0x17 | Wrist rotation |
| J8 | gripper | DM4310 | 0x08 | 0x18 | Gripper |
For dual arm setups, the left arm uses IDs 0x09-0x10 for joints 1-8 with the same motor types.
## Quick Start (macOS)
If you're on macOS, here's the fastest way to get started:
```bash
# 1. Install LeRobot with OpenArms dependencies
pip install -e ".[openarms]"
# 2. Find your USB-CAN adapter
ls /dev/cu.usbmodem*
# 3. Test communication
python3 -c "
import can
bus = can.interface.Bus(channel='/dev/cu.usbmodem00000000050C1', interface='slcan', bitrate=1000000)
print('✓ CAN interface connected')
bus.shutdown()
"
```
Then use this configuration:
```python
from lerobot.robots.openarms import OpenArmsFollower
from lerobot.robots.openarms.config_openarms_follower import OpenArmsFollowerConfig
config = OpenArmsFollowerConfig(
port="/dev/cu.usbmodem00000000050C1", # Your adapter
can_interface="auto", # Auto-detects slcan for /dev/* ports
is_dual_arm=True,
)
robot = OpenArmsFollower(config)
robot.connect()
```
## Prerequisites
### Software Requirements
**Linux:**
- Ubuntu 22.04/24.04 (or any Linux with SocketCAN)
- Python 3.8+
- `can-utils` and `iproute2` packages
- LeRobot with OpenArms dependencies
```bash
# Install system dependencies
sudo apt install can-utils iproute2
# Install LeRobot with OpenArms support
pip install -e ".[openarms]"
```
**macOS:**
- macOS 12+ (Monterey or later)
- Python 3.8+
- LeRobot with OpenArms dependencies
```bash
# Install LeRobot with OpenArms support (includes python-can)
pip install -e ".[openarms]"
```
The `openarms` extra installs:
- `python-can>=4.2.0` - CAN bus communication library (supports SocketCAN on Linux and SLCAN on macOS)
:::tip
If you've already installed LeRobot and want to add OpenArms support, run:
```bash
pip install -e ".[openarms]"
```
:::
## Setup Guide
### Step 1: Motor ID Configuration
**IMPORTANT**: Before using the robot, motors must be configured with the correct CAN IDs.
Refer to the [OpenArm Motor ID Configuration Guide](https://docs.openarm.dev/software/setup/motor-id) for detailed instructions using the Damiao Debugging Tools on Windows.
Key points:
- Each motor needs a unique **Sender CAN ID** (0x01-0x08 for first arm)
- Each motor needs a unique **Receiver/Master ID** (0x11-0x18 for first arm)
- Use the Damiao Debugging Tools to set these IDs
- For dual arm setups, use 0x09-0x10 for the second arm
### Step 2: Setup CAN Interface
Configure your CAN interface as described in the [OpenArm CAN Setup Guide](https://docs.openarm.dev/software/setup/can-setup):
#### Linux (SocketCAN)
```bash
# Find your CAN interface
ip link show
# Setup CAN 2.0 at 1 Mbps (standard)
sudo ip link set can0 down
sudo ip link set can0 type can bitrate 1000000
sudo ip link set can0 up
# Verify configuration
ip link show can0
```
#### macOS
macOS doesn't have native SocketCAN support.
**Use SLCAN (Serial Line CAN)**
For USB-CAN adapters that support SLCAN protocol (like CANable):
```bash
# Install python-can if not already installed
pip install python-can
# The adapter will appear as a serial device
ls /dev/cu.usbmodem*
# Use with python-can slcan interface
# Example: /dev/cu.usbmodem14201
```
In your code, specify the slcan interface:
```python
from lerobot.robots.openarms.config_openarms_follower import OpenArmsFollowerConfig
config = OpenArmsFollowerConfig(
port="/dev/cu.usbmodem14201", # Your USB-CAN adapter
can_interface="slcan", # Will auto-detect if set to "auto"
)
```
### Step 3: Test Motor Communication
**On Linux:**
Test basic communication as described in the [OpenArm Motor Test Guide](https://docs.openarm.dev/software/setup/configure-test):
```bash
# Terminal 1: Monitor CAN traffic
candump can0
# Terminal 2: Enable motor 1
cansend can0 001#FFFFFFFFFFFFFFFC
# Expected response on Terminal 1:
# can0 011 [8] XX XX XX XX XX XX XX XX
# Disable motor 1
cansend can0 001#FFFFFFFFFFFFFFFD
```
**On macOS:**
Testing is done differently since you'll use serial-based adapters:
```bash
# Find your USB-CAN adapter
ls /dev/cu.usbmodem*
# Example output: /dev/cu.usbmodem00000000050C1
# Test with Python directly (can-utils don't work on macOS)
python3 -c "
import can
bus = can.interface.Bus(channel='/dev/cu.usbmodem00000000050C1', interface='slcan', bitrate=1000000)
msg = can.Message(arbitration_id=0x01, data=[0xFF]*7+[0xFC])
bus.send(msg)
response = bus.recv(timeout=1.0)
if response:
print(f'✓ Motor responded: ID 0x{response.arbitration_id:02X}')
else:
print('✗ No response')
bus.shutdown()
"
```
## Usage
### Basic Setup
**On Linux:**
```python
from lerobot.robots.openarms import OpenArmsFollower
from lerobot.robots.openarms.config_openarms_follower import OpenArmsFollowerConfig
# Configure for dual arm setup
config = OpenArmsFollowerConfig(
port="can0",
can_interface="socketcan", # Or "auto" for auto-detection
id="openarms_dual",
is_dual_arm=True,
)
robot = OpenArmsFollower(config)
robot.connect()
```
**On macOS:**
```python
from lerobot.robots.openarms import OpenArmsFollower
from lerobot.robots.openarms.config_openarms_follower import OpenArmsFollowerConfig
# Find your USB-CAN adapter first
# ls /dev/cu.usbmodem*
config = OpenArmsFollowerConfig(
port="/dev/cu.usbmodem14201", # Your adapter's serial port
can_interface="slcan", # Or "auto" for auto-detection
id="openarms_dual",
is_dual_arm=True,
)
robot = OpenArmsFollower(config)
robot.connect()
```
### Calibration
On first use, you'll need to calibrate the robot:
```python
robot.calibrate()
```
The calibration process will:
1. Disable torque on all motors
2. Ask you to position arms in **hanging position with grippers closed**
3. Set this as the zero position
4. Ask you to move each joint through its full range
5. Record min/max positions for each joint
6. Save calibration to file
### Reading Observations
The robot provides comprehensive state information:
```python
observation = robot.get_observation()
# Observation includes for each motor:
# - {motor_name}.pos: Position in degrees
# - {motor_name}.vel: Velocity in degrees/second
# - {motor_name}.torque: Motor torque
# - {camera_name}: Camera images (if configured)
print(f"Right arm joint 1 position: {observation['right_joint_1.pos']:.1f}°")
print(f"Right arm joint 1 velocity: {observation['right_joint_1.vel']:.1f}°/s")
print(f"Right arm joint 1 torque: {observation['right_joint_1.torque']:.3f} N·m")
```
### Sending Actions
```python
# Send target positions (in degrees)
action = {
"right_joint_1.pos": 45.0,
"right_joint_2.pos": -30.0,
# ... all joints
"right_gripper.pos": 45.0, # Half-closed
}
actual_action = robot.send_action(action)
```
### Gripper Control
```python
# Open gripper
robot.open_gripper(arm="right")
# Close gripper
robot.close_gripper(arm="right")
```
## Safety Features
### 1. Maximum Relative Target
Limits how far a joint can move in a single command to prevent sudden movements:
```python
config = OpenArmsFollowerConfig(
port="can0",
# Limit all joints to 10 degrees per command
max_relative_target=10.0,
# Or set per-motor limits
max_relative_target={
"right_joint_1": 15.0, # Slower moving joint
"right_joint_2": 10.0,
"right_gripper": 5.0, # Very slow gripper
}
)
```
**How it works**: If current position is 50° and you command 80°, with `max_relative_target=10.0`, the robot will only move to 60° in that step.
### 2. Torque Limits
Control maximum torque output, especially important for grippers and teleoperation:
```python
config = OpenArmsFollowerConfig(
port="can0",
# Gripper torque limit (fraction of motor's max torque)
gripper_torque_limit=0.5, # 50% of max torque
)
```
Lower torque limits prevent damage when gripping delicate objects.
### 3. MIT Control Gains
Control responsiveness and stability via PID-like gains:
```python
config = OpenArmsFollowerConfig(
port="can0",
position_kp=10.0, # Position gain (higher = more responsive)
position_kd=0.5, # Velocity damping (higher = more damped)
)
```
**Guidelines**:
- **For following (robot)**: Higher gains for responsiveness
- `position_kp=10.0`, `position_kd=0.5`
- **For teleoperation (leader)**: Lower gains or disable torque for manual movement
- `manual_control=True` (torque disabled)
### 4. Velocity Limits
Velocity limits are enforced by the Damiao motors based on motor type. For DM4310:
- Max velocity: 30 rad/s ≈ 1718°/s
The motors will automatically limit velocity to safe values.
## Teleoperation
### Leader Arm Setup
The leader arm is moved manually (torque disabled) to generate commands:
```python
from lerobot.teleoperators.openarms import OpenArmsLeader
from lerobot.teleoperators.openarms.config_openarms_leader import OpenArmsLeaderConfig
config = OpenArmsLeaderConfig(
port="can1", # Separate CAN interface for leader
id="openarms_leader",
manual_control=True, # Torque disabled for manual movement
is_dual_arm=True,
)
leader = OpenArmsLeader(config)
leader.connect()
# Read current position as action
action = leader.get_action()
# action contains positions for all joints in degrees
```
### Safety Considerations for Teleoperation
1. **Use separate CAN interfaces** for leader and follower to avoid conflicts
2. **Enable max_relative_target** on follower to smooth abrupt movements
3. **Lower torque limits** on follower to prevent damage from tracking errors
4. **Test with one arm** before enabling dual arm teleoperation
5. **Have emergency stop** ready (power switch or CAN disable)
```python
# Recommended follower config for teleoperation
follower_config = OpenArmsFollowerConfig(
port="can0",
max_relative_target=5.0, # Small steps for smooth following
gripper_torque_limit=0.3, # Low torque for safety
position_kp=5.0, # Lower gains for gentler following
position_kd=0.3,
)
```
## Troubleshooting
### Motors Not Responding
**Linux:**
1. **Check power supply**: 24V with sufficient current
2. **Verify CAN interface**: `ip link show can0` should show "UP"
3. **Test with cansend**: Follow [motor test guide](https://docs.openarm.dev/software/setup/configure-test)
4. **Check motor IDs**: Use Damiao Debugging Tools to verify IDs
5. **Check termination**: 120Ω resistor should be enabled on CAN interface
**macOS:**
1. **Check power supply**: 24V with sufficient current
2. **Find adapter**: `ls /dev/cu.usbmodem*` should show your device
3. **Test connection**: Use Python script above to test communication
4. **Check motor IDs**: Use Damiao Debugging Tools on Windows
5. **Verify drivers**: Ensure USB-CAN adapter drivers are installed
6. **Try different baudrate**: Some adapters default to different rates
### macOS-Specific Issues
**"No such interface" error:**
```python
# Try auto-detection
config.can_interface = "auto"
# Or explicitly list available interfaces
import can
print(can.detect_available_configs())
```
**Permission denied on `/dev/cu.*`:**
```bash
# Add user to dialout group (if applicable)
sudo dscl . -append /Groups/_dialout GroupMembership $USER
# Or run with sudo (not recommended)
sudo python your_script.py
```
**Adapter not showing up:**
```bash
# Check USB devices
system_profiler SPUSBDataType
# Reinstall python-can
pip install --upgrade --force-reinstall python-can
```
### Motor Shaking/Unstable
- **Lower control gains**: Reduce `position_kp` and `position_kd`
- **Check calibration**: Re-run calibration procedure
- **Verify power**: Insufficient current can cause instability
- **Check mechanical**: Loose connections, binding, or damaged components
### CAN Bus Errors
**Linux:**
```bash
# Check for errors
ip -s link show can0
# Reset CAN interface
sudo ip link set can0 down
sudo ip link set can0 up
```
**macOS:**
```bash
# Reconnect USB adapter
# Unplug and replug the USB cable
# Restart Python script
# The slcan interface auto-reconnects
```
### Position Drift
- **Re-calibrate**: Run calibration procedure
- **Set zero position**: Use `robot.bus.set_zero_position()` with arm in known position
- **Check temperature**: Motors may drift when hot
## Technical Details
### Position Units
All positions are in **degrees**:
- Motor internal representation: radians
- User API: degrees
- Automatic conversion handled by `DamiaoMotorsBus`
### Control Mode
OpenArms uses **MIT control mode** which allows simultaneous control of:
- Position (degrees)
- Velocity (degrees/second)
- Torque (N·m)
- Position gain (Kp)
- Velocity damping (Kd)
### Communication
- **Protocol**: CAN 2.0 at 1 Mbps (or CAN-FD at 5 Mbps)
- **Frame format**: Standard 11-bit IDs
- **Update rate**: Typically 50-100 Hz depending on motor count
- **Latency**: ~10-20ms per motor command
## References
- [OpenArm Official Documentation](https://docs.openarm.dev/)
- [OpenArm Setup Guide](https://docs.openarm.dev/software/setup/)
- [Motor ID Configuration](https://docs.openarm.dev/software/setup/motor-id)
- [CAN Interface Setup](https://docs.openarm.dev/software/setup/can-setup)
- [Motor Communication Test](https://docs.openarm.dev/software/setup/configure-test)
- [Damiao Motor Documentation](https://wiki.seeedstudio.com/damiao_series/)
- [Enactic GitHub](https://github.com/enactic/openarm_can)