electron_bot_controller.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. Electron Bot机器人控制器 - MCP协议版本
  3. */
  4. #include <cJSON.h>
  5. #include <esp_log.h>
  6. #include <cstring>
  7. #include "application.h"
  8. #include "board.h"
  9. #include "config.h"
  10. #include "mcp_server.h"
  11. #include "movements.h"
  12. #include "sdkconfig.h"
  13. #include "settings.h"
  14. #define TAG "ElectronBotController"
  15. struct ElectronBotActionParams {
  16. int action_type;
  17. int steps;
  18. int speed;
  19. int direction;
  20. int amount;
  21. };
  22. class ElectronBotController {
  23. private:
  24. Otto electron_bot_;
  25. TaskHandle_t action_task_handle_ = nullptr;
  26. QueueHandle_t action_queue_;
  27. bool is_action_in_progress_ = false;
  28. enum ActionType {
  29. // 手部动作 1-12
  30. ACTION_HAND_LEFT_UP = 1, // 举左手
  31. ACTION_HAND_RIGHT_UP = 2, // 举右手
  32. ACTION_HAND_BOTH_UP = 3, // 举双手
  33. ACTION_HAND_LEFT_DOWN = 4, // 放左手
  34. ACTION_HAND_RIGHT_DOWN = 5, // 放右手
  35. ACTION_HAND_BOTH_DOWN = 6, // 放双手
  36. ACTION_HAND_LEFT_WAVE = 7, // 挥左手
  37. ACTION_HAND_RIGHT_WAVE = 8, // 挥右手
  38. ACTION_HAND_BOTH_WAVE = 9, // 挥双手
  39. ACTION_HAND_LEFT_FLAP = 10, // 拍打左手
  40. ACTION_HAND_RIGHT_FLAP = 11, // 拍打右手
  41. ACTION_HAND_BOTH_FLAP = 12, // 拍打双手
  42. // 身体动作 13-14
  43. ACTION_BODY_TURN_LEFT = 13, // 左转
  44. ACTION_BODY_TURN_RIGHT = 14, // 右转
  45. ACTION_BODY_TURN_CENTER = 15, // 回中心
  46. // 头部动作 16-20
  47. ACTION_HEAD_UP = 16, // 抬头
  48. ACTION_HEAD_DOWN = 17, // 低头
  49. ACTION_HEAD_NOD_ONCE = 18, // 点头一次
  50. ACTION_HEAD_CENTER = 19, // 回中心
  51. ACTION_HEAD_NOD_REPEAT = 20, // 连续点头
  52. // 系统动作 21
  53. ACTION_HOME = 21 // 复位到初始位置
  54. };
  55. static void ActionTask(void* arg) {
  56. ElectronBotController* controller = static_cast<ElectronBotController*>(arg);
  57. ElectronBotActionParams params;
  58. controller->electron_bot_.AttachServos();
  59. while (true) {
  60. if (xQueueReceive(controller->action_queue_, &params, pdMS_TO_TICKS(1000)) == pdTRUE) {
  61. ESP_LOGI(TAG, "执行动作: %d", params.action_type);
  62. controller->is_action_in_progress_ = true; // 开始执行动作
  63. // 执行相应的动作
  64. if (params.action_type >= ACTION_HAND_LEFT_UP &&
  65. params.action_type <= ACTION_HAND_BOTH_FLAP) {
  66. // 手部动作
  67. controller->electron_bot_.HandAction(params.action_type, params.steps,
  68. params.amount, params.speed);
  69. } else if (params.action_type >= ACTION_BODY_TURN_LEFT &&
  70. params.action_type <= ACTION_BODY_TURN_CENTER) {
  71. // 身体动作
  72. int body_direction = params.action_type - ACTION_BODY_TURN_LEFT + 1;
  73. controller->electron_bot_.BodyAction(body_direction, params.steps,
  74. params.amount, params.speed);
  75. } else if (params.action_type >= ACTION_HEAD_UP &&
  76. params.action_type <= ACTION_HEAD_NOD_REPEAT) {
  77. // 头部动作
  78. int head_action = params.action_type - ACTION_HEAD_UP + 1;
  79. controller->electron_bot_.HeadAction(head_action, params.steps, params.amount,
  80. params.speed);
  81. } else if (params.action_type == ACTION_HOME) {
  82. // 复位动作
  83. controller->electron_bot_.Home(true);
  84. }
  85. controller->is_action_in_progress_ = false; // 动作执行完毕
  86. }
  87. vTaskDelay(pdMS_TO_TICKS(20));
  88. }
  89. }
  90. void QueueAction(int action_type, int steps, int speed, int direction, int amount) {
  91. ESP_LOGI(TAG, "动作控制: 类型=%d, 步数=%d, 速度=%d, 方向=%d, 幅度=%d", action_type, steps,
  92. speed, direction, amount);
  93. ElectronBotActionParams params = {action_type, steps, speed, direction, amount};
  94. xQueueSend(action_queue_, &params, portMAX_DELAY);
  95. StartActionTaskIfNeeded();
  96. }
  97. void StartActionTaskIfNeeded() {
  98. if (action_task_handle_ == nullptr) {
  99. xTaskCreate(ActionTask, "electron_bot_action", 1024 * 4, this, configMAX_PRIORITIES - 1,
  100. &action_task_handle_);
  101. }
  102. }
  103. void LoadTrimsFromNVS() {
  104. Settings settings("electron_trims", false);
  105. int right_pitch = settings.GetInt("right_pitch", 0);
  106. int right_roll = settings.GetInt("right_roll", 0);
  107. int left_pitch = settings.GetInt("left_pitch", 0);
  108. int left_roll = settings.GetInt("left_roll", 0);
  109. int body = settings.GetInt("body", 0);
  110. int head = settings.GetInt("head", 0);
  111. electron_bot_.SetTrims(right_pitch, right_roll, left_pitch, left_roll, body, head);
  112. }
  113. public:
  114. ElectronBotController() {
  115. electron_bot_.Init(Right_Pitch_Pin, Right_Roll_Pin, Left_Pitch_Pin, Left_Roll_Pin, Body_Pin,
  116. Head_Pin);
  117. LoadTrimsFromNVS();
  118. action_queue_ = xQueueCreate(10, sizeof(ElectronBotActionParams));
  119. QueueAction(ACTION_HOME, 1, 1000, 0, 0);
  120. RegisterMcpTools();
  121. ESP_LOGI(TAG, "Electron Bot控制器已初始化并注册MCP工具");
  122. }
  123. void RegisterMcpTools() {
  124. auto& mcp_server = McpServer::GetInstance();
  125. ESP_LOGI(TAG, "开始注册Electron Bot MCP工具...");
  126. // 手部动作统一工具
  127. mcp_server.AddTool(
  128. "self.electron.hand_action",
  129. "手部动作控制。action: 1=举手, 2=放手, 3=挥手, 4=拍打; hand: 1=左手, 2=右手, 3=双手; "
  130. "steps: 动作重复次数(1-10); speed: 动作速度(500-1500,数值越小越快); amount: "
  131. "动作幅度(10-50,仅举手动作使用)",
  132. PropertyList({Property("action", kPropertyTypeInteger, 1, 1, 4),
  133. Property("hand", kPropertyTypeInteger, 3, 1, 3),
  134. Property("steps", kPropertyTypeInteger, 1, 1, 10),
  135. Property("speed", kPropertyTypeInteger, 1000, 500, 1500),
  136. Property("amount", kPropertyTypeInteger, 30, 10, 50)}),
  137. [this](const PropertyList& properties) -> ReturnValue {
  138. int action_type = properties["action"].value<int>();
  139. int hand_type = properties["hand"].value<int>();
  140. int steps = properties["steps"].value<int>();
  141. int speed = properties["speed"].value<int>();
  142. int amount = properties["amount"].value<int>();
  143. // 根据动作类型和手部类型计算具体动作
  144. int base_action;
  145. switch (action_type) {
  146. case 1:
  147. base_action = ACTION_HAND_LEFT_UP;
  148. break; // 举手
  149. case 2:
  150. base_action = ACTION_HAND_LEFT_DOWN;
  151. amount = 0;
  152. break; // 放手
  153. case 3:
  154. base_action = ACTION_HAND_LEFT_WAVE;
  155. amount = 0;
  156. break; // 挥手
  157. case 4:
  158. base_action = ACTION_HAND_LEFT_FLAP;
  159. amount = 0;
  160. break; // 拍打
  161. default:
  162. base_action = ACTION_HAND_LEFT_UP;
  163. }
  164. int action_id = base_action + (hand_type - 1);
  165. QueueAction(action_id, steps, speed, 0, amount);
  166. return true;
  167. });
  168. // 身体动作
  169. mcp_server.AddTool(
  170. "self.electron.body_turn",
  171. "身体转向。steps: 转向步数(1-10); speed: 转向速度(500-1500,数值越小越快); direction: "
  172. "转向方向(1=左转, 2=右转, 3=回中心); angle: 转向角度(0-90度)",
  173. PropertyList({Property("steps", kPropertyTypeInteger, 1, 1, 10),
  174. Property("speed", kPropertyTypeInteger, 1000, 500, 1500),
  175. Property("direction", kPropertyTypeInteger, 1, 1, 3),
  176. Property("angle", kPropertyTypeInteger, 45, 0, 90)}),
  177. [this](const PropertyList& properties) -> ReturnValue {
  178. int steps = properties["steps"].value<int>();
  179. int speed = properties["speed"].value<int>();
  180. int direction = properties["direction"].value<int>();
  181. int amount = properties["angle"].value<int>();
  182. int action;
  183. switch (direction) {
  184. case 1:
  185. action = ACTION_BODY_TURN_LEFT;
  186. break;
  187. case 2:
  188. action = ACTION_BODY_TURN_RIGHT;
  189. break;
  190. case 3:
  191. action = ACTION_BODY_TURN_CENTER;
  192. break;
  193. default:
  194. action = ACTION_BODY_TURN_LEFT;
  195. }
  196. QueueAction(action, steps, speed, 0, amount);
  197. return true;
  198. });
  199. // 头部动作
  200. mcp_server.AddTool("self.electron.head_move",
  201. "头部运动。action: 1=抬头, 2=低头, 3=点头, 4=回中心, 5=连续点头; steps: "
  202. "动作重复次数(1-10); speed: 动作速度(500-1500,数值越小越快); angle: "
  203. "头部转动角度(1-15度)",
  204. PropertyList({Property("action", kPropertyTypeInteger, 3, 1, 5),
  205. Property("steps", kPropertyTypeInteger, 1, 1, 10),
  206. Property("speed", kPropertyTypeInteger, 1000, 500, 1500),
  207. Property("angle", kPropertyTypeInteger, 5, 1, 15)}),
  208. [this](const PropertyList& properties) -> ReturnValue {
  209. int action_num = properties["action"].value<int>();
  210. int steps = properties["steps"].value<int>();
  211. int speed = properties["speed"].value<int>();
  212. int amount = properties["angle"].value<int>();
  213. int action = ACTION_HEAD_UP + (action_num - 1);
  214. QueueAction(action, steps, speed, 0, amount);
  215. return true;
  216. });
  217. // 系统工具
  218. mcp_server.AddTool("self.electron.stop", "立即停止", PropertyList(),
  219. [this](const PropertyList& properties) -> ReturnValue {
  220. // 清空队列但保持任务常驻
  221. xQueueReset(action_queue_);
  222. is_action_in_progress_ = false;
  223. QueueAction(ACTION_HOME, 1, 1000, 0, 0);
  224. return true;
  225. });
  226. mcp_server.AddTool("self.electron.get_status", "获取机器人状态,返回 moving 或 idle",
  227. PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
  228. return is_action_in_progress_ ? "moving" : "idle";
  229. });
  230. // 单个舵机校准工具
  231. mcp_server.AddTool(
  232. "self.electron.set_trim",
  233. "校准单个舵机位置。设置指定舵机的微调参数以调整ElectronBot的初始姿态,设置将永久保存。"
  234. "servo_type: 舵机类型(right_pitch:右臂旋转, right_roll:右臂推拉, left_pitch:左臂旋转, "
  235. "left_roll:左臂推拉, body:身体, head:头部); "
  236. "trim_value: 微调值(-30到30度)",
  237. PropertyList({Property("servo_type", kPropertyTypeString, "right_pitch"),
  238. Property("trim_value", kPropertyTypeInteger, 0, -30, 30)}),
  239. [this](const PropertyList& properties) -> ReturnValue {
  240. std::string servo_type = properties["servo_type"].value<std::string>();
  241. int trim_value = properties["trim_value"].value<int>();
  242. ESP_LOGI(TAG, "设置舵机微调: %s = %d度", servo_type.c_str(), trim_value);
  243. // 获取当前所有微调值
  244. Settings settings("electron_trims", true);
  245. int right_pitch = settings.GetInt("right_pitch", 0);
  246. int right_roll = settings.GetInt("right_roll", 0);
  247. int left_pitch = settings.GetInt("left_pitch", 0);
  248. int left_roll = settings.GetInt("left_roll", 0);
  249. int body = settings.GetInt("body", 0);
  250. int head = settings.GetInt("head", 0);
  251. // 更新指定舵机的微调值
  252. if (servo_type == "right_pitch") {
  253. right_pitch = trim_value;
  254. settings.SetInt("right_pitch", right_pitch);
  255. } else if (servo_type == "right_roll") {
  256. right_roll = trim_value;
  257. settings.SetInt("right_roll", right_roll);
  258. } else if (servo_type == "left_pitch") {
  259. left_pitch = trim_value;
  260. settings.SetInt("left_pitch", left_pitch);
  261. } else if (servo_type == "left_roll") {
  262. left_roll = trim_value;
  263. settings.SetInt("left_roll", left_roll);
  264. } else if (servo_type == "body") {
  265. body = trim_value;
  266. settings.SetInt("body", body);
  267. } else if (servo_type == "head") {
  268. head = trim_value;
  269. settings.SetInt("head", head);
  270. } else {
  271. return "错误:无效的舵机类型,请使用: right_pitch, right_roll, left_pitch, "
  272. "left_roll, body, head";
  273. }
  274. electron_bot_.SetTrims(right_pitch, right_roll, left_pitch, left_roll, body, head);
  275. QueueAction(ACTION_HOME, 1, 500, 0, 0);
  276. return "舵机 " + servo_type + " 微调设置为 " + std::to_string(trim_value) +
  277. " 度,已永久保存";
  278. });
  279. mcp_server.AddTool("self.electron.get_trims", "获取当前的舵机微调设置", PropertyList(),
  280. [this](const PropertyList& properties) -> ReturnValue {
  281. Settings settings("electron_trims", false);
  282. int right_pitch = settings.GetInt("right_pitch", 0);
  283. int right_roll = settings.GetInt("right_roll", 0);
  284. int left_pitch = settings.GetInt("left_pitch", 0);
  285. int left_roll = settings.GetInt("left_roll", 0);
  286. int body = settings.GetInt("body", 0);
  287. int head = settings.GetInt("head", 0);
  288. std::string result =
  289. "{\"right_pitch\":" + std::to_string(right_pitch) +
  290. ",\"right_roll\":" + std::to_string(right_roll) +
  291. ",\"left_pitch\":" + std::to_string(left_pitch) +
  292. ",\"left_roll\":" + std::to_string(left_roll) +
  293. ",\"body\":" + std::to_string(body) +
  294. ",\"head\":" + std::to_string(head) + "}";
  295. ESP_LOGI(TAG, "获取微调设置: %s", result.c_str());
  296. return result;
  297. });
  298. mcp_server.AddTool("self.battery.get_level", "获取机器人电池电量和充电状态", PropertyList(),
  299. [](const PropertyList& properties) -> ReturnValue {
  300. auto& board = Board::GetInstance();
  301. int level = 0;
  302. bool charging = false;
  303. bool discharging = false;
  304. board.GetBatteryLevel(level, charging, discharging);
  305. std::string status =
  306. "{\"level\":" + std::to_string(level) +
  307. ",\"charging\":" + (charging ? "true" : "false") + "}";
  308. return status;
  309. });
  310. ESP_LOGI(TAG, "Electron Bot MCP工具注册完成");
  311. }
  312. ~ElectronBotController() {
  313. if (action_task_handle_ != nullptr) {
  314. vTaskDelete(action_task_handle_);
  315. action_task_handle_ = nullptr;
  316. }
  317. vQueueDelete(action_queue_);
  318. }
  319. };
  320. static ElectronBotController* g_electron_controller = nullptr;
  321. void InitializeElectronBotController() {
  322. if (g_electron_controller == nullptr) {
  323. g_electron_controller = new ElectronBotController();
  324. ESP_LOGI(TAG, "Electron Bot控制器已初始化并注册MCP工具");
  325. }
  326. }