9.9
【目标任务】
在社区看到有老师做过四个舵机的宠物小狗,在B站一看,更多,就想着,啥时候自己也做一个出来玩玩,加上语音互动,很是好玩。虽然一直没有动手,却是在默默积累着力量。
当商城里出了行空板K10多功能扩展板,它支持四电机,所以做了小智MCP自然语言控制 K10 行空板麦轮小车- Makelog(造物记),它还支持6舵机,这不就可以试试做宠物小狗了么。
然而我的水平却是很菜,没法子一下子搞得很高端,只有从简单入手,慢慢来。
所以在这个帖子中,将记录我的制作过程,它会很low。
我是边做边记的,记下小狗的成长过程,请大家多多指导。


装上K10后:

任务分两部分:
视频1,展示K10离线语音识别控制宠物小狗,唤醒词是你好小新。

视频2,展示K10小智MCP自然语音控制宠物小狗,唤醒词是你好小智。

请看演示:
步骤1 从MIND+图形化开始
1、Mind+,选择K10,导入扩展板库:
Mind+用户库:
https://gitee.com/yeezb/ext-unihiker-expansion

2、编写简单程序,检测4个舵机的摆动方式。



它还是一个宝宝啊,没有任何的修饰。
它还没有头啊,扎的线束当做尾巴,屏幕也不是脸。突然想到二哈可以当头啊(手动狗头)。
舵机是胶枪粘上去的,分别左前--S0,左后--S1,右前--S2,右后--S3。

记录下四个舵机的摆动方式,以线束尾巴为后,左侧舵机大角度向后摆,右侧舵机大角度向前摆。

然后开始定义基本动作并上传测试:(以下角度为初步测试角度,而后面的经验证明要先装上长腿再测试)
每写一个动作都要充分测试。
站立 - 所有腿回到中立位:

坐下 - 后腿弯曲,前腿稍收:(左右舵机相同动作计算方法,左前+右前=180,左后+右后=180)

趴下 - 身体更贴近地面:

伸懒腰 - 前后腿伸展:

行走(步数): 左前右后腿向后蹬、右前左后腿直立,左前右后腿直立、右前左后腿向后蹬,交替进行:

打招呼 - 抬起一只前腿摆动:

玩耍 - 所有腿快速小范围移动:

先写以上几个动作吧,完整测试:



其实上网查查,还可以写更多,比如后退、左转、右转、叫两声等等。
下面是mind+生成的代码:
/*!
* MindPlus
* esp32s3bit
*
*/
#include "unihiker_k10.h"
#include "DFRobot_UnihikerExpansion.h"
// 函数声明
void DF_stand();
void DF_sit();
void DF_lieDown();
void DF_stretch();
void DF_walkForward(float mind_n_steps);
void DF_wave();
void DF_play();
// 创建对象
uint8_t screen_dir=2;
UNIHIKER_K10 k10;
DFRobot_UnihikerExpansion_I2C eunihiker(&Wire) ;
// 主程序开始
void setup() {
k10.begin();
k10.initScreen(screen_dir);
k10.creatCanvas();
while(!eunihiker.begin()){delay(1000);}
k10.setScreenBackground(0x000000);
k10.canvas->canvasText(" 行空板桌面宠物", 1, 0xFFFFFF);
k10.canvas->updateCanvas();
DF_stand();
delay(1000);
for (int index = 0; index < 3; index++) {
k10.canvas->canvasClear(3);
k10.canvas->canvasText("坐下", 3, 0xFFFFFF);
k10.canvas->updateCanvas();
DF_sit();
delay(1000);
k10.canvas->canvasClear(3);
k10.canvas->canvasText("趴下", 3, 0xFFFFFF);
k10.canvas->updateCanvas();
DF_lieDown();
delay(1000);
k10.canvas->canvasClear(3);
k10.canvas->canvasText("伸懒腰", 3, 0xFFFFFF);
k10.canvas->updateCanvas();
DF_stretch();
delay(1000);
k10.canvas->canvasClear(3);
k10.canvas->canvasText("玩耍", 3, 0xFFFFFF);
k10.canvas->updateCanvas();
DF_play();
delay(1000);
k10.canvas->canvasClear(3);
k10.canvas->canvasText("打招呼", 3, 0xFFFFFF);
k10.canvas->updateCanvas();
DF_wave();
delay(1000);
k10.canvas->canvasClear(3);
k10.canvas->canvasText("走几步", 3, 0xFFFFFF);
k10.canvas->updateCanvas();
DF_walkForward(10);
delay(1000);
k10.canvas->canvasClear(3);
k10.canvas->canvasText("站立", 3, 0xFFFFFF);
k10.canvas->updateCanvas();
DF_stand();
delay(1000);
}
}
void loop() {
}
// 自定义函数
void DF_stand() {
eunihiker.setServoAngle(eServo0, 90);
eunihiker.setServoAngle(eServo1, 90);
eunihiker.setServoAngle(eServo2, 90);
eunihiker.setServoAngle(eServo3, 90);
}
void DF_sit() {
eunihiker.setServoAngle(eServo0, 70);
eunihiker.setServoAngle(eServo1, 45);
eunihiker.setServoAngle(eServo2, 110);
eunihiker.setServoAngle(eServo3, 135);
}
void DF_lieDown() {
eunihiker.setServoAngle(eServo0, 30);
eunihiker.setServoAngle(eServo1, 30);
eunihiker.setServoAngle(eServo2, 150);
eunihiker.setServoAngle(eServo3, 150);
}
void DF_stretch() {
eunihiker.setServoAngle(eServo0, 45);
eunihiker.setServoAngle(eServo1, 160);
eunihiker.setServoAngle(eServo2, 135);
eunihiker.setServoAngle(eServo3, 20);
}
void DF_walkForward(float mind_n_steps) {
for (int index = 0; index < mind_n_steps; index++) {
eunihiker.setServoAngle(eServo0, 120);
eunihiker.setServoAngle(eServo3, 60);
eunihiker.setServoAngle(eServo1, 90);
eunihiker.setServoAngle(eServo2, 90);
delay(300);
eunihiker.setServoAngle(eServo0, 90);
eunihiker.setServoAngle(eServo3, 90);
eunihiker.setServoAngle(eServo1, 120);
eunihiker.setServoAngle(eServo2, 60);
delay(300);
}
delay(200);
DF_stand();
}
void DF_wave() {
DF_sit();
for (int index = 0; index < 3; index++) {
eunihiker.setServoAngle(eServo0, 45);
delay(200);
eunihiker.setServoAngle(eServo0, 90);
delay(200);
}
}
void DF_play() {
for (int index = 0; index < 5; index++) {
eunihiker.setServoAngle(eServo0, (random(50, 130+1)));
eunihiker.setServoAngle(eServo1, (random(50, 130+1)));
eunihiker.setServoAngle(eServo2, (random(50, 130+1)));
eunihiker.setServoAngle(eServo3, (random(50, 130+1)));
delay(150);
}
DF_stand();
}
步骤2 用mind+图形化写的语音控制程序
基本动作调试完成后,就想要用mind+写一个语音控制的程序了,K10上有双麦克风,离线语音识别效果拔群。
9.11
可是这个宠物太小短腿了,画一个长一点的腿出来。

打印……
装上……二哈……
桌面宠物小狗变样子了。
如果没有K10屏幕……还真有点可爱……。


不过……
小腿变长后,像狗了,可是重心变高了,原来小短腿测试通过动作,舵机角度还要再调调了。
现在后悔没有早点给小狗装上长腿了,小短腿和大长腿的步态有较大的不同啊。
还是继续改角度,再调试吧。
四足机器人的调试是一个“迭代”的过程,很少能一次成功。
小幅调整、仔细观察、记录参数是最好的方法。
现在先让小狗简单的运动起来,粗暴的动作有时会让小狗重心失衡。



动作测试基本满意了,就要加上语音命令了。
哈哈,加上语音命令后,发现上面调的动作还是有很多不足,继续调啊。
好吧,又做了些微调,基本上通过了,先贴程序在下面:

这只是阶段性成果,已经能听命令做动作了,虽然小狗的动作僵硬,但并不妨碍心中的快乐。
步骤3 Arduino IDE 写的代码
9.12
下面是用Arduino IDE 写的宠物小狗(短腿)运动测试代码,4个舵机的在不同动作时的角度,是参考图形化代码调出来的。
(因为后面我计划用小智mcp控制,还要用代码)。

(追记:后面换长腿了,下面代码中舵机角度也要调整。)
#include "DFRobot_UnihikerExpansion.h"
DFRobot_UnihikerExpansion_I2C eunihiker(&Wire);
// 舵机引脚定义
#define LEFT_FRONT eServo0 // S0 - 左前腿
#define LEFT_REAR eServo1 // S1 - 左后腿
#define RIGHT_FRONT eServo2 // S2 - 右前腿
#define RIGHT_REAR eServo3 // S3 - 右后腿
// 动作基准角度定义 (需要根据您的实际机械结构精细调整)
#define NEUTRAL 90 // 中立位角度
#define SIT_LF 70 // 坐下-左前
#define SIT_LR 45 // 坐下-左后
#define SIT_RF 110 // 坐下-右前
#define SIT_RR 135 // 坐下-右后
#define DOWN_LF 30 // 趴下-左前
#define DOWN_LR 30 // 趴下-左后
#define DOWN_RF 150 // 趴下-右前
#define DOWN_RR 150 // 趴下-右后
#define STRETCH_LF 45 // 伸懒腰-左前
#define STRETCH_LR 160 // 伸懒腰-左后
#define STRETCH_RF 135 // 伸懒腰-右前
#define STRETCH_RR 20 // 伸懒腰-右后
#define WALK1_LF_FWD 120 // 行走-左前后
#define WALK1_LR_BWD 120 // 行走-左后向后
#define WALK1_RF_FWD 60 // 行走-右前向后
#define WALK1_RR_BWD 60 // 行走-右后向后
#define WAVE_MIN 90 // 打招呼-抬起最小角度
#define WAVE_MAX 60 // 打招呼-抬起最大角度
#define PLAY_RANGE 40 // 玩耍动作变化范围
void setup() {
Serial.begin(115200);
while (!eunihiker.begin()) {
Serial.println("扩展板未连接!");
delay(1000);
}
Serial.println("扩展板连接成功!");
// 初始化后让小狗站立
stand();
delay(1000);
}
void loop() {
// 基础动作测试序列
Serial.println("测试: 站立");
stand();
delay(2000);
Serial.println("测试: 坐下");
sit();
delay(2000);
Serial.println("测试: 趴下");
lieDown();
delay(2000);
Serial.println("测试: 伸懒腰");
stretch();
delay(2000);
Serial.println("测试: 行走模式");
walk(10);
delay(1000);
Serial.println("测试: 打招呼");
wave();
delay(2000);
Serial.println("测试: 玩耍");
play();
delay(2000);
// 返回站立姿势
stand();
delay(5000); // 等待5秒后重新开始循环
}
// 站立 - 所有腿回到中立位
void stand() {
eunihiker.setServoAngle(LEFT_FRONT, NEUTRAL);
eunihiker.setServoAngle(LEFT_REAR, NEUTRAL);
eunihiker.setServoAngle(RIGHT_FRONT, NEUTRAL);
eunihiker.setServoAngle(RIGHT_REAR, NEUTRAL);
}
// 坐下 - 后腿弯曲,前腿稍收
void sit() {
eunihiker.setServoAngle(LEFT_FRONT, SIT_LF);
eunihiker.setServoAngle(LEFT_REAR, SIT_LR);
eunihiker.setServoAngle(RIGHT_FRONT, SIT_RF);
eunihiker.setServoAngle(RIGHT_REAR, SIT_RR);
}
// 趴下 - 身体更贴近地面
void lieDown() {
eunihiker.setServoAngle(LEFT_FRONT, DOWN_LF);
eunihiker.setServoAngle(LEFT_REAR, DOWN_LR);
eunihiker.setServoAngle(RIGHT_FRONT, DOWN_RF);
eunihiker.setServoAngle(RIGHT_REAR, DOWN_RR);
}
// 伸懒腰 - 前后腿伸展
void stretch() {
eunihiker.setServoAngle(LEFT_FRONT, STRETCH_LF);
eunihiker.setServoAngle(LEFT_REAR, STRETCH_LR);
eunihiker.setServoAngle(RIGHT_FRONT, STRETCH_RF);
eunihiker.setServoAngle(RIGHT_REAR, STRETCH_RR);
}
// 行走
void walk(int steps) {
for (int i = 0; i < steps; i++) {
// 左前右后腿向后,然后右前左后腿向后
eunihiker.setServoAngle(LEFT_FRONT, WALK1_LF_FWD);
eunihiker.setServoAngle(RIGHT_REAR, WALK1_RR_BWD);
eunihiker.setServoAngle(RIGHT_FRONT, NEUTRAL);
eunihiker.setServoAngle(LEFT_REAR, NEUTRAL);
delay(300);
eunihiker.setServoAngle(LEFT_FRONT, NEUTRAL);
eunihiker.setServoAngle(RIGHT_REAR, NEUTRAL);
eunihiker.setServoAngle(RIGHT_FRONT, WALK1_RF_FWD);
eunihiker.setServoAngle(LEFT_REAR, WALK1_LR_BWD);
delay(300);
}
delay(200);
stand(); // 回到站立姿势
}
// 打招呼 - 抬起一只前腿摆动
void wave() {
for (int i = 0; i < 3; i++) {
eunihiker.setServoAngle(LEFT_FRONT, WAVE_MIN);
delay(200);
eunihiker.setServoAngle(LEFT_FRONT, WAVE_MAX);
delay(200);
}
eunihiker.setServoAngle(LEFT_FRONT, NEUTRAL); // 回归中立位
}
// 玩耍 - 所有腿快速小范围移动
void play() {
for (int i = 0; i < 5; i++) {
// 随机小范围移动各个腿
eunihiker.setServoAngle(LEFT_FRONT, NEUTRAL + random(-PLAY_RANGE, PLAY_RANGE));
eunihiker.setServoAngle(LEFT_REAR, NEUTRAL + random(-PLAY_RANGE, PLAY_RANGE));
eunihiker.setServoAngle(RIGHT_FRONT, NEUTRAL + random(-PLAY_RANGE, PLAY_RANGE));
eunihiker.setServoAngle(RIGHT_REAR, NEUTRAL + random(-PLAY_RANGE, PLAY_RANGE));
delay(150);
}
stand(); // 回归站立姿势
}
步骤4 小智mcp出马,自然语言控制的K10桌面宠物它来了
接着,小智要出马了,结合xiaozhi_mcp库来改写代码,这次的代码主要是由大圣老师参考上一个项目代码改写的,中间出现了一些语法错误,找AI帮助解决了。

#include <WiFi.h>
#include <WebSocketMCP.h>
#include "unihiker_k10.h"
#include "DFRobot_UnihikerExpansion.h"
DFRobot_UnihikerExpansion_I2C eunihiker(&Wire);
// 定义运动模式枚举
enum DogMovementMode {
MODE_STAND, // 站立
MODE_SIT, // 坐下
MODE_LIEDOWN, // 趴下
MODE_PLAY, // 玩耍
MODE_WAVE, // 打招呼
MODE_WALK, // 行走
MODE_STRETCH, // 伸懒腰
};
// WiFi配置
const char* ssid = "********";
const char* password = "********";
// MCP服务器配置
const char* mcpEndpoint = "ws://api.xiaozhi.me/mcp/?token=e**********";
// 创建WebSocketMCP实例
WebSocketMCP mcpClient;
UNIHIKER_K10 k10;
uint8_t screen_dir = 2;
// 连接状态回调函数
void onConnectionStatus(bool connected) {
if (connected) {
Serial.println("[MCP] 已连接到服务器");
// 连接成功后注册工具
registerMcpTools();
} else {
Serial.println("[MCP] 与服务器断开连接");
}
}
// 舵机引脚定义
#define LEFT_FRONT eServo0 // S0 - 左前腿
#define LEFT_REAR eServo1 // S1 - 左后腿
#define RIGHT_FRONT eServo2 // S2 - 右前腿
#define RIGHT_REAR eServo3 // S3 - 右后腿
// 动作基准角度定义 (需要根据您的实际机械结构精细调整)
#define NEUTRAL 90 // 中立位角度
#define SIT_LF 90 // 坐下-左前
#define SIT_LR 75 // 坐下-左后
#define SIT_RF 90 // 坐下-右前
#define SIT_RR 105 // 坐下-右后
#define SIT_LR1 60 // 坐下-左后
#define SIT_RR1 120 // 坐下-右后
#define DOWN_LF 30 // 趴下-左前
#define DOWN_RF 150 // 趴下-右前
#define DOWN_LR 70 // 趴下-左后
#define DOWN_RR 110 // 趴下-右后
#define DOWN_LR1 50 // 趴下-左后
#define DOWN_RR1 130 // 趴下-右后
#define STRETCH_LF 45 // 伸懒腰-左前
#define STRETCH_LR 160 // 伸懒腰-左后
#define STRETCH_RF 135 // 伸懒腰-右前
#define STRETCH_RR 20 // 伸懒腰-右后
#define WALK_LF_FWD 120 // 行走-左前后
#define WALK_LR_BWD 120 // 行走-左后向后
#define WALK_RF_FWD 60 // 行走-右前向后
#define WALK_RR_BWD 60 // 行走-右后向后
#define WAVE_MIN 135 // 打招呼-抬起最小角度
#define WAVE_MAX 180 // 打招呼-抬起最大角度
#define PLAY_RANGE 40 // 玩耍动作变化范围
// 宠物小狗运动控制函数
void DogMove(DogMovementMode mode) {
switch(mode) {
case MODE_STAND:// 站立 - 所有腿回到中立位
eunihiker.setServoAngle(LEFT_FRONT, NEUTRAL);
eunihiker.setServoAngle(LEFT_REAR, NEUTRAL);
eunihiker.setServoAngle(RIGHT_FRONT, NEUTRAL);
eunihiker.setServoAngle(RIGHT_REAR, NEUTRAL);
break;
case MODE_PLAY:// 玩耍 - 所有腿快速小范围移动
for (int i = 0; i < 5; i++) {
// 随机小范围移动各个腿
eunihiker.setServoAngle(LEFT_FRONT, NEUTRAL + random(-PLAY_RANGE, PLAY_RANGE));
eunihiker.setServoAngle(LEFT_REAR, NEUTRAL + random(-PLAY_RANGE, PLAY_RANGE));
eunihiker.setServoAngle(RIGHT_FRONT, NEUTRAL + random(-PLAY_RANGE, PLAY_RANGE));
eunihiker.setServoAngle(RIGHT_REAR, NEUTRAL + random(-PLAY_RANGE, PLAY_RANGE));
delay(150);
}
eunihiker.setServoAngle(LEFT_FRONT, NEUTRAL);
eunihiker.setServoAngle(LEFT_REAR, NEUTRAL);
eunihiker.setServoAngle(RIGHT_FRONT, NEUTRAL);
eunihiker.setServoAngle(RIGHT_REAR, NEUTRAL);
break;
case MODE_WAVE:// 打招呼 - 抬起一只前腿摆动
eunihiker.setServoAngle(LEFT_FRONT, SIT_LF);
eunihiker.setServoAngle(LEFT_REAR, SIT_LR);
eunihiker.setServoAngle(RIGHT_FRONT, SIT_RF);
eunihiker.setServoAngle(RIGHT_REAR, SIT_RR);
delay(1000);
eunihiker.setServoAngle(LEFT_REAR, SIT_LR1);
eunihiker.setServoAngle(RIGHT_REAR, SIT_RR1);
delay(1000);
for (int i = 0; i < 3; i++) {
eunihiker.setServoAngle(RIGHT_FRONT, WAVE_MIN);
delay(200);
eunihiker.setServoAngle(RIGHT_FRONT, WAVE_MAX);
delay(200);
}
eunihiker.setServoAngle(RIGHT_FRONT, NEUTRAL); // 回归中立位
break;
case MODE_SIT:// 坐下 - 后腿弯曲,前腿稍收
eunihiker.setServoAngle(LEFT_FRONT, SIT_LF);
eunihiker.setServoAngle(LEFT_REAR, SIT_LR);
eunihiker.setServoAngle(RIGHT_FRONT, SIT_RF);
eunihiker.setServoAngle(RIGHT_REAR, SIT_RR);
delay(1000);
eunihiker.setServoAngle(LEFT_REAR, SIT_LR1);
eunihiker.setServoAngle(RIGHT_REAR, SIT_RR1);
delay(1000);
break;
case MODE_STRETCH:// 伸懒腰 - 前后腿伸展
eunihiker.setServoAngle(LEFT_FRONT, STRETCH_LF);
eunihiker.setServoAngle(LEFT_REAR, STRETCH_LR);
eunihiker.setServoAngle(RIGHT_FRONT, STRETCH_RF);
eunihiker.setServoAngle(RIGHT_REAR, STRETCH_RR);
break;
case MODE_LIEDOWN: // 趴下 - 身体更贴近地面
eunihiker.setServoAngle(LEFT_FRONT, DOWN_LF);
eunihiker.setServoAngle(RIGHT_FRONT, DOWN_RF);
delay(500);
eunihiker.setServoAngle(LEFT_REAR, DOWN_LR);
eunihiker.setServoAngle(RIGHT_REAR, DOWN_RR);
delay(500);
eunihiker.setServoAngle(LEFT_REAR, DOWN_LR1);
eunihiker.setServoAngle(RIGHT_REAR, DOWN_RR1);
break;
case MODE_WALK:// 行走
for (int i = 0; i < 10; i++) {
// 左前右后腿向后,然后右前左后腿向后
eunihiker.setServoAngle(LEFT_FRONT, WALK_LF_FWD);
eunihiker.setServoAngle(RIGHT_REAR, WALK_RR_BWD);
eunihiker.setServoAngle(RIGHT_FRONT, NEUTRAL);
eunihiker.setServoAngle(LEFT_REAR, NEUTRAL);
delay(300);
eunihiker.setServoAngle(LEFT_FRONT, NEUTRAL);
eunihiker.setServoAngle(RIGHT_REAR, NEUTRAL);
eunihiker.setServoAngle(RIGHT_FRONT, WALK_RF_FWD);
eunihiker.setServoAngle(LEFT_REAR, WALK_LR_BWD);
delay(300);
}
delay(200);
eunihiker.setServoAngle(LEFT_FRONT, NEUTRAL);
eunihiker.setServoAngle(LEFT_REAR, NEUTRAL);
eunihiker.setServoAngle(RIGHT_FRONT, NEUTRAL);
eunihiker.setServoAngle(RIGHT_REAR, NEUTRAL);
break;
default:
// 未知模式,回到站立姿态
eunihiker.setServoAngle(LEFT_FRONT, NEUTRAL);
eunihiker.setServoAngle(LEFT_REAR, NEUTRAL);
eunihiker.setServoAngle(RIGHT_FRONT, NEUTRAL);
eunihiker.setServoAngle(RIGHT_REAR, NEUTRAL);
return;
}
}
// 注册MCP工具
void registerMcpTools() {
mcpClient.registerTool(
"dog_move", // 工具名称
"控制桌面4足宠物小狗进行7种运动模式。模式包括: walk, stand, sit, play, wave, liedown, stretch", // 详细描述
"{\"type\":\"object\",\"properties\":{\"mode\":{\"type\":\"string\",\"enum\":[\"walk\",\"sit\",\"stand\",\"stretch\",\"liedown\",\"play\",\"wave\"]}},\"required\":[\"mode\"]}", // 修正Schema: 补全括号,添加required字段
[](const String& args) {
DynamicJsonDocument doc(256);
deserializeJson(doc, args);
String modeStr = doc["mode"].as<String>();
// 将字符串模式转换为枚举值
DogMovementMode mode;
if (modeStr == "stand") mode = MODE_STAND;
else if (modeStr == "sit") mode = MODE_SIT;
else if (modeStr == "play") mode = MODE_PLAY;
else if (modeStr == "walk") mode = MODE_WALK;
else if (modeStr == "wave") mode = MODE_WAVE;
else if (modeStr == "stretch") mode = MODE_STRETCH;
else if (modeStr == "liedown") mode = MODE_LIEDOWN;
else {
String response = "{\"success\": false, \"error\": \"Invalid mode: " + modeStr + "\"}";
return WebSocketMCP::ToolResponse(response);
}
DogMove(mode);
String response = "{\"success\": true, \"action\": \"" + modeStr + "\"}";
return WebSocketMCP::ToolResponse(response);
}
);
Serial.println("[MCP] 桌面宠物小狗运动统一工具已注册");
}
void setup() {
Serial.begin(115200);
Serial.print("连接到WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
unsigned long wifiStartTime = millis();
while (WiFi.status() != WL_CONNECTED && millis() - wifiStartTime < 10000) {
delay(200);
Serial.print(".");
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("WiFi已连接");
Serial.println("IP地址: " + WiFi.localIP().toString());
mcpClient.begin(mcpEndpoint, onConnectionStatus);
} else {
Serial.println("WiFi连接失败");
return;
}
k10.begin();
k10.initScreen(screen_dir);
k10.creatCanvas();
k10.setScreenBackground(0x000000);
k10.canvas->canvasText("K10桌面宠物小狗狗", 10, 10, 0xFFFFFF, k10.canvas->eCNAndENFont24, 200, true);
k10.canvas->updateCanvas();
if(eunihiker.begin()){
Serial.println("Device connected !");
DogMove(MODE_STAND); // 让小狗站立
} else {
Serial.println("扩展板初始化失败!");
}
}
void loop() {
mcpClient.loop();
delay(10);
}
成功接入小智MCP,可以用小智AI控制了。

【小结】
这是我第一次做四舵机宠物小狗,从9.9开始,到9.13,花费了5天的工余时间,从裸奔的板子到可以语音互动一个有头(装饰)有腿有点像样的桌面宠物,可以两种方式控制,还是蛮开心的。
我不打算给它做外壳了,只希望有时间了增加动作、优化代码,让舵机角度渐变而不是瞬间切换,让步伐更平滑。这需要更复杂的代码,比如使用循环逐步改变角度。这将是后续努力方向。
评论