8.28
【写在前面】
这个帖子是roco小智双电机小车+传感器,变身环境监测小车- Makelog(造物记)的续集,也是体验编程狮Roco的最后一帖,其实加上创意,用roco可以完成很多好玩的功能,不过我就是浅浅的体验一下,所以在体验ROCO的MCP功能后,就结束了。
先说结论,ROCO的MCP功能用图形化实现,简单且方便。

材料清单
- K10小智AI X1
- ESP32 S3 N16R8开发板 X1
- DF L298N电机驱动模块 X1
- 7V 电池盒 X1
- 双电机小车底盘 X1
- DHT11温湿度传感器 X1
- DF模拟光线传感器 X1
步骤1 先记录小车的组装与接线
组装双电机小车+DHT11和光线传感器接线:

组装完成后:

步骤2 编写程序,读取传感器数据,小车运动。
软件编程狮1.3.0
选择roco小智AI开发板

添加DHT和ESP MCP库

程序功能,读取温湿度和光线数据,小车运动(只能控制前后左右停,不能准确控制运动时间)


小智后台

代码
//代码部分
#include <Arduino.h>
#include <WiFi.h>
#include "RocoMCP.h"
#include <dhtESP32-rmt.h>
const char* WIFI_SSID = "your_ssid";
const char* WIFI_PASS = "your_password";
const char* MCP_ENDPOINT = "wss://api.xiaozhi.me/mcp/?token=...";
RocoMCP mcpClient;
DHT dht(20, DHT11);
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
attempts++;
}
if (mcpClient.begin(MCP_ENDPOINT)) {
Serial.println("[编程狮roco MCP客户端] 初始化成功");
}
ledcAttachChannel(4, 5000, 8, 0);
pinMode(5, OUTPUT);
ledcAttachChannel(6, 5000, 8, 1);
pinMode(7, OUTPUT);
mcpClient.registerTool(
"system-info",
"获取系统信息",
"{\"properties\":{},\"title\":\"systemInfoArguments\",\"type\":\"object\"}",
[](const String& args) {
String chipModel = ESP.getChipModel();
uint32_t chipId = ESP.getEfuseMac() & 0xFFFFFFFF;
uint32_t flashSize = ESP.getFlashChipSize() / 1024;
uint32_t freeHeap = ESP.getFreeHeap() / 1024;
String resultJson = "{\"success\":true,\"model\":\"" + chipModel +
"\",\"chipId\":\"" + String(chipId, HEX) +
"\",\"flashSize\":" + String(flashSize) +
",\"freeHeap\":" + String(freeHeap) +
",\"wifiStatus\":\"" +
(WiFi.status() == WL_CONNECTED ? "connected" : "disconnected") +
"\",\"ipAddress\":\"" + WiFi.localIP().toString() + "\"}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"dht_tem",
"读取DHT11温度数值 单位:摄氏度",
"{\"properties\":{},\"required\":[],\"title\":\"sensorArguments\",\"type\":\"object\"}",
[](const String& args) {
String resultJson = "{\"success\":true,\"value\":" + String(dht.readTemperature()) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"dht_hum",
"读取DHT11温度数值 单位:%",
"{\"properties\":{},\"required\":[],\"title\":\"sensorArguments\",\"type\":\"object\"}",
[](const String& args) {
String resultJson = "{\"success\":true,\"value\":" + String(dht.readHumidity()) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"light_date",
"读取模拟光线传感器数值 单位:勒克斯",
"{\"properties\":{},\"required\":[],\"title\":\"sensorArguments\",\"type\":\"object\"}",
[](const String& args) {
String resultJson = "{\"success\":true,\"value\":" + String(analogRead(17)) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"car_forward",
"控制小车前进",
"{\n \"properties\": {\n \"angle\": {\"title\": \"控制数值\", \"type\": \"integer\"},\n \"state\": {\"title\": \"控制小车前进\", \"type\": \"string\", \"enum\": [\"前进\"]}\n },\n \"required\": [\"state\"],\n \"title\": \"ledControlArguments\",\n \"type\": \"object\"\n}",
[](const String& args) {
DynamicJsonDocument doc(256);
deserializeJson(doc, args);
String state = doc["state"].as<String>();
if (state == "前进") {
ledcWrite(4, 180);
digitalWrite(5, HIGH);
ledcWrite(6, 180);
digitalWrite(7, HIGH);
}
String resultJson = "{\"success\":true,\"state\":\"" + state + "\",\"angle\":" + String(doc["angle"].as<int>()) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"car_backward",
"控制小车后退",
"{\n \"properties\": {\n \"angle\": {\"title\": \"控制数值\", \"type\": \"integer\"},\n \"state\": {\"title\": \"控制小车后退\", \"type\": \"string\", \"enum\": [\"后退\"]}\n },\n \"required\": [\"state\"],\n \"title\": \"ledControlArguments\",\n \"type\": \"object\"\n}",
[](const String& args) {
DynamicJsonDocument doc(256);
deserializeJson(doc, args);
String state = doc["state"].as<String>();
if (state == "后退") {
ledcWrite(4, 180);
digitalWrite(5, LOW);
ledcWrite(6, 180);
digitalWrite(7, LOW);
}
String resultJson = "{\"success\":true,\"state\":\"" + state + "\",\"angle\":" + String(doc["angle"].as<int>()) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"car_left",
"控制小车左转",
"{\n \"properties\": {\n \"angle\": {\"title\": \"控制数值\", \"type\": \"integer\"},\n \"state\": {\"title\": \"控制小车左转\", \"type\": \"string\", \"enum\": [\"左转\"]}\n },\n \"required\": [\"state\"],\n \"title\": \"ledControlArguments\",\n \"type\": \"object\"\n}",
[](const String& args) {
DynamicJsonDocument doc(256);
deserializeJson(doc, args);
String state = doc["state"].as<String>();
if (state == "左转") {
ledcWrite(4, 150);
digitalWrite(5, HIGH);
ledcWrite(6, 180);
digitalWrite(7, HIGH);
}
String resultJson = "{\"success\":true,\"state\":\"" + state + "\",\"angle\":" + String(doc["angle"].as<int>()) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"car_right",
"控制小车右转",
"{\n \"properties\": {\n \"angle\": {\"title\": \"控制数值\", \"type\": \"integer\"},\n \"state\": {\"title\": \"控制小车右转\", \"type\": \"string\", \"enum\": [\"右转\"]}\n },\n \"required\": [\"state\"],\n \"title\": \"ledControlArguments\",\n \"type\": \"object\"\n}",
[](const String& args) {
DynamicJsonDocument doc(256);
deserializeJson(doc, args);
String state = doc["state"].as<String>();
if (state == "右转") {
ledcWrite(4, 220);
digitalWrite(5, HIGH);
ledcWrite(6, 150);
digitalWrite(7, HIGH);
}
String resultJson = "{\"success\":true,\"state\":\"" + state + "\",\"angle\":" + String(doc["angle"].as<int>()) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"car_stop",
"控制小车停止",
"{\n \"properties\": {\n \"angle\": {\"title\": \"控制数值\", \"type\": \"integer\"},\n \"state\": {\"title\": \"控制小车停止\", \"type\": \"string\", \"enum\": [\"停止\"]}\n },\n \"required\": [\"state\"],\n \"title\": \"ledControlArguments\",\n \"type\": \"object\"\n}",
[](const String& args) {
DynamicJsonDocument doc(256);
deserializeJson(doc, args);
String state = doc["state"].as<String>();
if (state == "停止") {
ledcWrite(4, 0);
ledcWrite(6, 0);
}
String resultJson = "{\"success\":true,\"state\":\"" + state + "\",\"angle\":" + String(doc["angle"].as<int>()) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
}
void loop() {
repeat();
}
void repeat() {
mcpClient.loop();
}
步骤3 优化程序,用一个MCP工具控制小车
程序优化


小智后台

代码
//代码部分
#include <Arduino.h>
#include <WiFi.h>
#include "RocoMCP.h"
#include <dhtESP32-rmt.h>
const char* WIFI_SSID = "your_ssid";
const char* WIFI_PASS = "your_password";
const char* MCP_ENDPOINT = "wss://api.xiaozhi.me/mcp/?token=...";
RocoMCP mcpClient;
DHT dht(20, DHT11);
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
attempts++;
}
if (mcpClient.begin(MCP_ENDPOINT)) {
Serial.println("[编程狮roco MCP客户端] 初始化成功");
}
ledcAttachChannel(4, 5000, 8, 0);
pinMode(5, OUTPUT);
ledcAttachChannel(6, 5000, 8, 1);
pinMode(7, OUTPUT);
mcpClient.registerTool(
"system-info",
"获取系统信息",
"{\"properties\":{},\"title\":\"systemInfoArguments\",\"type\":\"object\"}",
[](const String& args) {
String chipModel = ESP.getChipModel();
uint32_t chipId = ESP.getEfuseMac() & 0xFFFFFFFF;
uint32_t flashSize = ESP.getFlashChipSize() / 1024;
uint32_t freeHeap = ESP.getFreeHeap() / 1024;
String resultJson = "{\"success\":true,\"model\":\"" + chipModel +
"\",\"chipId\":\"" + String(chipId, HEX) +
"\",\"flashSize\":" + String(flashSize) +
",\"freeHeap\":" + String(freeHeap) +
",\"wifiStatus\":\"" +
(WiFi.status() == WL_CONNECTED ? "connected" : "disconnected") +
"\",\"ipAddress\":\"" + WiFi.localIP().toString() + "\"}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"dht_tem",
"读取DHT11温度数值 单位:摄氏度",
"{\"properties\":{},\"required\":[],\"title\":\"sensorArguments\",\"type\":\"object\"}",
[](const String& args) {
String resultJson = "{\"success\":true,\"value\":" + String(dht.readTemperature()) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"dht_hum",
"读取DHT11温度数值 单位:%",
"{\"properties\":{},\"required\":[],\"title\":\"sensorArguments\",\"type\":\"object\"}",
[](const String& args) {
String resultJson = "{\"success\":true,\"value\":" + String(dht.readHumidity()) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"light_date",
"读取模拟光线传感器数值 单位:勒克斯",
"{\"properties\":{},\"required\":[],\"title\":\"sensorArguments\",\"type\":\"object\"}",
[](const String& args) {
String resultJson = "{\"success\":true,\"value\":" + String(analogRead(17)) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"car_control",
"控制小车运动状态",
"{\n \"properties\": {\n \"angle\": {\"title\": \"控制数值\", \"type\": \"integer\"},\n \"state\": {\"title\": \"控制小车运动状态\", \"type\": \"string\", \"enum\": [\"前进\",\"后退\",\"左转\",\"右转\",\"停止\"]}\n },\n \"required\": [\"state\"],\n \"title\": \"ledControlArguments\",\n \"type\": \"object\"\n}",
[](const String& args) {
DynamicJsonDocument doc(256);
deserializeJson(doc, args);
String state = doc["state"].as<String>();
if (state == "前进") {
ledcWrite(4, 180);
digitalWrite(5, HIGH);
ledcWrite(6, 180);
digitalWrite(7, HIGH);
}
if (state == "后退") {
ledcWrite(4, 180);
digitalWrite(5, LOW);
ledcWrite(6, 180);
digitalWrite(7, LOW);
}
if (state == "左转") {
ledcWrite(4, 150);
digitalWrite(5, HIGH);
ledcWrite(6, 180);
digitalWrite(7, HIGH);
}
if (state == "右转") {
ledcWrite(4, 220);
digitalWrite(5, HIGH);
ledcWrite(6, 150);
digitalWrite(7, HIGH);
}
if (state == "停止") {
ledcWrite(4, 0);
ledcWrite(6, 0);
}
String resultJson = "{\"success\":true,\"state\":\"" + state + "\",\"angle\":" + String(doc["angle"].as<int>()) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
}
void loop() {
repeat();
}
void repeat() {
mcpClient.loop();
}
步骤4 优化程序,增加运动时间控制
程序优化



小智后台

代码
//代码部分
#include <Arduino.h>
#include <WiFi.h>
#include "RocoMCP.h"
#include <dhtESP32-rmt.h>
const char* WIFI_SSID = "your_ssid";
const char* WIFI_PASS = "your_password";
const char* MCP_ENDPOINT = "wss://api.xiaozhi.me/mcp/?token=...";
RocoMCP mcpClient;
DHT dht(20, DHT11);
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
attempts++;
}
if (mcpClient.begin(MCP_ENDPOINT)) {
Serial.println("[编程狮roco MCP客户端] 初始化成功");
}
ledcAttachChannel(4, 5000, 8, 0);
pinMode(5, OUTPUT);
ledcAttachChannel(6, 5000, 8, 1);
pinMode(7, OUTPUT);
mcpClient.registerTool(
"system-info",
"获取系统信息",
"{\"properties\":{},\"title\":\"systemInfoArguments\",\"type\":\"object\"}",
[](const String& args) {
String chipModel = ESP.getChipModel();
uint32_t chipId = ESP.getEfuseMac() & 0xFFFFFFFF;
uint32_t flashSize = ESP.getFlashChipSize() / 1024;
uint32_t freeHeap = ESP.getFreeHeap() / 1024;
String resultJson = "{\"success\":true,\"model\":\"" + chipModel +
"\",\"chipId\":\"" + String(chipId, HEX) +
"\",\"flashSize\":" + String(flashSize) +
",\"freeHeap\":" + String(freeHeap) +
",\"wifiStatus\":\"" +
(WiFi.status() == WL_CONNECTED ? "connected" : "disconnected") +
"\",\"ipAddress\":\"" + WiFi.localIP().toString() + "\"}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"dht_tem",
"读取DHT11温度数值 单位:摄氏度",
"{\"properties\":{},\"required\":[],\"title\":\"sensorArguments\",\"type\":\"object\"}",
[](const String& args) {
String resultJson = "{\"success\":true,\"value\":" + String(dht.readTemperature()) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"dht_hum",
"读取DHT11温度数值 单位:%",
"{\"properties\":{},\"required\":[],\"title\":\"sensorArguments\",\"type\":\"object\"}",
[](const String& args) {
String resultJson = "{\"success\":true,\"value\":" + String(dht.readHumidity()) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"light_date",
"读取模拟光线传感器数值 单位:勒克斯",
"{\"properties\":{},\"required\":[],\"title\":\"sensorArguments\",\"type\":\"object\"}",
[](const String& args) {
String resultJson = "{\"success\":true,\"value\":" + String(analogRead(17)) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
mcpClient.registerTool(
"car_control",
"控制小车运动状态及时间",
"{\n \"properties\": {\n \"angle\": {\"title\": \"控制数值\", \"type\": \"integer\"},\n \"state\": {\"title\": \"控制小车运动状态及时间\", \"type\": \"string\", \"enum\": [\"前进\",\"后退\",\"左转\",\"右转\",\"停止\",\"时间\"]}\n },\n \"required\": [\"state\"],\n \"title\": \"ledControlArguments\",\n \"type\": \"object\"\n}",
[](const String& args) {
DynamicJsonDocument doc(256);
deserializeJson(doc, args);
String state = doc["state"].as<String>();
if (state == "前进") {
ledcWrite(4, 180);
digitalWrite(5, HIGH);
ledcWrite(6, 180);
digitalWrite(7, HIGH);
delay(doc["angle"].as<int>() * 1000);
ledcWrite(4, 0);
ledcWrite(6, 0);
}
if (state == "后退") {
ledcWrite(4, 180);
digitalWrite(5, LOW);
ledcWrite(6, 180);
digitalWrite(7, LOW);
delay(doc["angle"].as<int>() * 1000);
ledcWrite(4, 0);
ledcWrite(6, 0);
}
if (state == "左转") {
ledcWrite(4, 150);
digitalWrite(5, HIGH);
ledcWrite(6, 180);
digitalWrite(7, HIGH);
delay(doc["angle"].as<int>() * 1000);
ledcWrite(4, 0);
ledcWrite(6, 0);
}
if (state == "右转") {
ledcWrite(4, 220);
digitalWrite(5, HIGH);
ledcWrite(6, 150);
digitalWrite(7, HIGH);
delay(doc["angle"].as<int>() * 1000);
ledcWrite(4, 0);
ledcWrite(6, 0);
}
if (state == "停止") {
ledcWrite(4, 0);
ledcWrite(6, 0);
}
String resultJson = "{\"success\":true,\"state\":\"" + state + "\",\"angle\":" + String(doc["angle"].as<int>()) + "}";
return RocoMCP::ToolResponse(resultJson);
}
);
}
void loop() {
repeat();
}
void repeat() {
mcpClient.loop();
}
评论