voice_control_smart_car_2(语音控制智能小车-自动巡航)
摘要: 本文介绍了基于ESP32S3的智能小车优化方案,新增自动巡航模式,通过独立线程处理运动控制。硬件配置包括小智AI开发套件、超声波模块、电机驱动器和锂电池等。软件方面修改了GPIO配置,屏蔽了部分按钮功能,并在关键代码中集成小车控制逻辑。着重优化了application.cc的状态管理,确保小车在空闲/工作状态间平滑切换。新增SmartCarControl类实现运动控制,并通过McpServ
前言
前面已经使用语音可以控制智能小车,这章主要是优化,增加自动巡航模式,单独启动一个线程处理小车运动
1:硬件及环境
esp-idf5.4.*
win11
小智AI全套(基于esp32s3(n16r8) 44pin 小智ai1.9.2版本) 增加一个HC-RS04 超声波(位置有限,下层想加舵机,没位置装)
小车 全套(2个层板,2个L298N,4个电机,4个轮子,2个节锂电池)
一个船型开关,控制电源开关
杜邦线 若干
2:主要代码
boards\bread-compact-wifi\compact_wifi_board.cc
有些GPIO 拿来他用了,所以屏蔽了(ENBALE_CONTROL_BUTTON 不用定义(默认)就可以了)
void InitializeButtons() {
boot_button_.OnClick([this]() {
auto& app = Application::GetInstance();
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
ResetWifiConfiguration();
}
app.ToggleChatState();
});
#ifdef ENBALE_CONTROL_BUTTON
touch_button_.OnPressDown([this]() {
Application::GetInstance().StartListening();
});
touch_button_.OnPressUp([this]() {
Application::GetInstance().StopListening();
});
volume_up_button_.OnClick([this]() {
auto codec = GetAudioCodec();
auto volume = codec->output_volume() + 10;
if (volume > 100) {
volume = 100;
}
codec->SetOutputVolume(volume);
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume));
});
volume_up_button_.OnLongPress([this]() {
GetAudioCodec()->SetOutputVolume(100);
GetDisplay()->ShowNotification(Lang::Strings::MAX_VOLUME);
});
volume_down_button_.OnClick([this]() {
auto codec = GetAudioCodec();
auto volume = codec->output_volume() - 10;
if (volume < 0) {
volume = 0;
}
codec->SetOutputVolume(volume);
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume));
});
volume_down_button_.OnLongPress([this]() {
GetAudioCodec()->SetOutputVolume(0);
GetDisplay()->ShowNotification(Lang::Strings::MUTED);
});
#endif
}
application.cc 修改处
void Application::Start() {
//........省略
Ota ota;
CheckNewVersion(ota);
//########################by eh add 2025////就增加了这两句
auto carcontrol = board.GetSmartCarControl();
carcontrol->car_init_config();
//########################
// Initialize the protocol
display->SetStatus(Lang::Strings::LOADING_PROTOCOL);
//........省略
}
void Application::SetDeviceState(DeviceState state) {
//........省略
//////////////////////////////////////////////////////////////
//kDeviceStateIdle,
if(state ==kDeviceStateListening &&( previous_state == kDeviceStateIdle ||previous_state == kDeviceStateConnecting)){
//auto carcontrol = board.GetSmartCarControl();
// carcontrol->car_init_config();
board.GetSmartCarControl()->car_resume();
}else if(state ==kDeviceStateIdle &&(previous_state == kDeviceStateListening ||previous_state == kDeviceStateSpeaking)){
board.GetSmartCarControl()->car_suspend();
}
//////////////////////////////////////////////////////////////
}
bool Application::CanEnterSleepMode() {
if (device_state_ != kDeviceStateIdle) {
return false;
}
if (protocol_ && protocol_->IsAudioChannelOpened()) {
return false;
}
if (!audio_service_.IsIdle()) {
return false;
}
//by eh add 2025 这里根本就不条用,改了也显示出来吧//////////////////////
auto& board = Board::GetInstance();
auto carcontrol = board.GetSmartCarControl();
if(!carcontrol->car_is_stop_state()){
return false;
}
////////////////////////////////////////////////
// Now it is safe to enter sleep mode
return true;
}
board.h
//........省略
class SmartCarControl; //2025 eh add
class Board {
//........省略
virtual SmartCarControl* GetSmartCarControl();////2025 eh add
}
board.cc
//........省略
#include "smartcar/smart_car_run.h" //2025 eh add
//........省略
SmartCarControl* Board::GetSmartCarControl()////2025 eh add
{
static SmartCarControl smart_car;
return &smart_car;
}
mcp_server.cc
//........省略
#include "smartcar/smart_car_run.h"
//........省略
void McpServer::AddCommonTools() {
//........省略
/////////////////////////////////////////////////////////////////////////////////
auto carcontrol = board.GetSmartCarControl();
if(carcontrol){
//前进
AddTool("self.car.go_forward",
"Control the car to move forward. Use this tool to make the car move in the forward direction.\n"
"Parameters:\n"
" duration: Moving duration in milliseconds. Default is 500ms.\n"
"Usage scenarios:\n"
"1. When the user asks the car to move forward\n"
"2. When traveling straight on a road\n"
"3. When needing to advance to a specific location",
PropertyList({
Property("duration", kPropertyTypeInteger, 100, 5000)
}),
[carcontrol](const PropertyList& properties) -> ReturnValue {
int duration = properties["duration"].value<int>();
carcontrol->car_forward(duration);
// return CarControlTurnRight(angle, speed);
ESP_LOGI(TAG, "self.car.go_backward %d",duration);
return true;
});
//后退
AddTool("self.car.go_backward",
"Control the car to move backward. Use this tool to make the car move in the reverse direction.\n"
"Parameters:\n"
" duration: Moving duration in milliseconds. Default is 500ms.\n"
"Usage scenarios:\n"
"1. When the user asks the car to move backward\n"
"2. When reversing from a parking space\n"
"3. When needing to back away from obstacles",
PropertyList({
Property("duration", kPropertyTypeInteger, 100, 5000)
}),
[carcontrol](const PropertyList& properties) -> ReturnValue {
int duration = properties["duration"].value<int>();
// return CarControlTurnRight(angle, speed);
carcontrol->car_backward(duration);
ESP_LOGI(TAG, "self.car.go_backward %d",duration);
return true;
});
AddTool("self.car.stop",
"Control the car to stop moving. Use this tool to bring the car to a complete halt.\n"
"Usage scenarios:\n"
"1. When the user asks the car to stop\n"
"2. When encountering obstacles or danger\n"
"3. When reaching the destination\n"
"4. In emergency situations requiring immediate stopping",
PropertyList(),
[carcontrol](const PropertyList& properties) -> ReturnValue {
// int duration = properties["duration"].value<int>();
// return CarControlTurnRight(angle, speed);
carcontrol->car_stop();
ESP_LOGI(TAG, "self.car.stop");
return true;
});
AddTool("self.car.auto_cruise",
"Control the car to enter automatic cruise mode. Use this tool to enable autonomous driving with obstacle avoidance for 30 seconds.\n"
"Parameters:\n"
" duration: Cruise duration in seconds. Default is 30 seconds.\n"
"Usage scenarios:\n"
"1. When the user wants hands-free driving\n"
"2. For long distance highway driving\n"
"3. When maintaining consistent speed is desired\n"
"4. When adaptive cruise control is needed",
PropertyList({
Property("duration", kPropertyTypeInteger, 5, 50)
}),
[carcontrol](const PropertyList& properties) -> ReturnValue {
int duration = properties["duration"].value<int>();
// return CarControlTurnRight(angle, speed);
carcontrol->car_auto_cruise(duration); //自动巡航 单位秒
ESP_LOGI(TAG, "self.car.auto_cruise %d",duration);
return true;
});
/////
AddTool("self.car.turn_left",
"Control the car to turn rleftight. Use this tool to make the car turn to the left side.\n"
"Parameters:\n"
" duration: Moving duration in milliseconds, range 0-5000. Default is 500ms.\n"
" speed: Turning speed, range 0-1000. Default is 800 (half speed).\n"
"Usage scenarios:\n"
"1. When the user asks the car to turn left\n"
"2. When avoiding obstacles\n"
"3. When changing direction is needed",
PropertyList({
Property("duration", kPropertyTypeInteger, 0, 5000),
Property("speed", kPropertyTypeInteger, 0, 1000)
}),
[carcontrol](const PropertyList& properties) -> ReturnValue {
int duration = properties["duration"].value<int>();
// int speed = properties["speed"].value<int>();
// return CarControlTurnRight(angle, speed);
carcontrol->car_turn_left(duration);
ESP_LOGI(TAG, "self.car.turn_right %d",duration);
return true;
});
AddTool("self.car.turn_right",
"Control the car to turn right. Use this tool to make the car turn to the right side.\n"
"Parameters:\n"
" duration: Moving duration in milliseconds, range 0-5000. Default is 500ms.\n"
" speed: Turning speed, range 0-1000. Default is 800 (half speed).\n"
"Usage scenarios:\n"
"1. When the user asks the car to turn right\n"
"2. When avoiding obstacles\n"
"3. When changing direction is needed",
PropertyList({
Property("duration", kPropertyTypeInteger, 0, 5000),
Property("speed", kPropertyTypeInteger, 0, 1000)
}),
[carcontrol](const PropertyList& properties) -> ReturnValue {
int duration = properties["duration"].value<int>();
int speed = properties["speed"].value<int>();
// return CarControlTurnRight(angle, speed);
carcontrol->car_turn_right(duration);
ESP_LOGI(TAG, "self.car.turn_right %d-%d",duration,speed);
return true;
});
}
// Restore the original tools list to the end of the tools list
tools_.insert(tools_.end(), original_tools.begin(), original_tools.end());
}
增加的6个文件
smart_car_run.h
#ifndef SMART_CAR_RUN_H
#define SMART_CAR_RUN_H
//void car_run_main();
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
enum car_state
{
CAR_STATE_STOP,
CAR_STATE_FORWARD,
CAR_STATE_BACKWARD,
CAR_STATE_TURN_LEFT,
CAR_STATE_TURN_RIGHT,
CAR_STATE_AUTO_CRUISE,
};
struct smart_car_event
{
car_state state;
int delay_ms;
};
class MotorControl;
class Senor_Manager;
class SmartCarControl{
public:
SmartCarControl();
~SmartCarControl();
void car_init_config();
void car_forward(int ms);
void car_backward(int ms);
void car_turn_left(int ms);
void car_turn_right(int ms);
void car_stop();
void car_auto_cruise(int seconds); //自动巡航
bool car_is_stop_state();
void car_setup();
void car_exit();
private:
MotorControl* getMotorControl();
Senor_Manager* getSenorManager();
private:
smart_car_event ev_data;
void _car_forward(int ms,bool bupdateSate=true);
void _car_backward(int ms,bool bupdateSate=true);
void _car_turn_left(int ms,bool bupdateSate=true);
void _car_turn_right(int ms,bool bupdateSate=true);
void _car_stop(bool bupdateSate=true);
void _car_auto_cruise(int seconds); //自动巡航 //暂时用不上
void _car_run();
void _logic_auto_cruise(); //巡航过程
void _auto_cruise_forward(int ms); //巡航时前进,
private:
volatile int current_state;
QueueHandle_t control_evt_queue ;
TaskHandle_t xTask1Handle;
volatile bool run_flag;
bool car_state_is_stop ;//是否为停止状态
void clear_queue();
int get_current_state();
void set_current_state(int state);
void exit_loop();
public:
void car_resume();
void car_suspend();
};
#endif
smart_car_run.cc
#include "motor_control.h"
#include "smart_car_run.h"
#include "senor_control.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#define TAG "SMARTCAR"
#define QUEUE_SIZE 10
#define MIN_DELAY_MS 300
#define MAX_DELAY_MS 2000
#define CHECK_MS_COMMON(X) if(X<MIN_DELAY_MS){X=MIN_DELAY_MS;}else if(X>MAX_DELAY_MS){X = MAX_DELAY_MS;}
//巡航间隔
#define MIN_AUTO_CRISE_DELAY_MS 300
#define MAX_AUTO_CRISE_DELAY_MS 2000
#define CHECK_MS_AUTO_CRISE(X) if(X<MIN_DELAY_MS){X=MIN_DELAY_MS;}else if(X>MAX_DELAY_MS){X = MAX_DELAY_MS;}
#define MIN_AUTO_CRUISE_MS 10
#define MAX_AUTO_CRUISE_MS 80
#define CHECK_SEC_AUTO_CRUISE(X) if(X<MIN_AUTO_CRUISE_MS){X=MIN_AUTO_CRUISE_MS;}else if(X>MAX_AUTO_CRUISE_MS){X = MAX_AUTO_CRUISE_MS;}
#define STANDARD_ACTION_MS 500 //标准动作持续时间
#define AUTO_CRUISE_ACTION_MS 60 //巡航标准时间50ms
#define CAR_RUN_HIGH_SPEED 850
#define CAR_RUN_COMMON_SPEED 800
#define CAR_RUN_LOW_SPEED 750
#define CHANGE_CAR_STATE_TO_STOP(X) if(!X){ X=true;}
#define CHANGE_CAR_STATE_TO_RUN(X) if(X){ X=false;}
#define AUTO_CRUISE_SET_SPEED(X) (X?CAR_RUN_COMMON_SPEED:CAR_RUN_LOW_SPEED)
// if(X){ return CAR_RUN_COMMON_SPEED;}else{return CAR_RUN_LOW_SPEED;}
//#define DIRECT_SHELL
#define CALL_TARGET_FUNC(cls, obj,funname,...) (obj)->cls##::_##funname(__VA_ARGS__)
#define TEST_MODE 0 //1 小车 不运动 0 会动
#define CHECK_TESTING() if(TEST_MODE){ return ;}
SmartCarControl::SmartCarControl(){
current_state=0;
run_flag= false;
control_evt_queue= NULL;
xTask1Handle= NULL;
car_state_is_stop= true;
}
SmartCarControl::~SmartCarControl(){
if(control_evt_queue){
vQueueDelete(control_evt_queue);
control_evt_queue = NULL;
}
}
void SmartCarControl::car_init_config(){
getMotorControl()->motor_control_init();
control_evt_queue = xQueueCreate( QUEUE_SIZE, sizeof(smart_car_event) );
getSenorManager()->init_all_senors(); //超声波初始化
ESP_LOGI(TAG, "-------------------car_init_config-----------------");
}
void SmartCarControl::car_forward(int ms){
CHECK_MS_COMMON(ms)
#ifdef DIRECT_SHELL
// CALL_TARGET_FUNC(SmartCarControl,this,car_forward,ms);
_car_forward(ms);
#else
ev_data.state = CAR_STATE_FORWARD;
ev_data.delay_ms = ms;
BaseType_t xStatus = xQueueSend(control_evt_queue, &ev_data, pdMS_TO_TICKS(200));
if (xStatus == pdPASS) {
// printf("发送成功:ID=%d, 温度=%.1f℃, 湿度=%.1f%%\n",
// data.id, data.temperature, data.humidity);
} else {
ESP_LOGI(TAG, "car_forward xQueueSend fail");
}
#endif
// auto motor=getMotorControl();
// motor->car_control(CAR_FORWARD, 800); // 中等速度
// vTaskDelay(pdMS_TO_TICKS(ms)); //500
// motor->car_control(CAR_STOP, 0);
// vTaskDelay(pdMS_TO_TICKS(1000));
}
void SmartCarControl::car_backward(int ms){
CHECK_MS_COMMON(ms)
#ifdef DIRECT_SHELL
// CALL_TARGET_FUNC(SmartCarControl,this,car_forward,ms);
_car_backward(ms);
#else
ev_data.state = CAR_STATE_BACKWARD;
ev_data.delay_ms = ms;
BaseType_t xStatus = xQueueSend(control_evt_queue, &ev_data, pdMS_TO_TICKS(200));
if (xStatus == pdPASS) {
// printf("发送成功:ID=%d, 温度=%.1f℃, 湿度=%.1f%%\n",
// data.id, data.temperature, data.humidity);
} else {
// printf("入队失败!\n");
ESP_LOGI(TAG, "car_backward xQueueSend fail");
}
#endif
// auto motor=getMotorControl();
// motor->car_control(CAR_BACKWARD, 800); // 中等速度
// vTaskDelay(pdMS_TO_TICKS(ms));
// motor->car_control(CAR_STOP, 0);
// vTaskDelay(pdMS_TO_TICKS(1000));
}
void SmartCarControl::car_turn_left(int ms){
CHECK_MS_COMMON(ms)
#ifdef DIRECT_SHELL
// CALL_TARGET_FUNC(SmartCarControl,this,car_forward,ms);
_car_turn_left(ms);
#else
ev_data.state = CAR_STATE_TURN_LEFT;
ev_data.delay_ms = ms;
BaseType_t xStatus = xQueueSend(control_evt_queue, &ev_data, pdMS_TO_TICKS(200));
if (xStatus == pdPASS) {
// printf("发送成功:ID=%d, 温度=%.1f℃, 湿度=%.1f%%\n",
// data.id, data.temperature, data.humidity);
} else {
// printf("入队失败!\n");
ESP_LOGI(TAG, "car_turn_left xQueueSend fail");
}
#endif
// auto motor=getMotorControl();
// motor->car_control(CAR_LEFT, 800);
// vTaskDelay(pdMS_TO_TICKS(ms));
// motor-> car_control(CAR_STOP, 0);
// vTaskDelay(pdMS_TO_TICKS(1000));
}
void SmartCarControl::car_turn_right(int ms){
CHECK_MS_COMMON(ms)
#ifdef DIRECT_SHELL
// CALL_TARGET_FUNC(SmartCarControl,this,car_forward,ms);
_car_turn_right(ms);
#else
ev_data.state = CAR_STATE_TURN_RIGHT;
ev_data.delay_ms = ms;
BaseType_t xStatus = xQueueSend(control_evt_queue, &ev_data, pdMS_TO_TICKS(200));
if (xStatus == pdPASS) {
// printf("发送成功:ID=%d, 温度=%.1f℃, 湿度=%.1f%%\n",
// data.id, data.temperature, data.humidity);
} else {
// printf("入队失败!\n");
ESP_LOGI(TAG, "car_turn_right xQueueSend fail");
}
#endif
// auto motor=getMotorControl();
// motor->car_control(CAR_RIGHT, 800);
// vTaskDelay(pdMS_TO_TICKS(ms));
// motor-> car_control(CAR_STOP, 0);
// vTaskDelay(pdMS_TO_TICKS(1000));
}
void SmartCarControl::car_stop(){
#ifdef DIRECT_SHELL
// CALL_TARGET_FUNC(SmartCarControl,this,car_forward,ms);
_car_stop();
#else
ev_data.state = CAR_STATE_STOP;
ev_data.delay_ms = 0;
BaseType_t xStatus = xQueueSend(control_evt_queue, &ev_data, pdMS_TO_TICKS(200));
if (xStatus == pdPASS) {
// printf("发送成功:ID=%d, 温度=%.1f℃, 湿度=%.1f%%\n",
// data.id, data.temperature, data.humidity);
} else {
// printf("入队失败!\n");
ESP_LOGI(TAG, "car_stop xQueueSend fail");
}
#endif
// auto motor=getMotorControl();
// motor-> car_control(CAR_STOP, 0);
// vTaskDelay(pdMS_TO_TICKS(500));
}
void SmartCarControl::car_auto_cruise(int seconds)//自动巡航
{
CHECK_SEC_AUTO_CRUISE(seconds)
#ifdef DIRECT_SHELL
// CALL_TARGET_FUNC(SmartCarControl,this,car_forward,ms);
// _car_turn_right(ms);
#else
ev_data.state = CAR_STATE_AUTO_CRUISE;
ev_data.delay_ms = seconds; //秒
BaseType_t xStatus = xQueueSend(control_evt_queue, &ev_data, pdMS_TO_TICKS(200));
if (xStatus == pdPASS) {
// printf("发送成功:ID=%d, 温度=%.1f℃, 湿度=%.1f%%\n",
// data.id, data.temperature, data.humidity);
} else {
// printf("入队失败!\n");
ESP_LOGI(TAG, "car_turn_right xQueueSend fail");
}
#endif
}
//private
void SmartCarControl::clear_queue(){
if(control_evt_queue){
smart_car_event ev;
int count = QUEUE_SIZE;
while (xQueueReceive(control_evt_queue, &ev, 0) == pdTRUE) {
if(--count <= 0) break;
}
}
}
int SmartCarControl::get_current_state(){
return current_state;
}
void SmartCarControl::set_current_state(int state){
current_state=state;
}
MotorControl* SmartCarControl::getMotorControl(){
static MotorControl motor_control;
return &motor_control;
}
Senor_Manager* SmartCarControl::getSenorManager(){
static Senor_Manager senor_manager;
return &senor_manager;
}
bool SmartCarControl::car_is_stop_state(){
return get_current_state() == CAR_STATE_STOP ;
}
void SmartCarControl::car_setup(){
#ifndef DIRECT_SHELL
// smart_car_event ev;
// bool is_continue_shell= false;
run_flag =true;
// xTaskCreate(key_task, "key_task", 2048, NULL, 5, NULL);
xTaskCreate([](void* arg) {
SmartCarControl* control = (SmartCarControl*)arg;
control->_car_run();
vTaskDelete(NULL);
control->exit_loop();
}, "car_setup", 2048 * 2, this, 8, &xTask1Handle);//&audio_input_task_handle_);
#endif
}
void SmartCarControl::car_exit(){
run_flag =false;
// if(control_evt_queue){
// xQueueDelete(control_evt_queue);
// control_evt_queue= NULL;
// }
// if(xTask1Handle){
// vTaskDelete(xTask1Handle);
// xTask1Handle=NULL;
// }
}
void SmartCarControl::exit_loop(){
if(control_evt_queue){
vQueueDelete(control_evt_queue);
control_evt_queue= NULL;
}
xTask1Handle=NULL;
}
void SmartCarControl::car_resume(){
if(!run_flag){car_setup();} //没与启动就启动
else if(xTask1Handle)vTaskResume(xTask1Handle);
}
void SmartCarControl::car_suspend(){
if(run_flag){
clear_queue();
if(xTask1Handle)vTaskSuspend(xTask1Handle);
}
}
//////////////////////////////////////////////////////////
//private
void SmartCarControl:: _logic_auto_cruise(){//巡航过程
//超声波看下前面有没有障碍物
int distance = getSenorManager()->get_senor_distance(Senor_Ultrasonic,Senor_Direction_Forward);
// ESP_LOGI(TAG, "#######[auto]_logic_auto_cruise get_senor_distance=%d cm",distance);
if(distance <0){
ESP_LOGE(TAG, "get_senor_distance fail");
return ;
}
if(distance < 20){ //障碍物
//向左 或向右 或后退
_car_backward(STANDARD_ACTION_MS,false);
if(xTaskGetTickCount()&1){
_car_turn_left(STANDARD_ACTION_MS,false);
}else{
_car_turn_right(STANDARD_ACTION_MS,false);
}
}else{
//_car_forward(STANDARD_ACTION_MS,false);
_auto_cruise_forward(AUTO_CRUISE_ACTION_MS);
}
}
void SmartCarControl::_auto_cruise_forward(int ms){ //巡航时前进,
// CHECK_MS_AUTO_CRISE(ms)
auto motor=getMotorControl();
motor->car_control(CAR_FORWARD, AUTO_CRUISE_SET_SPEED(car_state_is_stop)); // 中等速度 800->700
vTaskDelay(pdMS_TO_TICKS(ms)); //500
CHANGE_CAR_STATE_TO_RUN(car_state_is_stop)
// motor->car_control(CAR_STOP, 0);
// vTaskDelay(pdMS_TO_TICKS(1000));
}
void SmartCarControl::_car_run(){
smart_car_event ev;
bool bAuto_cruise = false;
TickType_t start_ticks,end_ticks;
while(run_flag){
if(bAuto_cruise){
if(xQueueReceive(control_evt_queue, &ev, 0) == pdTRUE){
// ESP_LOGI(TAG, "#######[auto]car_run state=%d,time=%d",ev.state,ev.delay_ms);
if(ev.state != CAR_STATE_AUTO_CRUISE)
{
bAuto_cruise =false;
_car_stop();
switch (ev.state)
{
case CAR_STATE_FORWARD:
_car_forward(ev.delay_ms);
break;
case CAR_STATE_BACKWARD:
_car_backward(ev.delay_ms);
break;
case CAR_STATE_TURN_LEFT:
_car_turn_left(ev.delay_ms);
break;
case CAR_STATE_TURN_RIGHT:
_car_turn_right(ev.delay_ms);
break;
default:
break;
}
}else{
//原有的数据上更新
start_ticks=xTaskGetTickCount()/configTICK_RATE_HZ;
CHECK_SEC_AUTO_CRUISE(ev.delay_ms)
end_ticks = start_ticks+ev.delay_ms;
}
}
if (bAuto_cruise)
{
start_ticks=xTaskGetTickCount()/configTICK_RATE_HZ;
if(start_ticks >= end_ticks){
bAuto_cruise =false;
start_ticks= end_ticks =0;
_car_stop();
//自动巡航结束
}else{
//继续执行
_logic_auto_cruise();
}
}
}else if (xQueueReceive(control_evt_queue, &ev, portMAX_DELAY)){
if(ev.state == get_current_state()){
continue;
}else{
set_current_state(ev.state);
}
ESP_LOGI(TAG, "#######car_run state=%d,time=%d",ev.state,ev.delay_ms);
switch (ev.state)
{
case CAR_STATE_STOP:
_car_stop();
break;
case CAR_STATE_FORWARD:
_car_forward(ev.delay_ms);
break;
case CAR_STATE_BACKWARD:
_car_backward(ev.delay_ms);
break;
case CAR_STATE_TURN_LEFT:
_car_turn_left(ev.delay_ms);
break;
case CAR_STATE_TURN_RIGHT:
_car_turn_right(ev.delay_ms);
break;
case CAR_STATE_AUTO_CRUISE:
{
// _car_auto_cruise(ev.delay_ms);
start_ticks=xTaskGetTickCount()/configTICK_RATE_HZ;
CHECK_SEC_AUTO_CRUISE(ev.delay_ms)
end_ticks = start_ticks+ev.delay_ms;
bAuto_cruise = true;
}
break;
default:
break;
}
}
}
}
///////////////////////////////////////
//private
void SmartCarControl::_car_forward(int ms,bool bupdateSate){
CHECK_TESTING()
auto motor=getMotorControl();
motor->car_control(CAR_FORWARD, CAR_RUN_COMMON_SPEED); // 中等速度
vTaskDelay(pdMS_TO_TICKS(ms)); //500
motor->car_control(CAR_STOP, 0);
vTaskDelay(pdMS_TO_TICKS(1000));
if(bupdateSate)set_current_state(CAR_STATE_STOP);
CHANGE_CAR_STATE_TO_STOP(car_state_is_stop)
}
void SmartCarControl::_car_backward(int ms,bool bupdateSate){
CHECK_TESTING()
auto motor=getMotorControl();
motor->car_control(CAR_BACKWARD, CAR_RUN_COMMON_SPEED); // 中等速度
vTaskDelay(pdMS_TO_TICKS(ms));
motor->car_control(CAR_STOP, 0);
vTaskDelay(pdMS_TO_TICKS(1000));
if(bupdateSate)set_current_state(CAR_STATE_STOP);
CHANGE_CAR_STATE_TO_STOP(car_state_is_stop)
}
void SmartCarControl::_car_turn_left(int ms,bool bupdateSate){
CHECK_TESTING()
auto motor=getMotorControl();
motor->car_control(CAR_LEFT, CAR_RUN_COMMON_SPEED);
vTaskDelay(pdMS_TO_TICKS(ms));
motor-> car_control(CAR_STOP, 0);
vTaskDelay(pdMS_TO_TICKS(1000));
if(bupdateSate)set_current_state(CAR_STATE_STOP);
CHANGE_CAR_STATE_TO_STOP(car_state_is_stop)
}
void SmartCarControl::_car_turn_right(int ms,bool bupdateSate){
CHECK_TESTING()
auto motor=getMotorControl();
motor->car_control(CAR_RIGHT, CAR_RUN_COMMON_SPEED);
vTaskDelay(pdMS_TO_TICKS(ms));
motor-> car_control(CAR_STOP, 0);
vTaskDelay(pdMS_TO_TICKS(1000));
if(bupdateSate)set_current_state(CAR_STATE_STOP);
CHANGE_CAR_STATE_TO_STOP(car_state_is_stop)
}
void SmartCarControl::_car_stop(bool bupdateSate){
CHECK_TESTING()
auto motor=getMotorControl();
motor-> car_control(CAR_STOP, 0);
vTaskDelay(pdMS_TO_TICKS(500));
if(bupdateSate)set_current_state(CAR_STATE_STOP);
CHANGE_CAR_STATE_TO_STOP(car_state_is_stop)
}
void SmartCarControl::_car_auto_cruise(int seconds){ //自动巡航
}
senor_control.h
#ifndef SENOR_CONTROL_H
#define SENOR_CONTROL_H
#include <cstdint>
#include "driver/gpio.h"
#include "driver/ledc.h"
///////////////////////////////////////////////////////////////////
enum Senor_Type{
Senor_Unknown,
Senor_Ultrasonic,
Senor_Total,
};
enum Senor_Direction{
Senor_Direction_Unknown,
Senor_Direction_Forward,
Senor_Direction_Backward,
Senor_Direction_Left,
Senor_Direction_Right,
Senor_Direction_Total,
};
#define CURRENT_ULTRASONIC_SENNOR_COUNT 1 //超声波当前1个
// 超声波模块///////////////////////////////////////////
// 硬件引脚定义
#define TRIG_PIN GPIO_NUM_12
#define ECHO_PIN GPIO_NUM_13
// #define RIGHT_PWM_PIN GPIO_NUM_12 //使能RIGHT
// // 方向控制引脚
// #define FWD_RIGHT_PIN GPIO_NUM_13 // 右IN1 IN3
// #define BWD_RIGHT_PIN GPIO_NUM_14 // 右IN2 IN4
// 超声波模块参数
#define MAX_DISTANCE_CM 400 // 最大测量距离 4米
#define SOUND_SPEED_CM_US 0.034 // 声速 340m/s = 0.034 cm/μs = 34cm/ms = 34*1000 cm /S = 340m/s
#define TIMEOUT_US (MAX_DISTANCE_CM * 58) // 超时时间(微秒) 400cm /(34cm/ms) = 11.7647ms //40/34=1.176470588235
// typedef struct {
// float distance_cm;
// bool success;
// uint32_t duration_us;
// } ultrasonic_measurement_t;
//#define ULTRASONIC_PIN_LIST
const uint64_t ULTRASONIC_PIN_LIST[Senor_Direction_Total][2]={{0,0},{GPIO_NUM_12,GPIO_NUM_13},
{0,0},{0,0},{0,0}};
///////////////////////////////////////////////////////////////////
class Senor_Object
{
private:
/* data */
Senor_Type senor_type;
Senor_Direction senor_direction;
public:
Senor_Object(Senor_Type senortype,Senor_Direction senordirection);
virtual ~Senor_Object();
public:
// void set_senor_type(Senor_Type type);
// void set_senor_direction(Senor_Direction direction);
virtual void init_senor()=0;
virtual int get_senor_distance()=0;
};
////////////////////////////////////////////////////////////////////
class ultrasonic_control:public Senor_Object
{
private:
/* data */
public:
ultrasonic_control(Senor_Direction senordirection);
~ultrasonic_control();
void init_senor();
int get_senor_distance();
public:
void ultrasonic_init();
int ultrasonic_measure_distance();
};
// 传感器管理//////////////////////////////////////////
class Senor_Manager
{
private:
ultrasonic_control* get_ultrasonic_senor(Senor_Direction direction);
public:
Senor_Manager(/* args */);
~Senor_Manager();
public:
void init_all_senors();
int get_senor_distance(Senor_Type ty,Senor_Direction direction);
};
#endif
senor_control.cc
#include "senor_control.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h" // Add this line to fix ESP_LOGI
#define TAG "SENOR"
Senor_Object::Senor_Object(Senor_Type senortype,Senor_Direction senordirection){
senor_type=senortype;
senor_direction=senordirection;
}
Senor_Object::~Senor_Object(){
}
int Senor_Object::get_senor_distance(){
return senor_direction;
}
/// @brief /////////////////////////////////////////////////////////
/// @param senordirection
ultrasonic_control::ultrasonic_control(Senor_Direction senordirection):Senor_Object(Senor_Ultrasonic,senordirection)
{
}
ultrasonic_control::~ultrasonic_control()
{
}
void ultrasonic_control::init_senor(){
ultrasonic_init();
}
int ultrasonic_control::get_senor_distance(){
return ultrasonic_measure_distance();
}
void ultrasonic_control::ultrasonic_init(){
auto pins = ULTRASONIC_PIN_LIST[get_senor_distance()];
uint64_t trig_pin = pins[0];
uint64_t echo_pin = pins[1];
// 配置 TRIG 引脚为输出
gpio_config_t trig_config = {
.pin_bit_mask = (1ULL << TRIG_PIN),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&trig_config);
// 配置 ECHO 引脚为输入
gpio_config_t echo_config = {
.pin_bit_mask = (1ULL << ECHO_PIN),
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_ENABLE, // 下拉确保默认低电平
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&echo_config);
// 初始状态:TRIG 低电平
gpio_set_level(TRIG_PIN, 0);
ESP_LOGI(TAG, "---Ultrasonic sensor initialized");
}
int ultrasonic_control::ultrasonic_measure_distance(){
// ultrasonic_measurement_t result = {
// .distance_cm = 0.0f,
// .success = false,
// .duration_us = 0
// };
int result = -1;
// 1. 发送 10us 的触发脉冲
gpio_set_level(TRIG_PIN, 1);
esp_rom_delay_us(10); // 精确延迟 10us
gpio_set_level(TRIG_PIN, 0);
// 2. 等待 ECHO 变为高电平(开始信号)
int64_t start_time = esp_timer_get_time();
int64_t timeout_time = start_time + 1000*60; // 数字小了会导致Timeout //这里使用60ms 超时(一般20-30够用)
while (gpio_get_level(ECHO_PIN) == 0) {
if (esp_timer_get_time() > timeout_time) {
ESP_LOGW(TAG, "Timeout waiting for echo start");
return result;
}else{
// vTaskDelay(pdMS_TO_TICKS(1)); //1ms
esp_rom_delay_us(2); // 精确延迟 10us
}
}
// 3. 记录 Echo 开始时间
int64_t echo_start = esp_timer_get_time();
timeout_time = echo_start + TIMEOUT_US;
// 4. 等待 ECHO 变为低电平(结束信号)
while (gpio_get_level(ECHO_PIN) == 1) {
if (esp_timer_get_time() > timeout_time) {
ESP_LOGW(TAG, "Timeout waiting for echo end");
return result;
}else{
esp_rom_delay_us(2); // 精确延迟 10us
}
}
// 5. 记录 Echo 结束时间
int64_t echo_end = esp_timer_get_time();
uint32_t duration_us = (uint32_t)(echo_end - echo_start);
uint32_t distance_cm = (duration_us * SOUND_SPEED_CM_US) / 2.0f;
if(distance_cm > MAX_DISTANCE_CM) distance_cm = distance_cm;
// ESP_LOGW(TAG, "###ultrasonic_measure_distance %d",(int)distance_cm);
return (int)distance_cm;
// 6. 计算持续时间
// result.duration_us = (uint32_t)(echo_end - echo_start);
// 7. 计算距离(单位:cm)
// 距离 = (时间 * 声速) / 2 (往返时间所以要除以2)
// result.distance_cm = (result.duration_us * SOUND_SPEED_CM_US) / 2.0f;
// result.success = true;
// return result;
}
//////////////////////////////////////////////////////////////////////////
//senor manager
Senor_Manager::Senor_Manager(){
}
Senor_Manager::~Senor_Manager(){
}
void Senor_Manager::init_all_senors(){
get_ultrasonic_senor(Senor_Direction_Forward)->ultrasonic_init();
}
int Senor_Manager::get_senor_distance(Senor_Type ty,Senor_Direction direction){
if(ty == Senor_Ultrasonic){
switch(direction){
case Senor_Direction_Forward:return get_ultrasonic_senor(direction)->get_senor_distance(); break;
default:
break;
}
}
return -1;
}
//private
ultrasonic_control* Senor_Manager::get_ultrasonic_senor(Senor_Direction direction){
//暂时只有一个,参数无用,后续增加再修改
static ultrasonic_control ultrasonic(Senor_Direction_Forward);
return &ultrasonic;
// static ultrasonic_control ultrasonic[Senor_Direction_Total];
// return &ultrasonic[direction];
}
motor_control.h
#ifndef MOTOR_CONTROL_H
#define MOTOR_CONTROL_H
#include "driver/gpio.h"
#include "driver/ledc.h"
#include "esp_log.h"
#define SIMPLE_GPIO_CONTROL
#define ESP32_S3
//SIMPLE_MODE//////////////////////////////////////////////
// L298N模块1 (控制左侧两个电机):
// ENA → GPIO_2 (PWM)
// IN1 → GPIO_4 (FWD_LEFT) → 同时连接到电机1和电机3的方向控制
// IN2 → GPIO_5 (BWD_LEFT) → 同时连接到电机1和电机3的方向控制
// IN3 → GPIO_4 (FWD_LEFT) → 并联到IN1
// IN4 → GPIO_5 (BWD_LEFT) → 并联到IN2
// L298N模块2 (控制右侧两个电机):
// ENA → GPIO_3 (PWM)
// IN1 → GPIO_6 (FWD_RIGHT) → 同时连接到电机2和电机4的方向控制
// IN2 → GPIO_7 (BWD_RIGHT) → 同时连接到电机2和电机4的方向控制
// IN3 → GPIO_6 (FWD_RIGHT) → 并联到IN1
// IN4 → GPIO_7 (BWD_RIGHT) → 并联到IN2
////////////////////////////////////////////////
// 电机引脚定义 - 请根据实际接线修改
#ifdef SIMPLE_GPIO_CONTROL
// PWM控制引脚
#ifndef ESP32_S3
#define LEFT_PWM_PIN GPIO_NUM_0 //使能LEFT
#define RIGHT_PWM_PIN GPIO_NUM_10 //使能RIGHT
// #define FWD_RIGHT_PIN GPIO_NUM_3 // 右轮前进
// #define BWD_RIGHT_PIN GPIO_NUM_2 // 右轮后退
// 方向控制引脚
#define FWD_LEFT_PIN GPIO_NUM_2 // 左边 IN1 IN3
#define BWD_LEFT_PIN GPIO_NUM_3 // 左边 IN2 IN4
//
#define FWD_RIGHT_PIN GPIO_NUM_18 // 右IN1 IN3
#define BWD_RIGHT_PIN GPIO_NUM_12 // 右IN2 IN4
// #define FWD_LEFT_PIN GPIO_NUM_12 // 左轮前进
// #define BWD_LEFT_PIN GPIO_NUM_18 // 左轮后退
// PWM通道
#define LEFT_PWM_CH LEDC_CHANNEL_1
#define RIGHT_PWM_CH LEDC_CHANNEL_2
#else
#define LEFT_PWM_PIN GPIO_NUM_9 //使能LEFT
// 方向控制引脚
// #define FWD_LEFT_PIN GPIO_NUM_10 // 左边 IN1 IN3
// #define BWD_LEFT_PIN GPIO_NUM_11 // 左边 IN2 IN4
#define FWD_LEFT_PIN GPIO_NUM_11 // 左边 IN1 IN3
#define BWD_LEFT_PIN GPIO_NUM_10 // 左边 IN2 IN4
// #define RIGHT_PWM_PIN GPIO_NUM_12 //使能RIGHT
// // 方向控制引脚
// #define FWD_RIGHT_PIN GPIO_NUM_13 // 右IN1 IN3
// #define BWD_RIGHT_PIN GPIO_NUM_14 // 右IN2 IN4
//35->38 不要用 只有输入功能没输出功能
// #define RIGHT_PWM_PIN GPIO_NUM_38 //使能RIGHT
// // 方向控制引脚
// #define FWD_RIGHT_PIN GPIO_NUM_37 // 右IN1 IN3
// #define BWD_RIGHT_PIN GPIO_NUM_36 // 右IN2 IN4
#define RIGHT_PWM_PIN GPIO_NUM_45 //使能RIGHT
// 方向控制引脚
#define FWD_RIGHT_PIN GPIO_NUM_40 // 右IN1 IN3
#define BWD_RIGHT_PIN GPIO_NUM_39 // 右IN2 IN4
// PWM通道
#define LEFT_PWM_CH LEDC_CHANNEL_0
#define RIGHT_PWM_CH LEDC_CHANNEL_1
#endif
#else
//c3 右边 GPIO
#define MOTOR1_IN1 GPIO_NUM_2
#define MOTOR1_IN2 GPIO_NUM_3
#define MOTOR1_ENA GPIO_NUM_10
#define MOTOR2_IN1 GPIO_NUM_6
#define MOTOR2_IN2 GPIO_NUM_7
#define MOTOR2_ENB GPIO_NUM_5
//左边 GPIO
#define MOTOR3_IN1 GPIO_NUM_0
#define MOTOR3_IN2 GPIO_NUM_1
#define MOTOR3_ENA GPIO_NUM_12
#define MOTOR4_IN1 GPIO_NUM_18
#define MOTOR4_IN2 GPIO_NUM_19
#define MOTOR4_ENB GPIO_NUM_13
// 电机通道定义
#define MOTOR1_PWM_CH LEDC_CHANNEL_0
#define MOTOR2_PWM_CH LEDC_CHANNEL_1
#define MOTOR3_PWM_CH LEDC_CHANNEL_2
#define MOTOR4_PWM_CH LEDC_CHANNEL_3
#endif
// PWM配置
#ifndef ESP32_S3
#define LEDC_TIMER LEDC_TIMER_1
#else
#define LEDC_TIMER LEDC_TIMER_3
#endif
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_DUTY_RES LEDC_TIMER_10_BIT
#define LEDC_FREQUENCY 5000
// 电机结构体
typedef struct {
gpio_num_t in1;
gpio_num_t in2;
ledc_channel_t pwm_ch;
} motor_t;
// 运动方向枚举
typedef enum {
CAR_FORWARD,
CAR_BACKWARD,
CAR_LEFT,
CAR_RIGHT,
CAR_STOP
} car_direction_t;
class MotorControl{
public:
MotorControl();
~MotorControl();
// 函数声明
void motor_control_init(void);
void set_motor_speed(ledc_channel_t channel, uint32_t duty);
void motor_forward(motor_t motor);
void motor_backward(motor_t motor);
void motor_stop(motor_t motor);
void car_control(car_direction_t direction, uint32_t speed);
void car_differential_control(int left_speed, int right_speed);
};
#endif
motor_control.cc
#include "motor_control.h"
#include <driver/ledc.h>
#define TAG "MOTORCON"
#ifdef SIMPLE_GPIO_CONTROL
#define TOTAL_DIR 2
#else
#define TOTAL_DIR 4;
#endif
#ifdef SIMPLE_GPIO_CONTROL
//电机对象定义
static motor_t motors[TOTAL_DIR]= {
{FWD_LEFT_PIN, BWD_LEFT_PIN, LEFT_PWM_CH}, // 左边轮
{FWD_RIGHT_PIN, BWD_RIGHT_PIN, RIGHT_PWM_CH} // 右边轮
};
#else
// 电机对象定义
static motor_t motors[TOTAL_DIR] = {
{MOTOR1_IN1, MOTOR1_IN2, MOTOR1_PWM_CH}, // 左前轮
{MOTOR2_IN1, MOTOR2_IN2, MOTOR2_PWM_CH}, // 右前轮
{MOTOR3_IN1, MOTOR3_IN2, MOTOR3_PWM_CH}, // 左后轮
{MOTOR4_IN1, MOTOR4_IN2, MOTOR4_PWM_CH} // 右后轮
};
#endif
MotorControl::MotorControl(){}
MotorControl::~MotorControl(){}
void MotorControl::motor_control_init(void) {
ESP_LOGI(TAG, "Initializing motor control...");
// GPIO配置
#ifdef SIMPLE_GPIO_CONTROL
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << FWD_LEFT_PIN) | (1ULL << BWD_LEFT_PIN) |
(1ULL << FWD_RIGHT_PIN) | (1ULL << BWD_RIGHT_PIN),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
#else
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << MOTOR1_IN1) | (1ULL << MOTOR1_IN2) |
(1ULL << MOTOR2_IN1) | (1ULL << MOTOR2_IN2) |
(1ULL << MOTOR3_IN1) | (1ULL << MOTOR3_IN2) |
(1ULL << MOTOR4_IN1) | (1ULL << MOTOR4_IN2),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
#endif
gpio_config(&io_conf);
// 初始化所有电机为停止状态
for (int i = 0; i < TOTAL_DIR; i++) {
gpio_set_level(motors[i].in1, 0);
gpio_set_level(motors[i].in2, 0);
}
//
//freq = source_clock / (prescaler * (2^resolution - 1))
//source_clock = 80MHz (APB_CLK)
// prescaler = 分频系数 (1-65535)
// resolution = 占空比分辨率位数
// 你的配置计算:
// source_clock = 80,000,000 Hz
// resolution = 10位 → (2^10 - 1) = 1023
// desired_freq = 5000 Hz
// 所需分频系数 = 80,000,000 / (5000 * 1023) ≈ 15.64
// 实际使用分频系数 = 16
// 实际频率 = 80,000,000 / (16 * 1023) ≈ 4885 Hz
// 这个实际频率(4885Hz)非常接近你设定的5000Hz,是完全可接受的
// PWM定时器配置
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_MODE, //高速模式-LEDC_LOW_SPEED_MODE,低速模式-LEDC_SPEED_MODE_MAX
.duty_resolution = LEDC_DUTY_RES, // LEDC通道占空比分辨率 10bit 0-1023
.timer_num = LEDC_TIMER, //通道的定时器源(0 -> LEDC_TIMER_MAX - 1)
.freq_hz = LEDC_FREQUENCY, //LEDC定时器频率(赫兹)0到2^(8)-1 =>0->255 // 0->(2^(PWM_RESOLUTION) -1)
.clk_cfg = LEDC_AUTO_CLK
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
#ifdef SIMPLE_GPIO_CONTROL
// PWM通道配置
ledc_channel_config_t ledc_channel[TOTAL_DIR] = {
{
.gpio_num = LEFT_PWM_PIN,
.speed_mode = LEDC_MODE,
.channel = LEFT_PWM_CH,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LEDC_TIMER,
.duty = 0,
.hpoint = 0
},
{
.gpio_num = RIGHT_PWM_PIN,
.speed_mode = LEDC_MODE,
.channel = RIGHT_PWM_CH,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LEDC_TIMER,
.duty = 0,
.hpoint = 0
}
};
for (int i = 0; i < TOTAL_DIR; i++) {
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel[i]));
}
#else
// PWM通道配置
ledc_channel_config_t ledc_channel[TOTAL_DIR] = {
{
.speed_mode = LEDC_MODE,
.channel = MOTOR1_PWM_CH,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = MOTOR1_ENA,
.duty = 0,
.hpoint = 0
},
{
.speed_mode = LEDC_MODE,
.channel = MOTOR2_PWM_CH,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = MOTOR2_ENB,
.duty = 0,
.hpoint = 0
},
{
.speed_mode = LEDC_MODE,
.channel = MOTOR3_PWM_CH,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = MOTOR3_ENA,
.duty = 0,
.hpoint = 0
},
{
.speed_mode = LEDC_MODE,
.channel = MOTOR4_PWM_CH,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = MOTOR4_ENB,
.duty = 0,
.hpoint = 0
}
};
for (int i = 0; i < TOTAL_DIR; i++) {
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel[i]));
}
#endif
ESP_LOGI(TAG, "Motor control initialized successfully");
}
void MotorControl::set_motor_speed(ledc_channel_t channel, uint32_t duty) {
// 限制占空比在0-1023范围内 (10位分辨率)
if (duty > 1023) {
duty = 1023;
}
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, channel, duty));
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, channel));
}
void MotorControl::motor_forward(motor_t motor) {
gpio_set_level(motor.in1, 1);
gpio_set_level(motor.in2, 0);
}
void MotorControl::motor_backward(motor_t motor) {
gpio_set_level(motor.in1, 0);
gpio_set_level(motor.in2, 1);
}
void MotorControl::motor_stop(motor_t motor) {
gpio_set_level(motor.in1, 0);
gpio_set_level(motor.in2, 0);
set_motor_speed(motor.pwm_ch, 0);
}
void MotorControl::car_control(car_direction_t direction, uint32_t speed) {
switch (direction) {
case CAR_FORWARD:
// 所有电机前进
for (int i = 0; i < TOTAL_DIR; i++) {
motor_forward(motors[i]);
set_motor_speed(motors[i].pwm_ch, speed);
}
ESP_LOGI(TAG, "Car moving FORWARD at speed: %lu", speed);
break;
case CAR_BACKWARD:
// 所有电机后退
for (int i = 0; i < TOTAL_DIR; i++) {
motor_backward(motors[i]);
set_motor_speed(motors[i].pwm_ch, speed);
}
ESP_LOGI(TAG, "Car moving BACKWARD at speed: %lu", speed);
break;
case CAR_LEFT:
{
#ifdef SIMPLE_GPIO_CONTROL
motor_forward(motors[1]); // 右前
motor_backward(motors[0]); // 左前
#else
// 右侧电机前进,左侧电机后退或停止实现左转
motor_forward(motors[1]); // 右前
motor_forward(motors[3]); // 右后
motor_backward(motors[0]); // 左前
motor_backward(motors[2]); // 左后
#endif
for (int i = 0; i < TOTAL_DIR; i++) {
set_motor_speed(motors[i].pwm_ch, speed);
}
ESP_LOGI(TAG, "Car turning LEFT at speed: %lu", speed);
}
break;
case CAR_RIGHT:
{
#ifdef SIMPLE_GPIO_CONTROL
motor_forward(motors[0]); // 左前
motor_backward(motors[1]); // 右前
for (int i = 0; i < TOTAL_DIR; i++) {
set_motor_speed(motors[i].pwm_ch, speed);
}
#else
// 左侧电机前进,右侧电机后退或停止实现右转
motor_forward(motors[0]); // 左前
motor_forward(motors[2]); // 左后
motor_backward(motors[1]); // 右前
motor_backward(motors[3]); // 右后
#endif
for (int i = 0; i < TOTAL_DIR; i++) {
set_motor_speed(motors[i].pwm_ch, speed);
}
ESP_LOGI(TAG, "Car turning RIGHT at speed: %lu", speed);
}
break;
case CAR_STOP:
// 所有电机停止
for (int i = 0; i < TOTAL_DIR; i++) {
motor_stop(motors[i]);
}
// ESP_LOGI(TAG, "Car STOPPED");
break;
}
}
void MotorControl::car_differential_control(int left_speed, int right_speed) {
// 确保速度值在有效范围内
if (left_speed > 1023) left_speed = 1023;
if (left_speed < -1023) left_speed = -1023;
if (right_speed > 1023) right_speed = 1023;
if (right_speed < -1023) right_speed = -1023;
// 控制左侧电机 (0和2)
if (left_speed > 0) {
motor_forward(motors[0]);
#ifndef SIMPLE_GPIO_CONTROL
motor_forward(motors[2]);
#endif
set_motor_speed(motors[0].pwm_ch, left_speed);
#ifndef SIMPLE_GPIO_CONTROL
set_motor_speed(motors[2].pwm_ch, left_speed);
#endif
} else if (left_speed < 0) {
motor_backward(motors[0]);
#ifndef SIMPLE_GPIO_CONTROL
motor_backward(motors[2]);
#endif
set_motor_speed(motors[0].pwm_ch, -left_speed);
#ifndef SIMPLE_GPIO_CONTROL
set_motor_speed(motors[2].pwm_ch, -left_speed);
#endif
} else {
motor_stop(motors[0]);
#ifndef SIMPLE_GPIO_CONTROL
motor_stop(motors[2]);
#endif
}
// 控制右侧电机 (1和3)
if (right_speed > 0) {
motor_forward(motors[1]);
#ifndef SIMPLE_GPIO_CONTROL
motor_forward(motors[3]);
#endif
set_motor_speed(motors[1].pwm_ch, right_speed);
#ifndef SIMPLE_GPIO_CONTROL
set_motor_speed(motors[3].pwm_ch, right_speed);
#endif
} else if (right_speed < 0) {
motor_backward(motors[1]);
#ifndef SIMPLE_GPIO_CONTROL
motor_backward(motors[3]);
#endif
set_motor_speed(motors[1].pwm_ch, -right_speed);
#ifndef SIMPLE_GPIO_CONTROL
set_motor_speed(motors[3].pwm_ch, -right_speed);
#endif
} else {
motor_stop(motors[1]);
#ifndef SIMPLE_GPIO_CONTROL
motor_stop(motors[3]);
#endif
}
}
2:代码说明
设置为1 测试模式下, 小车轮子是不动的,用于测试 命令是否执行,也可以测试超声波,反正小车不会动
设置为0 就是正常模式了
还有就是,如果不小心把工程清理了,重新编译 会遇到问题,按照下面的修改就可以了,
espressif2022 的2个依赖 版本变了,老的没有了,详细的自己去github上查看
当前位置没合适孔,临时绑了下超声波模块,
在自动巡航时,会用到超声波测距,其他暂时不用,因为时间比较短,没加,可以自行增加超声波障碍物检测
3:测试结果 如果对你又帮助,麻烦点个赞,加个关注
esp32_auto_cruise
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)