wl_pro_robot.ino
这个代码是一个完整的机器人控制程序,涉及到多个硬件模块的控制和通信,包括电机、传感器、舵机、PID控制器、滤波器、Web服务器等。下面简要解释一些关键部分:
-
电机与驱动控制:代码定义了两个电机(
motor1
和motor2
)及其驱动器(driver1
和driver2
),并通过FOC(Field-Oriented Control)技术来进行电机控制。 -
PID控制器:通过PID控制器调节机器人的角度、速度、位移等参数,以实现平衡和精确控制。多个PID控制器(如
pid_angle
,pid_gyro
,pid_distance
等)分别用于处理不同的控制任务。 -
传感器与数据读取:使用MPU6050传感器获取角度和陀螺仪数据,利用AS5600磁编码器来获取电机的位置和速度。
-
LQR平衡控制:使用线性二次调节器(LQR)来进行自平衡控制。LQR通过优化控制策略来实现机器人的平衡,结合角度、速度、位移等因素来计算控制输出。
-
Web与Wi-Fi控制:通过Web服务器(
WebServer
)和WebSocket(WebSocketsServer
)实现远程控制。Wi-Fi功能用于连接到无线网络,并通过Web界面或Socket进行实时数据交互。 -
电池监控与舵机控制:通过ADC读取电池电压,使用舵机(
sms_sts
)控制机器人的腿部动作。 -
安全保护与状态检测:设定了“失控”状态检测(如过大的倾斜角度),并在此情况下停止电机输出,确保机器人安全。
每个部分都通过精细的调节和控制算法实现机器人的平衡、动作和响应。在loop()
函数中,机器人不断监控状态并根据传感器数据调整动作,确保机器人能够稳定运行。
这段代码主要涉及一个基于控制算法和硬件驱动的机器人系统。它包括电机控制、姿态稳定(自平衡)控制、WebSocket通信、舵机控制等功能。接下来,我将详细分析代码的结构和各部分功能:
1. 硬件模块
1.1 电机控制(BLDCMotor, BLDCDriver3PWM)
motor1
和motor2
是两个无刷直流电机的实例。BLDCMotor
类用于控制电机的转动,BLDCDriver3PWM
类则用于控制电机驱动器,通过三个PWM信号来控制电机的转速和转向。- 电机的初始化和驱动逻辑通过
motor1
和motor2
关联传感器和驱动器,并设置控制类型为电压(voltage
)和运动类型为转矩(torque
)。
1.2 编码器控制(MagneticSensorI2C)
- 使用磁编码器(
MagneticSensorI2C
)来获取电机的旋转角度信息。代码中通过 I2C 与编码器通信来获取电机的当前位置,从而实现精确的运动控制。
1.3 IMU(MPU6050)
MPU6050
是一个集成了加速度计和陀螺仪的传感器,主要用于检测机器人的角度和角速度。mpu6050.calcGyroOffsets(true)
用于计算陀螺仪的偏移量,确保数据准确。mpu6050.getAngleY()
和mpu6050.getGyroY()
分别用于获取机器人的俯仰角和陀螺仪的角速度。
1.4 电压检测
bat_check()
用于电池电压的检测,通过 ESP32 的 ADC 引脚读取电池电压值。
2. 控制算法
2.1 PID 控制器
-
代码中使用了多种 PID 控制器来处理机器人的各项运动控制,包括:
- 角度控制(
pid_angle
) - 角速度控制(
pid_gyro
) - 位移控制(
pid_distance
) - 速度控制(
pid_speed
) - YAW(偏航)控制(
pid_yaw_angle
,pid_yaw_gyro
) - LQR 控制(
pid_lqr_u
) - 其他特定任务的 PID(
pid_roll_angle
,pid_zeropoint
等)
每个 PID 控制器都有相应的
P
、I
和D
参数,分别控制比例、积分和微分部分,这些参数能够调节控制器的响应和稳定性。 - 角度控制(
2.2 LQR 自平衡控制
- LQR(线性二次调节器)是一个用于优化状态反馈控制的算法,目的是使系统达到平衡。代码中的
lqr_balance_loop
函数通过 PID 控制器来实现机器人自平衡:LQR_angle
和LQR_gyro
分别表示机器人的俯仰角和角速度。distance_control
和speed_control
分别处理机器人的位移和速度控制。LQR_u
是控制输出,用于计算机器人所需的力矩。angle_control
和gyro_control
负责调整机器人角度和角速度。
2.3 控制策略
- 当机器人处于失控状态(例如倾斜角度超过 25°),会禁用输出,停止电机运转。这是通过
uncontrolable
标志位来实现的,防止机器人进一步失控。 jump_flag
用于标记机器人是否处于跳跃状态,如果是跳跃状态,系统会停止电机控制,等待机器人恢复。wrobot_move_stop_flag
用于标记是否需要停止机器人运动(例如通过遥控器指令或其他条件)。
2.4 腿部控制
- 代码中的
leg_loop
函数控制机器人的腿部运动,特别是与跳跃和姿态平衡相关的动作。leg_position_add
和leg_position
控制腿部的位置,确保机器人的动作平衡。
3. 通信与控制
3.1 WebSocket 和 HTTP 服务器
- 使用 WebSocket 和 HTTP 服务器来接收远程控制命令。这使得机器人能够通过 Wi-Fi 接受来自外部设备(如计算机或手机)的指令。
webserver
作为 HTTP 服务器,处理与前端的基本通信,websocket
用于处理实时控制命令。web_loop()
和webSocketEventCallback()
函数分别处理 Web 服务器的循环和事件回调,确保远程控制的实时性。
3.2 Commander
Commander
类用于将控制命令传递给不同的 PID 控制器。例如,命令'A'
对应StabAngle
函数,用于控制机器人角度的 PID。- 每个控制命令都有一个对应的函数(例如
StabAngle
、StabGyro
等),通过command.add
将它们注册到commander
中,从而实现实时控制。
4. 初始化与执行
setup()
函数用于初始化各个硬件模块和控制器,并启动 Web 服务和控制协议。loop()
函数是主循环,在每次迭代中执行:- 电压检测
- Web 数据更新
- IMU 数据更新
- 自平衡控制(LQR)
- YAW 控制
- 腿部动作控制
- 计算电机输出并执行
- 处理遥控命令
总结
该代码实现了一个高度集成的机器人控制系统,涉及电机控制、姿态控制、Web通信和实时控制命令处理。通过 PID 控制、LQR 算法和遥控指令,机器人能够执行自平衡、转向、速度调节等任务,并能通过 WebSocket 接受来自外部的控制命令。
robot.cpp
这段代码是一个关于机器人控制协议的实现。它定义了一个 RobotProtocol
类,用于通过串口通信控制机器人。具体来说,这段代码的功能包括接收来自 web 端的控制数据、更新控制信息、以及将更新后的数据发送到串口设备。下面是代码的逐步解析:
1. 头文件和类定义
#include "robot.h"
Wrobot wrobot;
RobotProtocol::RobotProtocol(uint8_t len)
#include "robot.h"
: 引入机器人控制相关的头文件,假设robot.h
定义了机器人相关的数据结构和常量。Wrobot wrobot;
:创建一个Wrobot
类型的全局对象wrobot
,这个对象包含了机器人状态的各种变量,如方向、角度、速度等。RobotProtocol::RobotProtocol(uint8_t len)
:RobotProtocol
类的构造函数,接收一个参数len
(协议缓冲区的大小)。
2. 构造函数
_len = len;
_now_buf = new uint8_t[_len];
_old_buf = new uint8_t[_len];
for(int i=0; i<_len; i++) {
_now_buf[i] = 0;
}
_now_buf[0] = 0xAA;
_now_buf[1] = 0x55;
len
参数定义了控制数据的缓冲区大小。_now_buf
和_old_buf
是两个动态分配的缓冲区,用来存储当前的控制数据和上一周期的控制数据。for
循环将_now_buf
初始化为零,确保缓冲区开始时为空。- 接着设置缓冲区的前两个字节:
_now_buf[0] = 0xAA;
和_now_buf[1] = 0x55;
,这些字节通常用于协议的标识。
3. 析构函数
RobotProtocol::~RobotProtocol()
{
delete [] _now_buf;
delete [] _old_buf;
}
- 析构函数释放了
new
分配的内存,以防止内存泄漏。
4. spinOnce
函数
void RobotProtocol::spinOnce(void)
{
int flag = checkBufRefresh();
if(flag)
{
// UART_WriteBuf(); //发送数据到串口
}
}
spinOnce
是一个周期性调用的函数,通常在主循环中调用。- 调用
checkBufRefresh
检查当前缓冲区_now_buf
是否与_old_buf
有所不同。如果不同,表示控制信息已经变化,需要更新并发送数据。 - 如果
checkBufRefresh
返回 1(缓冲区数据已更新),则可以通过UART_WriteBuf()
将数据发送到串口设备。
5. UART_WriteBuf
函数
void RobotProtocol::UART_WriteBuf(void)
{
for(int i=0; i<_len; i++) {
Serial.write(_now_buf[i]);
}
}
- 该函数负责将当前缓冲区
_now_buf
的数据发送到串口。 - 使用
Serial.write()
按字节发送数据。
6. checkBufRefresh
函数
int RobotProtocol::checkBufRefresh(void)
{
int ret = 0;
for(int i=0; i<_len; i++)
{
if(_now_buf[i] != _old_buf[i]) {
ret = 1;
break;
}else {
ret = 0;
}
}
for(int i=0; i<_len; i++) {
_old_buf[i]= _now_buf[i];
}
return ret;
}
- 该函数用于检查当前缓冲区
_now_buf
是否与上一周期的缓冲区_old_buf
相同。如果不同,则返回 1,表示需要刷新(更新)数据并发送。 - 如果没有变化,则返回 0。
- 在检查完毕后,
_old_buf
被更新为当前的_now_buf
。
7. parseBasic
函数
void RobotProtocol::parseBasic(StaticJsonDocument<300> &doc)
{
_now_buf[2] = BASIC;
// 解析 JSON 数据并更新缓冲区
}
parseBasic
函数用于解析从 Web 端(JSON 格式)收到的控制命令,并根据命令更新控制缓冲区_now_buf
。StaticJsonDocument<300>
是 Arduino JSON 库中的一个文档类型,用于存储和解析 JSON 数据。- 通过
doc["key"]
获取 JSON 数据中的各个字段,并将它们转换成对应的控制命令。
例如:
- 方向控制:根据
"dir"
字段的值更新wrobot.dir
和_now_buf[3]
。例如,如果"dir"
是"forward"
,则设置_now_buf[3] = FORWARD
。 - 高度控制:根据
"height"
字段的值更新wrobot.height
和_now_buf[4]
。 - 角度控制:类似地,
roll
、linear
、angular
、stable
、joy_x
、joy_y
等字段被解析并对应更新机器人控制状态以及缓冲区中的相应字节。
总结
这段代码主要用于实现机器人控制协议的基础功能。它接收来自 Web 端的 JSON 格式控制命令,并将这些命令转换为机器人可以理解的串口协议数据。数据通过串口发送,控制机器人进行相应的动作,如前进、后退、跳跃等。通过 checkBufRefresh
函数,代码确保只有在控制命令变化时才会发送数据,从而优化通信效率。
web端
“Web 端” 指的是通过 Web 浏览器或基于 Web 技术(如 HTML、CSS、JavaScript)开发的前端界面或应用程序,通常用于与用户交互并向后端服务发送请求或接收数据。
在你提供的代码中,“Web 端” 指的是一个基于 Web 技术的用户界面,用户可以通过浏览器向机器人发送控制命令(如运动方向、速度等)。这些命令通常以 JSON 格式发送,机器人通过串口通信接收这些命令并执行相应的动作。简而言之,“Web 端” 是通过 Web 浏览器与设备(如机器人)交互的用户界面部分。
典型的 Web 端工作流程:
- 用户操作:用户在 Web 端界面上进行操作,比如点击按钮、选择选项、输入数据等。
- 数据传输:这些操作生成的控制数据(如 JSON 格式的命令)通过网络发送到后端服务器或直接发送到设备。
- 后端处理:如果有后端服务器,它会处理来自 Web 端的请求,进行相应的计算或数据转发。
- 设备控制:设备(比如机器人)通过接收这些命令并执行相应的动作(例如,改变方向、调整速度等)。
因此,Web 端是与机器人进行通信的用户接口,允许用户通过浏览器来控制和监视机器人的状态。
robot.h
感谢提供 robot.h
文件。根据这个文件,RobotProtocol
类的定义可以更清晰地分析出来。下面我会详细解释 robot.h
中的各个部分。
1. 版权声明和许可
// -----------------------------------------------------------------------------
// Copyright (c) 2024 Mu Shibo
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// -----------------------------------------------------------------------------
这部分代码是版权声明和许可信息,表示这个软件可以自由使用、修改、分发、甚至销售,但不提供任何形式的保证,使用者需自担风险。
2. 库的引用
#include <WiFi.h>
#include <ArduinoJson.h>
这部分代码包含了两个库:
WiFi.h
:用于 Wi-Fi 连接,适用于 ESP32 或其他支持 Wi-Fi 的硬件。ArduinoJson.h
:用于处理 JSON 数据,帮助你解析和构建 JSON 格式的数据。
3. Wrobot 结构体
typedef struct {
int height = 38;
int roll;
int linear;
int angular;
int dir;
int dir_last;
int joyy;
int joyy_last;
int joyx;
int joyx_last;
bool go;
} Wrobot;
extern Wrobot wrobot;
-
Wrobot
结构体是用于表示机器人状态的变量,包含以下字段:height
:机器人的高度(默认值是 38)。roll
:机器人倾斜的角度。linear
:机器人沿直线运动的速度。angular
:机器人旋转的速度或角度。dir
:机器人当前的方向。dir_last
:机器人上次的方向。joyy
和joyx
:机器人控制的摇杆(joystick)值。joyy_last
和joyx_last
:机器人控制的上次摇杆值。go
:一个布尔值,表示是否允许机器人继续运动(比如稳定状态)。
-
extern Wrobot wrobot;
:声明了一个外部的wrobot
变量,它存储机器人的当前状态。这个变量会在其他地方(比如robot.cpp
)定义和使用。
4. 机器人运动状态枚举 QR_State_t
typedef enum {
FORWARD = 0,
BACK,
RIGHT,
LEFT,
STOP,
JUMP,
} QR_State_t;
QR_State_t
枚举定义了机器人可以采取的几种基本状态:FORWARD
:向前运动。BACK
:向后运动。RIGHT
:向右转。LEFT
:向左转。STOP
:停止运动。JUMP
:跳跃。
5. 机器人模式枚举 Robot_Mode_t
typedef enum {
BASIC = 0,
} Robot_Mode_t;
Robot_Mode_t
枚举定义了机器人可能的操作模式。在当前代码中,仅有一个模式BASIC
,可以扩展为更多模式,如ADVANCED
等。
6. RobotProtocol
类的定义
class RobotProtocol
{
public:
RobotProtocol(uint8_t len);
~RobotProtocol();
void spinOnce(void);
void parseBasic(StaticJsonDocument<300> &doc);
private:
uint8_t *_now_buf;
uint8_t *_old_buf;
uint8_t _len;
void UART_WriteBuf(void);
int checkBufRefresh(void);
};
-
构造函数:
RobotProtocol(uint8_t len)
,用于初始化协议缓冲区的大小,len
表示协议数据的长度。 -
析构函数:
~RobotProtocol()
,用于释放动态分配的内存,避免内存泄漏。 -
成员函数:
spinOnce(void)
:该函数的作用是检查是否需要刷新并发送新的数据。它通常会在主循环中调用(比如在loop()
函数中)。parseBasic(StaticJsonDocument<300> &doc)
:这个函数用于解析传入的 JSON 数据,更新当前缓冲区_now_buf
中的状态。UART_WriteBuf(void)
:这个函数将当前的数据缓冲区内容通过串口发送出去(例如通过 Wi-Fi 发送给机器人)。checkBufRefresh(void)
:检查当前缓冲区_now_buf
是否与上一轮的缓冲区_old_buf
有变化。如果有变化,返回 1,否则返回 0。
-
成员变量:
_now_buf
和_old_buf
:用于存储当前和上一轮的控制数据缓冲区。_len
:表示缓冲区的长度。
总结
- 结构体
Wrobot
:表示机器人当前的状态,包含机器人的运动、方向、控制状态等信息。 - 枚举类型
QR_State_t
和Robot_Mode_t
:定义了机器人的运动状态和模式。 RobotProtocol
类:负责与机器人之间的通信协议,包括解析来自 Web 端的数据、发送命令给机器人等功能。该类通过串口和 Wi-Fi 进行通信,确保机器人根据指令执行相应动作。
RobotProtocol
类的作用就是处理与机器人之间的所有通信工作,确保能够从 Web 端接收指令、解析指令并通过硬件接口(如串口)发送指令到机器人。
JSON数据
JSON(JavaScript Object Notation,即 JavaScript 对象表示法)是一种轻量级的数据交换格式,它非常易于人类阅读和编写,同时也易于机器解析和生成。JSON 格式通常用于在客户端和服务器之间交换数据,尤其是在 Web 开发和 API(应用程序编程接口)中非常常见。
JSON 数据的基本特点:
- 结构简单:JSON 数据由一系列键值对(key-value pair)组成,格式类似于 JavaScript 中的对象或字典(在其他编程语言中如 Python、C# 等也有类似的数据结构)。
- 数据类型支持:JSON 支持以下数据类型:
- 字符串(String):由双引号包围的字符集。
- 数字(Number):整数或浮动的数字。
- 布尔值(Boolean):
true
或false
。 - 数组(Array):由中括号
[]
包围的一系列值,值之间用逗号分隔。 - 对象(Object):由大括号
{}
包围的一组键值对,键是字符串,值可以是任意数据类型。 - 空值(null):表示空值或无值。
JSON 的格式示例:
{
"name": "Alice",
"age": 25,
"isStudent": false,
"courses": ["Math", "Science", "English"],
"address": {
"street": "123 Main St",
"city": "Somewhere",
"zip": "12345"
}
}
解释这个示例:
"name": "Alice"
:这是一个键值对,键是"name"
,值是字符串"Alice"
。"age": 25
:键是"age"
,值是数字25
。"isStudent": false
:键是"isStudent"
,值是布尔值false
。"courses": ["Math", "Science", "English"]
:键是"courses"
,值是一个数组,包含了三个字符串元素。"address": {...}
:键是"address"
,值是一个嵌套对象,包含了street
、city
和zip
三个键值对。
JSON 的优点:
- 简洁:JSON 格式简单,易于理解。
- 轻量:它的结构简单,适用于网络传输。
- 易于解析:JSON 可以方便地被编程语言(如 JavaScript、Python、C++ 等)解析。
- 广泛应用:JSON 是 Web 开发中最常见的数据交换格式,尤其适用于 RESTful API 和前后端通信。
JSON 和 JavaScript:
JSON 的语法实际上是 JavaScript 对象字面量(Object Literal)的子集。它与 JavaScript 的对象非常相似,但有一些不同之处:
- 键必须是字符串,并且必须用双引号包围(JavaScript 对象的键可以不加引号)。
- 没有函数和日期:JSON 中不能包含 JavaScript 函数或
Date
类型。
在实际应用中的使用:
- Web 前后端通信:前端使用 JavaScript 发起 HTTP 请求(如使用
fetch
或XMLHttpRequest
),服务器返回 JSON 格式的数据,前端解析这些数据并渲染页面。 - API 数据交换:许多 Web 服务使用 JSON 格式进行数据交换。例如,获取天气数据、社交媒体数据等,通常通过 JSON 格式返回。
- 配置文件:JSON 常常被用来存储配置文件,例如存储应用程序的配置设置(如数据库连接信息、用户偏好等)。
JSON 数据的解析:
在代码中,JSON 数据通常需要经过解析才能使用。不同编程语言提供了相应的解析方法。
1. 在 JavaScript 中:
let jsonString = '{"name": "Alice", "age": 25}';
let obj = JSON.parse(jsonString); // 将 JSON 字符串解析成对象
console.log(obj.name); // 输出 "Alice"
2. 在 Python 中:
import json
json_string = '{"name": "Alice", "age": 25}'
obj = json.loads(json_string) # 将 JSON 字符串解析成字典
print(obj["name"]) # 输出 "Alice"
3. 在 C++ 中:
如果使用 Arduino 进行开发(正如你提供的代码中所见),则需要使用 ArduinoJson
库来处理 JSON 数据:
#include <ArduinoJson.h>
StaticJsonDocument<200> doc;
deserializeJson(doc, "{\"name\":\"Alice\", \"age\":25}");
const char* name = doc["name"]; // "Alice"
int age = doc["age"]; // 25
总结
JSON 数据格式是一种用于存储和传输数据的格式,它易于阅读和解析,广泛应用于 Web 开发中用于前后端数据交换。通过将数据以键值对的形式进行表示,JSON 格式不仅支持多种数据类型,还能在不同平台之间进行高效传输。
Servo_STS3032.cpp
这段代码是关于飞特(Feetech)舵机的控制实现,具体用于串行通信控制和同步写入指令。下面是对代码的逐步分析和解释:
代码结构概述:
- SCS 类:是一个串行通信协议类,用于与舵机通信,主要功能包括将数据分解为低位和高位的字节、发送同步写入指令等。
- SCSerial 类:是一个继承自
SCS
的类,负责具体的串行通信操作,比如写数据到串口、读取串口等。 - SMS_STS 类:用于飞特舵机(如STS系列舵机)的高级应用控制,比如同步写入舵机位置、速度和加速度。
代码解析:
1. SCS
类:
SCS
类定义了多个构造函数和一些方法,提供了与飞特舵机通信的基本功能。
-
构造函数:
SCS::SCS() { Level = 1; Error = 0; } SCS::SCS(u8 End) { Level = 1; this->End = End; Error = 0; } SCS::SCS(u8 End, u8 Level) { this->Level = Level; this->End = End; Error = 0; }
Level
:控制舵机响应方式(可能影响舵机的反馈)。End
:指示数据结束符的设置。
-
Host2SCS
方法:void SCS::Host2SCS(u8 *DataL, u8* DataH, u16 Data)
- 该方法将 16 位数据(
Data
)拆分为两个 8 位数据,并存储在DataL
(低字节)和DataH
(高字节)中。 End
控制字节的顺序(低字节在前还是高字节在前)。
- 该方法将 16 位数据(
-
syncWrite
方法:void SCS::syncWrite(u8 ID[], u8 IDN, u8 MemAddr, u8 *nDat, u8 nLen)
- 用于同步写入多个舵机的数据。舵机的 ID 和要写入的内存地址(
MemAddr
)以及数据(nDat
)和数据长度(nLen
)会一起被发送。 - 计算并发送校验和(
Sum
)以确保数据的完整性。
- 用于同步写入多个舵机的数据。舵机的 ID 和要写入的内存地址(
2. SCSerial
类:
SCSerial
类是 SCS
类的一个子类,扩展了串行通信的功能,负责将数据通过串口传输给舵机。
-
writeSCS
方法:int SCSerial::writeSCS(unsigned char *nDat, int nLen)
- 用于将数据(
nDat
)通过串口写入,nLen
为数据的长度。 - 还提供了单字节写入的版本。
- 用于将数据(
-
rFlushSCS
和wFlushSCS
方法:void SCSerial::rFlushSCS() { while(pSerial->read() != -1); } void SCSerial::wFlushSCS() { }
rFlushSCS
用于清空串口接收缓存,防止残留的数据影响后续的通信。wFlushSCS
方法未实现,可能用于清空串口发送缓存。
3. SMS_STS
类:
SMS_STS
类用于飞特舵机的应用层协议,主要实现了舵机的同步控制,允许控制多个舵机的运动,包括位置、速度和加速度。
SyncWritePosEx
方法:void SMS_STS::SyncWritePosEx(u8 ID[], u8 IDN, s16 Position[], u16 Speed[], u8 ACC[])
-
该方法用于同步控制多个舵机的目标位置、速度和加速度。
-
ID[]
:舵机 ID 数组。 -
IDN
:舵机 ID 数量。 -
Position[]
:目标位置数组。 -
Speed[]
:目标速度数组(可以为空,默认速度为 0)。 -
ACC[]
:目标加速度数组(可以为空,默认加速度为 0)。 -
在方法内部,首先根据传入的位置信息处理并构造数据包,调用
syncWrite
方法将这些数据写入指定舵机的内存地址。
-
总结:
这段代码实现了飞特串行舵机的通信协议和控制指令,包括数据的拆分、同步写入指令的发送等。通过这个协议,用户可以同时控制多个舵机,设置它们的运动参数(如位置、速度、加速度),并确保数据传输的完整性。
Servo_STS3032.h
这段代码定义了用于控制飞特(Feetech)舵机的多个类和函数。代码主要分为三大部分:舵机通信协议层、硬件接口层和应用层。
1. 数据结构与类型定义:
代码首先定义了一些常见的数据类型:
typedef char s8;
typedef unsigned char u8;
typedef unsigned short u16;
typedef short s16;
typedef unsigned long u32;
typedef long s32;
这些类型用于舵机控制数据的表示。
2. 舵机通信协议层(SCS
类):
SCS
类用于实现飞特串行舵机的基本通信协议,包括向舵机发送同步写入指令、数据处理等。
2.1 构造函数与成员变量:
SCS
类有多个构造函数,用于初始化不同的参数:
SCS();
SCS(u8 End);
SCS(u8 End, u8 Level);
Level
:控制舵机返回数据的等级。End
:决定数据处理时使用的大端或小端结构。Error
:用于存储舵机的状态。
2.2 syncWrite
方法:
void syncWrite(u8 ID[], u8 IDN, u8 MemAddr, u8 *nDat, u8 nLen);
- 功能:该方法用来向多个舵机同步写入数据。它将舵机 ID 数组、内存地址、数据和数据长度一起发送给舵机进行同步控制。
- 参数:
ID[]
:舵机的 ID 数组。IDN
:舵机的数量。MemAddr
:写入数据的内存地址。nDat
:要写入的数据。nLen
:数据的长度。
2.3 Host2SCS
方法:
void Host2SCS(u8 *DataL, u8* DataH, u16 Data);
- 功能:该方法将一个 16 位数据(
Data
)拆分为两个 8 位数据(低字节DataL
和高字节DataH
)。 End
用于确定拆分顺序(大端或小端)。
2.4 Ack
方法:
int Ack(u8 ID);
- 功能:该方法返回舵机的应答,用于检查舵机是否成功接收到并执行指令。
2.5 checkHead
方法:
int checkHead();
- 功能:检查数据包的帧头,以确保数据包的正确性。
3. 硬件接口层(SCSerial
类):
SCSerial
类继承自 SCS
类,负责具体的串行通信操作,例如数据的发送和接收。
3.1 构造函数与成员变量:
SCSerial();
SCSerial(u8 End);
SCSerial(u8 End, u8 Level);
这些构造函数与 SCS
类中的类似,用于初始化通信参数。
3.2 writeSCS
方法:
int writeSCS(unsigned char *nDat, int nLen);
int writeSCS(unsigned char bDat);
- 功能:这两个方法负责将数据通过串口发送到舵机。第一个方法发送多字节数据,第二个方法发送单字节数据。
3.3 rFlushSCS
和 wFlushSCS
方法:
void rFlushSCS();
void wFlushSCS();
- 功能:
rFlushSCS
用于清空串口接收缓存,以防止旧数据影响通信。wFlushSCS
用于清空发送缓存。
3.4 IOTimeOut
和 pSerial
:
IOTimeOut
:用于设置串行通信的超时时间。pSerial
:指向硬件串口的指针,实际发送和接收数据通过它来操作。
4. 应用层(SMS_STS
类):
SMS_STS
类继承自 SCSerial
类,提供了更高层次的应用功能,主要用于控制多个舵机。
4.1 SyncWritePosEx
方法:
virtual void SyncWritePosEx(u8 ID[], u8 IDN, s16 Position[], u16 Speed[], u8 ACC[]);
- 功能:该方法用于同步写入多个舵机的目标位置、速度和加速度。
- 参数:
ID[]
:舵机的 ID 数组。IDN
:舵机的数量。Position[]
:目标位置数组。Speed[]
:目标速度数组(可选,默认为 0)。ACC[]
:目标加速度数组(可选,默认为 0)。
该方法首先根据传入的位置信息处理并构造数据包,然后调用父类的 syncWrite
方法将数据发送到各个舵机。
总结
这个文件定义了用于控制飞特舵机的通信协议和硬件接口类。它实现了向多个舵机发送同步控制指令的功能,并提供了对舵机状态的反馈处理。SCS
类是最基本的通信协议层,SCSerial
类提供了具体的串口操作接口,而 SMS_STS
类则实现了高层的舵机控制功能,能够同步控制多个舵机的运动。
wifi.cpp
这段代码是用于配置和使用 ESP-01S 模块的 Wi-Fi 功能。它提供了两种工作模式:AP(热点)模式和 STA(站点)模式,通过这两种模式可以使 ESP-01S 作为一个无线接入点或连接到现有的 Wi-Fi 网络。
1. 常量定义:
// 配置AP(热点)模式相关参数
const char *AP_SSID = "WLROBOT";
const char *AP_PSW = "12345678";
IPAddress AP_IP(192, 168, 1, 11);
IPAddress AP_GATEWAY(192, 168, 1, 11);
IPAddress AP_SUBNET(255, 255, 255, 0);
// 配置STA模式相关参数
char *sta_ssid = "MUJITECH";
char *sta_password = "mujitech";
-
AP模式:ESP-01S 在此模式下将成为一个 Wi-Fi 热点,允许其他设备连接到它。
AP_SSID
和AP_PSW
分别是 ESP-01S 热点的 SSID(网络名称)和密码。AP_IP
,AP_GATEWAY
,AP_SUBNET
用于配置 ESP-01S 在热点模式下的静态 IP 地址、网关地址和子网掩码。
-
STA模式:ESP-01S 作为客户端连接到其他 Wi-Fi 网络。
sta_ssid
和sta_password
是用来连接到指定 Wi-Fi 网络的凭据。
2. WiFi_SetAP()
函数:
void WiFi_SetAP(void)
{
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(AP_IP, AP_GATEWAY, AP_SUBNET);
WiFi.softAP(AP_SSID, AP_PSW);
}
- 功能:将 ESP-01S 设置为 Wi-Fi 热点模式。
WiFi.mode(WIFI_AP)
:将 Wi-Fi 模式设置为 AP(热点模式)。WiFi.softAPConfig(AP_IP, AP_GATEWAY, AP_SUBNET)
:设置热点模式下的静态 IP 地址、网关和子网掩码。WiFi.softAP(AP_SSID, AP_PSW)
:启动 Wi-Fi 热点,SSID 为AP_SSID
,密码为AP_PSW
。
3. set_sta_wifi()
函数:
void set_sta_wifi()
{
WiFi.begin(sta_ssid, sta_password); // 连接到指定的 Wi-Fi 网络
// 等待连接
while(WiFi.status() != WL_CONNECTED)
{
delay(500); // 每隔 500 毫秒检查一次连接状态
}
// 打印ESP-01S的IP地址
Serial.println("");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP()); // 打印 ESP-01S 获取的本地 IP 地址
}
- 功能:将 ESP-01S 设置为客户端模式,连接到指定的 Wi-Fi 网络。
WiFi.begin(sta_ssid, sta_password)
:启动连接到指定的 Wi-Fi 网络(SSID 为sta_ssid
,密码为sta_password
)。- 在
while
循环中,ESP-01S 将持续等待,直到它成功连接到 Wi-Fi 网络。每 500 毫秒检查一次连接状态。 - 一旦连接成功,打印出 ESP-01S 获得的 IP 地址。
4. 说明与总结:
- AP模式:通过
WiFi_SetAP()
函数,ESP-01S 变成一个热点,其他设备可以连接到这个热点,获取从 ESP-01S 配置的静态 IP 地址(192.168.1.11
)。 - STA模式:通过
set_sta_wifi()
函数,ESP-01S 会连接到一个指定的 Wi-Fi 网络,并获得该网络的分配 IP 地址。
可能的扩展:
- 添加错误处理:可以在
set_sta_wifi()
函数中添加超时处理,以防止设备在无法连接的情况下无限等待。 - 动态 IP 分配:如果不需要固定 IP 地址,可以使用 DHCP 自动获取 IP 地址,而不是指定静态 IP。
- 调试信息:如果需要调试,使用
Serial.println()
输出更多的信息,例如连接状态、连接时间等。
总体来说,这段代码简单、实用,适合用于基础的 ESP-01S Wi-Fi 网络连接或创建自己的 Wi-Fi 热点。
wifi.h
这段代码是 Wifi.h
的头文件,它定义了用于配置和控制 ESP32 或其他基于 ESP 的设备(如 ESP-01S)的 Wi-Fi 功能的接口。它声明了两个函数:WiFi_SetAP()
和 set_sta_wifi()
。
1. WiFi_SetAP()
函数:
- 该函数用于将设备设置为 AP模式(热点模式),使得该设备能够创建一个 Wi-Fi 热点,其他设备可以连接到它。
- 头文件中声明了该函数,但没有定义具体的功能实现。具体的实现代码应该在
Wifi.cpp
文件中。
2. set_sta_wifi()
函数:
- 该函数用于将设备设置为 STA模式(客户端模式),并通过提供的网络凭据连接到 Wi-Fi 网络。
- 头文件中声明了该函数,具体实现同样会在
Wifi.cpp
文件中提供。
3. 头文件中的内容:
#pragma once
#pragma once
是一个编译指令,用来确保该头文件只会被编译一次。这样可以避免同一个头文件在多个地方被重复包含,导致的多重定义问题。相较于传统的#ifndef
和#define
保护方式,#pragma once
是一个更加简洁且有效的替代方案。
4. 包含 Wi-Fi 库:
#include <WiFi.h>
WiFi.h
是 ESP32 等基于 ESP 平台的官方 Wi-Fi 库,它提供了连接和管理 Wi-Fi 网络所需的功能。通过WiFi.h
,可以轻松实现热点模式、客户端模式、获取设备 IP 地址等操作。
总结
- 这个头文件是 ESP32 或类似设备与 Wi-Fi 网络交互的基础接口声明文件。它依赖于在
Wifi.cpp
文件中提供具体的函数实现,Wifi_SetAP()
用于设置设备为热点模式,set_sta_wifi()
用于连接 Wi-Fi 网络。 - 使用
#pragma once
来避免重复包含头文件,并通过WiFi.h
库实现所有 Wi-Fi 操作。
debug_custom.json
这是一个用于调试 ESP32 上的 Arduino 程序的 debug_custom.json
配置文件,通常在使用调试工具(如 GDB)时配置。文件中的内容控制了调试会话的行为。以下是对每个字段的解释:
1. "name": "Arduino on ESP32"
- 这是调试会话的名称,通常用来标识不同的调试配置。
- 在 IDE(例如 VS Code)中,这个名字将出现在调试配置列表中。
2. "toolchainPrefix": "xtensa-esp32-elf"
- 这是指定用于 ESP32 的编译工具链前缀。
xtensa-esp32-elf
是针对 ESP32 的交叉编译工具链。 - 该工具链包含编译器、链接器等,用于生成 ESP32 可执行代码。
3. "svdFile": "esp32.svd"
- SVD 文件(System View Description file)包含有关 ESP32 微控制器硬件的描述。它定义了寄存器、位域和其他硬件特性,用于调试工具(如 GDB)识别和访问硬件寄存器。
- 这个文件帮助 GDB 在调试过程中显示硬件信息和寄存器的实时数据。
4. "request": "attach"
- 这个字段告诉调试器是连接到正在运行的程序(
attach
),而不是启动一个新的程序实例。 - 如果你希望调试已经在 ESP32 上运行的程序,你应该使用
attach
。
5. "postAttachCommands"
- 这些是连接后(即当 GDB 与 ESP32 设备连接时)要执行的 GDB 命令。
- 具体命令说明:
"set remote hardware-watchpoint-limit 2"
:设置 GDB 监视硬件断点的最大数量为 2。硬件断点用于监视特定内存位置的变化。"monitor reset halt"
:发送重置命令,并使 ESP32 在启动时停止。这通常用于确保调试器从一个已知的、停止的状态开始。"monitor gdb_sync"
:使调试器与设备同步。"thb setup"
:这可能是一个自定义的 GDB 命令,设置某些调试功能(如断点或初始化)。"c"
:继续执行(GDB 命令),一旦设置了所有初始条件,调试器会继续程序执行。
6. "overrideRestartCommands"
- 这些命令会在调试会话重启时执行。例如,当你在调试会话中停止程序后,再次启动它时,GDB 会自动执行这些命令。
- 这些命令与
postAttachCommands
相似,通常用于确保调试器从一致的状态开始。
总结
debug_custom.json
配置文件的作用是为 ESP32 调试会话提供初始化命令和调试参数,帮助开发者调试程序时控制调试器的行为。它通过自定义 GDB 命令来设置硬件断点、同步 GDB、控制重启等操作。- 如果你使用的 IDE 是 VS Code 或其他集成调试环境,这个文件的配置可以帮助调试器正确连接到你的 ESP32 设备,并控制调试过程。