世博轮腿机器人Software

wl_pro_robot.ino

这个代码是一个完整的机器人控制程序,涉及到多个硬件模块的控制和通信,包括电机、传感器、舵机、PID控制器、滤波器、Web服务器等。下面简要解释一些关键部分:

  1. 电机与驱动控制:代码定义了两个电机(motor1motor2)及其驱动器(driver1driver2),并通过FOC(Field-Oriented Control)技术来进行电机控制。

  2. PID控制器:通过PID控制器调节机器人的角度、速度、位移等参数,以实现平衡和精确控制。多个PID控制器(如pid_angle, pid_gyro, pid_distance等)分别用于处理不同的控制任务。

  3. 传感器与数据读取:使用MPU6050传感器获取角度和陀螺仪数据,利用AS5600磁编码器来获取电机的位置和速度。

  4. LQR平衡控制:使用线性二次调节器(LQR)来进行自平衡控制。LQR通过优化控制策略来实现机器人的平衡,结合角度、速度、位移等因素来计算控制输出。

  5. Web与Wi-Fi控制:通过Web服务器(WebServer)和WebSocket(WebSocketsServer)实现远程控制。Wi-Fi功能用于连接到无线网络,并通过Web界面或Socket进行实时数据交互。

  6. 电池监控与舵机控制:通过ADC读取电池电压,使用舵机(sms_sts)控制机器人的腿部动作。

  7. 安全保护与状态检测:设定了“失控”状态检测(如过大的倾斜角度),并在此情况下停止电机输出,确保机器人安全。

每个部分都通过精细的调节和控制算法实现机器人的平衡、动作和响应。在loop()函数中,机器人不断监控状态并根据传感器数据调整动作,确保机器人能够稳定运行。
这段代码主要涉及一个基于控制算法和硬件驱动的机器人系统。它包括电机控制、姿态稳定(自平衡)控制、WebSocket通信、舵机控制等功能。接下来,我将详细分析代码的结构和各部分功能:

1. 硬件模块

1.1 电机控制(BLDCMotor, BLDCDriver3PWM)
  • motor1motor2 是两个无刷直流电机的实例。BLDCMotor 类用于控制电机的转动,BLDCDriver3PWM 类则用于控制电机驱动器,通过三个PWM信号来控制电机的转速和转向。
  • 电机的初始化和驱动逻辑通过 motor1motor2 关联传感器和驱动器,并设置控制类型为电压(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 控制器都有相应的 PID 参数,分别控制比例、积分和微分部分,这些参数能够调节控制器的响应和稳定性。

2.2 LQR 自平衡控制
  • LQR(线性二次调节器)是一个用于优化状态反馈控制的算法,目的是使系统达到平衡。代码中的 lqr_balance_loop 函数通过 PID 控制器来实现机器人自平衡:
    • LQR_angleLQR_gyro 分别表示机器人的俯仰角和角速度。
    • distance_controlspeed_control 分别处理机器人的位移和速度控制。
    • LQR_u 是控制输出,用于计算机器人所需的力矩。
    • angle_controlgyro_control 负责调整机器人角度和角速度。
2.3 控制策略
  • 当机器人处于失控状态(例如倾斜角度超过 25°),会禁用输出,停止电机运转。这是通过 uncontrolable 标志位来实现的,防止机器人进一步失控。
  • jump_flag 用于标记机器人是否处于跳跃状态,如果是跳跃状态,系统会停止电机控制,等待机器人恢复。
  • wrobot_move_stop_flag 用于标记是否需要停止机器人运动(例如通过遥控器指令或其他条件)。
2.4 腿部控制
  • 代码中的 leg_loop 函数控制机器人的腿部运动,特别是与跳跃和姿态平衡相关的动作。leg_position_addleg_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。
  • 每个控制命令都有一个对应的函数(例如 StabAngleStabGyro 等),通过 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]
  • 角度控制:类似地,rolllinearangularstablejoy_xjoy_y 等字段被解析并对应更新机器人控制状态以及缓冲区中的相应字节。

总结

这段代码主要用于实现机器人控制协议的基础功能。它接收来自 Web 端的 JSON 格式控制命令,并将这些命令转换为机器人可以理解的串口协议数据。数据通过串口发送,控制机器人进行相应的动作,如前进、后退、跳跃等。通过 checkBufRefresh 函数,代码确保只有在控制命令变化时才会发送数据,从而优化通信效率。

web端

“Web 端” 指的是通过 Web 浏览器或基于 Web 技术(如 HTML、CSS、JavaScript)开发的前端界面或应用程序,通常用于与用户交互并向后端服务发送请求或接收数据。

在你提供的代码中,“Web 端” 指的是一个基于 Web 技术的用户界面,用户可以通过浏览器向机器人发送控制命令(如运动方向、速度等)。这些命令通常以 JSON 格式发送,机器人通过串口通信接收这些命令并执行相应的动作。简而言之,“Web 端” 是通过 Web 浏览器与设备(如机器人)交互的用户界面部分。

典型的 Web 端工作流程:

  1. 用户操作:用户在 Web 端界面上进行操作,比如点击按钮、选择选项、输入数据等。
  2. 数据传输:这些操作生成的控制数据(如 JSON 格式的命令)通过网络发送到后端服务器或直接发送到设备。
  3. 后端处理:如果有后端服务器,它会处理来自 Web 端的请求,进行相应的计算或数据转发。
  4. 设备控制:设备(比如机器人)通过接收这些命令并执行相应的动作(例如,改变方向、调整速度等)。

因此,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:机器人上次的方向。
    • joyyjoyx:机器人控制的摇杆(joystick)值。
    • joyy_lastjoyx_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_tRobot_Mode_t:定义了机器人的运动状态和模式。
  • RobotProtocol:负责与机器人之间的通信协议,包括解析来自 Web 端的数据、发送命令给机器人等功能。该类通过串口和 Wi-Fi 进行通信,确保机器人根据指令执行相应动作。

RobotProtocol 类的作用就是处理与机器人之间的所有通信工作,确保能够从 Web 端接收指令、解析指令并通过硬件接口(如串口)发送指令到机器人。

JSON数据

JSON(JavaScript Object Notation,即 JavaScript 对象表示法)是一种轻量级的数据交换格式,它非常易于人类阅读和编写,同时也易于机器解析和生成。JSON 格式通常用于在客户端和服务器之间交换数据,尤其是在 Web 开发和 API(应用程序编程接口)中非常常见。

JSON 数据的基本特点:

  1. 结构简单:JSON 数据由一系列键值对(key-value pair)组成,格式类似于 JavaScript 中的对象或字典(在其他编程语言中如 Python、C# 等也有类似的数据结构)。
  2. 数据类型支持:JSON 支持以下数据类型:
    • 字符串(String):由双引号包围的字符集。
    • 数字(Number):整数或浮动的数字。
    • 布尔值(Boolean):truefalse
    • 数组(Array):由中括号 [] 包围的一系列值,值之间用逗号分隔。
    • 对象(Object):由大括号 {} 包围的一组键值对,键是字符串,值可以是任意数据类型。
    • 空值(null):表示空值或无值。

JSON 的格式示例:

{
  "name": "Alice",
  "age": 25,
  "isStudent": false,
  "courses": ["Math", "Science", "English"],
  "address": {
    "street": "123 Main St",
    "city": "Somewhere",
    "zip": "12345"
  }
}

解释这个示例:

  1. "name": "Alice":这是一个键值对,键是 "name",值是字符串 "Alice"
  2. "age": 25:键是 "age",值是数字 25
  3. "isStudent": false:键是 "isStudent",值是布尔值 false
  4. "courses": ["Math", "Science", "English"]:键是 "courses",值是一个数组,包含了三个字符串元素。
  5. "address": {...}:键是 "address",值是一个嵌套对象,包含了 streetcityzip 三个键值对。

JSON 的优点:

  • 简洁:JSON 格式简单,易于理解。
  • 轻量:它的结构简单,适用于网络传输。
  • 易于解析:JSON 可以方便地被编程语言(如 JavaScript、Python、C++ 等)解析。
  • 广泛应用:JSON 是 Web 开发中最常见的数据交换格式,尤其适用于 RESTful API 和前后端通信。

JSON 和 JavaScript:

JSON 的语法实际上是 JavaScript 对象字面量(Object Literal)的子集。它与 JavaScript 的对象非常相似,但有一些不同之处:

  • 键必须是字符串,并且必须用双引号包围(JavaScript 对象的键可以不加引号)。
  • 没有函数和日期:JSON 中不能包含 JavaScript 函数或 Date 类型。

在实际应用中的使用:

  1. Web 前后端通信:前端使用 JavaScript 发起 HTTP 请求(如使用 fetchXMLHttpRequest),服务器返回 JSON 格式的数据,前端解析这些数据并渲染页面。
  2. API 数据交换:许多 Web 服务使用 JSON 格式进行数据交换。例如,获取天气数据、社交媒体数据等,通常通过 JSON 格式返回。
  3. 配置文件: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)舵机的控制实现,具体用于串行通信控制和同步写入指令。下面是对代码的逐步分析和解释:

代码结构概述:

  1. SCS 类:是一个串行通信协议类,用于与舵机通信,主要功能包括将数据分解为低位和高位的字节、发送同步写入指令等。
  2. SCSerial 类:是一个继承自 SCS 的类,负责具体的串行通信操作,比如写数据到串口、读取串口等。
  3. 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 控制字节的顺序(低字节在前还是高字节在前)。
  • syncWrite 方法

    void SCS::syncWrite(u8 ID[], u8 IDN, u8 MemAddr, u8 *nDat, u8 nLen)
    
    • 用于同步写入多个舵机的数据。舵机的 ID 和要写入的内存地址(MemAddr)以及数据(nDat)和数据长度(nLen)会一起被发送。
    • 计算并发送校验和(Sum)以确保数据的完整性。
2. SCSerial 类:

SCSerial 类是 SCS 类的一个子类,扩展了串行通信的功能,负责将数据通过串口传输给舵机。

  • writeSCS 方法

    int SCSerial::writeSCS(unsigned char *nDat, int nLen)
    
    • 用于将数据(nDat)通过串口写入,nLen 为数据的长度。
    • 还提供了单字节写入的版本。
  • rFlushSCSwFlushSCS 方法

    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 rFlushSCSwFlushSCS 方法
void rFlushSCS();
void wFlushSCS();
  • 功能rFlushSCS 用于清空串口接收缓存,以防止旧数据影响通信。wFlushSCS 用于清空发送缓存。
3.4 IOTimeOutpSerial
  • 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_SSIDAP_PSW 分别是 ESP-01S 热点的 SSID(网络名称)和密码。
    • AP_IP, AP_GATEWAY, AP_SUBNET 用于配置 ESP-01S 在热点模式下的静态 IP 地址、网关地址和子网掩码。
  • STA模式:ESP-01S 作为客户端连接到其他 Wi-Fi 网络。

    • sta_ssidsta_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 设备,并控制调试过程。
### 式自平衡机器人 Adams仿真建模方法 #### 3.1 Adams环境搭建与模型创建 为了构建式自平衡机器人的Adams仿真模型,首先需在Adams环境中设置工作空间并导入必要的几何文件。通常情况下,会使用CAD软件预先设计好机器人的三维结构,并将其导出为STEP或其他兼容格式,在Adams中作为基础构件加载[^2]。 #### 3.2 关键部件定义 接着定义各个关键组件,包括但不限于车架、驱动电机、悬挂系统以及部机构等部分。特别需要注意的是,对于具有复杂运动特性的部位如部关节处,应该仔细设定其自由度(DOF),确保能够真实再现物理世界中的行为模式。 #### 3.3 动力学特性赋值 赋予各组成部分适当的质量属性和惯性矩,这一步骤至关重要因为它直接影响到后续的动力学计算准确性。此外还需考虑摩擦力等因素的影响,通过实验数据校准这些参数使得模拟更加贴近实际情况。 #### 3.4 控制器集成 由于涉及到复杂的动态平衡控制逻辑,建议采用MATLAB/Simulink平台开发相应的PID或者其他类型的控制器,并借助联合仿真的方式实现两者之间的无缝对接。这样不仅可以简化控制系统的设计流程,同时也便于后期调整优化策略。 ```matlab % 创建Simulink模型并与ADAMS连接 set_param('myRobotModel','Solver','ode15s'); adms = adams_link; adms.connect('myRobotModel', 'path_to_adams_model.adm'); ``` #### 3.5 验证与测试 完成初步建模之后,应当进行全面的功能验证,比如执行不同场景下的行走动作来检验稳定性;同时记录各项指标用于评估整体性能表现。如果发现任何异常情况,则应回溯至上一阶段查找原因直至满足预期目标为止。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值