This commit is contained in:
玖叁 2024-12-12 15:38:11 +08:00
commit 327994ff36
8 changed files with 364 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

10
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

8
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,8 @@
{
"files.exclude": {
"**/*.rpyc": true,
"**/*.rpa": true,
"**/*.rpymc": true,
"**/cache/": true
}
}

39
include/README Normal file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

46
lib/README Normal file
View File

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

14
platformio.ini Normal file
View File

@ -0,0 +1,14 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino

231
src/main.cpp Normal file
View File

@ -0,0 +1,231 @@
#include <Arduino.h>
#include <BluetoothSerial.h>
// 使用 2 片 TB6612 控制 4 个电机
// 使用差速控制转向
// TB6612 #1 控制 A B 电机
#define MOTOR_AB_STBY 14 // TB6612 #1 待机控制
// A 电机 左前轮
#define MOTOR_A_PWMA 25 // 电机 A PWM
#define MOTOR_A_AIN1 26 // 电机 A 方向控制1
#define MOTOR_A_AIN2 27 // 电机 A 方向控制2
// B 电机 左后轮
#define MOTOR_B_PWMB 32 // 电机 B PWM
#define MOTOR_B_BIN1 33 // 电机 B 方向控制1
#define MOTOR_B_BIN2 34 // 电机 B 方向控制2
// TB6612 #2 控制 C D 电机
#define MOTOR_CD_STBY 19 // TB6612 #2 待机控制
// C 电机 右前轮
#define MOTOR_C_PWMA 16 // 电机 C PWM
#define MOTOR_C_AIN1 17 // 电机 C 方向控制1
#define MOTOR_C_AIN2 18 // 电机 C 方向控制2
// D 电机 右后轮
#define MOTOR_D_PWMB 21 // 电机 D PWM
#define MOTOR_D_BIN1 22 // 电机 D 方向控制1
#define MOTOR_D_BIN2 23 // 电机 D 方向控制2
// 运动控制参数
#define MAX_SPEED 255 // 最大速度
#define BASE_SPEED 200 // 基础速度
#define MIN_SPEED 50 // 最小速度
#define TURN_RATIO 0.6 // 转向时的速度比例
#define SPEED_INCREMENT 10 // 速度增量
// 全局变量
int currentSpeed = 0; // 当前速度
int turnOffset = 0; // 转向偏移量 (-100 到 100)
bool isMoving = false; // 运动状态
bool isTurning = false; // 转向状态
BluetoothSerial SerialBT;
// 电机控制函数
void motorControl(int pwmPin, int in1Pin, int in2Pin, int speed) {
if (speed > 0) {
digitalWrite(in1Pin, HIGH);
digitalWrite(in2Pin, LOW);
} else if (speed < 0) {
digitalWrite(in1Pin, LOW);
digitalWrite(in2Pin, HIGH);
speed = -speed;
} else {
digitalWrite(in1Pin, LOW);
digitalWrite(in2Pin, LOW);
}
analogWrite(pwmPin, speed);
}
// 小车运动控制函数
void carControl(int leftSpeed, int rightSpeed) {
motorControl(MOTOR_A_PWMA, MOTOR_A_AIN1, MOTOR_A_AIN2, leftSpeed); // 左前
motorControl(MOTOR_B_PWMB, MOTOR_B_BIN1, MOTOR_B_BIN2, leftSpeed); // 左后
motorControl(MOTOR_C_PWMA, MOTOR_C_AIN1, MOTOR_C_AIN2, rightSpeed); // 右前
motorControl(MOTOR_D_PWMB, MOTOR_D_BIN1, MOTOR_D_BIN2, rightSpeed); // 右后
}
// 计算左右轮速度
void calculateWheelSpeeds(int baseSpeed, int turnOffset, int &leftSpeed, int &rightSpeed) {
// turnOffset 范围:-100 到 100
// 负值表示向左转,正值表示向右转
float turnMultiplier = 1.0 - (abs(turnOffset) / 100.0) * (1.0 - TURN_RATIO);
if (turnOffset < 0) { // 向左转
leftSpeed = baseSpeed * turnMultiplier;
rightSpeed = baseSpeed;
} else if (turnOffset > 0) { // 向右转
leftSpeed = baseSpeed;
rightSpeed = baseSpeed * turnMultiplier;
} else { // 直行
leftSpeed = baseSpeed;
rightSpeed = baseSpeed;
}
}
// 更新小车运动
void updateCarMovement() {
int leftSpeed = 0, rightSpeed = 0;
if (isMoving) {
calculateWheelSpeeds(currentSpeed, turnOffset, leftSpeed, rightSpeed);
if (!isTurning) {
// 逐渐加速
currentSpeed = min(currentSpeed + SPEED_INCREMENT, BASE_SPEED);
}
} else {
// 逐渐减速
currentSpeed = max(currentSpeed - SPEED_INCREMENT, 0);
if (currentSpeed > 0) {
calculateWheelSpeeds(currentSpeed, turnOffset, leftSpeed, rightSpeed);
}
}
carControl(leftSpeed, rightSpeed);
}
// CCD 巡线相关函数
#define CCD_PIN 35 // CCD 数据引脚
#define CCD_CLK_PIN 36 // CCD 时钟引脚
#define CCD_SI_PIN 39 // CCD 启动引脚
#define CCD_PIXELS 128 // CCD 像素数
int ccdData[CCD_PIXELS]; // CCD 数据数组
// 读取 CCD 数据
void readCCD() {
// 启动信号
digitalWrite(CCD_SI_PIN, HIGH);
digitalWrite(CCD_CLK_PIN, HIGH);
digitalWrite(CCD_SI_PIN, LOW);
digitalWrite(CCD_CLK_PIN, LOW);
// 读取像素数据
for(int i = 0; i < CCD_PIXELS; i++) {
digitalWrite(CCD_CLK_PIN, HIGH);
ccdData[i] = analogRead(CCD_PIN);
digitalWrite(CCD_CLK_PIN, LOW);
}
}
// 计算巡线偏移量
int calculateLineOffset() {
// 这里添加线位置检测算法
// 返回值范围:-100 到 100
// 0 表示线在中间,负值表示线在左边,正值表示线在右边
return 0; // 临时返回值
}
void setup()
{
// 初始化串口
Serial.begin(115200);
// 初始化蓝牙
SerialBT.begin("ESP32_Car"); // 蓝牙设备名称
// 设置引脚模式
pinMode(MOTOR_AB_STBY, OUTPUT);
pinMode(MOTOR_CD_STBY, OUTPUT);
pinMode(MOTOR_A_PWMA, OUTPUT);
pinMode(MOTOR_A_AIN1, OUTPUT);
pinMode(MOTOR_A_AIN2, OUTPUT);
pinMode(MOTOR_B_PWMB, OUTPUT);
pinMode(MOTOR_B_BIN1, OUTPUT);
pinMode(MOTOR_B_BIN2, OUTPUT);
pinMode(MOTOR_C_PWMA, OUTPUT);
pinMode(MOTOR_C_AIN1, OUTPUT);
pinMode(MOTOR_C_AIN2, OUTPUT);
pinMode(MOTOR_D_PWMB, OUTPUT);
pinMode(MOTOR_D_BIN1, OUTPUT);
pinMode(MOTOR_D_BIN2, OUTPUT);
// 启用电机驱动
digitalWrite(MOTOR_AB_STBY, HIGH);
digitalWrite(MOTOR_CD_STBY, HIGH);
// 添加 CCD 引脚初始化
// pinMode(CCD_CLK_PIN, OUTPUT);
// pinMode(CCD_SI_PIN, OUTPUT);
// pinMode(CCD_PIN, INPUT);
}
void loop()
{
if (SerialBT.available()) {
char cmd = SerialBT.read();
switch(cmd) {
case 'F': // 前进
isMoving = true;
turnOffset = 0;
break;
case 'B': // 后退
isMoving = true;
currentSpeed = -BASE_SPEED;
turnOffset = 0;
break;
case 'L': // 左转
isTurning = true;
turnOffset = -100;
break;
case 'R': // 右转
isTurning = true;
turnOffset = 100;
break;
case 'S': // 停止
isMoving = false;
isTurning = false;
turnOffset = 0;
break;
case 'l': // 微左转
turnOffset = max(turnOffset - 20, -100);
break;
case 'r': // 微右转
turnOffset = min(turnOffset + 20, 100);
break;
}
}
// 更新小车运动
updateCarMovement();
// 巡线模式代码(后续启用)
/*
readCCD();
int lineOffset = calculateLineOffset();
turnOffset = lineOffset;
isMoving = true;
updateCarMovement();
*/
delay(20); // 控制更新频率
}

11
test/README Normal file
View File

@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html