ESP32智能小车开发文档¶
目录¶
1. 项目概述¶
1.1 项目简介¶
本项目实现了一个基于ESP32-S3的4轮智能小车,通过CAN总线与上位机(ROS2)通信,支持蓝牙手柄控制。
1.2 功能特性¶
| 功能 | 说明 |
|---|---|
| 电机控制 | 4个编码器电机,PWM调速 |
| 运动模式 | 差速转向模式 |
| 通信方式 | CAN总线TWAI(主)、蓝牙手柄(本地) |
| 传感器 | MPU6050陀螺仪、QMC5883L磁力计(选配)、编码器 |
| 上报数据 | 电池电压、姿态角、线速度、角速度、电机转速、编码器累计值 |
1.3 开发指引¶
本项目使用vscode + PlatformIO 的开发环境
如之前没有接触过,可以自行B站搜索相关,很容易上手
2. 硬件配置¶
2.1 硬件清单¶
| 设备 | 型号/规格 | 数量 | 说明 |
|---|---|---|---|
| 主控 | ESP32-S3-DevKitC-1 | 1 | 主控制器,集成电机驱动 |
| 电机电机 | 36-555 | 4 | 直流减速电机 |
| 编码器 | 霍尔编码器 | 4 | 集成在电机上 |
| 陀螺仪 | MPU6050 | 1 | 内置于开发板 |
| 磁力计 | QMC5883L | 1 | 没有用到 |
| 蓝牙手柄 | BLE手柄 | 1 | 本地控制 |
| CAN收发器 | USB转Can分析仪 | 1 | 接电脑端 |
| CAN转TTL模块 | Can转TTL | 1 | 接ESP32 |
2.2 引脚分配¶
ESP32-S3 引脚资源:
├── GPIO5 : TWAI TX (CAN发送)
├── GPIO6 : TWAI RX (CAN接收)
├── GPIO2 : ADC (电池电压检测)
├── GPIO46 : LED指示
└── 编码器引脚 : 通过配置读取
2.3 CAN总线接线¶
ESP32-S3 CAN转TTL模块
───────────────── ────────────────
GPIO5 (TX) → TX
GPIO6 (RX) → RX
3.3V → VCC
GND → GND
CAN转TTL模块另一头 CAN收发器 电脑
────────────────── ────────────── ───────────
CANH → CANH -> usb
CANL → CANL
2.4 CAN收发器及上位机¶
请查看交付目录的文件夹 《CAN收发器文档》
3. 通信架构¶
┌─────────────┐ USB-CAN ┌──────────────┐ CAN总线 ┌─────────────────┐
│ ROS2 PC │ ←──────────────→ │ USB-CAN收发器 │ ←───────────→ │ CAN转TTL模块 │
└─────────────┘ └──────────────┘ └───────┬─────────┘
│
↓
┌─────────────┐ ┌────────────────────────────────────┐
│ 蓝牙手柄 │ ←──── BLE ──────────────→ │ ESP32-S3 (TWAI) │
│ (本地控制) │ │ ┌────────────────────────────────┐│
└─────────────┘ │ │ • TWAI控制器(硬件处理CAN协议) ││
│ │ • 蓝牙优先级最高 ││
│ └────────────────────────────────┘│
└───────────────────────────────────┘
4. CAN通信协议¶
4.1 通信参数¶
| 参数 | 值 |
|---|---|
| 波特率 | 500Kbps |
| 帧格式 | 标准帧 (11位ID) |
| 数据格式 | 小端序 (低字节在前) |
| 过滤器 | 接收所有帧 |
4.2 CAN ID分配表¶
| ID | 方向 | 功能 | 数据长度 |
|---|---|---|---|
| 0x101 | 上行 | 姿态数据 | 8字节 |
| 0x102 | 上行 | 电机转速 (4电机) | 8字节 |
| 0x103 | 上行 | 编码器累计值 (1-2) | 8字节 |
| 0x104 | 上行 | 编码器累计值 (3-4) | 8字节 |
| 0x105 | 上行 | 同步帧 (丢包检测+延迟估计) | 8字节 |
| 0x201 | 下行 | PWM模式控制 (+seq) | 8字节 |
| 0x202 | 下行 | ROS速度模式控制 (+seq) | 8字节 |
| 0x203 | 下行 | 刹车指令 (+seq) | 2字节 |
4.3 上行数据帧格式(ESP32 → 上位机)¶
0x101 - 姿态数据(8字节)¶
| 字节 | 类型 | 名称 | 单位 | 说明 |
|---|---|---|---|---|
| 0-1 | uint16 | voltage | 0.01V | 电池电压,如241=24.1V |
| 2-3 | int16 | angleZ | deg | 航向角,-180~180 |
| 4-5 | int16 | linearX | mm/s | X轴线速度 |
| 6-7 | int16 | linearY | mm/s | Y轴线速度 |
测试示例:
| 场景 | 数据(hex) | 说明 |
|---|---|---|
| 静止 | F1 00 00 00 00 00 00 00 |
电压24.1V, 航向0°, 线速度0 |
| 向右转90° | F1 00 5A 00 00 00 00 00 |
电压24.1V, 航向90°, 线速度0 |
| 前进中 | F1 00 00 00 64 00 00 00 |
电压24.1V, 航向0°, X线速度100mm/s |
| 满电前进 | C8 00 00 00 64 00 00 00 |
电压20.0V, 航向0°, X线速度100mm/s |
0x102 - 电机转速(8字节)¶
| 字节 | 类型 | 名称 | 单位 |
|---|---|---|---|
| 0-1 | int16 | rpm1 | RPM |
| 2-3 | int16 | rpm2 | RPM |
| 4-5 | int16 | rpm3 | RPM |
| 6-7 | int16 | rpm4 | RPM |
测试示例:
| 场景 | 数据(hex) | 说明 |
|---|---|---|
| 静止 | 00 00 00 00 00 00 00 00 |
全部停止 |
| 前进 | 32 00 1E 00 0A 00 14 00 |
电机1=50, 电机2=30, 电机3=10, 电机4=20RPM |
| 倒退 | CE FF E2 FF F6 FF 0A 00 |
电机1=-50, 电机2=-30, 电机3=-10, 电机4=10RPM |
0x103 - 编码器累计值1-2(8字节)¶
| 字节 | 类型 | 名称 | 说明 |
|---|---|---|---|
| 0-3 | int32 | encoder1 | 编码器1累计脉冲数 |
| 4-7 | int32 | encoder2 | 编码器2累计脉冲数 |
测试示例: [0x64 0x00 0x00 0x00 0xE8 0x03 0x00 0x00] → 编码器1=100, 编码器2=1000
0x104 - 编码器累计值3-4(8字节)¶
| 字节 | 类型 | 名称 | 说明 |
|---|---|---|---|
| 0-3 | int32 | encoder3 | 编码器3累计脉冲数 |
| 4-7 | int32 | encoder4 | 编码器4累计脉冲数 |
测试示例: [0x00 0x00 0x00 0x00 0x10 0x27 0x00 0x00] → 编码器3=0, 编码器4=10000
0x105 - 同步帧(8字节,ESP32 → PC,1Hz)¶
用于上位机实现丢包检测和延迟估计。由ESP32定期发送,携带系统运行时间和帧序号。
| 字节 | 类型 | 名称 | 说明 |
|---|---|---|---|
| 0-3 | uint32 | uptime_ms | 系统运行时间(ms),可用于延迟估计 |
| 4-5 | uint16 | frame_seq | 全局帧序号,单调递增,跳变即丢包 |
| 6 | uint8 | rx_seq_echo | 最近收到的下行帧序号,上位机可据此计算RTT |
| 7 | uint8 | reserved | 保留 |
测试示例:
| 场景 | 数据(hex) | 说明 |
|---|---|---|
| 启动1秒后 | E8 03 00 00 05 00 00 00 |
uptime=1000ms, seq=5, rx_echo=0 |
| 运行10秒 | 10 27 00 00 32 00 0A 00 |
uptime=10000ms, seq=50, rx_echo=10 |
4.4 下行数据帧格式(上位机 → ESP32)¶
0x201 - PWM模式控制(8字节)¶
| 字节 | 类型 | 名称 | 范围 | 说明 |
|---|---|---|---|---|
| 0-1 | int16 | x_speed | -100~100 | X轴功率百分比 |
| 2-3 | int16 | y_speed | -100~100 | Y轴功率百分比 |
| 4-5 | int16 | z_speed | -100~100 | Z轴功率百分比 |
| 6 | uint8 | seq | 0~255 | 帧序号,上位机递增,用于丢包检测 |
| 7 | uint8 | reserved | - | 保留 |
测试示例(上位机填写:CAN ID = 0x201, 数据8字节hex, 数据长度8):
| 场景 | 数据(hex 8字节) | X | Z | 说明 |
|---|---|---|---|---|
| 前进50% | 32 00 00 00 00 00 00 00 |
50 | 0 | X轴50%前进 |
| 前进100% | 64 00 00 00 00 00 00 00 |
100 | 0 | X轴全速前进 |
| 后退50% | CE FF 00 00 00 00 00 00 |
-50 | 0 | X轴-50%后退 |
| 顺时针旋转50% | 00 00 00 00 32 00 00 00 |
0 | 50 | Z轴50%右转 |
| 逆时针旋转50% | 00 00 00 00 CE FF 00 00 00 |
0 | -50 | Z轴-50%左转 |
| 停车 | 00 00 00 00 00 00 00 00 |
0 | 0 | 全部归零 |
注意:橡胶轮不支持横移,Y轴填0
0x202 - ROS速度模式控制(8字节)¶
| 字节 | 类型 | 名称 | 单位 | 说明 |
|---|---|---|---|---|
| 0-1 | int16 | x_speed | mm/s | X轴线速度 |
| 2-3 | int16 | y_speed | mm/s | Y轴线速度 |
| 4-5 | int16 | z_speed | deg/s | Z轴角速度 |
| 6 | uint8 | seq | 0~255 | 帧序号,上位机递增,用于丢包检测 |
| 7 | uint8 | reserved | - | 保留 |
测试示例(上位机填写:CAN ID = 0x202, 数据8字节hex, 数据长度8):
| 场景 | 数据(hex 8字节) | X(mm/s) | Z(deg/s) | 说明 |
|---|---|---|---|---|
| 前进0.2m/s | C8 00 00 00 00 00 00 00 |
200 | 0 | 约0.2m/s前进 |
| 前进0.8m/s | 20 03 00 00 00 00 00 00 |
800 | 0 | 约0.8m/s前进 |
| 后退0.2m/s | 38 FF 00 00 00 00 00 00 |
-200 | 0 | 约0.2m/s后退 |
| 旋转90°/s | 00 00 00 00 5A 00 00 00 |
0 | 90 | 90°/s顺时针旋转 |
| 停车 | 00 00 00 00 00 00 00 00 |
0 | 0 | 全部归零 |
0x203 - 刹车指令(2字节)¶
| 字节 | 类型 | 名称 | 范围 | 说明 |
|---|---|---|---|---|
| 0 | uint8 | brakeForce | 0~100 | 刹车力度,0=滑行停车,1~100=主动刹车+驻车保持 |
| 1 | uint8 | seq | 0~255 | 帧序号,上位机递增,用于丢包检测 |
- brakeForce = 0:滑行停车(电机释放,自由减速至停止)
- brakeForce > 0:主动刹车 → 电机短接制动至停稳 → 自动进入驻车位置保持(编码器闭环反推,抵抗外力推移)
测试示例(上位机填写:CAN ID = 0x203, 数据长度2):
| 场景 | 数据(hex) | 说明 |
|---|---|---|
| 滑行停车 | 00 |
刹车力0,释放电机自由停止 |
| 轻柔刹车 | 30 |
30%刹车力度制动,停稳后驻车保持 |
| 紧急刹车 | 64 |
100%全力刹车,停稳后驻车保持 |
5. ESP32代码说明¶
5.1 代码结构¶
cust20/
├── src/
│ ├── main.cpp # 主程序入口
│ └── main.h # 全局变量和函数声明
├── lib/
│ ├── CanBus/ # CAN通信模块
│ │ ├── CanBus.h/cpp # MCP2515方案(参考)
│ │ ├── CanBusTTL.h/cpp # CAN转TTL方案(参考)
│ │ └── CanBusTWAI.h/cpp # TWAI方案(当前使用)
│ ├── Config/ # 配置存储
│ ├── ControlStick/ # 蓝牙手柄
│ ├── encoder/ # 编码器驱动
│ ├── motor/ # 电机驱动
│ ├── Pid/ # PID控制
│ ├── protocal/ # 通信协议定义
│ └── Head.h # 硬件参数配置
└── platformio.ini # 项目配置
5.2 核心类说明¶
CanBusTWAI 类¶
使用ESP32-S3内置TWAI控制器,通过硬件自动处理CAN协议。
class CanBusTWAI
{
public:
// 初始化TWAI控制器
bool begin(CanRxCallback callback);
// 发送原始CAN帧
bool sendFrame(uint16_t canId, const uint8_t* data, uint8_t len);
// 发送姿态数据帧
bool sendPoseData(float voltage, int16_t angleZ, ...);
// 发送电机转速帧
bool sendMotorRpm(int16_t rpm1, int16_t rpm2, int16_t rpm3);
// 发送编码器累计值帧
bool sendEncoderTicks(int32_t tick1, int32_t tick2, ...);
};
handleCanFrame 回调函数¶
解析上位机发送的CAN指令:
0x201PWM模式 → 调用controlEMotors()0x202ROS模式 → 单位转换后调用controlEMotors()0x203刹车指令 → 调用stop()
5.3 多任务架构¶
ESP32-S3双核处理器,任务分配如下:
| 任务 | 核心 | 说明 |
|---|---|---|
loop() |
Core 1 | 主循环 |
xCore_task |
Core 0 | 电机控制、传感器采集 |
twaiTask |
Core 0 | CAN帧接收(独立任务) |
5.4 关键参数(必须自行调整)¶
/**Head.h*/
// 根据实际情况修改参数配置
const int maxRpm = 110; // 电机最大转速RPM
const int gear = 90; // 减速比
const float wheelCircumference = PI * 80; // 轮子周长(mm)
const int wheelSpacing = 220; // 轮间距(mm)
const int wheelBase = 200; // 轴距(mm)
/**main.h*/
// 可以根据实际情况修改参数配置
const int gapNotice = 100; // 定时发送状态的间隔,单位毫秒
const int outPutCountLimit = 10; // 电机满负荷运行多少次后降低速度
const float maxDe = 0.3; // 电机如果超负荷运行,最大降速比例
/**pid.h*/
// 必须根据实际情况修改参数配置,例如下行数据的频率,影响到电机的转速
double kp = 0.25; // 比例系数
double ki = 0.02; // 积分系数
double kd = 0.5; // 微分系数
5.5 数据上报周期¶
- 姿态数据:100ms (10Hz)
- 电机转速:100ms (10Hz)
- 编码器:100ms (10Hz)
6. 调试与维护¶
6.1 调试方法¶
串口监视¶
波特率115200,可查看:
-
TWAI初始化状态
-
接收到的指令
-
电机转速反馈
-
错误信息
6.2 联系方式¶
如有问题,请联系技术 15827639032
附录¶
A. CAN帧测试快速参考表¶
下行测试(PC上位机 → ESP32,用USB-CAN分析仪发送)¶
| 操作 | CAN ID | 数据(hex 8字节) | 数据长度 |
|---|---|---|---|
| 50%功率前进 | 0x201 | 32 00 00 00 00 00 01 00 |
8 |
| 100%功率前进 | 0x201 | 64 00 00 00 00 00 02 00 |
8 |
| 50%功率后退 | 0x201 | CE FF 00 00 00 00 03 00 |
8 |
| 50%顺时针旋转 | 0x201 | 00 00 00 00 32 00 04 00 |
8 |
| 50%逆时针旋转 | 0x201 | 00 00 00 00 CE FF 05 00 |
8 |
| 停车 | 0x201 | 00 00 00 00 00 00 06 00 |
8 |
| 前进0.2m/s | 0x202 | C8 00 00 00 00 00 01 00 |
8 |
| 前进0.8m/s | 0x202 | 20 03 00 00 00 00 02 00 |
8 |
| 后退0.2m/s | 0x202 | 38 FF 00 00 00 00 03 00 |
8 |
| 旋转90°/s | 0x202 | 00 00 00 00 5A 00 04 00 |
8 |
| 停车 | 0x202 | 00 00 00 00 00 00 05 00 |
8 |
| 滑行停车 | 0x203 | 00 01 00 00 00 00 00 00 |
2 |
| 轻柔刹车+驻车 | 0x203 | 1E 02 00 00 00 00 00 00 |
2 |
| 紧急刹车+驻车 | 0x203 | 64 03 00 00 00 00 00 00 |
2 |
上行测试(ESP32 → PC上位机,用USB-CAN分析仪接收)¶
| 数据含义 | CAN ID | 数据(hex 8字节) |
|---|---|---|
| 电压24.1V, 静止 | 0x101 | F1 00 00 00 00 00 00 00 |
| 电压24.1V, 航向90° | 0x101 | F1 00 5A 00 00 00 00 00 |
| 电压24.1V, X线速度100mm/s | 0x101 | F1 00 00 00 64 00 00 00 |
| 电机1=50, 2=30, 3=10, 4=20RPM | 0x102 | 32 00 1E 00 0A 00 14 00 |
| 编码器1=100, 编码器2=1000 | 0x103 | 64 00 00 00 E8 03 00 00 |
| 编码器3=0, 编码器4=10000 | 0x104 | 00 00 00 00 10 27 00 00 |
| 同步: uptime=1000ms, seq=5 | 0x105 | E8 03 00 00 05 00 00 00 |
USB-CAN分析仪上位机操作步骤¶
- 接线如下图:杜邦线接esp2,usb插电脑

-
按资料包中的文档安装驱动和上位机
-
esp32代码上传至开发板
-
打开上位机,会自动弹窗connect,如没有则手动连接

- 自行设置测试包

B. 修订历史¶
| 版本 | 日期 | 修改内容 |
|---|---|---|
| 1.0 | 2026-05-12 | 初始版本 |
| 1.1 | 2026-05-14 | 改用TWAI方案,增加CAN收发器接线说明 |
| 1.2 | 2026-05-27 | 增加各CAN ID完整测试数据表及USB-CAN上位机操作说明 |
| 1.3 | 2026-06-26 | 新增0x105同步帧;0x201/0x202/0x203增加seq序号;0x102扩展为4电机8字节 |