基于arduino的循迹小车(含有PID算法)

2023-05-16

       循迹小车一般分为两方面:一方面是简单的闭环赛道只有直道和弯道,另一方面是毕设类型的包括一些元素:90度弯道、十字道路、S形弯道等。

 

1、CSDN下载:

含有PID:https://download.csdn.net/download/qq_38351824/11107048

没有PID:https://download.csdn.net/download/qq_38351824/11107175

2、可以关注点赞并在下方评论,我给你邮箱发过去。

3、关注微信公众号下载:

     ① 关注微信公众号:Tech云  

     ②

 

       本篇博客试根据下图来进行书写的,如果大家有什么新的元素,也可以在下方评论,我进行更新。

作者:sumjess

 

注意本篇博客循迹模块使用了5个

一、简单的闭环赛道

随意画了一个

(1)逻辑部分:

   

所以程序的写法也很简单,就是检测到哪种情况对应着哪种反应。这一过程可以用switch也可以用if来实现这一过程。下文用if来演示。

(2)各程序片段

总的循环:

void loop()
{
     read_sensor_values();  //获取5个循迹模块的数值情况
     calc_pid();            //pid计算出转向的pwm值
     motor_control();       //电机转动
}

第一部分:检测部分程序片段

void read_sensor_values()
{
  sensor[0] = digitalRead(leftA_track_PIN);
  sensor[1] = digitalRead(leftB_track_PIN);
  sensor[2] = digitalRead(middle_track_PIN);
  sensor[3] = digitalRead(righA_track_PIN);
  sensor[4] = digitalRead(righB_track_PIN);
  
  if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 1)) {
      error = 2;//          0 0 0 0 1
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 1) && (sensor[4] == 0)) {
      error = 1;//          0 0 0 1 0
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 1) && (sensor[3] == 0) && (sensor[4] == 0)) {
      error = 0;//          0 0 1 0 0
    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 0)) {
      error = -1;//         0 1 0 0 0
    } else if ((sensor[0] == 1) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 0)) {
      error = -2;//         1 0 0 0 0
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 0)) {
      if (error == -2) {//  0 0 0 0 0
        error = -3;
      }else{
        error = 3;
      }
    }
  }

解释:

<1>  将读取到的五个循迹模块的数据存入数组sensor:

  sensor[0] = digitalRead(leftA_track_PIN);      左边第一个循迹模块
  sensor[1] = digitalRead(leftB_track_PIN);      左边第二个循迹模块
  sensor[2] = digitalRead(middle_track_PIN);   中间的循迹模块
  sensor[3] = digitalRead(righA_track_PIN);     右边第二个循迹模块
  sensor[4] = digitalRead(righB_track_PIN);     右边第一个循迹模块

<2>  检测到哪种情况对应着哪种反应:

if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 1)) {
      error = 2;//          0 0 0 0 1
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 1) && (sensor[4] == 0)) {
      error = 1;//          0 0 0 1 0
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 1) && (sensor[3] == 0) && (sensor[4] == 0)) {
      error = 0;//          0 0 1 0 0
    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 0)) {
      error = -1;//         0 1 0 0 0
    } else if ((sensor[0] == 1) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 0)) {
      error = -2;//         1 0 0 0 0
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 0)) {
      if (error == -2) {//  0 0 0 0 0
        error = -3;
      }else{
        error = 3;
      }
    }

前面几个就不解释了完全按照前面excel写的,最后一个是所有传感器均没有检测到黑线的情况,下面具体解释一下:

else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 0)) {

 检测到为0000的情况
      if (error == -2) {// //如果上一次 error == -2

意味着上一次是1000,也就是意味着这次可能车在左面第一个传感器和第二个传感器之间或者是在左边第一个传感器的左边,无论是上面的哪种情况,车都需要大左转
        error = -3;
      }else{

否则就是相反的情况,都需要大右转
        error = 3;
      }
    }

第二部分:计算PID(计算转向大小)

void calc_pid()
{
  P = error;
  I = I + error;
  D = error - previous_error;
 
  PID_value = (Kp * P) + (Ki * I) + (Kd * D);
 
  previous_error = error;
}

利用上一部分得到的error计算车的偏离情况,车偏离赛道的情况从而来调整下一次给出的PWM进而快速转正车身。

这一部分的kp、ki、kd需要不断地调试,从而得出最佳解。

 

第三部分:电机转向

//速度设定范围(-255,255)
void motorsWrite(int speedL, int speedR)
{
  if (speedR > 0) {
    analogWrite(leftA_PIN, speedR);
    analogWrite(leftB_PIN, 0);
  } else {
    analogWrite(leftA_PIN, 0);
    analogWrite(leftB_PIN, -speedR);
  }
 
  if (speedL > 0) {
    analogWrite(righA_PIN, speedL);
    analogWrite(righB_PIN, 0);
  } else {
    analogWrite(righA_PIN, 0);
    analogWrite(righB_PIN, -speedL);
  }
}
//速度设定范围(-100,100)
void motorsWritePct(int speedLpct, int speedRpct) {
  //speedLpct, speedRpct ranges from -100 to 100
  motorsWrite(speedLpct * 2.55, speedRpct * 2.55);
}
void motor_control()
{
  int left_motor_speed = initial_motor_speed - PID_value;
  int right_motor_speed = initial_motor_speed + PID_value;
  
  if(left_motor_speed < -255){
    left_motor_speed = -255;
  }
  if(left_motor_speed > 255){
    left_motor_speed = 255;
  }
  motorsWrite(left_motor_speed,right_motor_speed);
} 

第一个函数是在检查更改正负值,来保证PWM都是正的,即轮子不会倒转。

第二个函数是在利用一次函数,将输入范围变成0-100

第三个函数是在控制范围,ardunio的PWM范围是在正负255,此函数是在做一个限制·

 

二、在上面的基础上添加元素

 

(1)逻辑部分:

(2)各程序片段

 

除了read_sensor_values() 各程序片段与之前都一样,read_sensor_values() 只是添加了一部分,情况如下:

void read_sensor_values()
{
  sensor[0] = digitalRead(leftA_track_PIN);
  sensor[1] = digitalRead(leftB_track_PIN);
  sensor[2] = digitalRead(middle_track_PIN);
  sensor[3] = digitalRead(righA_track_PIN);
  sensor[4] = digitalRead(righB_track_PIN);
  
      if ((sensor[0] == 1) && (sensor[1] == 1) && (sensor[2] == 1) && (sensor[3] == 1) && (sensor[4] == 1)) {
      decide = 1;//十字路口 1 1 1 1 1   直行
    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 1) && (sensor[3] == 1) && (sensor[4] == 0)) {
      decide = 1;//十字路口 0 1 1 1 0   直行
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 1) && (sensor[3] == 1) && (sensor[4] == 1)) {
      decide = 2;//90度路口 0 0 1 1 1    右转90度
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 1) && (sensor[3] == 1) && (sensor[4] == 0)) {
      decide = 2;//90度路口 0 0 1 1 0    右转90度 
    } else if ((sensor[0] == 1) && (sensor[1] == 1) && (sensor[2] == 1) && (sensor[3] == 0) && (sensor[4] == 0)) {
      decide = 3;//90度路口 1 1 1 0 0    左转90度 
    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 1) && (sensor[3] == 0) && (sensor[4] == 0)) {
      decide = 3;//90度路口 0 1 1 0 0    左转90度 
    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 1) && (sensor[3] == 0) && (sensor[4] == 0)) {
      decide = 3;//向上锐角 0 1 1 0 0    向上锐角 
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 1)) {
      error = 2;//          0 0 0 0 1
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 1) && (sensor[4] == 0)) {
      error = 1;//          0 0 0 1 0
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 1) && (sensor[3] == 0) && (sensor[4] == 0)) {
      error = 0;//          0 0 1 0 0
    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 0)) {
      error = -1;//         0 1 0 0 0
    } else if ((sensor[0] == 1) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 0)) {
      error = -2;//         1 0 0 0 0
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 0)) {
      if (error == -2) {//  0 0 0 0 0
        error = -3;
      }else{
        error = 3;
      }
    }
 
}

各个条件都是按照前面excel写的

附全套程序

//电机使用:5-6-9-10
//循迹模块使用:2-3-7-8-11

//-------------------------------------------------------------------//
//*******************************************************************//
///
//小车部分/
///

//           电机设置             //
#define leftA_PIN 5
#define leftB_PIN 6
#define righA_PIN 9
#define righB_PIN 10

float Kp = 10, Ki = 0.5, Kd = 0;                    //pid弯道参数参数 
float error = 0, P = 0, I = 0, D = 0, PID_value = 0;//pid直道参数 
float decide = 0;                                   //元素判断
float previous_error = 0, previous_I = 0;           //误差值 
int sensor[5] = {0, 0, 0, 0, 0};                    //
5个传感器数值的数组 
static int initial_motor_speed = 60;                //初始速度 
 
void read_sensor_values(void);                      //读取初值 
void calc_pid(void);                                //计算pid 
void motor_control(void);                           //电机控制 

void motor_pinint( );     //引脚初始化
void _stop();             //停车
///
//*******************************************************************//
//-------------------------------------------------------------------//

//-------------------------------------------------------------------//
//*******************************************************************//
///
循迹部分///
///

//             循迹模块设置               //
#define leftA_track_PIN 3
#define leftB_track_PIN 4
#define middle_track_PIN 12
#define righA_track_PIN 7
#define righB_track_PIN 13


//----------------------------------算法部分-----------------------------
---//
void obstacle( );      //避障小车算法
                       //循迹小车算法/*  read_sensor_values(); calc_pid(
); motor_control();  */     
//--------------------------------------------------------------------------//

void setup()
{
  Serial.begin(9600); //串口波特率115200(PC端使用)
  track_pinint( );     //循迹引脚初始化
  motor_pinint();        //电机引脚初始化

}
void loop()
{
    read_sensor_values();         //循迹小车
    calc_pid();
    motor_control();
}

/*循迹模块引脚初始化*/
void track_pinint( )
{ 
  pinMode (leftA_track_PIN, INPUT); //设置引脚为输入引脚
  pinMode (leftB_track_PIN, INPUT); //设置引脚为输入引脚
  pinMode (middle_track_PIN, INPUT);//设置引脚为输入引脚
  pinMode (righA_track_PIN, INPUT); //设置引脚为输入引脚
  pinMode (righB_track_PIN, INPUT); //设置引脚为输入引脚
}

/*电机引脚初始化*/
void motor_pinint( )
{
  pinMode (leftA_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (leftB_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (righA_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (righB_PIN, OUTPUT); //设置引脚为输出引脚
  }

/**************************************************
stop子函数—停止子函数
函数功能:控制车停止
**************************************************/
void _stop()
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,0);         //左轮静止不动
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,0);         //右轮静止不动
}
//速度设定范围(-255,255)
void motorsWrite(int speedL, int speedR)
{
  if (speedR > 0) {
    analogWrite(leftA_PIN, speedR);
    analogWrite(leftB_PIN, 0);
  } else {
    analogWrite(leftA_PIN, 0);
    analogWrite(leftB_PIN, -speedR);
  }
 
  if (speedL > 0) {
    analogWrite(righA_PIN, speedL);
    analogWrite(righB_PIN, 0);
  } else {
    analogWrite(righA_PIN, 0);
    analogWrite(righB_PIN, -speedL);
  }
}
//速度设定范围(-100,100)
void motorsWritePct(int speedLpct, int speedRpct) {
  //speedLpct, speedRpct ranges from -100 to 100
  motorsWrite(speedLpct * 2.55, speedRpct * 2.55);
}
void motorsStop() 
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,0);         //左轮静止不动
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,0);         //右轮静止不动
}
 
void read_sensor_values()
{
  sensor[0] = digitalRead(leftA_track_PIN);
  sensor[1] = digitalRead(leftB_track_PIN);
  sensor[2] = digitalRead(middle_track_PIN);
  sensor[3] = digitalRead(righA_track_PIN);
  sensor[4] = digitalRead(righB_track_PIN);
  
    if ((sensor[0] == 1) && (sensor[1] == 1) && (sensor[2] == 1) && (sensor[3
] == 1) && (sensor[4] == 1)) {
      decide = 1;//十字路口 1 1 1 1 1   直行
    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 1) && (
sensor[3] == 1) && (sensor[4] == 0)) {
      decide = 1;//十字路口 0 1 1 1 0   直行
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 1) && (
sensor[3] == 1) && (sensor[4] == 1)) {
      decide = 2;//90度路口 0 0 1 1 1    右转90度
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 1) && (
sensor[3] == 1) && (sensor[4] == 0)) {
      decide = 2;//90度路口 0 0 1 1 0    右转90度 
    } else if ((sensor[0] == 1) && (sensor[1] == 1) && (sensor[2] == 1) && (
sensor[3] == 0) && (sensor[4] == 0)) {
      decide = 3;//90度路口 1 1 1 0 0    左转90度 
    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 1) && (
sensor[3] == 0) && (sensor[4] == 0)) {
      decide = 3;//90度路口 0 1 1 0 0    左转90度 
    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 1) && (
sensor[3] == 0) && (sensor[4] == 0)) {
      decide = 3;//向上锐角 0 1 1 0 0    向上锐角 
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (
sensor[3] == 0) && (sensor[4] == 1)) {
      error = 2;//          0 0 0 0 1
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (
sensor[3] == 1) && (sensor[4] == 0)) {
      error = 1;//          0 0 0 1 0
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 1) && (
sensor[3] == 0) && (sensor[4] == 0)) {
      error = 0;//          0 0 1 0 0
    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 0) && (
sensor[3] == 0) && (sensor[4] == 0)) {
      error = -1;//         0 1 0 0 0
    } else if ((sensor[0] == 1) && (sensor[1] == 0) && (sensor[2] == 0) && (
sensor[3] == 0) && (sensor[4] == 0)) {
      error = -2;//         1 0 0 0 0
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (
sensor[3] == 0) && (sensor[4] == 0)) {
      if (error == -2) {//  0 0 0 0 0
        error = -3;
      }else{
        error = 3;
      }
    }
}
void calc_pid()
{
  P = error;
  I = I + error;
  D = error - previous_error;
 
  PID_value = (Kp * P) + (Ki * I) + (Kd * D);
 
  previous_error = error;
}
void motor_control()
{
  int left_motor_speed = initial_motor_speed - PID_value;
  int right_motor_speed = initial_motor_speed + PID_value;
  
  if(left_motor_speed < -255){
    left_motor_speed = -255;
  }
  if(left_motor_speed > 255){
    left_motor_speed = 255;
  }
  motorsWrite(left_motor_speed,right_motor_speed);
 
  Serial.print("move_A: ");
  Serial.print(left_motor_speed, OCT);
  Serial.print(" move_B: ");
  Serial.print(right_motor_speed, OCT);
  Serial.print(" error: ");
  Serial.print(error, OCT);
  Serial.print(" P: ");
  Serial.print(Kp, OCT);
  Serial.print(" PID_value: ");
  Serial.print(PID_value, OCT);
  Serial.println();
} 

附加:不含PID的代码

#define leftA_PIN 5
#define leftB_PIN 6
#define righA_PIN 9
#define righB_PIN 10

#define leftA_track_PIN 3
#define leftB_track_PIN 4
#define middle_track_PIN 12
#define righA_track_PIN 7
#define righB_track_PIN 13

void motor_pinint( );                               //引脚初始化
void _stop();                                       //停车
void forward();  
void turnSRight();                                 //小右转
void turnSLeft();                                  //小左转
void turnRight();                                  //右转
void turnLeft();                                   //左转
void nine(); 
void ten() ;
int error = 0;
int sensor[5] = {0, 0, 0, 0, 0};                    //5个传感器数值的数组 
int read_sensor_values(void);                      //读取初值 

void setup() {
  Serial.begin(9600); //串口波特率9600(PC端使用)
  track_pinint( );    //循迹引脚初始化
  motor_pinint();     //电机引脚初始化
}

void loop() {
  static int b=0;
  b=read_sensor_values();         //循迹小车
  switch (b){              //读取初值  
     case 0:  forward(); Serial.println(1); break; //直行
     case -1: turnSRight();Serial.println(2); break; //小左
     case -2: turnRight();Serial.println(3);break; //大左 
     case 1:  turnSLeft(); Serial.println(4); break; //小右
     case 2:  turnLeft();Serial.println(5); break; //大右    
     case 3:  _stop();Serial.println(6); break; //停
//     case -3: turnLeft(); Serial.println(7);break; //大左
//     case 4:  forward();  Serial.println(9);break; //直行   
     case 5:   nine() ;  Serial.println(9);break; //右转90度
     case 6:    ten();   Serial.println(9);break; 
     default: _stop();Serial.println(8);break; 
  }

}

/*循迹模块引脚初始化*/
void track_pinint( )
{ 
  pinMode (leftA_track_PIN, INPUT); //设置引脚为输入引脚
  pinMode (leftB_track_PIN, INPUT); //设置引脚为输入引脚
  pinMode (middle_track_PIN, INPUT);//设置引脚为输入引脚
  pinMode (righA_track_PIN, INPUT); //设置引脚为输入引脚
  pinMode (righB_track_PIN, INPUT); //设置引脚为输入引脚
}

/*电机引脚初始化*/
void motor_pinint( )
{
  pinMode (leftA_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (leftB_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (righA_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (righB_PIN, OUTPUT); //设置引脚为输出引脚
  }

/**************************************************
stop子函数—停止子函数
函数功能:控制车停止
**************************************************/
void _stop()
{
   analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,0);         //左轮静止不动
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,0);         //右轮静止不动
}
int read_sensor_values()
{
  sensor[0] = digitalRead(leftA_track_PIN);
  sensor[1] = digitalRead(leftB_track_PIN);
  sensor[2] = digitalRead(middle_track_PIN);
  sensor[3] = digitalRead(righA_track_PIN);
  sensor[4] = digitalRead(righB_track_PIN);
  //1为遇到黑线
//   if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 1)) {
//      error = 2;//          00001
//    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 1) && (sensor[4] == 0)) {
//      error = 1;//          00010
//    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 1) && (sensor[3] == 0) && (sensor[4] == 0)) {
//      error = 0;//          00100
//    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 0)) {
//      error = -1;//         01000
//    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 1) && (sensor[3] == 0) && (sensor[4] == 0)) {
//      error = -1;//         01100
//    }  else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 1) && (sensor[3] == 1) && (sensor[4] == 0)) {
//      error = 1;//          00110
//    } else if ((sensor[0] == 1) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 0)) {
//      error = -2;//         10000
//    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0) && (sensor[4] == 0)) {
//      if (error == -2) {//  00000
//        error = 4;//-3;
//      }else{
//        error = 4;//3;
//      }
//    }
//    else error = -error;  
 //000-001-010-011-100-101-110-111
           if ((sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 0)) {
      error = 0;//          000  停
    } else if ((sensor[1] == 0) && (sensor[2] == 0) && (sensor[3] == 1)) {
      error = -2;//          001  右转
    } else if ((sensor[1] == 0) && (sensor[2] == 1) && (sensor[3] == 0)) {
      error = 0;//          010  直行
    } else if ((sensor[1] == 0) && (sensor[2] == 1) && (sensor[3] == 1)) {
      error = -1;//         011  右转
    } else if ((sensor[1] == 1) && (sensor[2] == 0) && (sensor[3] == 0)) {
      error = 2;//         100  左转
    }  else if ((sensor[1] == 1) && (sensor[2] == 1) && (sensor[3] == 0)) {
      error = 1;//         110  左转
    } else if ((sensor[1] == 1) && (sensor[2] == 1) && (sensor[3] == 1)) {
      error = 0;//          111  直行
    } /*else if ((sensor[1] == 1) && (sensor[2] == 0) && (sensor[3] == 1)) {
      error = 1;//          101
    }*/
    if (sensor[4] == 1)  error=5;
    if (sensor[0] == 1)  error=6;
    for(int i=1;i<4;i++)
    Serial.print(sensor[i]);
    Serial.println( );
    return error;
}
/********************** ****************************
forward子函数——前进子函数
函数功能:控制车前进
**************************************************/
 void forward()
{
  analogWrite(leftA_PIN,60);      
  analogWrite(leftB_PIN,0);         //左轮前进60
  analogWrite(righA_PIN,60);      
  analogWrite(righB_PIN,0);         //右轮前进
}
/**************************************************
turnLeft子函数——大左转子函数
函数功能:控制车大左转
**************************************************/
void turnLeft() 
{
  analogWrite(leftA_PIN,40);      
  analogWrite(leftB_PIN,0);         //左轮前进20
  analogWrite(righA_PIN,140);      
  analogWrite(righB_PIN,0);         //右轮前进70
}
/**************************************************
turnRight子函数——小右转子函数
函数功能:控制车大右转弯
**************************************************/
void turnRight()
{
  analogWrite(leftA_PIN,140);      
  analogWrite(leftB_PIN,0);         //左轮前进
  analogWrite(righA_PIN,40);      
  analogWrite(righB_PIN,0);         //右轮前进
}
/**************************************************
turnLeft子函数——大左转子函数
函数功能:控制车小左转
**************************************************/
void turnSLeft()
{
  analogWrite(leftA_PIN,60);      
  analogWrite(leftB_PIN,0);         //左轮前进20
  analogWrite(righA_PIN,110);      
  analogWrite(righB_PIN,0);         //右轮前进30
}
/**************************************************
turnRight子函数——小右转子函数
函数功能:控制车小右转弯
**************************************************/
void turnSRight()
{
  analogWrite(leftA_PIN,110);      
  analogWrite(leftB_PIN,0);         //左轮前进
  analogWrite(righA_PIN,60);      
  analogWrite(righB_PIN,0);         //右轮前进
}
void nine() 
{
  analogWrite(leftA_PIN,140);      
  analogWrite(leftB_PIN,0);         //左轮前进20
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,0);         //右轮前进70
}
void ten() 
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,0);         //左轮前进20
  analogWrite(righA_PIN,140);      
  analogWrite(righB_PIN,0);         //右轮前进70
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于arduino的循迹小车(含有PID算法) 的相关文章

  • linux命令之数据库操作

    五 数据库操作 1 mysql 重新启动 sudo etc init d mysql restart ps 看 etc mysql my conf 下的log的配置信息 一般在 var log mysql error log 2 mysql
  • Word删除单独页页眉与分节处理

    通常在word中处理页眉页脚时 xff0c 我们会发现一删全删 xff0c 一改全变的情况 xff0c 而网上方案往往难以解决且晦涩难懂 xff0c 因此 xff0c 将方法分享一下 xff0c 希望大家一看便懂 xff08 本文以遇到的三
  • Threat of Adversarial Attacks on Deep Learning in Computer Vision: A Survey 论文阅读笔记

    本文是论文的阅读笔记 Paper A Threat of Adversarial Attacks on Deep Learning in Computer Vision A Survey Author Naveed Akhtar cor n
  • ubuntu20.04安装skopeo

    文章目录 1 先安装好go环境2 配置环境3 安装skopeo3 1 安装依赖3 2 获取项目 xff0c 并进行编译3 3 构建文档3 4 安装3 5 验证 4 注意 1 先安装好go环境 如何安装go环境 xff0c 最好选择系统范围内
  • go get得到的东西不在$GOPATH中

    最近在ubuntu20 04上安装oci image tool xff0c 按照官方文档执行 xff0c 结果第一步就发现go get得到的东西找不到 xff0c 后来查阅了这篇博客 xff0c 发现了原因 xff0c 是因为开了gopro
  • 容器镜像加密-containerd imgcrypt实践

    最近在研究容器镜像加密 xff0c 发现国内对容器镜像这部分的博客好像不太多 xff0c 在看了一些人的博客后 xff0c 跟着他们的步骤进行了containerd imgcrypt的实践 xff0c 期间出现了一些错误 xff0c 决定记
  • ubuntu20.04安装howdy

    howdy是一款用于Linux系统的人脸识别身份验证系统 xff0c 可以看作是Windows中的Windows Hello的替代品 xff0c howdy在安装的过程中会去外网下载一些安装包 xff0c 所以前提条件是有访问外网的手段 h
  • zipimport.ZipImportError: can‘t decompress data; zlib not available

    在Ubuntu16 04上通过pyenv安装python3 6 8时出现以下错误 xff0c 记录一下 ubuntu 64 ubuntu pyenv span class token function install span 3 6 8
  • Ubuntu16.04安装zabbix4.0

    以下教程为Ubuntu16 04安装zabbix4 0 xff0c 需提前自己安装好Mysql数据库 其中第1 7点为主节点安装配置Zabbix server Zabbix agent Web前端 xff0c 第8点不用进行 xff1b 第
  • Ubuntu16.04搭建gitea1.14.1

    以下教程为在Ubuntu16 04上搭建gitea1 14 1 xff0c 同时附上官方教程链接 文章目录 1 数据库准备1 1 登录数据库1 2 创建gitea用户1 3 创建gitea数据库1 4 给gitea用户赋予数据库的权限1 5
  • ubuntu16.04搭建spice-html5用于配合KVM

    文章目录 0 配置需求1 启动spice客户端2 配置websockify3 配置spice html54 浏览器访问 0 配置需求 Firefox或Chrome浏览器 xff0c IE浏览器也可以 xff0c 但是效果不是太好 WebSo
  • python 数据挖掘中的数值计算

    一 环境安装 环境配置 xff1a OS xff1a Red Hat 4 4 7 11 查看命令 xff1a uname a xff1a 电脑以及操作系统的相关信息 cat proc version xff1a 正在运行的内核版本 cat
  • 银河麒麟下libguestfs-tools中virt工具无法使用情况

    银河麒麟下libguestfs tools中virt工具无法使用情况 问题描述 xff1a 在银河麒麟高级服务器版本V10下安装libguestfs tools工具包后 xff0c 使用virt xx等一系列命令都会出现以下错误 xff1a
  • ubuntu16.04搭建containerd

    本博客具体介绍在ubuntu16 04下安装containerd的过程 xff0c 有关ctr的命令都要有root权限才能运行 搭建过程 下载containerd安装包解压containerd安装包到根目录下启动containerd并设置开
  • KVM安装Windows11系列(一)

    本教程系列为KVM安装Windows11 xff0c 会分成两部分 xff0c 第一部分会跳过Windows11的硬件要求TPM和安全启动 xff0c 第二部分会安装TPM模拟器进行模拟 文章目录 软件环境下载Windows11镜像和驱动创
  • 容器技术对比(Docker/LXC/LXD/Multipass)

    DockerLXCLXDMultipass基本介绍为了打破 程序即应用 的观念 xff0c 通过镜像imges将作业系统核心除外 xff0c 运作应用程序所需的系统环境 xff0c 由下而上打包 xff0c 达到应用程序跨平台间的无缝接轨运
  • KVM虚拟机配置静态IP(一):Ubuntu16.04

    该系列文章为制作KVM虚拟机镜像的同时配置静态IP xff0c 为用户直接提供好固定IP xff0c 无需手动配置 系列文章目录 Ubuntu16 04Ubuntu18 04Centos6Centos7 文章目录 系列文章目录软件环境一 安
  • KVM虚拟机配置静态IP(二):Ubuntu18.04

    该系列文章为制作KVM虚拟机镜像的同时配置静态IP xff0c 为用户直接提供好固定IP xff0c 无需手动配置 系列文章目录 Ubuntu16 04Ubuntu18 04Centos6Centos7 文章目录 系列文章目录软件环境一 安
  • KVM虚拟机配置静态IP(三):Centos6

    该系列文章为制作KVM虚拟机镜像的同时配置静态IP xff0c 为用户直接提供好固定IP xff0c 无需手动配置 系列文章目录 Ubuntu16 04Ubuntu18 04Centos6Centos7 文章目录 系列文章目录软件环境一 安
  • KVM虚拟机配置静态IP(四):Centos7

    该系列文章为制作KVM虚拟机镜像的同时配置静态IP xff0c 为用户直接提供好固定IP xff0c 无需手动配置 系列文章目录 Ubuntu16 04Ubuntu18 04Centos6Centos7 文章目录 系列文章目录软件环境一 安

随机推荐

  • KVM下Ubuntu18.04打开设置注销问题

    问题描述 xff1a 在KVM中创建Ubuntu18 04 xff0c 打开系统设置 xff0c 发现直接注销 xff08 不是锁屏 xff0c 因为所有程序都退出 xff09 解决思路 在google上搜索发现大多数都是指向显卡问题 xf
  • cloud-init中NoCloud配置

    本文章主要记录cloud init工具中NoCloud数据源的使用方法 xff0c 可以搭配KVM镜像制作系列文章 xff0c 为用户定制操作系统 文章目录 NoCloud使用方法1 安装并初始化文件2 修改cloud init配置文件3
  • winform界面设计

    来自于以下两个地址 xff0c 为便于查阅 xff0c 所以全复制到了自己的BLOG xff1a http dotnet chinaitlab com VCNET 436373 html http www aspxboy com priva
  • cloud-init离线安装编程环境

    本博客主要介绍通过cloud init工具实现在Ubuntu16 04操作系统和KVM虚拟化技术下实现创建虚拟机同时离线安装编程环境 文章目录 1 准备离线安装包1 xff09 下载软件包2 xff09 创建放置软件包的磁盘3 xff09
  • openEuler22.03安装zabbix4.0

    以下教程为openEuler22 03安装zabbix4 0 xff0c 主要原因是openEuler官方和zabbix官方提供的提供的软件源中没有相关软件 xff0c 因此需要使用zabbix源码进行编译 xff0c 并且安装过程中会出现
  • 1.2 SingleThreadExecutor

    线程池工具类给我们提供了一些常见的线程池 xff0c 这篇来谈一谈SingleThreadExecutor线程池 使用方式 创建方式比较简单 xff0c 直接使用工具创建就ok xff0c Executors newSingleThread
  • pycharm终止代码运行时报错:进程已结束,退出代码137 (interrupted by signal 9: SIGKILL)

    在pycharm中调试代码 xff0c 终止时报错 xff1a 进程已结束 退出代码137 interrupted by signal 9 SIGKILL 网上查找时 xff0c 遇到这个问题的一般是训练网络时的内存不足 xff0c 进程被
  • 【多机多卡】mmsegmentation训练报错“RuntimeError: NCCL error in: /opt/pytorch/pytorch/torch/csrc/distributed/”

    多机多卡训练代码 xff1a 报错信息 xff1a RuntimeError NCCL error in opt pytorch pytorch torch csrc distributed c10d ProcessGroupNCCL cp
  • STM32F4工程--串口--配置一个发送函数(详细版)

    STM32F4工程 串口 配置一个发送函数 xff08 库函数 xff09 芯片 xff1a STM32F429IGT6 目录 一 初始化串口相关的参数 二 初始化串口IO口时钟等参数 三 函数声明 四 主函数 xff08 执行函数 xff
  • Ubuntu:NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver. 解决方法总结

    在Ubuntu上运行Cuda并行计算的渲染项目 xff08 Massively Parallel Rendering of Complex Closed Form Implicit Surfaces 论文代码GUI部分源码 xff09 xf
  • Ubuntu16.04下基于BUCK安装onos

    踩了很多坑 xff0c 其中很多错误也没整明白怎么回事 xff0c 实在搞不了就重装系统 xff0c 经过多次测试 xff0c 找到了一个合适的安装步骤安装ONNO 1 13 2 1 安装mininet 需要可以安装 xff09 此步骤安装
  • Ubuntu16.04安装中文输入法

    转载自 xff1a https jingyan baidu com article 86f4a73e8f534637d752695e html 这是基于Fcitx框架的 可以安装Google pinyin xff0c Sougou piny
  • 基于IDEA分析ONOS源码

    1 安装Java依赖 sudo apt get install software properties common y amp amp sudo add apt repository ppa webupd8team java y amp
  • ESP8266- 使用AT指令获取网络时间

    前言 xff1a 很早就考虑过用 ESP8266 获取网络时间 xff0c 以前都是用 ESP8266 刷机智云的 Gagent 固件 xff0c 但无奈现在手头的 ESP 01 的 Flash 只有 1M xff0c 实在无法胜任 经过在
  • 使用git在项目中的一些经验

    近期在使用gitLab管理项目 xff0c 在使用过程中遇到一些问题 xff0c 在此整理一下 git的基本配置在这里就不累赘了 xff0c 主要讲一下如何将项目托管到gitLab xff0c 并实现多人协作开发 尤其介绍一下如何解决冲突
  • Ubuntu安装ROS报错 sudo: rosdep:找不到命令

    安装ROS时初始化rosdep过程中 xff0c 执行到 xff1a sodu rosdep init 报错 xff1a sudo rosdep xff1a 找不到命令 原因 xff1a 没有安装python rosdep这个包 解决方法
  • C语言进阶 ~ 内存四区(栈、堆、全局、代码区)

    特别声明 xff1a 该部分是根据B站大佬 什么都想干好的视频学习而来 目录 1 1 数据类型本质分析 1 1 1 数据类型概念 1 1 2 数据类型的本质 1 1 3 数据类型的别名 1 1 4 数据类型之 void 1 2 变量的本质分
  • C语言进阶 ~ 一级指针与字符串

    目录 2 1 指针强化 2 2 一级指针 char 易错地方 2 2 1 对空字符串和非法字符串的判断 2 2 2 越界 2 2 3 指针的叠加会不断改变指针的方向 2 2 4 局部变量不要外传 2 2 5 函数内使用辅助变量的重要性 2
  • STC51从入门到精通(汇编)~~~ 第八讲:串行通信技术

    目录 8 1 80C51单片机串行通信技术的特点 8 2 串行通信基本知识 8 2 1 数据通信 8 2 2 串行通信的传输方式 8 2 3 异步通信和同步通信 8 3 串行接口的组成和特性 8 3 1 串行口的结构 8 3 2 串行口控制
  • 基于arduino的循迹小车(含有PID算法)

    循迹小车一般分为两方面 xff1a 一方面是简单的闭环赛道只有直道和弯道 xff0c 另一方面是毕设类型的包括一些元素 xff1a 90度弯道 十字道路 S形弯道等 1 CSDN下载 xff1a 含有PID xff1a https down