From 7435c98609d7dab10a6938ae1f41c5844d581dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=B9=8F?= <52451470+txp666@users.noreply.github.com> Date: Fri, 13 Jun 2025 21:02:03 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=A2=9E=E5=8A=A0robot=E8=88=B5=E6=9C=BA?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E4=BD=8D=E7=BD=AE=E6=A0=A1=E5=87=86=202.fix(?= =?UTF-8?q?mcp=5Fsever)=20=E8=B6=85=E5=87=BA=E8=8C=83=E5=9B=B4=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E6=8D=95=E8=8E=B7=E7=B1=BB=E5=9E=8B=20=20bug=20(#817)?= 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 --- main/boards/electron-bot/config.h | 2 +- .../electron-bot/electron_bot_controller.cc | 114 ++++++++++++++++- .../electron-bot/electron_emoji_display.cc | 2 +- main/boards/electron-bot/movements.cc | 19 +++ main/boards/otto-robot/config.h | 2 +- main/boards/otto-robot/otto_controller.cc | 120 +++++++++++++++++- main/mcp_server.cc | 4 +- 7 files changed, 246 insertions(+), 17 deletions(-) diff --git a/main/boards/electron-bot/config.h b/main/boards/electron-bot/config.h index 64c49831..e7191d69 100644 --- a/main/boards/electron-bot/config.h +++ b/main/boards/electron-bot/config.h @@ -47,5 +47,5 @@ #define BOOT_BUTTON_GPIO GPIO_NUM_0 -#define ELECTRON_BOT_VERSION "1.1.2" +#define ELECTRON_BOT_VERSION "1.1.3" #endif // _BOARD_CONFIG_H_ diff --git a/main/boards/electron-bot/electron_bot_controller.cc b/main/boards/electron-bot/electron_bot_controller.cc index ecd32062..b11c9ec9 100644 --- a/main/boards/electron-bot/electron_bot_controller.cc +++ b/main/boards/electron-bot/electron_bot_controller.cc @@ -13,6 +13,7 @@ #include "mcp_server.h" #include "movements.h" #include "sdkconfig.h" +#include "settings.h" #define TAG "ElectronBotController" @@ -52,11 +53,14 @@ private: ACTION_BODY_TURN_CENTER = 15, // 回中心 // 头部动作 16-20 - ACTION_HEAD_UP = 16, // 抬头 - ACTION_HEAD_DOWN = 17, // 低头 - ACTION_HEAD_NOD_ONCE = 18, // 点头一次 - ACTION_HEAD_CENTER = 19, // 回中心 - ACTION_HEAD_NOD_REPEAT = 20 // 连续点头 + ACTION_HEAD_UP = 16, // 抬头 + ACTION_HEAD_DOWN = 17, // 低头 + ACTION_HEAD_NOD_ONCE = 18, // 点头一次 + ACTION_HEAD_CENTER = 19, // 回中心 + ACTION_HEAD_NOD_REPEAT = 20, // 连续点头 + + // 系统动作 21 + ACTION_HOME = 21 // 复位到初始位置 }; static void ActionTask(void* arg) { @@ -87,6 +91,9 @@ private: int head_action = params.action_type - ACTION_HEAD_UP + 1; controller->electron_bot_.HeadAction(head_action, params.steps, params.amount, params.speed); + } else if (params.action_type == ACTION_HOME) { + // 复位动作 + controller->electron_bot_.Home(true); } controller->is_action_in_progress_ = false; // 动作执行完毕 } @@ -110,14 +117,28 @@ private: } } + void LoadTrimsFromNVS() { + Settings settings("electron_trims", false); + + int right_pitch = settings.GetInt("right_pitch", 0); + int right_roll = settings.GetInt("right_roll", 0); + int left_pitch = settings.GetInt("left_pitch", 0); + int left_roll = settings.GetInt("left_roll", 0); + int body = settings.GetInt("body", 0); + int head = settings.GetInt("head", 0); + electron_bot_.SetTrims(right_pitch, right_roll, left_pitch, left_roll, body, head); + } + public: ElectronBotController() { electron_bot_.Init(Right_Pitch_Pin, Right_Roll_Pin, Left_Pitch_Pin, Left_Roll_Pin, Body_Pin, Head_Pin); - electron_bot_.Home(true); + LoadTrimsFromNVS(); action_queue_ = xQueueCreate(10, sizeof(ElectronBotActionParams)); + QueueAction(ACTION_HOME, 1, 1000, 0, 0); + RegisterMcpTools(); ESP_LOGI(TAG, "Electron Bot控制器已初始化并注册MCP工具"); } @@ -231,7 +252,7 @@ public: // 清空队列但保持任务常驻 xQueueReset(action_queue_); is_action_in_progress_ = false; - electron_bot_.Home(true); + QueueAction(ACTION_HOME, 1, 1000, 0, 0); return true; }); @@ -240,6 +261,85 @@ public: return is_action_in_progress_ ? "moving" : "idle"; }); + // 单个舵机校准工具 + mcp_server.AddTool( + "self.electron.set_trim", + "校准单个舵机位置。设置指定舵机的微调参数以调整ElectronBot的初始姿态,设置将永久保存。" + "servo_type: 舵机类型(right_pitch:右臂旋转, right_roll:右臂推拉, left_pitch:左臂旋转, " + "left_roll:左臂推拉, body:身体, head:头部); " + "trim_value: 微调值(-30到30度)", + PropertyList({Property("servo_type", kPropertyTypeString, "right_pitch"), + Property("trim_value", kPropertyTypeInteger, 0, -30, 30)}), + [this](const PropertyList& properties) -> ReturnValue { + std::string servo_type = properties["servo_type"].value(); + int trim_value = properties["trim_value"].value(); + + ESP_LOGI(TAG, "设置舵机微调: %s = %d度", servo_type.c_str(), trim_value); + + // 获取当前所有微调值 + Settings settings("electron_trims", true); + int right_pitch = settings.GetInt("right_pitch", 0); + int right_roll = settings.GetInt("right_roll", 0); + int left_pitch = settings.GetInt("left_pitch", 0); + int left_roll = settings.GetInt("left_roll", 0); + int body = settings.GetInt("body", 0); + int head = settings.GetInt("head", 0); + + // 更新指定舵机的微调值 + if (servo_type == "right_pitch") { + right_pitch = trim_value; + settings.SetInt("right_pitch", right_pitch); + } else if (servo_type == "right_roll") { + right_roll = trim_value; + settings.SetInt("right_roll", right_roll); + } else if (servo_type == "left_pitch") { + left_pitch = trim_value; + settings.SetInt("left_pitch", left_pitch); + } else if (servo_type == "left_roll") { + left_roll = trim_value; + settings.SetInt("left_roll", left_roll); + } else if (servo_type == "body") { + body = trim_value; + settings.SetInt("body", body); + } else if (servo_type == "head") { + head = trim_value; + settings.SetInt("head", head); + } else { + return "错误:无效的舵机类型,请使用: right_pitch, right_roll, left_pitch, " + "left_roll, body, head"; + } + + electron_bot_.SetTrims(right_pitch, right_roll, left_pitch, left_roll, body, head); + + QueueAction(ACTION_HOME, 1, 500, 0, 0); + + return "舵机 " + servo_type + " 微调设置为 " + std::to_string(trim_value) + + " 度,已永久保存"; + }); + + mcp_server.AddTool("self.electron.get_trims", "获取当前的舵机微调设置", PropertyList(), + [this](const PropertyList& properties) -> ReturnValue { + Settings settings("electron_trims", false); + + int right_pitch = settings.GetInt("right_pitch", 0); + int right_roll = settings.GetInt("right_roll", 0); + int left_pitch = settings.GetInt("left_pitch", 0); + int left_roll = settings.GetInt("left_roll", 0); + int body = settings.GetInt("body", 0); + int head = settings.GetInt("head", 0); + + std::string result = + "{\"right_pitch\":" + std::to_string(right_pitch) + + ",\"right_roll\":" + std::to_string(right_roll) + + ",\"left_pitch\":" + std::to_string(left_pitch) + + ",\"left_roll\":" + std::to_string(left_roll) + + ",\"body\":" + std::to_string(body) + + ",\"head\":" + std::to_string(head) + "}"; + + ESP_LOGI(TAG, "获取微调设置: %s", result.c_str()); + return result; + }); + mcp_server.AddTool("self.battery.get_level", "获取机器人电池电量和充电状态", PropertyList(), [](const PropertyList& properties) -> ReturnValue { auto& board = Board::GetInstance(); diff --git a/main/boards/electron-bot/electron_emoji_display.cc b/main/boards/electron-bot/electron_emoji_display.cc index b43fa481..fda0fac3 100644 --- a/main/boards/electron-bot/electron_emoji_display.cc +++ b/main/boards/electron-bot/electron_emoji_display.cc @@ -71,7 +71,7 @@ void ElectronEmojiDisplay::SetupGifContainer() { lv_obj_del(content_); } - lv_obj_t* content_ = lv_obj_create(container_); + content_ = lv_obj_create(container_); lv_obj_set_scrollbar_mode(content_, LV_SCROLLBAR_MODE_OFF); lv_obj_set_size(content_, LV_HOR_RES, LV_HOR_RES); lv_obj_set_style_bg_opa(content_, LV_OPA_TRANSP, 0); diff --git a/main/boards/electron-bot/movements.cc b/main/boards/electron-bot/movements.cc index 2e0241ac..a2888e4b 100644 --- a/main/boards/electron-bot/movements.cc +++ b/main/boards/electron-bot/movements.cc @@ -55,6 +55,25 @@ void Otto::DetachServos() { } } +/////////////////////////////////////////////////////////////////// +//-- OSCILLATORS TRIMS ------------------------------------------// +/////////////////////////////////////////////////////////////////// +void Otto::SetTrims(int right_pitch, int right_roll, int left_pitch, int left_roll, int body, + int head) { + servo_trim_[RIGHT_PITCH] = right_pitch; + servo_trim_[RIGHT_ROLL] = right_roll; + servo_trim_[LEFT_PITCH] = left_pitch; + servo_trim_[LEFT_ROLL] = left_roll; + servo_trim_[BODY] = body; + servo_trim_[HEAD] = head; + + for (int i = 0; i < SERVO_COUNT; i++) { + if (servo_pins_[i] != -1) { + servo_[i].SetTrim(servo_trim_[i]); + } + } +} + /////////////////////////////////////////////////////////////////// //-- BASIC MOTION FUNCTIONS -------------------------------------// /////////////////////////////////////////////////////////////////// diff --git a/main/boards/otto-robot/config.h b/main/boards/otto-robot/config.h index e7663b3a..53ebcdaf 100644 --- a/main/boards/otto-robot/config.h +++ b/main/boards/otto-robot/config.h @@ -47,6 +47,6 @@ #define BOOT_BUTTON_GPIO GPIO_NUM_0 -#define OTTO_ROBOT_VERSION "1.4.3" +#define OTTO_ROBOT_VERSION "1.4.4" #endif // _BOARD_CONFIG_H_ diff --git a/main/boards/otto-robot/otto_controller.cc b/main/boards/otto-robot/otto_controller.cc index 4df66c55..421dbc78 100644 --- a/main/boards/otto-robot/otto_controller.cc +++ b/main/boards/otto-robot/otto_controller.cc @@ -13,6 +13,7 @@ #include "mcp_server.h" #include "otto_movements.h" #include "sdkconfig.h" +#include "settings.h" #define TAG "OttoController" @@ -48,7 +49,8 @@ private: ACTION_FLAPPING = 13, ACTION_HANDS_UP = 14, ACTION_HANDS_DOWN = 15, - ACTION_HAND_WAVE = 16 + ACTION_HAND_WAVE = 16, + ACTION_HOME = 17 }; static void ActionTask(void* arg) { @@ -121,11 +123,16 @@ private: controller->otto_.HandWave(params.speed, params.direction); } break; + case ACTION_HOME: + controller->otto_.Home(params.direction == 1); + break; + } + if (params.action_type != ACTION_HOME) { + controller->otto_.Home(params.action_type < ACTION_HANDS_UP); } - controller->otto_.Home(params.action_type < ACTION_HANDS_UP); controller->is_action_in_progress_ = false; + vTaskDelay(pdMS_TO_TICKS(20)); } - vTaskDelay(pdMS_TO_TICKS(20)); } } @@ -151,6 +158,22 @@ private: StartActionTaskIfNeeded(); } + void LoadTrimsFromNVS() { + Settings settings("otto_trims", false); + + int left_leg = settings.GetInt("left_leg", 0); + int right_leg = settings.GetInt("right_leg", 0); + int left_foot = settings.GetInt("left_foot", 0); + int right_foot = settings.GetInt("right_foot", 0); + int left_hand = settings.GetInt("left_hand", 0); + int right_hand = settings.GetInt("right_hand", 0); + + ESP_LOGI(TAG, "从NVS加载微调设置: 左腿=%d, 右腿=%d, 左脚=%d, 右脚=%d, 左手=%d, 右手=%d", + left_leg, right_leg, left_foot, right_foot, left_hand, right_hand); + + otto_.SetTrims(left_leg, right_leg, left_foot, right_foot, left_hand, right_hand); + } + public: OttoController() { otto_.Init(LEFT_LEG_PIN, RIGHT_LEG_PIN, LEFT_FOOT_PIN, RIGHT_FOOT_PIN, LEFT_HAND_PIN, @@ -159,9 +182,12 @@ public: has_hands_ = (LEFT_HAND_PIN != -1 && RIGHT_HAND_PIN != -1); ESP_LOGI(TAG, "Otto机器人初始化%s手部舵机", has_hands_ ? "带" : "不带"); - otto_.Home(true); + LoadTrimsFromNVS(); + action_queue_ = xQueueCreate(10, sizeof(OttoActionParams)); + QueueAction(ACTION_HOME, 1, 1000, 1, 0); // direction=1表示复位手部 + RegisterMcpTools(); } @@ -338,10 +364,94 @@ public: } is_action_in_progress_ = false; xQueueReset(action_queue_); - otto_.Home(true); + + QueueAction(ACTION_HOME, 1, 1000, 1, 0); return true; }); + mcp_server.AddTool( + "self.otto.set_trim", + "校准单个舵机位置。设置指定舵机的微调参数以调整Otto的初始站立姿态,设置将永久保存。" + "servo_type: 舵机类型(left_leg/right_leg/left_foot/right_foot/left_hand/right_hand); " + "trim_value: 微调值(-50到50度)", + PropertyList({Property("servo_type", kPropertyTypeString, "left_leg"), + Property("trim_value", kPropertyTypeInteger, 0, -50, 50)}), + [this](const PropertyList& properties) -> ReturnValue { + std::string servo_type = properties["servo_type"].value(); + int trim_value = properties["trim_value"].value(); + + ESP_LOGI(TAG, "设置舵机微调: %s = %d度", servo_type.c_str(), trim_value); + + // 获取当前所有微调值 + Settings settings("otto_trims", true); + int left_leg = settings.GetInt("left_leg", 0); + int right_leg = settings.GetInt("right_leg", 0); + int left_foot = settings.GetInt("left_foot", 0); + int right_foot = settings.GetInt("right_foot", 0); + int left_hand = settings.GetInt("left_hand", 0); + int right_hand = settings.GetInt("right_hand", 0); + + // 更新指定舵机的微调值 + if (servo_type == "left_leg") { + left_leg = trim_value; + settings.SetInt("left_leg", left_leg); + } else if (servo_type == "right_leg") { + right_leg = trim_value; + settings.SetInt("right_leg", right_leg); + } else if (servo_type == "left_foot") { + left_foot = trim_value; + settings.SetInt("left_foot", left_foot); + } else if (servo_type == "right_foot") { + right_foot = trim_value; + settings.SetInt("right_foot", right_foot); + } else if (servo_type == "left_hand") { + if (!has_hands_) { + return "错误:机器人没有配置手部舵机"; + } + left_hand = trim_value; + settings.SetInt("left_hand", left_hand); + } else if (servo_type == "right_hand") { + if (!has_hands_) { + return "错误:机器人没有配置手部舵机"; + } + right_hand = trim_value; + settings.SetInt("right_hand", right_hand); + } else { + return "错误:无效的舵机类型,请使用: left_leg, right_leg, left_foot, " + "right_foot, left_hand, right_hand"; + } + + otto_.SetTrims(left_leg, right_leg, left_foot, right_foot, left_hand, right_hand); + + QueueAction(ACTION_JUMP, 1, 500, 0, 0); + + return "舵机 " + servo_type + " 微调设置为 " + std::to_string(trim_value) + + " 度,已永久保存"; + }); + + mcp_server.AddTool("self.otto.get_trims", "获取当前的舵机微调设置", PropertyList(), + [this](const PropertyList& properties) -> ReturnValue { + Settings settings("otto_trims", false); + + int left_leg = settings.GetInt("left_leg", 0); + int right_leg = settings.GetInt("right_leg", 0); + int left_foot = settings.GetInt("left_foot", 0); + int right_foot = settings.GetInt("right_foot", 0); + int left_hand = settings.GetInt("left_hand", 0); + int right_hand = settings.GetInt("right_hand", 0); + + std::string result = + "{\"left_leg\":" + std::to_string(left_leg) + + ",\"right_leg\":" + std::to_string(right_leg) + + ",\"left_foot\":" + std::to_string(left_foot) + + ",\"right_foot\":" + std::to_string(right_foot) + + ",\"left_hand\":" + std::to_string(left_hand) + + ",\"right_hand\":" + std::to_string(right_hand) + "}"; + + ESP_LOGI(TAG, "获取微调设置: %s", result.c_str()); + return result; + }); + mcp_server.AddTool("self.otto.get_status", "获取机器人状态,返回 moving 或 idle", PropertyList(), [this](const PropertyList& properties) -> ReturnValue { return is_action_in_progress_ ? "moving" : "idle"; diff --git a/main/mcp_server.cc b/main/mcp_server.cc index dba41b40..df37729e 100644 --- a/main/mcp_server.cc +++ b/main/mcp_server.cc @@ -341,7 +341,7 @@ void McpServer::DoToolCall(int id, const std::string& tool_name, const cJSON* to return; } } - } catch (const std::runtime_error& e) { + } catch (const std::exception& e) { ESP_LOGE(TAG, "tools/call: %s", e.what()); ReplyError(id, e.what()); return; @@ -358,7 +358,7 @@ void McpServer::DoToolCall(int id, const std::string& tool_name, const cJSON* to tool_call_thread_ = std::thread([this, id, tool_iter, arguments = std::move(arguments)]() { try { ReplyResult(id, (*tool_iter)->Call(arguments)); - } catch (const std::runtime_error& e) { + } catch (const std::exception& e) { ESP_LOGE(TAG, "tools/call: %s", e.what()); ReplyError(id, e.what()); }