【花雕学编程】Arduino BLDC 之智能车GPS导航与转向控制

在这里插入图片描述
《Arduino 手册(思路与案例)》栏目介绍:
在电子制作与智能控制的应用领域,本栏目涵盖了丰富的内容,包括但不限于以下主题:Arduino BLDC、Arduino CNC、Arduino E-Ink、Arduino ESP32 SPP、Arduino FreeRTOS、Arduino FOC、Arduino GRBL、Arduino HTTP、Arduino HUB75、Arduino IoT Cloud、Arduino JSON、Arduino LCD、Arduino OLED、Arduino LVGL、Arduino PID、Arduino TFT,以及Arduino智能家居、智慧交通、月球基地、智慧校园和智慧农业等多个方面与领域。不仅探讨了这些技术的基础知识和应用领域,还提供了众多具体的参考案例,帮助读者更好地理解和运用Arduino平台进行创新项目。目前,本栏目已有近4000篇相关博客,旨在为广大电子爱好者和开发者提供全面的学习资源与实践指导。通过这些丰富的案例和思路,读者可以获取灵感,推动自己的创作与开发进程。
https://blog.csdn.net/weixin_41659040/category_12422453.html

在这里插入图片描述
Arduino BLDC之智能车GPS导航与转向控制

  1. GPS导航与转向控制概述
    智能车GPS导航与转向控制系统是一种基于全球定位系统(GPS)和传感器数据的自动导航技术,结合Arduino平台和电刷无刷直流电机(BLDC),实现智能小车的自主定位和路径规划。该系统通过实时获取位置信息,进行路径计算和转向控制,使车辆能够在复杂环境中自主行驶。

主要特点:

高精度定位:利用GPS模块获取车辆的实时位置,结合地图数据进行精准导航。
动态路径规划:能够根据实时位置信息和环境变化(如障碍物)动态调整行驶路径,确保安全和效率。
自动转向控制:通过控制电机的转速和方向,实现车辆的精准转向,确保按照预定路线行驶。
2. 应用场景
智能车GPS导航与转向控制的应用场景主要包括:

无人驾驶汽车:在无人驾驶技术中,GPS导航和转向控制是实现自动驾驶的核心技术之一,适用于城市道路和高速公路。
物流配送:在自动配送小车中,利用GPS进行路径规划和导航,提高物流效率,降低人工成本。
农业机器人:在智能农业中,GPS导航可以帮助农业机器人进行精准作业,如播种、施肥和巡检等。
教育与科研:在机器人和自动化课程中,智能车GPS导航系统可以作为教学工具,帮助学生理解导航和控制算法。
3. 注意事项
在实现智能车GPS导航与转向控制时,需要关注以下事项:

GPS精度:GPS信号受环境影响较大(如城市高楼、树木遮挡等),需考虑使用辅助定位技术(如IMU、差分GPS)来提高定位精度。
传感器融合:结合其他传感器(如超声波传感器、激光雷达)进行环境感知,确保车辆能够安全避开障碍物。
控制算法:开发高效的导航和控制算法,确保在动态环境中能够快速响应,调整行驶路径和转向角度。
电源管理:确保系统的电源管理稳定,避免在行驶过程中因电力不足导致系统失效。
安全性设计:在设计中考虑安全性,确保在出现异常情况(如GPS信号丢失)时能够安全停车或采取应急措施。

在这里插入图片描述

1、基础 GPS 导航控制

#include <TinyGPS++.h>
#include <SoftwareSerial.h>

TinyGPSPlus gps;
SoftwareSerial ss(4, 3); // RX, TX

#define LEFT_MOTOR_PIN 5
#define RIGHT_MOTOR_PIN 6

void setup() {
    Serial.begin(9600);
    ss.begin(9600);
    pinMode(LEFT_MOTOR_PIN, OUTPUT);
    pinMode(RIGHT_MOTOR_PIN, OUTPUT);
}

void loop() {
    while (ss.available()) {
        gps.encode(ss.read()); // 解析 GPS 数据
        if (gps.location.isUpdated()) {
            Serial.print("纬度: ");
            Serial.println(gps.location.lat(), 6);
            Serial.print("经度: ");
            Serial.println(gps.location.lng(), 6);
            // 根据位置控制小车移动
            navigateTo(gps.location.lat(), gps.location.lng());
        }
    }
}

void navigateTo(double targetLat, double targetLng) {
    // 简单的导航逻辑
    // 如果目标位置在当前经纬度的右侧,则右转
    // 这里需要结合实际的定位算法和方向判断
    if (/* 条件判断 */) {
        turnRight();
    } else {
        moveForward();
    }
}

void moveForward() {
    analogWrite(LEFT_MOTOR_PIN, 200);
    analogWrite(RIGHT_MOTOR_PIN, 200);
}

void turnRight() {
    analogWrite(LEFT_MOTOR_PIN, 200);
    analogWrite(RIGHT_MOTOR_PIN, 0); // 右侧电机停止
}

要点解读:
基础 GPS 数据解析:通过 TinyGPS++ 库获取 GPS 位置信息。
简单导航逻辑:根据当前位置信息控制小车的前进和转向。
实时输出:通过串口输出当前经纬度,便于调试。

2、带有目标点导航的智能车

#include <TinyGPS++.h>
#include <SoftwareSerial.h>

TinyGPSPlus gps;
SoftwareSerial ss(4, 3); // RX, TX

#define LEFT_MOTOR_PIN 5
#define RIGHT_MOTOR_PIN 6

double targetLat = 30.0; // 设置目标纬度
double targetLng = 120.0; // 设置目标经度

void setup() {
    Serial.begin(9600);
    ss.begin(9600);
    pinMode(LEFT_MOTOR_PIN, OUTPUT);
    pinMode(RIGHT_MOTOR_PIN, OUTPUT);
}

void loop() {
    while (ss.available()) {
        gps.encode(ss.read());
        if (gps.location.isUpdated()) {
            Serial.print("当前位置: ");
            Serial.print(gps.location.lat(), 6);
            Serial.print(", ");
            Serial.println(gps.location.lng(), 6);
            navigateTo(targetLat, targetLng);
        }
    }
}

void navigateTo(double lat, double lng) {
    double distance = calculateDistance(gps.location.lat(), gps.location.lng(), lat, lng);
    if (distance < 0.1) { // 到达目标点的阈值
        stopMotors();
    } else {
        moveForward();
    }
}

double calculateDistance(double lat1, double lng1, double lat2, double lng2) {
    // 使用 Haversine 公式计算两点之间的距离(单位:公里)
    const double R = 6371; // 地球半径
    double dLat = (lat2 - lat1) * (PI / 180);
    double dLng = (lng2 - lng1) * (PI / 180);
    double a = sin(dLat / 2) * sin(dLat / 2) + cos(lat1 * (PI / 180)) * cos(lat2 * (PI / 180)) * sin(dLng / 2) * sin(dLng / 2);
    double c = 2 * atan2(sqrt(a), sqrt(1 - a));
    return R * c; // 返回距离
}

void moveForward() {
    analogWrite(LEFT_MOTOR_PIN, 200);
    analogWrite(RIGHT_MOTOR_PIN, 200);
}

void stopMotors() {
    analogWrite(LEFT_MOTOR_PIN, 0);
    analogWrite(RIGHT_MOTOR_PIN, 0);
}

要点解读:
目标点设置:通过预设的目标经纬度实现导航。
距离计算:使用 Haversine 公式计算当前位置与目标点之间的距离。
简单导航逻辑:根据距离判断是否继续前进或停止。

3、根据方向调整导航与转向控制

#include <TinyGPS++.h>
#include <SoftwareSerial.h>

TinyGPSPlus gps;
SoftwareSerial ss(4, 3); // RX, TX

#define LEFT_MOTOR_PIN 5
#define RIGHT_MOTOR_PIN 6

double targetLat = 30.0; // 设置目标纬度
double targetLng = 120.0; // 设置目标经度

void setup() {
    Serial.begin(9600);
    ss.begin(9600);
    pinMode(LEFT_MOTOR_PIN, OUTPUT);
    pinMode(RIGHT_MOTOR_PIN, OUTPUT);
}

void loop() {
    while (ss.available()) {
        gps.encode(ss.read());
        if (gps.location.isUpdated()) {
            Serial.print("当前位置: ");
            Serial.print(gps.location.lat(), 6);
            Serial.print(", ");
            Serial.println(gps.location.lng(), 6);
            navigateTo(targetLat, targetLng);
        }
    }
}

void navigateTo(double lat, double lng) {
    double distance = calculateDistance(gps.location.lat(), gps.location.lng(), lat, lng);
    double bearing = calculateBearing(gps.location.lat(), gps.location.lng(), lat, lng);
    
    if (distance < 0.1) {
        stopMotors();
    } else {
        adjustDirection(bearing);
        moveForward();
    }
}

double calculateDistance(double lat1, double lng1, double lat2, double lng2) {
    const double R = 6371; // 地球半径
    double dLat = (lat2 - lat1) * (PI / 180);
    double dLng = (lng2 - lng1) * (PI / 180);
    double a = sin(dLat / 2) * sin(dLat / 2) + cos(lat1 * (PI / 180)) * cos(lat2 * (PI / 180)) * sin(dLng / 2) * sin(dLng / 2);
    double c = 2 * atan2(sqrt(a), sqrt(1 - a));
    return R * c; // 返回距离
}

double calculateBearing(double lat1, double lng1, double lat2, double lng2) {
    double y = sin(lng2 - lng1) * cos(lat2);
    double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lng2 - lng1);
    return atan2(y, x) * (180 / PI); // 返回方位角
}

void adjustDirection(double bearing) {
    // 根据方位角调整小车方向
    // 这里需要结合实际的方向判断和电机控制
    if (/* 判断左转 */) {
        turnLeft();
    } else if (/* 判断右转 */) {
        turnRight();
    }
}

void moveForward() {
    analogWrite(LEFT_MOTOR_PIN, 200);
    analogWrite(RIGHT_MOTOR_PIN, 200);
}

void stopMotors() {
    analogWrite(LEFT_MOTOR_PIN, 0);
    analogWrite(RIGHT_MOTOR_PIN, 0);
}

void turnLeft() {
    analogWrite(LEFT_MOTOR_PIN, 100); // 左轮减速
    analogWrite(RIGHT_MOTOR_PIN, 200); // 右轮保持速度
}

void turnRight() {
    analogWrite(LEFT_MOTOR_PIN, 200); // 左轮保持速度
    analogWrite(RIGHT_MOTOR_PIN, 100); // 右轮减速
}

要点解读:
方向调整:通过计算方位角来调整小车的行驶方向。
动态导航:根据当前位置与目标点的关系动态调整行驶和转向。
复杂导航逻辑:结合距离和方位角实现更智能的导航控制。

在这里插入图片描述
4、基础GPS导航(固定目标点)

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
 
TinyGPSPlus gps;
SoftwareSerial gpsSerial(4, 3); // RX, TX
 
// 目标经纬度(示例:北京天安门坐标)
float targetLat = 39.9075; 
float targetLng = 116.3972;
 
void setup() {
  Serial.begin(9600);
  gpsSerial.begin(9600);
  pinMode(5, OUTPUT); // BLDC电机方向控制引脚
  pinMode(6, OUTPUT); // BLDC电机PWM引脚
}
 
void loop() {
  while (gpsSerial.available() > 0) {
    if (gps.encode(gpsSerial.read())) {
      if (gps.location.isValid()) {
        // 计算当前位置与目标点的方位角(简化版)
        float bearing = gps.courseTo(
          gps.location.lat(), gps.location.lng(),
          targetLat, targetLng
        );
        
        // 简单转向控制(假设0°为正北)
        if (bearing > 10) {
          digitalWrite(5, HIGH); // 左转
          analogWrite(6, 150);   // 中速
        } else if (bearing < -10) {
          digitalWrite(5, LOW);  // 右转
          analogWrite(6, 150);   // 中速
        } else {
          analogWrite(6, 200);   // 直行全速
        }
 
        // 打印调试信息
        Serial.print("Bearing: "); Serial.println(bearing);
      }
    }
  }
}

要点解读:

GPS数据解析:使用TinyGPS++库解析NMEA数据,获取经纬度和航向。
方向计算:通过courseTo()函数计算目标方位角,简化转向逻辑。
BLDC控制:通过方向引脚(HIGH/LOW)和PWM控制电机转向和速度。
局限性:无闭环控制,转向依赖固定阈值(±10°),路径不平滑。

5、PID转向控制(带罗盘校正)

#include <TinyGPS++.h>
#include <Wire.h>
#include <HMC5883L.h>
#include <PID_v1.h>
 
TinyGPSPlus gps;
HMC5883L compass;
SoftwareSerial gpsSerial(4, 3);
 
// PID变量
double targetBearing, currentBearing, pidOutput;
PID pid(&currentBearing, &pidOutput, &targetBearing, 2.0, 5.0, 1.0, DIRECT);
 
void setup() {
  Serial.begin(9600);
  gpsSerial.begin(9600);
  Wire.begin();
  compass.begin();
  
  // 初始化目标点(同案例一)
  targetBearing = gps.courseTo(gps.location.lat(), gps.location.lng(), targetLat, targetLng);
  
  pid.SetMode(AUTOMATIC);
  pid.SetOutputLimits(-90, 90); // 限制转向角度
}
 
void loop() {
  // 更新GPS数据
  if (gpsSerial.available() && gps.encode(gpsSerial.read())) {
    if (gps.location.isValid()) {
      targetBearing = gps.courseTo(gps.location.lat(), gps.location.lng(), targetLat, targetLng);
    }
  }
 
  // 读取电子罗盘航向
  Vector mag = compass.readNormalize();
  float heading = atan2(mag.YAxis, mag.XAxis) * 180 / PI;
  if (heading < 0) heading += 360;
  
  currentBearing = heading;
  pid.Compute();
 
  // 控制BLDC转向(需替换为实际驱动代码)
  if (pidOutput > 10) {
    // 右转(pwm_right为BLDC右转向PWM值)
    analogWrite(5, map(pidOutput, 0, 90, 0, 255)); 
    analogWrite(6, 0); // 左轮停止(差速转向)
  } else if (pidOutput < -10) {
    // 左转
    analogWrite(6, map(-pidOutput, 0, 90, 0, 255));
    analogWrite(5, 0); // 右轮停止
  } else {
    // 直行
    analogWrite(5, 200); analogWrite(6, 200);
  }
}

要点解读:

多传感器融合:GPS提供目标方位,电子罗盘提供实时航向,减少GPS漂移影响。
PID动态调整:根据航向误差实时计算转向角度,避免振荡。
差速转向:通过控制左右轮速度差实现转向(需BLDC驱动支持)。
参数调优:PID参数需根据车辆动力学调整,避免过度转向。

6、多目标点路径规划(A*算法简化版)

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
 
TinyGPSPlus gps;
SoftwareSerial gpsSerial(4, 3);
 
// 路径点数组(经纬度)
float waypoints[][2] = {
  {39.9075, 116.3972}, // 点1:天安门
  {39.9085, 116.3982}, // 点2
  {39.9095, 116.3992}  // 点3
};
int currentWaypoint = 0;
 
void setup() {
  Serial.begin(9600);
  gpsSerial.begin(9600);
  pinMode(5, OUTPUT); // 左转
  pinMode(6, OUTPUT); // 右转
  pinMode(7, OUTPUT); // 前进
}
 
void loop() {
  while (gpsSerial.available() > 0) {
    if (gps.encode(gpsSerial.read()) && gps.location.isValid()) {
      float targetLat = waypoints[currentWaypoint][0];
      float targetLng = waypoints[currentWaypoint][1];
      
      // 计算到目标点的距离(米)
      float distance = gps.distanceBetween(
        gps.location.lat(), gps.location.lng(),
        targetLat, targetLng
      );
      
      // 到达目标点后切换下一个点
      if (distance < 5.0) { // 5米阈值
        currentWaypoint = (currentWaypoint + 1) % 3;
      } else {
        // 转向控制(同案例一)
        float bearing = gps.courseTo(gps.location.lat(), gps.location.lng(), targetLat, targetLng);
        steerToBearing(bearing);
        
        // 前进控制
        digitalWrite(7, HIGH);
        analogWrite(9, 180); // BLDC前进PWM
      }
    }
  }
}
 
void steerToBearing(float bearing) {
  // 简化转向逻辑(实际需PID优化)
  if (bearing > 15) {
    digitalWrite(5, HIGH); digitalWrite(6, LOW);
  } else if (bearing < -15) {
    digitalWrite(6, HIGH); digitalWrite(5, LOW);
  } else {
    digitalWrite(5, LOW); digitalWrite(6, LOW);
  }
}

要点解读:

路径点管理:通过数组存储多目标点,按顺序导航。
动态切换:检测到当前目标点距离<5米时自动切换下一目标。
模块化设计:转向逻辑封装为函数,便于扩展复杂算法(如A*)。
扩展建议:可结合SD卡模块读取外部路径文件,或通过无线通信更新目标点。

注意,以上案例只是为了拓展思路,仅供参考。它们可能有错误、不适用或者无法编译。您的硬件平台、使用场景和Arduino版本可能影响使用方法的选择。实际编程时,您要根据自己的硬件配置、使用场景和具体需求进行调整,并多次实际测试。您还要正确连接硬件,了解所用传感器和设备的规范和特性。涉及硬件操作的代码,您要在使用前确认引脚和电平等参数的正确性和安全性。

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

驴友花雕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值