🧪 New tutorials are being published — build from robot arms to sensors step by step
Skip to content

SCS0009 Web Control ​

This page is the SCS0009 serial bus version-specific guide for web control. For the general interface, startup, preset poses and camera teleoperation, see the web control overview.

Servo mapping ​

Data source: DEFAULT_HAND_SERVOS in AmazingHandControl/hand_logic.py and docs/zh-hans/CONFIG_FORMAT.md.

FingerRight hand IDLeft hand ID
Ring5, 611, 12
Middle3, 413, 14
Index1, 215, 16
Thumb7, 817, 18

Both servos drive one finger differentially ⚠️ ​

Each finger's two servos are mounted side by side with their shafts on the same line. It is not "one servo for flexion and one for splay"; instead, the two servos drive the same finger together:

  • The two servos rotate in the same direction → the finger splays left/right (abduction/adduction)
  • The two servos rotate in opposite directions → the finger extends / bends (flexion/extension)
  • The two servos carrying both same-direction and opposite-direction components → flexion and splay superimpose
text
Splay (same direction)          Flexion (opposite direction)
Axis 1 ↻   Axis 2 ↻          Axis 1 ↻   Axis 2 ↺

The interface shows two control axes, not two servos:

Flexion = (servo1 + servo2) / 2
Splay = (servo1 − servo2) / 2

Conversely, the program converts the control axes into target angles for the two servos:

servo1 = flexion + splay
servo2 = flexion − splay

Here servo1 / servo2 are software target angles (even IDs have already been negated for reverse mounting); they are not the physical directions of the servo output shafts. To judge whether the two servos rotate in the same or opposite directions in the actual mechanism, look at the output shafts — do not compare these two values directly.

Example: when only splay +20 is given, the software values are servo1 = +20, servo2 = −20; after negating the even ID, the two servos actually rotate in the same direction.

"The fingers won't spread / won't close" means the splay control value is zero, or the two servos are not forming a differential — a scissors-style V, for example, relies on index splay +17 and middle splay −30 (one positive, one negative).

Range (derived from the 19 official poses + middle):

AxisRangeDescription
Flexion−50 ~ +90open (negative) ↔ closed (positive)
Splay−45 ~ +45together (negative) ↔ apart (positive)

Two ID rules (getting them wrong burns servos or reverses motion):

  1. Odd IDs are each finger's first servo, even IDs its second. True on both hands (left 11/12, 13/14… also alternate odd/even). The second servo is mounted in reverse, so negate it in the conversion.
  2. The left hand's IDs are not 9–16 but 11–18, numbered "ring finger first". Wiring them as 1-8 in sequence is always wrong.

Physical direction and middle position: counting from right to left, the right servo is odd and the left servo even. Right-hand middle-position order (raw 0–1023) is 451,571,451,571,451,571,451,571; left hand 571,451,571,451,571,451,571,451.

Both_Hands-IDs


Conversion formulas ​

Identical to apply_pose() in AmazingHandControl (verified pose by pose):

1) when mirror_pose is true, first swap the two servo values of each finger
2) servo_deg = (ID odd ? +1 : -1) × (pose value − angle_offset_deg)
Handangle_offset_degmirror_pose
Right0yes ⚠️
Left-35.16yes

-35.16° is the physical half-slot offset of the left hand's servo horns relative to the right, measured from the official configuration.

About mirror_pose — this build differs from the official one

In the official reference only the left hand is true. This build's right-hand module also has its servo pairs mounted reversed, so the right hand is set to true as well.

Mathematically, the swap only flips splay and never touches flexion: base = (a+b)/2 is unchanged by a swap, while side = (a−b)/2 changes sign. So when "one hand's splay is entirely reversed", this switch is the first thing to check.

The pose array is always 8 values in the order [ring, middle, index, thumb], two values per finger — byte-identical to the official data/hand_config.yaml, for easy comparison.

Worked conversion examples ​

PoseRight handLeft hand
open [-35]*8ID5 −35 / ID6 +35ID11 +0.16 / ID12 −0.16
close [75]*8ID5 +75 / ID6 −75ID11 +110.16 / ID12 −110.16
middle [-17.578]*8ID5 −17.58 / ID6 +17.58ID11 +17.58 / ID12 −17.58

Note that the left hand's close needs ±110.16°, noticeably more than the right hand. That is why the limit in config.json is set to ±120° (the SCS0009 full range is about ±150°). Setting the limit to ±90 would clip the left hand's fist.


SCS0009 FAQ ​

Motion direction reversed → check that the wiring follows "odd ID first"; for the left hand, also confirm angle_offset_deg = -35.16.

Left hand's fist is not tight enough / servos buzz → the limit may still be ±90; check whether config.json has been raised to ±120.

Fingers do not move / "expected N motors, found M" → run tools/scan_servos.py; the left hand's IDs are the easiest to wire incorrectly.

Middle position incorrect → the middle value -17.578125 comes from converting the official raw 451/571; to calibrate for your own mechanical assembly, edit middle.positions in config.json.