otto_controller.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*
  2. Otto机器人控制器 - 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 "otto_movements.h"
  12. #include "sdkconfig.h"
  13. #include "settings.h"
  14. #define TAG "OttoController"
  15. class OttoController {
  16. private:
  17. Otto otto_;
  18. TaskHandle_t action_task_handle_ = nullptr;
  19. QueueHandle_t action_queue_;
  20. bool has_hands_ = false;
  21. bool is_action_in_progress_ = false;
  22. struct OttoActionParams {
  23. int action_type;
  24. int steps;
  25. int speed;
  26. int direction;
  27. int amount;
  28. };
  29. enum ActionType {
  30. ACTION_WALK = 1,
  31. ACTION_TURN = 2,
  32. ACTION_JUMP = 3,
  33. ACTION_SWING = 4,
  34. ACTION_MOONWALK = 5,
  35. ACTION_BEND = 6,
  36. ACTION_SHAKE_LEG = 7,
  37. ACTION_UPDOWN = 8,
  38. ACTION_TIPTOE_SWING = 9,
  39. ACTION_JITTER = 10,
  40. ACTION_ASCENDING_TURN = 11,
  41. ACTION_CRUSAITO = 12,
  42. ACTION_FLAPPING = 13,
  43. ACTION_HANDS_UP = 14,
  44. ACTION_HANDS_DOWN = 15,
  45. ACTION_HAND_WAVE = 16,
  46. ACTION_HOME = 17
  47. };
  48. static void ActionTask(void* arg) {
  49. OttoController* controller = static_cast<OttoController*>(arg);
  50. OttoActionParams params;
  51. controller->otto_.AttachServos();
  52. while (true) {
  53. if (xQueueReceive(controller->action_queue_, &params, pdMS_TO_TICKS(1000)) == pdTRUE) {
  54. ESP_LOGI(TAG, "执行动作: %d", params.action_type);
  55. controller->is_action_in_progress_ = true;
  56. switch (params.action_type) {
  57. case ACTION_WALK:
  58. controller->otto_.Walk(params.steps, params.speed, params.direction,
  59. params.amount);
  60. break;
  61. case ACTION_TURN:
  62. controller->otto_.Turn(params.steps, params.speed, params.direction,
  63. params.amount);
  64. break;
  65. case ACTION_JUMP:
  66. controller->otto_.Jump(params.steps, params.speed);
  67. break;
  68. case ACTION_SWING:
  69. controller->otto_.Swing(params.steps, params.speed, params.amount);
  70. break;
  71. case ACTION_MOONWALK:
  72. controller->otto_.Moonwalker(params.steps, params.speed, params.amount,
  73. params.direction);
  74. break;
  75. case ACTION_BEND:
  76. controller->otto_.Bend(params.steps, params.speed, params.direction);
  77. break;
  78. case ACTION_SHAKE_LEG:
  79. controller->otto_.ShakeLeg(params.steps, params.speed, params.direction);
  80. break;
  81. case ACTION_UPDOWN:
  82. controller->otto_.UpDown(params.steps, params.speed, params.amount);
  83. break;
  84. case ACTION_TIPTOE_SWING:
  85. controller->otto_.TiptoeSwing(params.steps, params.speed, params.amount);
  86. break;
  87. case ACTION_JITTER:
  88. controller->otto_.Jitter(params.steps, params.speed, params.amount);
  89. break;
  90. case ACTION_ASCENDING_TURN:
  91. controller->otto_.AscendingTurn(params.steps, params.speed, params.amount);
  92. break;
  93. case ACTION_CRUSAITO:
  94. controller->otto_.Crusaito(params.steps, params.speed, params.amount,
  95. params.direction);
  96. break;
  97. case ACTION_FLAPPING:
  98. controller->otto_.Flapping(params.steps, params.speed, params.amount,
  99. params.direction);
  100. break;
  101. case ACTION_HANDS_UP:
  102. if (controller->has_hands_) {
  103. controller->otto_.HandsUp(params.speed, params.direction);
  104. }
  105. break;
  106. case ACTION_HANDS_DOWN:
  107. if (controller->has_hands_) {
  108. controller->otto_.HandsDown(params.speed, params.direction);
  109. }
  110. break;
  111. case ACTION_HAND_WAVE:
  112. if (controller->has_hands_) {
  113. controller->otto_.HandWave(params.speed, params.direction);
  114. }
  115. break;
  116. case ACTION_HOME:
  117. controller->otto_.Home(params.direction == 1);
  118. break;
  119. }
  120. if (params.action_type != ACTION_HOME) {
  121. controller->otto_.Home(params.action_type < ACTION_HANDS_UP);
  122. }
  123. controller->is_action_in_progress_ = false;
  124. vTaskDelay(pdMS_TO_TICKS(20));
  125. }
  126. }
  127. }
  128. void StartActionTaskIfNeeded() {
  129. if (action_task_handle_ == nullptr) {
  130. xTaskCreate(ActionTask, "otto_action", 1024 * 3, this, configMAX_PRIORITIES - 1,
  131. &action_task_handle_);
  132. }
  133. }
  134. void QueueAction(int action_type, int steps, int speed, int direction, int amount) {
  135. // 检查手部动作
  136. if ((action_type >= ACTION_HANDS_UP && action_type <= ACTION_HAND_WAVE) && !has_hands_) {
  137. ESP_LOGW(TAG, "尝试执行手部动作,但机器人没有配置手部舵机");
  138. return;
  139. }
  140. ESP_LOGI(TAG, "动作控制: 类型=%d, 步数=%d, 速度=%d, 方向=%d, 幅度=%d", action_type, steps,
  141. speed, direction, amount);
  142. OttoActionParams params = {action_type, steps, speed, direction, amount};
  143. xQueueSend(action_queue_, &params, portMAX_DELAY);
  144. StartActionTaskIfNeeded();
  145. }
  146. void LoadTrimsFromNVS() {
  147. Settings settings("otto_trims", false);
  148. int left_leg = settings.GetInt("left_leg", 0);
  149. int right_leg = settings.GetInt("right_leg", 0);
  150. int left_foot = settings.GetInt("left_foot", 0);
  151. int right_foot = settings.GetInt("right_foot", 0);
  152. int left_hand = settings.GetInt("left_hand", 0);
  153. int right_hand = settings.GetInt("right_hand", 0);
  154. ESP_LOGI(TAG, "从NVS加载微调设置: 左腿=%d, 右腿=%d, 左脚=%d, 右脚=%d, 左手=%d, 右手=%d",
  155. left_leg, right_leg, left_foot, right_foot, left_hand, right_hand);
  156. otto_.SetTrims(left_leg, right_leg, left_foot, right_foot, left_hand, right_hand);
  157. }
  158. public:
  159. OttoController() {
  160. otto_.Init(LEFT_LEG_PIN, RIGHT_LEG_PIN, LEFT_FOOT_PIN, RIGHT_FOOT_PIN, LEFT_HAND_PIN,
  161. RIGHT_HAND_PIN);
  162. has_hands_ = (LEFT_HAND_PIN != -1 && RIGHT_HAND_PIN != -1);
  163. ESP_LOGI(TAG, "Otto机器人初始化%s手部舵机", has_hands_ ? "带" : "不带");
  164. LoadTrimsFromNVS();
  165. action_queue_ = xQueueCreate(10, sizeof(OttoActionParams));
  166. QueueAction(ACTION_HOME, 1, 1000, 1, 0); // direction=1表示复位手部
  167. RegisterMcpTools();
  168. }
  169. void RegisterMcpTools() {
  170. auto& mcp_server = McpServer::GetInstance();
  171. ESP_LOGI(TAG, "开始注册MCP工具...");
  172. // 基础移动动作
  173. mcp_server.AddTool("self.otto.walk_forward",
  174. "行走。steps: 行走步数(1-100); speed: 行走速度(500-1500,数值越小越快); "
  175. "direction: 行走方向(-1=后退, 1=前进); arm_swing: 手臂摆动幅度(0-170度)",
  176. PropertyList({Property("steps", kPropertyTypeInteger, 3, 1, 100),
  177. Property("speed", kPropertyTypeInteger, 1000, 500, 1500),
  178. Property("arm_swing", kPropertyTypeInteger, 50, 0, 170),
  179. Property("direction", kPropertyTypeInteger, 1, -1, 1)}),
  180. [this](const PropertyList& properties) -> ReturnValue {
  181. int steps = properties["steps"].value<int>();
  182. int speed = properties["speed"].value<int>();
  183. int arm_swing = properties["arm_swing"].value<int>();
  184. int direction = properties["direction"].value<int>();
  185. QueueAction(ACTION_WALK, steps, speed, direction, arm_swing);
  186. return true;
  187. });
  188. mcp_server.AddTool("self.otto.turn_left",
  189. "转身。steps: 转身步数(1-100); speed: 转身速度(500-1500,数值越小越快); "
  190. "direction: 转身方向(1=左转, -1=右转); arm_swing: 手臂摆动幅度(0-170度)",
  191. PropertyList({Property("steps", kPropertyTypeInteger, 3, 1, 100),
  192. Property("speed", kPropertyTypeInteger, 1000, 500, 1500),
  193. Property("arm_swing", kPropertyTypeInteger, 50, 0, 170),
  194. Property("direction", kPropertyTypeInteger, 1, -1, 1)}),
  195. [this](const PropertyList& properties) -> ReturnValue {
  196. int steps = properties["steps"].value<int>();
  197. int speed = properties["speed"].value<int>();
  198. int arm_swing = properties["arm_swing"].value<int>();
  199. int direction = properties["direction"].value<int>();
  200. QueueAction(ACTION_TURN, steps, speed, direction, arm_swing);
  201. return true;
  202. });
  203. mcp_server.AddTool("self.otto.jump",
  204. "跳跃。steps: 跳跃次数(1-100); speed: 跳跃速度(500-1500,数值越小越快)",
  205. PropertyList({Property("steps", kPropertyTypeInteger, 1, 1, 100),
  206. Property("speed", kPropertyTypeInteger, 1000, 500, 1500)}),
  207. [this](const PropertyList& properties) -> ReturnValue {
  208. int steps = properties["steps"].value<int>();
  209. int speed = properties["speed"].value<int>();
  210. QueueAction(ACTION_JUMP, steps, speed, 0, 0);
  211. return true;
  212. });
  213. // 特殊动作
  214. mcp_server.AddTool("self.otto.swing",
  215. "左右摇摆。steps: 摇摆次数(1-100); speed: "
  216. "摇摆速度(500-1500,数值越小越快); amount: 摇摆幅度(0-170度)",
  217. PropertyList({Property("steps", kPropertyTypeInteger, 3, 1, 100),
  218. Property("speed", kPropertyTypeInteger, 1000, 500, 1500),
  219. Property("amount", kPropertyTypeInteger, 30, 0, 170)}),
  220. [this](const PropertyList& properties) -> ReturnValue {
  221. int steps = properties["steps"].value<int>();
  222. int speed = properties["speed"].value<int>();
  223. int amount = properties["amount"].value<int>();
  224. QueueAction(ACTION_SWING, steps, speed, 0, amount);
  225. return true;
  226. });
  227. mcp_server.AddTool("self.otto.moonwalk",
  228. "太空步。steps: 太空步步数(1-100); speed: 速度(500-1500,数值越小越快); "
  229. "direction: 方向(1=左, -1=右); amount: 幅度(0-170度)",
  230. PropertyList({Property("steps", kPropertyTypeInteger, 3, 1, 100),
  231. Property("speed", kPropertyTypeInteger, 1000, 500, 1500),
  232. Property("direction", kPropertyTypeInteger, 1, -1, 1),
  233. Property("amount", kPropertyTypeInteger, 25, 0, 170)}),
  234. [this](const PropertyList& properties) -> ReturnValue {
  235. int steps = properties["steps"].value<int>();
  236. int speed = properties["speed"].value<int>();
  237. int direction = properties["direction"].value<int>();
  238. int amount = properties["amount"].value<int>();
  239. QueueAction(ACTION_MOONWALK, steps, speed, direction, amount);
  240. return true;
  241. });
  242. mcp_server.AddTool("self.otto.bend",
  243. "弯曲身体。steps: 弯曲次数(1-100); speed: "
  244. "弯曲速度(500-1500,数值越小越快); direction: 弯曲方向(1=左, -1=右)",
  245. PropertyList({Property("steps", kPropertyTypeInteger, 1, 1, 100),
  246. Property("speed", kPropertyTypeInteger, 1000, 500, 1500),
  247. Property("direction", kPropertyTypeInteger, 1, -1, 1)}),
  248. [this](const PropertyList& properties) -> ReturnValue {
  249. int steps = properties["steps"].value<int>();
  250. int speed = properties["speed"].value<int>();
  251. int direction = properties["direction"].value<int>();
  252. QueueAction(ACTION_BEND, steps, speed, direction, 0);
  253. return true;
  254. });
  255. mcp_server.AddTool("self.otto.shake_leg",
  256. "摇腿。steps: 摇腿次数(1-100); speed: 摇腿速度(500-1500,数值越小越快); "
  257. "direction: 腿部选择(1=左腿, -1=右腿)",
  258. PropertyList({Property("steps", kPropertyTypeInteger, 1, 1, 100),
  259. Property("speed", kPropertyTypeInteger, 1000, 500, 1500),
  260. Property("direction", kPropertyTypeInteger, 1, -1, 1)}),
  261. [this](const PropertyList& properties) -> ReturnValue {
  262. int steps = properties["steps"].value<int>();
  263. int speed = properties["speed"].value<int>();
  264. int direction = properties["direction"].value<int>();
  265. QueueAction(ACTION_SHAKE_LEG, steps, speed, direction, 0);
  266. return true;
  267. });
  268. mcp_server.AddTool("self.otto.updown",
  269. "上下运动。steps: 上下运动次数(1-100); speed: "
  270. "运动速度(500-1500,数值越小越快); amount: 运动幅度(0-170度)",
  271. PropertyList({Property("steps", kPropertyTypeInteger, 3, 1, 100),
  272. Property("speed", kPropertyTypeInteger, 1000, 500, 1500),
  273. Property("amount", kPropertyTypeInteger, 20, 0, 170)}),
  274. [this](const PropertyList& properties) -> ReturnValue {
  275. int steps = properties["steps"].value<int>();
  276. int speed = properties["speed"].value<int>();
  277. int amount = properties["amount"].value<int>();
  278. QueueAction(ACTION_UPDOWN, steps, speed, 0, amount);
  279. return true;
  280. });
  281. // 手部动作(仅在有手部舵机时可用)
  282. if (has_hands_) {
  283. mcp_server.AddTool(
  284. "self.otto.hands_up",
  285. "举手。speed: 举手速度(500-1500,数值越小越快); direction: 手部选择(1=左手, "
  286. "-1=右手, 0=双手)",
  287. PropertyList({Property("speed", kPropertyTypeInteger, 1000, 500, 1500),
  288. Property("direction", kPropertyTypeInteger, 1, -1, 1)}),
  289. [this](const PropertyList& properties) -> ReturnValue {
  290. int speed = properties["speed"].value<int>();
  291. int direction = properties["direction"].value<int>();
  292. QueueAction(ACTION_HANDS_UP, 1, speed, direction, 0);
  293. return true;
  294. });
  295. mcp_server.AddTool(
  296. "self.otto.hands_down",
  297. "放手。speed: 放手速度(500-1500,数值越小越快); direction: 手部选择(1=左手, "
  298. "-1=右手, 0=双手)",
  299. PropertyList({Property("speed", kPropertyTypeInteger, 1000, 500, 1500),
  300. Property("direction", kPropertyTypeInteger, 1, -1, 1)}),
  301. [this](const PropertyList& properties) -> ReturnValue {
  302. int speed = properties["speed"].value<int>();
  303. int direction = properties["direction"].value<int>();
  304. QueueAction(ACTION_HANDS_DOWN, 1, speed, direction, 0);
  305. return true;
  306. });
  307. mcp_server.AddTool(
  308. "self.otto.hand_wave",
  309. "挥手。speed: 挥手速度(500-1500,数值越小越快); direction: 手部选择(1=左手, "
  310. "-1=右手, 0=双手)",
  311. PropertyList({Property("speed", kPropertyTypeInteger, 1000, 500, 1500),
  312. Property("direction", kPropertyTypeInteger, 1, -1, 1)}),
  313. [this](const PropertyList& properties) -> ReturnValue {
  314. int speed = properties["speed"].value<int>();
  315. int direction = properties["direction"].value<int>();
  316. QueueAction(ACTION_HAND_WAVE, 1, speed, direction, 0);
  317. return true;
  318. });
  319. }
  320. // 系统工具
  321. mcp_server.AddTool("self.otto.stop", "立即停止", PropertyList(),
  322. [this](const PropertyList& properties) -> ReturnValue {
  323. if (action_task_handle_ != nullptr) {
  324. vTaskDelete(action_task_handle_);
  325. action_task_handle_ = nullptr;
  326. }
  327. is_action_in_progress_ = false;
  328. xQueueReset(action_queue_);
  329. QueueAction(ACTION_HOME, 1, 1000, 1, 0);
  330. return true;
  331. });
  332. mcp_server.AddTool(
  333. "self.otto.set_trim",
  334. "校准单个舵机位置。设置指定舵机的微调参数以调整Otto的初始站立姿态,设置将永久保存。"
  335. "servo_type: 舵机类型(left_leg/right_leg/left_foot/right_foot/left_hand/right_hand); "
  336. "trim_value: 微调值(-50到50度)",
  337. PropertyList({Property("servo_type", kPropertyTypeString, "left_leg"),
  338. Property("trim_value", kPropertyTypeInteger, 0, -50, 50)}),
  339. [this](const PropertyList& properties) -> ReturnValue {
  340. std::string servo_type = properties["servo_type"].value<std::string>();
  341. int trim_value = properties["trim_value"].value<int>();
  342. ESP_LOGI(TAG, "设置舵机微调: %s = %d度", servo_type.c_str(), trim_value);
  343. // 获取当前所有微调值
  344. Settings settings("otto_trims", true);
  345. int left_leg = settings.GetInt("left_leg", 0);
  346. int right_leg = settings.GetInt("right_leg", 0);
  347. int left_foot = settings.GetInt("left_foot", 0);
  348. int right_foot = settings.GetInt("right_foot", 0);
  349. int left_hand = settings.GetInt("left_hand", 0);
  350. int right_hand = settings.GetInt("right_hand", 0);
  351. // 更新指定舵机的微调值
  352. if (servo_type == "left_leg") {
  353. left_leg = trim_value;
  354. settings.SetInt("left_leg", left_leg);
  355. } else if (servo_type == "right_leg") {
  356. right_leg = trim_value;
  357. settings.SetInt("right_leg", right_leg);
  358. } else if (servo_type == "left_foot") {
  359. left_foot = trim_value;
  360. settings.SetInt("left_foot", left_foot);
  361. } else if (servo_type == "right_foot") {
  362. right_foot = trim_value;
  363. settings.SetInt("right_foot", right_foot);
  364. } else if (servo_type == "left_hand") {
  365. if (!has_hands_) {
  366. return "错误:机器人没有配置手部舵机";
  367. }
  368. left_hand = trim_value;
  369. settings.SetInt("left_hand", left_hand);
  370. } else if (servo_type == "right_hand") {
  371. if (!has_hands_) {
  372. return "错误:机器人没有配置手部舵机";
  373. }
  374. right_hand = trim_value;
  375. settings.SetInt("right_hand", right_hand);
  376. } else {
  377. return "错误:无效的舵机类型,请使用: left_leg, right_leg, left_foot, "
  378. "right_foot, left_hand, right_hand";
  379. }
  380. otto_.SetTrims(left_leg, right_leg, left_foot, right_foot, left_hand, right_hand);
  381. QueueAction(ACTION_JUMP, 1, 500, 0, 0);
  382. return "舵机 " + servo_type + " 微调设置为 " + std::to_string(trim_value) +
  383. " 度,已永久保存";
  384. });
  385. mcp_server.AddTool("self.otto.get_trims", "获取当前的舵机微调设置", PropertyList(),
  386. [this](const PropertyList& properties) -> ReturnValue {
  387. Settings settings("otto_trims", false);
  388. int left_leg = settings.GetInt("left_leg", 0);
  389. int right_leg = settings.GetInt("right_leg", 0);
  390. int left_foot = settings.GetInt("left_foot", 0);
  391. int right_foot = settings.GetInt("right_foot", 0);
  392. int left_hand = settings.GetInt("left_hand", 0);
  393. int right_hand = settings.GetInt("right_hand", 0);
  394. std::string result =
  395. "{\"left_leg\":" + std::to_string(left_leg) +
  396. ",\"right_leg\":" + std::to_string(right_leg) +
  397. ",\"left_foot\":" + std::to_string(left_foot) +
  398. ",\"right_foot\":" + std::to_string(right_foot) +
  399. ",\"left_hand\":" + std::to_string(left_hand) +
  400. ",\"right_hand\":" + std::to_string(right_hand) + "}";
  401. ESP_LOGI(TAG, "获取微调设置: %s", result.c_str());
  402. return result;
  403. });
  404. mcp_server.AddTool("self.otto.get_status", "获取机器人状态,返回 moving 或 idle",
  405. PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
  406. return is_action_in_progress_ ? "moving" : "idle";
  407. });
  408. mcp_server.AddTool("self.battery.get_level", "获取机器人电池电量和充电状态", PropertyList(),
  409. [](const PropertyList& properties) -> ReturnValue {
  410. auto& board = Board::GetInstance();
  411. int level = 0;
  412. bool charging = false;
  413. bool discharging = false;
  414. board.GetBatteryLevel(level, charging, discharging);
  415. std::string status =
  416. "{\"level\":" + std::to_string(level) +
  417. ",\"charging\":" + (charging ? "true" : "false") + "}";
  418. return status;
  419. });
  420. ESP_LOGI(TAG, "MCP工具注册完成");
  421. }
  422. ~OttoController() {
  423. if (action_task_handle_ != nullptr) {
  424. vTaskDelete(action_task_handle_);
  425. action_task_handle_ = nullptr;
  426. }
  427. vQueueDelete(action_queue_);
  428. }
  429. };
  430. static OttoController* g_otto_controller = nullptr;
  431. void InitializeOttoController() {
  432. if (g_otto_controller == nullptr) {
  433. g_otto_controller = new OttoController();
  434. ESP_LOGI(TAG, "Otto控制器已初始化并注册MCP工具");
  435. }
  436. }