forked from xiaozhi/xiaozhi-esp32
1.增加robot舵机初始位置校准 2.fix(mcp_sever) 超出范围异常捕获类型 bug (#817)
* 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
This commit is contained in:
@@ -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_
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "mcp_server.h"
|
||||
#include "movements.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "settings.h"
|
||||
|
||||
#define TAG "ElectronBotController"
|
||||
|
||||
@@ -56,7 +57,10 @@ private:
|
||||
ACTION_HEAD_DOWN = 17, // 低头
|
||||
ACTION_HEAD_NOD_ONCE = 18, // 点头一次
|
||||
ACTION_HEAD_CENTER = 19, // 回中心
|
||||
ACTION_HEAD_NOD_REPEAT = 20 // 连续点头
|
||||
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<std::string>();
|
||||
int trim_value = properties["trim_value"].value<int>();
|
||||
|
||||
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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 -------------------------------------//
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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,13 +123,18 @@ 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->is_action_in_progress_ = false;
|
||||
}
|
||||
controller->is_action_in_progress_ = false;
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StartActionTaskIfNeeded() {
|
||||
if (action_task_handle_ == nullptr) {
|
||||
@@ -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<std::string>();
|
||||
int trim_value = properties["trim_value"].value<int>();
|
||||
|
||||
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";
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user