基于arduino的避障.跟随小车(带有魔术手)

       避障小车的制作方法大概有两种:一个是利用超声波制作,一个是光电开关(避障模块),而跟随小车便一个是利用超声波和光电开关配合制作,一个是光电开关(避障模块)制作。

        所以本篇博客,最终决定:用超声波模块制作避障、小车的避障部分;用5个光电开关制作跟随部分。

1、CSDN下载:

     ① 避障:https://download.csdn.net/download/qq_38351824/11107034

     ② 跟随:https://download.csdn.net/download/qq_38351824/11107197

     ③ 魔术手:https://download.csdn.net/download/qq_38351824/11107060

 

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

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

     ① 关注微信公众号:Tech云  

     ②

 

作者:sumjess


 

 

1、避障小车的制作

(1)伪代码部分:


主函数

{

    舵机摆正

    循环部分

    {   

        c如果超声波采集的数据<X

         {

             电机停转

             舵机左摆

             b如果超声波采集的数据<X  

              {

                  舵机右摆

                 a如果超声波采集的数据<X  

                 {

                    舵机摆正

                    倒车

                    }

                     aelse

                     {

                       舵机摆正

                       电机右转--->停下---->直行

                        }

                   baelse

                     {

                       舵机摆正

                       电机左转--->停下---->直行

                        }

                      }

           celse

           {

            电机直行

              }

       }

}


.(2)滤波部分(超声波滤波):算术平均滤波法

/*
A、名称:算术平均滤波法
B、方法:
    连续取N个采样值进行算术平均运算:
    N值较大时:信号平滑度较高,但灵敏度较低;
    N值较小时:信号平滑度较低,但灵敏度较高;
    N值的选取:一般流量,N=12;压力:N=4。
C、优点:
    适用于对一般具有随机干扰的信号进行滤波;
    这种信号的特点是有一个平均值,信号在某一数值范围附近上下波动。
D、缺点:
    对于测量速度较慢或要求数据计算速度较快的实时控制不适用;
    比较浪费RAM。
E、整理:sumjess  2018-07-01
*/
 
int Filter_Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 算术平均滤波法
#define FILTER_N 12
int Filter() {
  int i;
  int filter_sum = 0;
  for(i = 0; i < FILTER_N; i++) {
    filter_sum += Get_AD();
    delay(1);
  }
  return (int)(filter_sum / FILTER_N);
}

(3)舵机转向:

调节出中值和左右摆的值,写一个按键程序,每按一次旋转一定角度,便可轻易记录下各个位置的数据,操作简单,此处就不再赘述。

(4)电机接线方式如下:

https://jingyan.baidu.com/article/75ab0bcbcb5320d6864db2e4.html

(5)按照伪代码写程序:

 

#include <Servo.h>
#include <NewPing.h>


///目前使用的引脚: 4-5-6-9-10-12-13
//舵机设置//
Servo myservo;        // 创建车体转向(X轴)舵机对象
#define servo_pin 4   // 定义车体转向舵机信号线接口
/*int servopin = 7;    //定义舵机接口数字接口7
  void servopulse(int angle)//定义一个脉冲函数
  {
  int pulsewidth=(angle*11)+500;  //将角度转化为500-2480的脉宽值
  digitalWrite(servopin,HIGH);    //将舵机接口电平至高
  delayMicroseconds(pulsewidth);  //延时脉宽值的微秒数
  digitalWrite(servopin,LOW);     //将舵机接口电平至低
  delayMicroseconds(20000-pulsewidth);
  }*/
超声波设置//
//#define PING_PIN  12  // Arduino pin tied to both trigger and echo pins on the ultrasonic sensor.
#define MAX_DISTANCE 450 // 设置最大距离(厘米)。最大传感器距离为400-500cm。
#define TRIG_PIN 12    //超声波引脚配置
#define ECHO_PIN 13    //超声波引脚配置
int Filter_Value;//滤波后的数值
int Filter();//用于滤波计算
int Get_ultra();//用于获取一个目前的超声波值
#define FILTER_N 10   //超声波均值滤波(去多少次做平均数)
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE); // 调整引脚和最大距离
电机设置//
#define leftA_PIN 5
#define leftB_PIN 6
#define righA_PIN 9
#define righB_PIN 10

void motor_pinint(void);  //引脚初始化
void forward( );          //前进
void back( );             //后退
void turnLeft( );         //左转
void turnRight( );        //右转
void turnbackLeft( );     //左后
void turnbackRight( );    //右后
void turnLeftOrigin( );   //原地左
void turnRightOrigin( );  //原地右
void _stop();             //停车

void setup()
{

  Serial.begin(115200); //串口波特率115200(PC端使用)
  myservo.attach(servo_pin, 1000, 2500);    // min 默认1000,max 默认2500     1200  1800  2300
  myservo.writeMicroseconds(1200);          //摆正舵机
  pinMode(TRIG_PIN, OUTPUT);  // 要检测引脚上输入的脉冲宽度,需要先设置为输入状态
  pinMode(ECHO_PIN, INPUT);  // 要检测引脚上输入的脉冲宽度,需要先设置为输入状态
  motor_pinint();        //电机引脚初始化
}

void loop()
{
if(Filter()<20)//危险
{
  _stop();//电机停转
  myservo.writeMicroseconds(2300);//向左转舵机
  if(Filter()<20)//危险
  {
    myservo.writeMicroseconds(1200);//向右转舵机
    if(Filter()<20)//危险
    {
      myservo.writeMicroseconds(1800);//向中间舵机
      back( );             //后退
    }
    else
    {
      myservo.writeMicroseconds(1800);//向中间舵机
      turnRight( );        //右转
      delay(30);
      _stop();//电机停转
      forward( );          //前进
    }
  }
    else 
    {
      turnLeft( );        //左转
      delay(30);
      _stop();//电机停转
      forward( );          //前进
    }
   }
  else 
  {
    forward( );          //前进
  }
}


//  Filter_Value = Filter();       // 获得滤波器输出值
//  Serial.println(Filter_Value); // 串口输出
//  delay(50);
//  if((int)Filter_Value>100)
//  myservo.writeMicroseconds(1200);//向右转舵机
//  else if((50<(int)Filter_Value)&&((int)Filter_Value<100))
//  myservo.writeMicroseconds(2300);//向左转舵机
//  else if((0<(int)Filter_Value)&&((int)Filter_Value<49))
//  myservo.writeMicroseconds(1800);//向中间舵机


/*
A、名称:算术平均滤波法
B、方法:
    连续取N个采样值进行算术平均运算:
    N值较大时:信号平滑度较高,但灵敏度较低;
    N值较小时:信号平滑度较低,但灵敏度较高;
    N值的选取:一般流量,N=12;压力:N=4。
C、优点:
    适用于对一般具有随机干扰的信号进行滤波;
    这种信号的特点是有一个平均值,信号在某一数值范围附近上下波动。
D、缺点:
    对于测量速度较慢或要求数据计算速度较快的实时控制不适用;
    比较浪费RAM。
E、整理:sumjess  2018-07-01
*/
 
// 用于获得一个超声波的当前值
int Get_ultra() 
{
      // 产生一个10us的高脉冲去触发TrigPin
        digitalWrite(TRIG_PIN, LOW);
        delayMicroseconds(2);
        digitalWrite(TRIG_PIN, HIGH);
        delayMicroseconds(10);
        digitalWrite(TRIG_PIN, LOW);
    // 检测脉冲宽度,并计算出距离
        return pulseIn(ECHO_PIN, HIGH) / 58.00;
        
}
int Filter() 
{
  int i;
  int filter_sum = 0;
  for(i = 0; i < FILTER_N; i++) 
  {
    filter_sum += Get_ultra();
    delay(30);//超声波采集用一般为30ms间隔
  }
  return (int)(filter_sum / FILTER_N);
}


//电机引脚初始化
  void motor_pinint(void)
  {
  pinMode (leftA_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (leftB_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (righA_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (righB_PIN, OUTPUT); //设置引脚为输出引脚
  }
/**************************************************
forward子函数——前进子函数
函数功能:控制车前进
**************************************************/
 void forward( )
{
  analogWrite(leftA_PIN,120);      
  analogWrite(leftB_PIN,0);         //左轮前进
  analogWrite(righA_PIN,120);      
  analogWrite(righB_PIN,0);         //右轮前进
}

/**************************************************
back子函数——后退子函数
函数功能:控制车后退
**************************************************/
void back( )
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,120);        //左轮后退
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,120);        //右轮后退
}

/**************************************************
turnLeft子函数——左转子函数
函数功能:控制车左转
**************************************************/
void turnLeft( )
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,0);         //左轮静止不动
  analogWrite(righA_PIN,120);      
  analogWrite(righB_PIN,0);         //右轮前进
}

/**************************************************
turnbackLeft子函数——左后转弯子函数
函数功能:控制车左后转弯
**************************************************/
void turnbackLeft( )
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,0);         //左轮静止不动
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,120);         //右轮后退
}

/**************************************************
turnRight子函数——右后转弯转子函数
函数功能:控制车右后转弯
**************************************************/
void turnRight( )
{
  analogWrite(leftA_PIN,120);      
  analogWrite(leftB_PIN,0);         //左轮前进
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,0);         //右轮静止不动
}

/**************************************************
turnbackRight子函数——右转子函数
函数功能:控制车右转
**************************************************/
void turnbackRight( )
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,120);         //左轮后退
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,0);         //右轮静止不动
}

/**************************************************
turnLeftOrigin子函数——原地左转子函数
函数功能:控制车原地左转
**************************************************/
void turnLeftOrigin( )
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,120);        //左轮后退
  analogWrite(righA_PIN,120);      
  analogWrite(righB_PIN,0);         //右轮前进
}

/**************************************************
turnRightOrigin子函数——原地右转子函数
函数功能:控制车原地右转
**************************************************/
void turnRightOrigin( )
{
  analogWrite(leftA_PIN,120);      
  analogWrite(leftB_PIN,0);        //左轮前进
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,120);       //右轮后退
}

/**************************************************
stop子函数—停止子函数
函数功能:控制车停止
**************************************************/
void _stop()
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,0);         //左轮静止不动
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,0);         //右轮静止不动
}

2、跟随小车的制作

一、接线:

(1)电机接线:

 

四个逻辑通道从左到右(即IN1到IN4)分别接5、6、9、10

12v供电,5伏输出给arduino供电

注意:此处驱动一定要和arduino共地!!!否则无法传输数据。

输出A接左边电机,输出B做右边电机

(2)避障模块接线:

使用了三个该模块,分别在车的前左、前中、前右。如图:

引脚从左到右分别接的是11、8、2

二、书写代码:

下载下面的代码:

//电机使用:5-6-9-10
//避障模块使用:11--8--2
//              左 中 右

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

void motor_pinint();                               //电机引脚初始化 
void _stop();                                      //停车
void turnSRight();                                 //小右转
void turnSLeft();                                  //小左转
void turnRight();                                  //右转
void turnLeft();                                   //左转
void forward();                                    //前进
int error;                                         //中间变量
int sensor[4];                                     //存取三个传感器数据信息的数组
//****************循迹模块设置 ***************//
#define left_track_PIN   11
#define middle_track_PIN 8
#define righ_track_PIN   2
int read_sensor_values(void);                      //读取初值 
void track_pinint();                               //避障引脚初始化 

void setup()
{  
  motor_pinint();        //电机引脚初始化
}
void loop()
{
  switch (read_sensor_values()){              //读取初值  
     case 0: turnLeft(); break; 
     case 1: turnSLeft(); break; 
     case 2: forward();break; 
     case 3: _stop(); break; 
     case 4: turnSRight(); break; 
     case 5: turnRight(); break; 
     default: _stop();break; 
     
  }
}
/*循迹模块引脚初始化*/
void track_pinint()
{ 
  pinMode (left_track_PIN  , INPUT); //设置引脚为输入引脚
  pinMode (middle_track_PIN, INPUT); //设置引脚为输入引脚
  pinMode (righ_track_PIN  , INPUT); //设置引脚为输入引脚
}
/*电机引脚初始化*/
void motor_pinint(void)
{
  pinMode (leftA_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (leftB_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (righA_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (righB_PIN, OUTPUT); //设置引脚为输出引脚
  }
int read_sensor_values()
{
  sensor[0] = digitalRead(left_track_PIN);
  sensor[1] = digitalRead(middle_track_PIN);
  sensor[2] = digitalRead(righ_track_PIN);
    //0为检测到障碍
    if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 1)) {
      error = 0;//          001  大左转
    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 1)) {
      error = 1;//          011  小左转
    } else if ((sensor[0] == 1) && (sensor[1] == 1) && (sensor[2] == 1)) {
      error = 2;//          111  前进
    } else if ((sensor[0] == 0) && (sensor[1] == 1) && (sensor[2] == 0)) {
      error = 3;//          010  停止
    } else if ((sensor[0] == 1) && (sensor[1] == 1) && (sensor[2] == 0)) {
      error = 4;//          110  小右转
    } else if ((sensor[0] == 1) && (sensor[1] == 0) && (sensor[2] == 0)) {
       error = 5;//         100  大右转
    } else if ((sensor[0] == 0) && (sensor[1] == 0) && (sensor[2] == 0)) {
       error = 3;//         000  前进
    } else if ((sensor[0] == 1) && (sensor[1] == 0) && (sensor[2] == 1)) {
       error = 3;//         101  停止
    } else error = 3;//    error 停止
    return error;
}
/**************************************************
forward子函数——前进子函数
函数功能:控制车前进
**************************************************/
 void forward()
{
  analogWrite(leftA_PIN,120);      
  analogWrite(leftB_PIN,0);         //左轮前进
  analogWrite(righA_PIN,120);      
  analogWrite(righB_PIN,0);         //右轮前进
}
/**************************************************
turnLeft子函数——大左转子函数
函数功能:控制车大左转
**************************************************/
void turnLeft() 
{
  analogWrite(leftA_PIN,50);      
  analogWrite(leftB_PIN,0);         //左轮前进
  analogWrite(righA_PIN,120);      
  analogWrite(righB_PIN,0);         //右轮前进
}
/**************************************************
turnRight子函数——小右转子函数
函数功能:控制车大右转弯
**************************************************/
void turnRight()
{
  analogWrite(leftA_PIN,120);      
  analogWrite(leftB_PIN,0);         //左轮前进
  analogWrite(righA_PIN,50);      
  analogWrite(righB_PIN,0);         //右轮前进
}
/**************************************************
turnLeft子函数——大左转子函数
函数功能:控制车小左转
**************************************************/
void turnSLeft()
{
  analogWrite(leftA_PIN,90);      
  analogWrite(leftB_PIN,0);         //左轮前进
  analogWrite(righA_PIN,120);      
  analogWrite(righB_PIN,0);         //右轮前进
}
/**************************************************
turnRight子函数——小右转子函数
函数功能:控制车小右转弯
**************************************************/
void turnSRight()
{
  analogWrite(leftA_PIN,120);      
  analogWrite(leftB_PIN,0);         //左轮前进
  analogWrite(righA_PIN,90);      
  analogWrite(righB_PIN,0);         //右轮前进
}
/**************************************************
stop子函数—停止子函数
函数功能:控制车停止
**************************************************/
void _stop()
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,0);         //左轮静止不动
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,0);         //右轮静止不动
}

3、魔术手的制作

(1)逻辑部分:

只写了一个简单的,能前后走的,用了跟随小车的左右两边的那个两个避障模块

 

(2)按照逻辑部分部分程序(算法):

//电机使用:5-6-9-10
//避障模块使用:11----2
//              左  右
 
/************电机设置*************/
#define leftA_PIN 5
#define leftB_PIN 6
#define righA_PIN 9
#define righB_PIN 10
 
void motor_pinint();                               //电机引脚初始化 
void back(int a);
void forward(int a);
//****************循迹模块设置 ***************//
#define left_track_PIN   11
#define righ_track_PIN   2
void read_sensor_values(void);                      //读取初值 
void track_pinint();                               //避障引脚初始化 
int error;                                         //中间变量
int sensor[4];                                     //存取三个传感器数据信息的数组
 
void setup()
{
  motor_pinint();        //电机引脚初始化
}
void loop()
{
  read_sensor_values3();
}
/*循迹模块引脚初始化*/
void track_pinint()
{ 
  pinMode (left_track_PIN  , INPUT); //设置引脚为输入引脚
  pinMode (righ_track_PIN  , INPUT); //设置引脚为输入引脚
}
/*电机引脚初始化*/
void motor_pinint()
{
  pinMode (leftA_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (leftB_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (righA_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (righB_PIN, OUTPUT); //设置引脚为输出引脚
  }
void read_sensor_values3()
{
  sensor[0] = digitalRead(left_track_PIN);
  sensor[2] = digitalRead(righ_track_PIN);
  /*****左边远、右边近*****/
    if ( (sensor[0] == 1) && (sensor[2] == 1) || (sensor[0] == 0) && (sensor[2] == 1)) {
    forward(80);   //  前进   1 1/0 1
  } else if ( (sensor[0] == 0)  && (sensor[2] == 0) || (sensor[0] == 1)  && (sensor[2] == 0)) {
    back(80);      //  后退   0 0/1 0
  }
 }
 /**************************************************
forward子函数——前进子函数
函数功能:控制车前进
**************************************************/
 void forward(int a)
{
  analogWrite(leftA_PIN,a);      
  analogWrite(leftB_PIN,0);         //左轮前进
  analogWrite(righA_PIN,a);      
  analogWrite(righB_PIN,0);         //右轮前进
}
/**************************************************
forward子函数——后退子函数
函数功能:控制车后退
**************************************************/
 void back(int a)
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,a);         //左轮后退
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,a);         //右轮后退
}

 

 

如果大家在制作过程中有什么问题或者思路可以在下方留言和我一起交流噢!

如果发现本文有错误,也请在下方评论区指出,感激不尽!

评论 36
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值