基于Arduino开发板的简易智能车项目介绍及源码

源码出处:😀

    浙江师范大学第九届智能车校赛 啊对对队的比赛源码(菜的一笔,仅供思路参考)

说在前面:😝

    这次的比赛还是有些遗憾的,只是跑完了全程,并没有取得太好的成绩,仅拿到了三等奖,确实也是因为自己太忙,没有把很多精力放在这个比赛上,然后还有一个不可控因素是我们车子的性能确实差。

    在这里感谢啊对对队的队长ly能邀请我参加这个比赛,并且也在这个比赛中投入了很多激情;还要感谢队伍的另一名队员wqy,对这个比赛投入了很高的热情和很多的时间,并且也是一直在感染我,让我有继续做下去的动力。在这个比赛中我学到了很多的硬件的知识,也收获了很多东西。这次的智能车校赛是我在大学里参加的第一个比赛,我会一直记得我们曾在实验室奋斗的时光,这也会成为我人生中一段宝贵的经历。

主要技术点:🧠

    车辆硬件的组装、OLED屏幕显示框架的使用,PID控制算法的简单实现(不考虑积分作用,不考虑积分限幅等作用),Arduino板数据存储函数库的使用,自研速度控制的代码(很菜,但很稳)

整体代码:🤑

/*
满电状态的代码
kp = 265
kd = 15
*/
#include <stdio.h>
#include <math.h>
#include <EEPROM.h>
//OLED使用头文件
#include<U8glib.h>
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST); // Fast I2C / TWI
const int led_Pin = 13;               //LED控制引脚
const int left_Forward_PWM_Pin = 10;  //左电机正转控制引脚
const int left_Backward_PWM_Pin = 5;  //左电机反转控制引脚
const int right_Forward_PWM_Pin = 6;  //右电机正转控制引脚
const int right_Backward_PWM_Pin = 9; //右电机反转控制电路
const int AD_Left_Pin = A0;           //左电磁传感器AD引脚
const int AD_Right_Pin = A1;          //右电磁传感器AD引脚
const int button_W_pin = 2;           //方向↑键
const int button_S_pin = 4;           //方向↓键
const int button_A_pin = 7;         //方向←键
const int button_D_pin = 8;           //方向→键
const int button_C_pin = 12;          //中心键

//初始化
void setup() {
  //---------初始化LED引脚-------------------
  pinMode(led_Pin, OUTPUT);
  //---------初始化电机引脚(默认直行)----------
  analogWrite(left_Forward_PWM_Pin, 175);
  analogWrite(left_Backward_PWM_Pin, 0);
  analogWrite(right_Forward_PWM_Pin, 245);
  analogWrite(right_Backward_PWM_Pin, 0);
  //---------初始化传感器引脚------------------
  pinMode(AD_Left_Pin, INPUT);
  pinMode(AD_Right_Pin, INPUT);
  //---------初始化按钮对应引脚----------------
  pinMode(button_W_pin, INPUT_PULLUP);
  pinMode(button_S_pin, INPUT_PULLUP);
  pinMode(button_A_pin, INPUT_PULLUP);
  pinMode(button_D_pin, INPUT_PULLUP);
  pinMode(button_C_pin, INPUT_PULLUP);
}
//清除数据(只有前10位要用)
void ClearMsg()
{
  for(int i=0;i<10;i++)
    EEPROM.write(i,0);
}
//存入数据
void WriteMsg(int K,bool flag)
{
  int i = 0;  //flag == true 就是存储Kp,从第一个位置开始
  if(flag == false) //否则就是存储Kd,从第六个位置开始
    i = 5;
  while(K > 255)
  {
    EEPROM.write(i,255);
    K -= 255;
    i++;
  }
  EEPROM.write(i,K);
}
//读取数据
int ReadMsg(bool flag)
{
  int sum = 0;
  int i = 0;
  if(flag == false)
    i = 5;
  for(int j=0;j<5;j++)
    sum += EEPROM.read(i++);
  return sum;
}

//以下系数为定值,在具体实验中进行调整,切记从小到大进行调整
//以下定义为全局变量
int Kp = ReadMsg(true);//比例系数
int Kd = ReadMsg(false);//微分系数
float Error = 0;//误差
int Last_Error = 0;//上一次误差
int E_Left;    //左边电感产生的电压
int E_Right;  //右边电感产生的电压
int PID = 0;
int menu = 1;
unsigned long Now_Time = millis();
unsigned long nowTime = millis();
//bool isStraight = true; 思考了一下,isStraight 好像是不需要的, nowTime 已经做到了控制

void return_PID()
{
  Error = (sqrt(E_Left) - sqrt(E_Right)) / (E_Left + E_Right);
  PID = Kp * Error + Kd * (Error - Last_Error);
  Last_Error = Error;
  PID = PID * 2;
}

void loop() {
  //电感定义
  E_Left = analogRead(AD_Left_Pin);
  E_Right = analogRead(AD_Right_Pin);
  //按键
  int buttonStateW = digitalRead(button_W_pin);
  int buttonStateS = digitalRead(button_S_pin);
  int buttonStateA = digitalRead(button_A_pin);
  int buttonStateD = digitalRead(button_D_pin);
  int buttonStateC = digitalRead(button_C_pin);
  //按键的控制
  /*menu=0 调节kp;menu=1 调节kd;menu=2
     在这里我们利用W S即上下键来控制menu的加减
     我们利用A D 来控制系数的加减
  */
  if (buttonStateW == LOW) {
    delay(300);
    if (buttonStateW == LOW)
      menu++;
  }
  if (buttonStateS == LOW) {
    delay(300);
    if (buttonStateS == LOW)
      menu--;
  }
  if(menu > 2)
    menu = 1;
  else if(menu < 1)
    menu = 2;
  //控制kp
  if (menu == 1) {
    if (buttonStateA == LOW) {
      delay(50);
      if (buttonStateA == LOW)
        Kp--;
    }
    if (buttonStateD == LOW) {
      delay(50);
      if (buttonStateD == LOW) {
        Kp++;
      }
    }
  }
  //控制Kd
  if (menu == 2) {
    if (buttonStateA == LOW) {
      delay(50);
      if (buttonStateA == LOW)
        Kd--;
    }
    if (buttonStateD == LOW) {
      delay(50);
      if (buttonStateD == LOW) {
        Kd++;
      }
    }
  }
  if(buttonStateC == LOW)
  {
    delay(200);
    if(buttonStateC == LOW)
    {
      ClearMsg();
      WriteMsg(Kp,true);
      WriteMsg(Kd,false);
      u8g.firstPage();
      do{
        u8g.setFont(u8g_font_6x10);
        u8g.drawStr(5, 30, "Save successfully!");
        u8g.drawStr(5,40,"A duiduidui yyds!");
      }while(u8g.nextPage());
      delay(2000);
    }
  }
  //OLED进行显示
  u8g.firstPage();
  do {
    u8g.setFont(u8g_font_6x10);
    //前两行显示电感的值如何实现
    //左电感
    u8g.drawStr(0, 10, " L=");
    u8g.setPrintPos(20, 10);
    u8g.print(E_Left);
    //右电感
    u8g.drawStr(40, 10, "R=");
    u8g.setPrintPos(55, 10);
    u8g.print(E_Right);
    //PID
    u8g.drawStr(80,10,"PID=");
    u8g.setPrintPos(105,10);
    u8g.print(PID);
    u8g.drawStr(0,20,"    -------------");
    //menu
    u8g.drawStr(0, 30, "    |menu =");
    u8g.setPrintPos(70, 30);
    u8g.print(menu);
    //打印Kp的值
    u8g.drawStr(0, 40, "    |Kp   =");
    u8g.setPrintPos(70, 40);
    u8g.print(Kp);
    //打印Kd的值
    u8g.drawStr(0, 50, "    |Kd   =");
    u8g.setPrintPos(70, 50);
    u8g.print(Kd);
    u8g.drawStr(0,60,"    -------------");
    u8g.drawStr(95,30,"|");
    u8g.drawStr(95,40,"|");
    u8g.drawStr(95,50,"|");
  } while ( u8g.nextPage() );
  //每 50ms 进行一次检测
  if (millis() - Now_Time > 50)
  {
    E_Left = analogRead(AD_Left_Pin);
    E_Right = analogRead(AD_Right_Pin);
    return_PID();

    //下述代码如果不太行,两个解决办法:
    //1、减去除最大速度外最大的两段速度(或者再加两段)
    //2、提高最小的电压差检测
    
    if(fabs(E_Left - E_Right) > 750)//750
    {
      //满电状态left再减5 现属于测试
      analogWrite(right_Forward_PWM_Pin, 77 + PID * 1.15);
      analogWrite(left_Forward_PWM_Pin, 55 - PID);
      nowTime = millis();
    }
    else if(fabs(E_Left - E_Right) > 550)//550
    {
      analogWrite(right_Forward_PWM_Pin, 91 + PID * 1.15);
      analogWrite(left_Forward_PWM_Pin, 65 - PID);
      nowTime = millis();
    }
    else if(fabs(E_Left - E_Right) > 350)//350
    {
      analogWrite(right_Forward_PWM_Pin, 119 + PID * 1.15);
      analogWrite(left_Forward_PWM_Pin, 85 - PID);
      nowTime = millis();      
    }
    else if(fabs(E_Left - E_Right) > 200)//200
    {
      analogWrite(right_Forward_PWM_Pin, 147 + PID * 1.15);
      analogWrite(left_Forward_PWM_Pin, 105 - PID);
      nowTime = millis();
    }
    else
    {
      if(millis() - nowTime < 1000)//250应该还需要更改
      {
        analogWrite(right_Forward_PWM_Pin, 175 + PID * 1.15);
        analogWrite(left_Forward_PWM_Pin, 125 - PID);
      }
      else
      {

        //细心的人应该已经发现了,我们的左右电机的电位是不一样的,这就是我说的我们的车子性能太差了,左右轮极度不对称。
        analogWrite(right_Forward_PWM_Pin, 245 + PID * 1.15);
        analogWrite(left_Forward_PWM_Pin, 175 - PID);
      }
    }
    Now_Time = millis();
  }
}

车辆图片:💯(拍摄手法拙劣)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值