esp32-car/src/main.cpp

393 lines
9.8 KiB
C++
Raw Normal View History

2024-12-12 15:38:11 +08:00
#include <Arduino.h>
2024-12-16 00:16:06 +08:00
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
2024-12-18 16:10:26 +08:00
#include <SPIFFS.h>
2024-12-18 14:16:02 +08:00
#include "consts.h"
2024-12-15 18:09:40 +08:00
2024-12-12 15:38:11 +08:00
// 使用 2 片 TB6612 控制 4 个电机
// 使用差速控制转向
2024-12-15 18:09:40 +08:00
#define PACKET_R_HEAD 0x00
#define PACKET_R_TAIL 0xFF
#define PACKET_T_HEAD 0x01
#define PACKET_T_TAIL 0xFE
#define PACKET_MAX_LENGTH 32 // 数据包最大长度
// 指令定义
2024-12-15 21:42:43 +08:00
#define CMD_GET_BT_STATUS 0x10
2024-12-18 16:10:26 +08:00
#define CMD_GET_SPIFFS_STATUS 0x11
#define CMD_GET_DISTANCE 0x12
2024-12-15 18:09:40 +08:00
#define CMD_MOTOR_MOVE_CONTROL 0x20
#define CMD_MOTOR_ROTATE_CONTROL 0x21
2024-12-16 00:16:06 +08:00
// 全局变量
int currentSpeed = 0; // 当前速度
int turnOffset = 0; // 转向偏移量 (-100 到 100)
bool isMoving = false; // 运动状态
bool isTurning = false; // 转向状态
// BLE 相关
BLEServer *pServer = nullptr;
BLECharacteristic *pTxCharacteristic = nullptr;
bool deviceConnected = false;
2024-12-15 18:09:40 +08:00
// 数据包缓冲区
uint8_t packetBuffer[PACKET_MAX_LENGTH];
int packetIndex = 0;
bool isReceivingPacket = false;
// 在全局变量定义区域添加
#define LED_FLASH_INTERVAL 1000 // LED闪烁间隔(ms)
unsigned long lastLedToggle = 0; // 上次LED切换状态的时间
bool ledState = false; // LED当前状态
2024-12-16 00:16:06 +08:00
void processSerialIncomingByte(uint8_t incomingByte, BLECharacteristic &characteristic);
class CarBLEServerCallbacks : public BLEServerCallbacks
{
void onConnect(BLEServer *pServer)
{
deviceConnected = true;
};
void onDisconnect(BLEServer *pServer)
{
deviceConnected = false;
// 重新开始广播
pServer->getAdvertising()->start();
}
};
class CarBLECharacteristicCallbacks : public BLECharacteristicCallbacks
{
void onWrite(BLECharacteristic *pCharacteristic)
{
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0)
{
for (int i = 0; i < rxValue.length(); i++)
{
processSerialIncomingByte((uint8_t)rxValue[i], *pTxCharacteristic);
}
}
}
};
2024-12-15 21:42:43 +08:00
void floatToBytes(float val, uint8_t *bytes)
{
union
{
float f;
uint8_t bytes[4];
} u;
u.f = val;
// 考虑大小端问题
for (int i = 0; i < 4; i++)
{
bytes[i] = u.bytes[i];
}
}
2024-12-12 15:38:11 +08:00
// 电机控制函数
2024-12-15 18:09:40 +08:00
void motorControl(int pwmPin, int in1Pin, int in2Pin, int speed)
{
if (speed > 0)
{
2024-12-12 15:38:11 +08:00
digitalWrite(in1Pin, HIGH);
digitalWrite(in2Pin, LOW);
2024-12-15 18:09:40 +08:00
}
else if (speed < 0)
{
2024-12-12 15:38:11 +08:00
digitalWrite(in1Pin, LOW);
digitalWrite(in2Pin, HIGH);
speed = -speed;
2024-12-15 18:09:40 +08:00
}
else
{
2024-12-12 15:38:11 +08:00
digitalWrite(in1Pin, LOW);
digitalWrite(in2Pin, LOW);
}
analogWrite(pwmPin, speed);
}
2024-12-15 21:42:43 +08:00
float getDistance()
{
digitalWrite(HC_SR04_TRIG, HIGH);
delayMicroseconds(1);
digitalWrite(HC_SR04_TRIG, LOW);
float distance = pulseIn(HC_SR04_ECHO, HIGH); // 计数接收高电平时间
distance = distance * 340 / 2 / 10000; // 计算距离 1声速340M/S 2实际距离为1/2声速距离 3计数时钟为1US//温补公式c=(331.45+0.61t/℃)m•s-1 (其中331.45是在0度
return distance;
}
2024-12-18 16:10:26 +08:00
class CarStorage
{
public:
static bool isMounted;
static void init()
{
if (!SPIFFS.begin(true))
{
Serial.println("SPIFFS Mount Failed");
isMounted = false;
}
else
isMounted = true;
}
static unsigned int getSensitivity()
{
if (!isMounted)
return 0xFF;
File file = SPIFFS.open("/sensitivity.txt", "r");
if (!file)
return 0xFF;
String sensitivity = file.readStringUntil('\n');
file.close();
return sensitivity.toInt();
}
static void setSensitivity(unsigned int sensitivity)
{
if (!isMounted)
return;
File file = SPIFFS.open("/sensitivity.txt", "w");
file.println(sensitivity);
file.close();
}
};
2024-12-12 15:38:11 +08:00
void setup()
{
// 初始化串口
Serial.begin(115200);
2024-12-15 18:09:40 +08:00
2024-12-16 00:16:06 +08:00
// 初始化 BLE
2024-12-18 14:12:46 +08:00
BLEDevice::init(DEVICE_NAME);
2024-12-16 00:16:06 +08:00
pServer = BLEDevice::createServer();
pServer->setCallbacks(new CarBLEServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
// 创建 RX 特征值 (用于接收数据)
BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE);
pRxCharacteristic->setCallbacks(new CarBLECharacteristicCallbacks());
// 创建 TX 特征值 (用于发送数据)
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY);
pTxCharacteristic->addDescriptor(new BLE2902());
pService->start();
pServer->getAdvertising()->start();
2024-12-15 18:09:40 +08:00
2024-12-18 16:10:26 +08:00
// 初始化 EEPROM
CarStorage::init();
2024-12-12 15:38:11 +08:00
// 设置引脚模式
2024-12-15 18:09:40 +08:00
pinMode(STATUS_LED, OUTPUT);
digitalWrite(STATUS_LED, HIGH);
2024-12-12 15:38:11 +08:00
pinMode(MOTOR_A_PWMA, OUTPUT);
pinMode(MOTOR_A_AIN1, OUTPUT);
pinMode(MOTOR_A_AIN2, OUTPUT);
2024-12-15 18:09:40 +08:00
2024-12-12 15:38:11 +08:00
pinMode(MOTOR_B_PWMB, OUTPUT);
pinMode(MOTOR_B_BIN1, OUTPUT);
pinMode(MOTOR_B_BIN2, OUTPUT);
2024-12-15 18:09:40 +08:00
2024-12-12 15:38:11 +08:00
pinMode(MOTOR_C_PWMA, OUTPUT);
pinMode(MOTOR_C_AIN1, OUTPUT);
pinMode(MOTOR_C_AIN2, OUTPUT);
2024-12-15 18:09:40 +08:00
2024-12-12 15:38:11 +08:00
pinMode(MOTOR_D_PWMB, OUTPUT);
pinMode(MOTOR_D_BIN1, OUTPUT);
pinMode(MOTOR_D_BIN2, OUTPUT);
2024-12-15 18:09:40 +08:00
2024-12-15 21:42:43 +08:00
pinMode(HC_SR04_TRIG, OUTPUT);
2024-12-15 18:09:40 +08:00
pinMode(HC_SR04_ECHO, INPUT);
2024-12-12 15:38:11 +08:00
}
2024-12-16 00:16:06 +08:00
void handleSerialPacket(uint8_t *packet, int length, BLECharacteristic &characteristic)
2024-12-15 18:09:40 +08:00
{
2024-12-16 00:16:06 +08:00
if (!deviceConnected || length < 4)
return;
2024-12-15 18:09:40 +08:00
uint8_t packetLength = packet[1]; // 获取长度
uint8_t cmd = packet[2]; // 获取指令
uint8_t direction, speed, time;
2024-12-15 21:42:43 +08:00
float distance;
2024-12-16 00:16:06 +08:00
uint8_t buffer[PACKET_MAX_LENGTH]; // 用于存储要发送的数据
int bufferIndex = 0;
2024-12-15 18:09:40 +08:00
switch (cmd)
{
2024-12-15 21:42:43 +08:00
case CMD_GET_BT_STATUS:
Serial.println("CMD_GET_BT_STATUS");
2024-12-16 00:16:06 +08:00
// 构建响应数据
buffer[0] = PACKET_T_HEAD;
buffer[1] = 0x05;
buffer[2] = CMD_GET_BT_STATUS;
buffer[3] = (uint8_t)(deviceConnected ? 0x01 : 0x00);
buffer[4] = PACKET_T_TAIL;
characteristic.setValue(buffer, 5);
characteristic.notify();
2024-12-15 18:09:40 +08:00
break;
2024-12-18 16:10:26 +08:00
case CMD_GET_SPIFFS_STATUS:
Serial.println("CMD_GET_SPIFFS_STATUS");
// 构建响应数据
buffer[0] = PACKET_T_HEAD;
buffer[1] = 0x05;
buffer[2] = CMD_GET_SPIFFS_STATUS;
buffer[3] = (uint8_t)(CarStorage::isMounted ? 0x01 : 0x00);
buffer[4] = PACKET_T_TAIL;
characteristic.setValue(buffer, 5);
characteristic.notify();
break;
2024-12-15 21:42:43 +08:00
case CMD_GET_DISTANCE:
distance = getDistance();
2024-12-16 00:16:06 +08:00
Serial.println("CMD_GET_DISTANCE, distance: " + String(distance));
// 构建响应数据
buffer[0] = PACKET_T_HEAD;
buffer[1] = 0x08;
buffer[2] = CMD_GET_DISTANCE;
floatToBytes(distance, &buffer[3]);
buffer[7] = PACKET_T_TAIL;
characteristic.setValue(buffer, 8);
characteristic.notify();
2024-12-15 21:42:43 +08:00
break;
2024-12-15 18:09:40 +08:00
case CMD_MOTOR_MOVE_CONTROL:
direction = packet[3];
speed = packet[4];
2024-12-16 00:16:06 +08:00
Serial.println("CMD_MOTOR_MOVE_CONTROL, direction: " + String(direction) + ", speed: " + String(speed));
2024-12-15 18:09:40 +08:00
// 移动
if (direction == 0x00)
{
motorControl(MOTOR_A_PWMA, MOTOR_A_AIN1, MOTOR_A_AIN2, 0);
motorControl(MOTOR_B_PWMB, MOTOR_B_BIN1, MOTOR_B_BIN2, 0);
motorControl(MOTOR_C_PWMA, MOTOR_C_AIN1, MOTOR_C_AIN2, 0);
motorControl(MOTOR_D_PWMB, MOTOR_D_BIN1, MOTOR_D_BIN2, 0);
}
// 前进
2024-12-16 00:16:06 +08:00
else if (direction == 0x01)
2024-12-15 18:09:40 +08:00
{
motorControl(MOTOR_A_PWMA, MOTOR_A_AIN1, MOTOR_A_AIN2, speed);
motorControl(MOTOR_B_PWMB, MOTOR_B_BIN2, MOTOR_B_BIN1, speed);
motorControl(MOTOR_C_PWMA, MOTOR_C_AIN2, MOTOR_C_AIN1, speed);
motorControl(MOTOR_D_PWMB, MOTOR_D_BIN1, MOTOR_D_BIN2, speed);
}
// 后退
2024-12-16 00:16:06 +08:00
else if (direction == 0x02)
2024-12-15 18:09:40 +08:00
{
motorControl(MOTOR_A_PWMA, MOTOR_A_AIN1, MOTOR_A_AIN2, -speed);
motorControl(MOTOR_B_PWMB, MOTOR_B_BIN2, MOTOR_B_BIN1, -speed);
motorControl(MOTOR_C_PWMA, MOTOR_C_AIN2, MOTOR_C_AIN1, -speed);
motorControl(MOTOR_D_PWMB, MOTOR_D_BIN1, MOTOR_D_BIN2, -speed);
}
break;
case CMD_MOTOR_ROTATE_CONTROL:
direction = packet[3];
time = packet[4];
2024-12-16 00:16:06 +08:00
Serial.println("CMD_MOTOR_ROTATE_CONTROL, direction: " + String(direction) + ", time: " + String(time));
2024-12-15 18:09:40 +08:00
// 顺时针
if (direction == 0x00)
{
2024-12-16 00:16:06 +08:00
motorControl(MOTOR_A_PWMA, MOTOR_A_AIN1, MOTOR_A_AIN2, 255);
motorControl(MOTOR_B_PWMB, MOTOR_B_BIN2, MOTOR_B_BIN1, 255);
motorControl(MOTOR_C_PWMA, MOTOR_C_AIN2, MOTOR_C_AIN1, -255);
motorControl(MOTOR_D_PWMB, MOTOR_D_BIN1, MOTOR_D_BIN2, -255);
2024-12-15 18:09:40 +08:00
}
// 逆时针
2024-12-16 00:16:06 +08:00
else if (direction == 0x01)
2024-12-15 18:09:40 +08:00
{
2024-12-16 00:16:06 +08:00
motorControl(MOTOR_A_PWMA, MOTOR_A_AIN1, MOTOR_A_AIN2, -255);
motorControl(MOTOR_B_PWMB, MOTOR_B_BIN2, MOTOR_B_BIN1, -255);
motorControl(MOTOR_C_PWMA, MOTOR_C_AIN2, MOTOR_C_AIN1, 255);
motorControl(MOTOR_D_PWMB, MOTOR_D_BIN1, MOTOR_D_BIN2, 255);
2024-12-15 18:09:40 +08:00
}
break;
default:
break;
}
}
2024-12-16 00:16:06 +08:00
void processSerialIncomingByte(uint8_t incomingByte, BLECharacteristic &characteristic)
2024-12-12 15:38:11 +08:00
{
2024-12-15 18:09:40 +08:00
static uint8_t expectedLength = 0;
packetIndex++;
if (incomingByte == PACKET_R_HEAD && !isReceivingPacket)
{
isReceivingPacket = true;
packetIndex = 0;
packetBuffer[packetIndex] = incomingByte;
}
else if (isReceivingPacket)
{
if (packetIndex < PACKET_MAX_LENGTH)
{
packetBuffer[packetIndex] = incomingByte;
// 第二个字节是包体长度
if (packetIndex == 1)
{
expectedLength = incomingByte;
}
// 到达预期长度时检查包尾
if (packetIndex == expectedLength - 1)
{
isReceivingPacket = false;
if (incomingByte == PACKET_R_TAIL)
{
2024-12-16 00:16:06 +08:00
handleSerialPacket(packetBuffer, packetIndex + 1, *pTxCharacteristic);
2024-12-15 18:09:40 +08:00
}
}
}
else
{
isReceivingPacket = false;
}
}
}
void updateStatusLED()
{
2024-12-16 00:16:06 +08:00
if (deviceConnected)
2024-12-15 18:09:40 +08:00
{
digitalWrite(STATUS_LED, HIGH);
}
else
{
unsigned long currentMillis = millis();
if (currentMillis - lastLedToggle >= LED_FLASH_INTERVAL)
{
lastLedToggle = currentMillis;
ledState = !ledState;
digitalWrite(STATUS_LED, ledState);
2024-12-12 15:38:11 +08:00
}
}
2024-12-15 18:09:40 +08:00
}
void loop()
{
2024-12-16 00:16:06 +08:00
updateStatusLED();
2024-12-12 15:38:11 +08:00
}