servo_dog · git:20260617.d9831f9 · 2026-06-17 · sha256 3555e08bb6d77922
servo_dog git:20260617.d9831f9C
Immutable. This exact content never changes and is served at /api/v1/blob/3555e08bb6d77922.
---
{
"name": "servo_dog",
"description": "Control a four-servo robotic dog named Servo Dog through Lua PWM actions, command calls, and a Lua HTTP Server web control panel.",
"metadata": {
"cap_groups": [
"cap_lua"
],
"manage_mode": "readonly",
"category": ["game"],
"tags": ["servo", "ai"]
}
}
---
# Servo Dog
Use this skill when the user asks to control a four-servo robotic dog, start the Servo Dog web control panel, calibrate dog leg servo offsets, or run dog actions such as forward, backward, turn, bow, shake hand, jump, or retract legs.
This skill controls four servos directly from Lua with `mcpwm`. Default GPIOs are:
- `fl_gpio`: `1`
- `fr_gpio`: `2`
- `bl_gpio`: `41`
- `br_gpio`: `42`
Default neutral angles are compatible with the original servo dog controller:
- `fl_neutral`: `70`
- `fr_neutral`: `110`
- `bl_neutral`: `110`
- `br_neutral`: `70`
## Start Web Control
Run the server script asynchronously. It starts the PWM worker, mounts the bundled web UI, and registers HTTP APIs.
```json
{
"path": "{CUR_SKILL_DIR}/scripts/servo_dog_server.lua",
"timeout_ms": 0,
"name": "servo_dog_server",
"exclusive": "servo_dog",
"replace": true,
"args": {
"app_id": "servo_dog",
"queue_name": "servo_dog_cmd",
"web_root": "{CUR_SKILL_DIR}/assets",
"worker_path": "{CUR_SKILL_DIR}/scripts/servo_dog_worker.lua",
"worker_args": {
"fl_gpio": 1,
"fr_gpio": 2,
"bl_gpio": 41,
"br_gpio": 42
}
}
}
```
After it starts, open:
```text
/lua/servo_dog/
```
The page uses:
- `GET /api/lua/servo_dog/state`
- `POST /api/lua/servo_dog/control`
- `GET /api/lua/servo_dog/start_calibration`
- `GET /api/lua/servo_dog/exit_calibration`
- `POST /api/lua/servo_dog/adjust`
## Command Control
For command or agent control, keep the server running and call:
```json
{
"path": "{CUR_SKILL_DIR}/scripts/servo_dog_command.lua",
"args": {
"queue_name": "servo_dog_cmd",
"action": "forward"
}
}
```
If the command script reports that the controller is not running, start the web control script first.
## Actions
Supported action names:
- `installation`
- `idle`
- `forward`
- `backward`
- `turn_left`
- `turn_right`
- `lay_down`
- `bow`
- `lean_back`
- `bow_lean`
- `sway_back_forth`
- `sway`
- `shake_hand`
- `poke`
- `shake_back_legs`
- `jump_forward`
- `jump_backward`
- `retract_legs`
Movement aliases:
```json
{"move":"F"}
{"move":"B"}
{"move":"L"}
{"move":"R"}
```
Original web action id aliases:
```json
{"action":"1"}
{"action":"2"}
{"action":"3"}
{"action":"4"}
{"action":"5"}
{"action":"6"}
{"action":"7"}
{"action":"8"}
{"action":"9"}
{"action":"10"}
{"action":"11"}
{"action":"12"}
```
These map to `lay_down`, `bow`, `lean_back`, `bow_lean`, `sway_back_forth`, `sway`, `shake_hand`, `poke`, `shake_back_legs`, `jump_forward`, `jump_backward`, and `retract_legs`.
## Optional Action Args
Some actions accept overrides:
```json
{
"action": "forward",
"args": {
"repeat_count": 3,
"speed": 90
}
}
```
Supported fields are:
- `repeat_count`: positive integer for repeated gait/action cycles.
- `speed`: higher values shorten interpolation delay.
- `hold_time_ms`: hold duration for actions such as `bow`, `lean_back`, and `shake_hand`.
- `angle_offset`: offset used by `idle` and `sway`.
## Calibration
Start calibration from the web UI or send:
```json
{"action":"installation"}
```
Adjust one servo offset:
```json
{
"path": "{CUR_SKILL_DIR}/scripts/servo_dog_command.lua",
"args": {
"queue_name": "servo_dog_cmd",
"type": "adjust",
"servo": "fl",
"value": 3
}
}
```
Valid servo ids are `fl`, `fr`, `bl`, and `br`. Values are clamped to `-25..25` and saved under the DATA root in `servo_dog/config.json`.
## Extension
To add a new dog action, edit `{CUR_SKILL_DIR}/scripts/servo_dog_worker.lua`:
1. Add a Lua function that calls `set_angle()` or `set_angles()` and uses `action_delay(ms)` inside long loops.
2. Register it in the `actions` table.
3. Optionally add an alias in `action_aliases`.
4. Add a button entry in the server `ACTIONS` list if the web UI should expose it.
Use `action_delay()` instead of `delay.delay_ms()` inside actions so a new command can interrupt the current action.