From 764f6e3349bd2462ecffabe8e86d7c307e6c877b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B0=8F=E9=B9=8F?=
<52451470+txp666@users.noreply.github.com>
Date: Mon, 17 Nov 2025 22:26:58 +0800
Subject: [PATCH] Add wechat-mini-program support for otto-robot (#1444)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* otto v1.4.0 MCP
1.使用MCP协议控制机器人
2.gif继承lcdDisplay,避免修改lcdDisplay
* otto v1.4.1 gif as components
gif as components
* electronBot v1.1.0 mcp
1.增加electronBot支持
2.mcp协议
3.gif 作为组件
4.display子类
* 规范代码
1.规范代码
2.修复切换主题死机bug
* fix(ota): 修复 ottoRobot和electronBot OTA 升级崩溃问题 bug
* 1.增加robot舵机初始位置校准
2.fix(mcp_sever) 超出范围异常捕获类型 bug
* refactor: Update Electron and Otto emoji display implementations
- Removed GIF selection from Kconfig for Electron and Otto boards.
- Updated Electron and Otto bot versions to 2.0.4 in their respective config files.
- Refactored emoji display classes to utilize EmojiCollection for managing emojis.
- Enhanced chat label setup and status display functionality in both classes.
- Cleaned up unused code and improved initialization logging for emoji displays.
* Rename OTTO_ICON_FONT.c to otto_icon_font.c
* Rename OTTO_ICON_FONT.c to otto_icon_font.c
* refactor: Update Otto emoji display configurations and functionalities
- Changed chat label text mode to circular scrolling for both Otto and Electron emoji displays.
- Bumped Otto robot version to 2.0.5 in the configuration file.
- Added new actions for Otto robot including Sit, WhirlwindLeg, Fitness, Greeting, Shy, RadioCalisthenics, MagicCircle, and Showcase.
- Enhanced servo sequence handling and added support for executing custom servo sequences.
- Improved logging and error handling for servo sequence execution.
* refactor: Update chat label long mode for Electron and Otto emoji displays
- Changed chat label text mode from wrap to circular scrolling for both Electron and Otto emoji displays.
- Improved consistency in chat label setup across both implementations.
* Update Otto robot README with new actions and parameters
* Update Otto controller parameters for oscillation settings
- Changed default oscillation period from 500ms to 300ms.
- Increased default steps from 5.0 to 8.0.
- Updated default amplitude from 20 degrees to 0 degrees.
- Enhanced documentation with new examples for oscillation modes and sequences.
* Fix default amplitude initialization in Otto controller to use a single zero instead of two digits.
* chore: update txp666/otto-emoji-gif-component version to 1.0.3 in idf_component.yml
* Refactor Otto controller
- Consolidated movement actions into a unified tool for the Otto robot, allowing for a single action command with various parameters.
- Removed individual movement tools (walk, turn, jump, etc.) and replaced them with a more flexible action system.
* Enhance Otto robot functionality by adding WebSocket control server and IP address retrieval feature. Updated config to support WebSocket, and revised README to include new control options and usage examples.
---
main/boards/otto-robot/README.md | 132 +++++++-----
main/boards/otto-robot/config.json | 4 +-
main/boards/otto-robot/otto_controller.cc | 12 ++
main/boards/otto-robot/otto_robot.cc | 22 ++
.../otto-robot/websocket_control_server.cc | 191 ++++++++++++++++++
.../otto-robot/websocket_control_server.h | 33 +++
6 files changed, 347 insertions(+), 47 deletions(-)
create mode 100644 main/boards/otto-robot/websocket_control_server.cc
create mode 100644 main/boards/otto-robot/websocket_control_server.h
diff --git a/main/boards/otto-robot/README.md b/main/boards/otto-robot/README.md
index bc311f3a..9aac1135 100644
--- a/main/boards/otto-robot/README.md
+++ b/main/boards/otto-robot/README.md
@@ -11,6 +11,14 @@ otto 机器人是一个开源的人形机器人平台,具有多种动作能力
- 复刻教程
+### 微信小程序控制
+
+
+
+
+
+扫描上方二维码,使用微信小程序控制 Otto 机器人。
+
## 硬件
- 立创开源
@@ -49,29 +57,43 @@ otto 机器人具有丰富的动作能力,包括行走、转向、跳跃、摇
### 动作
-| MCP工具名称 | 描述 | 参数说明 |
-|-------------------|-----------------|---------------------------------------------------|
-| self.otto.walk_forward | 行走 | **steps**: 行走步数(1-100,默认3)
**speed**: 行走速度(500-1500,数值越小越快,默认1000)
**direction**: 行走方向(-1=后退, 1=前进,默认1)
**arm_swing**: 手臂摆动幅度(0-170度,默认50) |
-| self.otto.turn_left | 转身 | **steps**: 转身步数(1-100,默认3)
**speed**: 转身速度(500-1500,数值越小越快,默认1000)
**direction**: 转身方向(1=左转, -1=右转,默认1)
**arm_swing**: 手臂摆动幅度(0-170度,默认50) |
-| self.otto.jump | 跳跃 | **steps**: 跳跃次数(1-100,默认1)
**speed**: 跳跃速度(500-1500,数值越小越快,默认1000) |
-| self.otto.swing | 左右摇摆 | **steps**: 摇摆次数(1-100,默认3)
**speed**: 摇摆速度(500-1500,数值越小越快,默认1000)
**amount**: 摇摆幅度(0-170度,默认30) |
-| self.otto.moonwalk | 太空步 | **steps**: 太空步步数(1-100,默认3)
**speed**: 速度(500-1500,数值越小越快,默认1000)
**direction**: 方向(1=左, -1=右,默认1)
**amount**: 幅度(0-170度,默认25) |
-| self.otto.bend | 弯曲身体 | **steps**: 弯曲次数(1-100,默认1)
**speed**: 弯曲速度(500-1500,数值越小越快,默认1000)
**direction**: 弯曲方向(1=左, -1=右,默认1) |
-| self.otto.shake_leg | 摇腿 | **steps**: 摇腿次数(1-100,默认1)
**speed**: 摇腿速度(500-1500,数值越小越快,默认1000)
**direction**: 腿部选择(1=左腿, -1=右腿,默认1) |
-| self.otto.sit | 坐下 | 不需要参数 |
-| self.otto.showcase | 展示动作 | 不需要参数。串联执行多个动作:往前走3步、挥挥手、跳舞(广播体操)、太空步、摇摆、起飞、健身、往后走3步 |
-| self.otto.updown | 上下运动 | **steps**: 上下运动次数(1-100,默认3)
**speed**: 运动速度(500-1500,数值越小越快,默认1000)
**amount**: 运动幅度(0-170度,默认20) |
-| self.otto.whirlwind_leg | 旋风腿 | **steps**: 动作次数(3-100,默认3)
**speed**: 动作速度(100-1000,数值越小越快,建议300)
**amplitude**: 踢腿幅度(20-40度,默认30) |
-| self.otto.hands_up | 举手 * | **speed**: 举手速度(500-1500,数值越小越快,默认1000)
**direction**: 手部选择(1=左手, -1=右手, 0=双手,默认1) |
-| self.otto.hands_down | 放手 * | **speed**: 放手速度(500-1500,数值越小越快,默认1000)
**direction**: 手部选择(1=左手, -1=右手, 0=双手,默认1) |
-| self.otto.hand_wave | 挥手 * | **direction**: 手部选择(1=左手, -1=右手, 0=双手,默认1) |
-| self.otto.windmill | 大风车 * | **steps**: 动作次数(3-100,默认6)
**speed**: 动作周期(300-2000毫秒,数值越小越快,默认500)
**amplitude**: 振荡幅度(50-90度,默认70) |
-| self.otto.takeoff | 起飞 * | **steps**: 动作次数(5-100,默认5)
**speed**: 动作周期(200-600毫秒,数值越小越快,建议300)
**amplitude**: 振荡幅度(20-60度,默认40) |
-| self.otto.fitness | 健身 * | **steps**: 动作次数(3-100,默认5)
**speed**: 动作速度(500-2000毫秒,数值越小越快,默认1000)
**amplitude**: 振荡幅度(10-50度,默认25) |
-| self.otto.greeting | 打招呼 * | **direction**: 手部选择(1=左手, -1=右手,默认1)
**steps**: 动作次数(3-100,默认5) |
-| self.otto.shy | 害羞 * | **direction**: 方向(1=左, -1=右,默认1)
**steps**: 动作次数(3-100,默认5) |
-| self.otto.radio_calisthenics | 广播体操 * | 不需要参数 |
-| self.otto.magic_circle | 爱的魔力转圈圈 * | 不需要参数 |
+所有动作通过统一的 `self.otto.action` 工具调用,通过 `action` 参数指定动作名称。
+
+| MCP工具名称 | 描述 | 参数说明 |
+|-----------|------|---------|
+| self.otto.action | 执行机器人动作 | **action**: 动作名称(必填)
**steps**: 动作步数(1-100,默认3)
**speed**: 动作速度(100-3000,数值越小越快,默认700)
**direction**: 方向参数(1/-1/0,默认1,根据动作类型不同含义不同)
**amount**: 动作幅度(0-170,默认30)
**arm_swing**: 手臂摆动幅度(0-170,默认50) |
+
+#### 支持的动作列表
+
+**基础移动动作**:
+- `walk` - 行走(需 steps/speed/direction/arm_swing)
+- `turn` - 转身(需 steps/speed/direction/arm_swing)
+- `jump` - 跳跃(需 steps/speed)
+
+**特殊动作**:
+- `swing` - 左右摇摆(需 steps/speed/amount)
+- `moonwalk` - 太空步(需 steps/speed/direction/amount)
+- `bend` - 弯曲身体(需 steps/speed/direction)
+- `shake_leg` - 摇腿(需 steps/speed/direction)
+- `updown` - 上下运动(需 steps/speed/amount)
+- `whirlwind_leg` - 旋风腿(需 steps/speed/amount)
+
+**固定动作**:
+- `sit` - 坐下(无需参数)
+- `showcase` - 展示动作(无需参数,串联执行多个动作)
+- `home` - 复位到初始位置(无需参数)
+
+**手部动作**(需手部舵机支持,标记 *):
+- `hands_up` - 举手(需 speed/direction)*
+- `hands_down` - 放手(需 speed/direction)*
+- `hand_wave` - 挥手(需 direction)*
+- `windmill` - 大风车(需 steps/speed/amount)*
+- `takeoff` - 起飞(需 steps/speed/amount)*
+- `fitness` - 健身(需 steps/speed/amount)*
+- `greeting` - 打招呼(需 direction/steps)*
+- `shy` - 害羞(需 direction/steps)*
+- `radio_calisthenics` - 广播体操(无需参数)*
+- `magic_circle` - 爱的魔力转圈圈(无需参数)*
**注**: 标记 * 的手部动作仅在配置了手部舵机时可用。
@@ -79,28 +101,31 @@ otto 机器人具有丰富的动作能力,包括行走、转向、跳跃、摇
| MCP工具名称 | 描述 | 返回值/说明 |
|-------------------|-----------------|---------------------------------------------------|
-| self.otto.home | 复位机器人到初始位置 | 不需要参数 |
| self.otto.stop | 立即停止所有动作并复位 | 停止当前动作并回到初始位置 |
| self.otto.get_status | 获取机器人状态 | 返回 "moving" 或 "idle" |
| self.otto.set_trim | 校准单个舵机位置 | **servo_type**: 舵机类型(left_leg/right_leg/left_foot/right_foot/left_hand/right_hand)
**trim_value**: 微调值(-50到50度) |
| self.otto.get_trims | 获取当前的舵机微调设置 | 返回所有舵机微调值的JSON格式 |
+| self.otto.get_ip | 获取机器人WiFi IP地址 | 返回IP地址和连接状态的JSON格式:`{"ip":"192.168.x.x","connected":true}` 或 `{"ip":"","connected":false}` |
| self.battery.get_level | 获取电池状态 | 返回电量百分比和充电状态的JSON格式 |
| self.otto.servo_sequences | 舵机序列自编程 | 支持分段发送序列,支持普通移动和振荡器两种模式。详见代码注释中的详细说明 |
+**注**: `home`(复位)动作通过 `self.otto.action` 工具调用,参数为 `{"action": "home"}`。
+
### 参数说明
-1. **steps**: 动作执行的步数/次数,数值越大动作持续时间越长
-2. **speed**: 动作执行速度/周期,**数值越小越快**
+`self.otto.action` 工具的参数说明:
+
+1. **action** (必填): 动作名称,支持的动作见上方"支持的动作列表"
+2. **steps**: 动作执行的步数/次数(1-100,默认3),数值越大动作持续时间越长
+3. **speed**: 动作执行速度/周期(100-3000,默认700),**数值越小越快**
- 大多数动作: 500-1500毫秒
- 特殊动作可能有所不同(如旋风腿: 100-1000,起飞: 200-600等)
- - 具体范围请参考各动作的说明
-3. **direction**: 方向参数
- - 移动动作: 1=左/前进, -1=右/后退
- - 手部动作: 1=左手, -1=右手, 0=双手
-4. **amount/amplitude/arm_swing**: 动作幅度,范围根据动作而定(通常0-170度)
- - 0表示不摆动(适用于手臂摆动)
- - 数值越大幅度越大
- - 不同动作可能有不同的幅度范围限制
+4. **direction**: 方向参数(-1/0/1,默认1),根据动作类型不同含义不同:
+ - **移动动作** (walk/turn): 1=前进/左转, -1=后退/右转
+ - **方向动作** (bend/shake_leg/moonwalk): 1=左, -1=右
+ - **手部动作** (hands_up/hands_down/hand_wave/greeting/shy): 1=左手, -1=右手, 0=双手(仅hands_up/hands_down支持0)
+5. **amount**: 动作幅度(0-170,默认30),数值越大幅度越大
+6. **arm_swing**: 手臂摆动幅度(0-170,默认50),仅用于 walk/turn 动作,0表示不摆动
### 动作控制
- 每个动作执行完成后,机器人会自动回到初始位置(home),以便于执行下一个动作
@@ -112,35 +137,50 @@ otto 机器人具有丰富的动作能力,包括行走、转向、跳跃、摇
### MCP工具调用示例
```json
-// 向前走3步
-{"name": "self.otto.walk_forward", "arguments": {}}
+// 向前走3步(使用默认参数)
+{"name": "self.otto.action", "arguments": {"action": "walk"}}
// 向前走5步,稍快一些
-{"name": "self.otto.walk_forward", "arguments": {"steps": 5, "speed": 800}}
+{"name": "self.otto.action", "arguments": {"action": "walk", "steps": 5, "speed": 800}}
-// 左转2步,大幅度摆动手臂
-{"name": "self.otto.turn_left", "arguments": {"steps": 2, "arm_swing": 100}}
+// 左转2步,大幅度摆动手臂
+{"name": "self.otto.action", "arguments": {"action": "turn", "steps": 2, "arm_swing": 100}}
// 摇摆舞蹈,中等幅度
-{"name": "self.otto.swing", "arguments": {"steps": 5, "amount": 50}}
+{"name": "self.otto.action", "arguments": {"action": "swing", "steps": 5, "amount": 50}}
+
+// 跳跃
+{"name": "self.otto.action", "arguments": {"action": "jump", "steps": 1, "speed": 1000}}
+
+// 太空步
+{"name": "self.otto.action", "arguments": {"action": "moonwalk", "steps": 3, "speed": 800, "direction": 1, "amount": 30}}
// 挥左手打招呼
-{"name": "self.otto.hand_wave", "arguments": {"direction": 1}}
+{"name": "self.otto.action", "arguments": {"action": "hand_wave", "direction": 1}}
// 展示动作(串联多个动作)
-{"name": "self.otto.showcase", "arguments": {}}
+{"name": "self.otto.action", "arguments": {"action": "showcase"}}
+
+// 坐下
+{"name": "self.otto.action", "arguments": {"action": "sit"}}
// 大风车动作
-{"name": "self.otto.windmill", "arguments": {"steps": 10, "amplitude": 80}}
+{"name": "self.otto.action", "arguments": {"action": "windmill", "steps": 10, "speed": 500, "amount": 80}}
// 起飞动作
-{"name": "self.otto.takeoff", "arguments": {"steps": 5, "speed": 300}}
+{"name": "self.otto.action", "arguments": {"action": "takeoff", "steps": 5, "speed": 300, "amount": 40}}
// 广播体操
-{"name": "self.otto.radio_calisthenics", "arguments": {}}
+{"name": "self.otto.action", "arguments": {"action": "radio_calisthenics"}}
-// 立即停止
+// 复位到初始位置
+{"name": "self.otto.action", "arguments": {"action": "home"}}
+
+// 立即停止所有动作并复位
{"name": "self.otto.stop", "arguments": {}}
+
+// 获取机器人IP地址
+{"name": "self.otto.get_ip", "arguments": {}}
```
### 语音指令示例
diff --git a/main/boards/otto-robot/config.json b/main/boards/otto-robot/config.json
index 1e0eabce..3eb14b91 100644
--- a/main/boards/otto-robot/config.json
+++ b/main/boards/otto-robot/config.json
@@ -3,7 +3,9 @@
"builds": [
{
"name": "otto-robot",
- "sdkconfig_append": []
+ "sdkconfig_append": [
+ "CONFIG_HTTPD_WS_SUPPORT=y"
+ ]
}
]
}
\ No newline at end of file
diff --git a/main/boards/otto-robot/otto_controller.cc b/main/boards/otto-robot/otto_controller.cc
index 6149a4b4..16d867e2 100644
--- a/main/boards/otto-robot/otto_controller.cc
+++ b/main/boards/otto-robot/otto_controller.cc
@@ -15,6 +15,7 @@
#include "otto_movements.h"
#include "sdkconfig.h"
#include "settings.h"
+#include
#define TAG "OttoController"
@@ -818,6 +819,17 @@ public:
",\"charging\":" + (charging ? "true" : "false") + "}";
return status;
});
+
+ mcp_server.AddTool("self.otto.get_ip", "获取机器人WiFi IP地址", PropertyList(),
+ [](const PropertyList& properties) -> ReturnValue {
+ auto& wifi_station = WifiStation::GetInstance();
+ std::string ip = wifi_station.GetIpAddress();
+ if (ip.empty()) {
+ return "{\"ip\":\"\",\"connected\":false}";
+ }
+ std::string status = "{\"ip\":\"" + ip + "\",\"connected\":true}";
+ return status;
+ });
ESP_LOGI(TAG, "MCP工具注册完成");
}
diff --git a/main/boards/otto-robot/otto_robot.cc b/main/boards/otto-robot/otto_robot.cc
index d0087875..13f36cec 100644
--- a/main/boards/otto-robot/otto_robot.cc
+++ b/main/boards/otto-robot/otto_robot.cc
@@ -18,6 +18,7 @@
#include "power_manager.h"
#include "system_reset.h"
#include "wifi_board.h"
+#include "websocket_control_server.h"
#define TAG "OttoRobot"
@@ -28,6 +29,7 @@ private:
LcdDisplay* display_;
PowerManager* power_manager_;
Button boot_button_;
+ WebSocketControlServer* ws_control_server_;
void InitializePowerManager() {
power_manager_ =
new PowerManager(POWER_CHARGE_DETECT_PIN, POWER_ADC_UNIT, POWER_ADC_CHANNEL);
@@ -94,6 +96,25 @@ private:
::InitializeOttoController();
}
+ void InitializeWebSocketControlServer() {
+ ESP_LOGI(TAG, "初始化WebSocket控制服务器");
+ ws_control_server_ = new WebSocketControlServer();
+ if (!ws_control_server_->Start(8080)) {
+ ESP_LOGE(TAG, "Failed to start WebSocket control server");
+ delete ws_control_server_;
+ ws_control_server_ = nullptr;
+ } else {
+ ESP_LOGI(TAG, "WebSocket control server started on port 8080");
+ }
+ }
+
+ void StartNetwork() override {
+ WifiBoard::StartNetwork();
+ vTaskDelay(pdMS_TO_TICKS(1000));
+
+ InitializeWebSocketControlServer();
+ }
+
public:
OttoRobot() : boot_button_(BOOT_BUTTON_GPIO) {
InitializeSpi();
@@ -101,6 +122,7 @@ public:
InitializeButtons();
InitializePowerManager();
InitializeOttoController();
+ ws_control_server_ = nullptr;
GetBacklight()->RestoreBrightness();
}
diff --git a/main/boards/otto-robot/websocket_control_server.cc b/main/boards/otto-robot/websocket_control_server.cc
new file mode 100644
index 00000000..a38944b8
--- /dev/null
+++ b/main/boards/otto-robot/websocket_control_server.cc
@@ -0,0 +1,191 @@
+#include "websocket_control_server.h"
+#include "mcp_server.h"
+#include
+#include
+#include
+#include
+#include
+#include