@@ -22,107 +22,104 @@ Example Phoenix application demonstrating the [Beam Bots](https://github.com/bea
2222
2323- Elixir ~ > 1.15
2424- SO-101 robot arm with Feetech STS3215 servos (or run in simulation mode)
25- - USB serial adapter connected to servo bus
25+ - Feetech URT-1 USB adapter or compatible TTL serial adapter
26+ - 6-7.4V DC power supply for the servos
2627
27- ## Quick Start
28+ ## Quick Start (Simulation)
29+
30+ No hardware required:
2831
2932``` bash
30- # Install dependencies and build assets
3133mix setup
32-
33- # Start in simulation mode (no hardware required)
3434SIMULATE=1 mix phx.server
35-
36- # Or start with real hardware
37- mix phx.server
3835```
3936
4037Visit [ localhost:4000] ( http://localhost:4000 ) to access the robot dashboard.
4138
4239## Hardware Setup
4340
44- ### Servo Configuration
41+ ### What You Need
4542
46- The SO-101 uses 6 Feetech STS3215 servos with IDs 1-6:
43+ - ** SO-101 arm** fully assembled with 6x Feetech STS3215 servos
44+ - ** USB serial adapter** (Feetech URT-1 or any 5V TTL serial adapter)
45+ - ** Power supply** 6-7.4V DC, connected to the servo bus
46+ - ** USB cable** connecting the adapter to your computer
4747
48- | Servo ID | Joint |
49- | ----------| -------|
50- | 1 | Shoulder Pan |
51- | 2 | Shoulder Lift |
52- | 3 | Elbow Flex |
53- | 4 | Wrist Flex |
54- | 5 | Wrist Roll |
55- | 6 | Gripper |
48+ The serial adapter connects to the servo bus (the same daisy-chain cable
49+ that connects all the servos). On Linux, it typically appears as
50+ ` /dev/ttyUSB0 ` or ` /dev/ttyACM0 ` .
5651
57- ### Serial Connection
52+ ### Step 1: Assign Servo IDs
5853
59- Configure your serial device in ` config/runtime.exs ` :
54+ STS3215 servos ship with a default ID of 1. Each servo in the arm needs
55+ a unique ID. The setup wizard walks you through connecting each servo
56+ one at a time and assigning the correct ID.
6057
61- ``` elixir
62- config :bb_example_so101 , BB .Example .SO101 .Robot ,
63- config: [
64- feetech: [
65- device: " /dev/ttyUSB0" , # Adjust for your system
66- baud_rate: 1_000_000
67- ]
68- ]
58+ ``` bash
59+ mix so101.setup_servos /dev/ttyUSB0
6960```
7061
71- ## Robot Definition
62+ The wizard will prompt you to connect each servo individually:
7263
73- The robot is defined in ` lib/bb/example/so101/robot.ex ` using the BB DSL:
64+ | Joint | Servo ID | Description |
65+ | ----------------| ----------| --------------------------|
66+ | shoulder_pan | 1 | Base rotation |
67+ | shoulder_lift | 2 | Shoulder up/down |
68+ | elbow_flex | 3 | Elbow bend |
69+ | wrist_flex | 4 | Wrist up/down |
70+ | wrist_roll | 5 | Wrist rotation |
71+ | gripper | 6 | Gripper open/close |
7472
75- ``` elixir
76- defmodule BB .Example .SO101 .Robot do
77- use BB
78-
79- parameters do
80- bridge (:feetech , {BB .Servo .Feetech .Bridge , controller: :feetech })
81- end
82-
83- commands do
84- command :home do
85- handler (BB .Example .SO101 .Command .Home )
86- allowed_states ([:idle ])
87- end
88- # ... additional commands
89- end
90-
91- controllers do
92- controller (:feetech , {BB .Servo .Feetech .Controller ,
93- port: param ([:config , :feetech , :device ]),
94- baud_rate: param ([:config , :feetech , :baud_rate ]),
95- control_table: Feetech .ControlTable .STS3215
96- })
97- end
98-
99- topology do
100- link :base_link do
101- joint :shoulder_pan do
102- # ... joint definition with actuator
103- link :shoulder_link do
104- # ... nested kinematic chain
105- end
106- end
107- end
108- end
109- end
73+ After assigning IDs, daisy-chain all servos together and reconnect to
74+ the controller board.
75+
76+ ### Step 2: Calibrate
77+
78+ With all servos connected and powered, run the calibration task:
79+
80+ ``` bash
81+ mix so101.calibrate /dev/ttyUSB0
11082```
11183
112- ## Kinematic Structure
84+ This will:
11385
114- Derived from the official [ SO-ARM100 URDF] ( https://github.com/TheRobotStudio/SO-ARM100/tree/main/Simulation/SO101 ) :
86+ 1 . Disable torque on all servos so you can move the arm freely
87+ 2 . Prompt you to move ** every joint** through its ** full range of motion**
88+ (push each joint to both mechanical limits)
89+ 3 . Track the min/max positions for each joint in real time
90+ 4 . When you press Enter, calculate the mechanical centre of each joint
91+ 5 . Write a position offset to each servo so that the centre corresponds
92+ to 0 radians
11593
116- | Joint | Range | Link Length |
117- | -------| -------| -------------|
118- | shoulder_pan | ±110° | 62mm (base) |
119- | shoulder_lift | ±100° | 54mm |
120- | elbow_flex | ±97° | 113mm (upper arm) |
121- | wrist_flex | ±95° | 135mm (forearm) |
122- | wrist_roll | ±160° | 61mm (wrist) |
123- | gripper | 10°-100° | ~ 98mm to EE |
94+ You can preview the results without writing to the servos:
12495
125- Total reach: ~ 350mm
96+ ``` bash
97+ mix so101.calibrate /dev/ttyUSB0 --dry-run
98+ ```
99+
100+ Calibration only needs to be done once - the offsets are stored in the
101+ servo's EEPROM and persist across power cycles. Re-run it if you
102+ physically reposition a servo on its bracket.
103+
104+ ### Step 3: Run
105+
106+ ``` bash
107+ mix phx.server
108+ ```
109+
110+ Visit [ localhost:4000] ( http://localhost:4000 ) . Use the dashboard to arm
111+ the robot, then send commands.
112+
113+ ### Serial Port Configuration
114+
115+ By default the application connects to ` /dev/ttyUSB0 ` at 1Mbaud. To use
116+ a different port, edit ` lib/bb_example_so101/application.ex ` :
117+
118+ ``` elixir
119+ defp robot_opts do
120+ [params: [config: [feetech: [device: " /dev/ttyACM0" ]]]]
121+ end
122+ ```
126123
127124## Commands
128125
@@ -132,25 +129,34 @@ Total reach: ~350mm
132129| ` disarm ` | Disable torque safely | ` [:idle] ` |
133130| ` home ` | Move all joints to zero position | ` [:idle] ` |
134131| ` demo_circle ` | Execute circular motion demo | ` [:idle] ` |
135- | ` disable_torque ` | Disable servo torque without state change | ` [:idle, :disarmed] ` |
132+ | ` disable_torque ` | Disable servo torque | ` [:idle, :disarmed] ` |
136133| ` move_to_pose ` | Move end effector to target position | ` [:idle] ` |
137134
138135Execute commands via the web dashboard or programmatically:
139136
140137``` elixir
141- # Arm the robot first
142138{:ok , cmd} = BB .Example .SO101 .Robot .arm ()
143139{:ok , :armed } = BB .Command .await (cmd)
144140
145- # Move to home position
146141{:ok , cmd} = BB .Example .SO101 .Robot .home ()
147142{:ok , :homed } = BB .Command .await (cmd)
148-
149- # Run demo circle
150- {:ok , cmd} = BB .Example .SO101 .Robot .demo_circle ()
151- {:ok , :complete } = BB .Command .await (cmd, 30_000 )
152143```
153144
145+ ## Kinematic Structure
146+
147+ Derived from the official [ SO-ARM100 URDF] ( https://github.com/TheRobotStudio/SO-ARM100/tree/main/Simulation/SO101 ) :
148+
149+ | Joint | Range | Link Length |
150+ | -------| -------| -------------|
151+ | shoulder_pan | ±110° | 62mm (base) |
152+ | shoulder_lift | -10° to 190° | 54mm |
153+ | elbow_flex | -187° to 7° | 113mm (upper arm) |
154+ | wrist_flex | ±95° | 135mm (forearm) |
155+ | wrist_roll | ±160° | 61mm (wrist) |
156+ | gripper | -10° to 100° | ~ 98mm to EE |
157+
158+ Total reach: ~ 350mm
159+
154160## Project Structure
155161
156162```
@@ -162,26 +168,22 @@ lib/
162168│ ├── demo_circle.ex
163169│ ├── move_to_pose.ex
164170│ └── disable_torque.ex
165- ├── bb_example_so101.ex # Application context
166171├── bb_example_so101/
167172│ └── application.ex # Supervision tree
168- └── bb_example_so101_web/ # Phoenix web layer
169- ├── router.ex # Mounts bb_dashboard
170- └── ...
173+ ├── bb_example_so101_web/ # Phoenix web layer
174+ │ ├── router.ex # Mounts bb_dashboard
175+ │ └── ...
176+ └── mix/tasks/
177+ ├── so101.setup_servos.ex # Servo ID assignment wizard
178+ └── so101.calibrate.ex # Servo calibration
171179```
172180
173181## Development
174182
175183``` bash
176- # Run in simulation mode
177- SIMULATE=1 mix phx.server
178-
179- # Run tests
180- mix test
181- mix test path/to/test.exs:42 # Single test at line
182-
183- # Run all checks
184- mix check --no-retry
184+ SIMULATE=1 mix phx.server # Run in simulation mode
185+ mix test # Run tests
186+ mix check --no-retry # Run all checks
185187```
186188
187189## Related Packages
0 commit comments