Arduino 初识+项目

目录

Arduino初识

电路的基本知识

基于此就可以做一些有趣的小玩意:

第一个大坑——串口通信:

项目:基于Arduino板控制小车

几大问题:

1⃣️控制电机转动:

2⃣️麦轮的安装:

3⃣️电路连接:

4⃣️使用PWM调速:

5⃣️优化小车行驶的平稳性(PID):

6⃣️为小车增加无线模块进行控制:



​​​​​​​

Arduino初识

来自官方:

Arduino程序main函数结构解析

#include <Arduino.h>

// Declared weak in Arduino.h to allow user redefinitions.
int atexit(void (* /*func*/ )()) { return 0; }

// Weak empty variant initialization function.
// May be redefined by variant files.
void initVariant() __attribute__((weak));
void initVariant() { }

void setupUSB() __attribute__((weak));
void setupUSB() { }

int main(void)
{
    init();

    initVariant();

#if defined(USBCON)
    USBDevice.attach();
#endif

    setup();

    for (;;) {
        loop();
        if (serialEventRun) serialEventRun();
    }

    return 0;
}

从官方的开发文档中,我看到了我们写在Arduion的代码是如何被实现的。

setup函数中的语句只会执行一次,因为loop函数被放进了for循环里面(且没有终止条件),由此loop函数一直循环。

电路的基本知识

        在高中物理中学过,电路从正极出发回到负极。其实当我们输入了解之后我们知道,要让一个 灯💡亮起来的条件是有电压差。比如说,我们给灯泡💡左端4V电压,右端给2V电压,这时候由于两端的电压差为2V,由此灯泡💡会亮。但是当灯泡💡两端的电压都为4V时,由于没有电压差,灯泡💡就不会亮。

因此就很容易理解Arduino中

int ledpin=13;
digitalWrite(ledpin,HIGH);
digitalWrite(ledpin-1,LOW);

这段代码就将13号引脚变成了高电位,12号引脚是低电位,这时候接上灯泡💡就会亮起来。(为保护电路,不要直接接💡,要接一个电阻,Arduino的HIGH是5V)。

基于此就可以做一些有趣的小玩意:

1⃣️使用analogWrite函数和支持PWM的引脚,实现灯的亮度渐变。

/*
Fading
通过analogWrite() 函数实现呼吸灯效果
*/

int ledPin = 9;    // LED连接在9号引脚上

void setup()  { 
  // Setup部分不进行任何处理
} 

void loop()  { 
  // 从暗到亮,以每次加5的形式逐渐亮起来
  for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
    // 输出PWM
    analogWrite(ledPin, fadeValue);         
    // 等待30ms,以便观察到渐变效果
    delay(30);                            
  } 

  // 从亮到暗,以每次减5的形式逐渐暗下来
  for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) { 
    // 输出PWM
    analogWrite(ledPin, fadeValue);         
    // 等待30ms,以便观察到渐变效果
    delay(30);                            
  } 
}

2⃣️使用analogRead函数和开关,通过读取引脚的输入,进而控制灯灯亮灭。​​​​​​​

3⃣️使用光敏电阻感受光的亮度,实现灯的控制。

4⃣️使用RGB灯通过控制不同引脚的输出,实现不同颜色灯灯切换。

第一个大坑——串口通信:

为实现两块Arduino板之间的信息发送我们需要去了解串口通信的知识。

首先我们接触串口通信的时候,使用的是1,2引脚(既TX,RX)

因此我们遇到了第一个问题:无法上传程序。在TX,RX被占用时是无法上传程序的,必须拔掉再上传。

第二个问题:无法通信。因为电脑和Arduino板的通信 和 Arduino之间的通信相占,因此导致无法通信。

由此我们找到了使用软件串口的方式,使用方法也算比较简单,引用库函数include<SoftwareSerial.h>后基本问题就不大了。

我们初学Arduino的时候就遇到这个就确实卡住了很久很久很久!!!

/*
 * arduino uno端程序
 * 串口使用情况
 serial -----computer
 serial1----- nano softwearserial
 */
 #include<SoftwareSerial.h>
 SoftwareSerial softSerial(6,5);
 
void setup() {
  //初始化serial,该串口用于与计算机连接通信:
  Serial.begin(9600);
  //初始化serial1,该串口用于与设备B连接通信;
  softSerial.begin(9600);
  softSerial.listen();
}
//两个字符串分别用于存储A,B两端传来的数据
String device_A_String="";
String device_B_String="";
 
void loop() {
  // 读取从计算机传入的数据,并通过softSerial发送个设备B:
  if(Serial.available()>0)
  {
    if(Serial.peek()!='\n')
    {
      device_A_String+=(char)Serial.read();
     
    }
    else
    {
      Serial.read();
      Serial.print("you said:");
      Serial.println(device_A_String);
      softSerial.println(device_A_String);
      device_A_String="";
     
    }
  }
  //读取从设备B传入的数据,并在串口监视器中显示
  if(softSerial.available()>0)
  {
    if(softSerial.peek()!='\n')
    {
      device_B_String+=(char)softSerial.read();
    }
    else
    {
      softSerial.read();
      Serial.print("device B said:");
      Serial.println(device_B_String);
      device_B_String="";
    }
  }
}




/*
 * arduino uno端程序
 * 串口使用情况
 serial -----computer
 serial1----- nano softwearserial
 */
 #include<SoftwareSerial.h>
 SoftwareSerial softSerial(3,2);
 
void setup() {
  //初始化serial,该串口用于与计算机连接通信:
  Serial.begin(9600);
  //初始化serial1,该串口用于与设备B连接通信;
  softSerial.begin(9600);
  softSerial.listen();
}
//两个字符串分别用于存储A,B两端传来的数据
String device_A_String="";
String device_B_String="";
 
void loop() {
  // 读取从计算机传入的数据,并通过softSerial发送个设备B:
  if(Serial.available()>0)
  {
    if(Serial.peek()!='\n')
    {
      device_A_String+=(char)Serial.read();
     
    }
    else
    {
      Serial.read();
      Serial.print("you said:");
      Serial.println(device_A_String);
      softSerial.println(device_A_String);
      device_A_String="";
     
    }
  }
  //读取从设备B传入的数据,并在串口监视器中显示
  if(softSerial.available()>0)
  {
    if(softSerial.peek()!='\n')
    {
      device_B_String+=(char)softSerial.read();
    }
    else
    {
      softSerial.read();
      Serial.print("device B said:");
      Serial.println(device_B_String);
      device_B_String="";
    }
  }
}

 

项目:基于Arduino板控制小车

几大问题:

1⃣️控制电机转动:

我们使用了L298N接入了Arduino板上的信号,再将L298N连接上了电机,一块L298N连接了两个电机,再通过电池给L298N供电,实现电机的基本转动。

2⃣️麦轮的安装:

麦轮——麦克纳姆轮,这是一种特殊的轮子。

比如说向前走的时候,普通的轮子会得到地面向前的摩擦力,从而向前。可是麦轮受到的摩擦力方向是斜向上。这样子的话,一对麦轮要想走直线,那么左右两个轮子就必须是左右方向(定为X方向)上的合力为零。这样子的话我们就会有两种麦轮(称为A,B),它们往前走的时候,受到的摩擦力方向分别是“东北”“西北”。这样子就能走直线了。

可为什么不直接用传统的轮子呢?

​​​​​​​

​​​​​​​图源:https://blog.csdn.net/weixin_36815313/article/details/108836458utm_source=app&app_version=4.20.0

由图可知,经过对四个轮子的方向进行控制,我们可以实现平移,原地旋转等传统轮子不能实现的功能,极大丰富了小车的灵活度。

3⃣️电路连接:

这是我们第二次加入了PID算法后的接线,由于Arduino UNO R3的接口不够,我们已经换成了Arduino mage2560.

其实这么复杂的接线我们也很头疼,板子和电池的固定也是一大问题,我们目前尝试通过面包板,简化我们的接线。同时由于电机的本身的线材不能直接的用在Arduino板上,我们自制了一种接线(忘记拍了,下次更新补)。也存在缺点,连接电机的时候稳定性不好,当然也还算不错,就是不能有100%的稳定性,我们目前计划通过改造原本线材达到目的。

4⃣️使用PWM调速:

PWM的使用需要支持PWM的引脚。

PWM就是在合适的信号频率下,通过一个周期里改变占空比的方式来改变输出的有效电压

占空比:
是一个脉冲周期内,高电平的时间与整个周期时间的比例

周期: 一个脉冲信号的时间         

1s内测周期次数等于频率

脉宽时间: 高电平时间

上图中 脉宽时间占总周期时间的比例,就是占空比

使用上还是比较简单的,通过digitalWrite函数,使用PWM对引脚输出0~255的PWM波(255时速度最大),进而实现速度对控制

5⃣️优化小车行驶的平稳性(PID):

这个就是我们遇到的最大的挑战了,由于平常四个电机的转动不能保证速度的一致,因此会导致走直线时就容易变成曲线。因此我们需要一种方式使得四个轮子的速度一致。

PID算法就提供了很好的途径,PID算法有增量式和位置式,我们这次选择的是增量式,位置式我们还没有了解。

//后左电机端口定义
#define MotorLpin1   35 //控制位3
#define MotorLpin2   37 //控制位4
#define MotorLpwm    3  //使能调速 ENB
#define MotorLcountA 18 //编码器A
 
//后右电机端口定义
#define MotorRpin1   31 //控制位1
#define MotorRpin2   33 //控制位2
#define MotorRpwm    2  //使能调速 ENA
#define MotorRcountA 19 //编码器A
 
//前左电机端口定义
#define MotorfLpin1   41 //控制位3
#define MotorfLpin2   43 //控制位4
#define MotorfLpwm    5  //使能调速 ENB
#define MotorfLcountA 20 //编码器Af
 
//前右电机端口定义
#define MotorfRpin1   45 //控制位3
#define MotorfRpin2   47 //控制位4
#define MotorfRpwm    6  //使能调速 ENB
#define MotorfRcountA 21 //编码器Af
 
volatile float motorL=0;//中断变量,左轮子脉冲计数
volatile float motorfL=0;//中断变量,前左轮子脉冲计数
volatile float motorR=0;//中断变量,右轮子脉冲计数
volatile float motorfR=0;//中断变量,前右轮子脉冲计数
float V_L=0; //左轮速度 单位cm/s
float V_fL=0;
float V_R=0; //右边轮速 单位cm/s
float V_fR=0;
int v1=0;  //单位cm/s
int v2=0;  //单位cm/s
int vf1=0;
int vf2=0;
float Target_V_L=50,Target_V_R=50;//单位cm/s
float Target_V_fL=50,Target_V_fR=50;
int Pwm_L=0,Pwm_R=0;  //左右轮PWM
int Pwm_fL=0,Pwm_fR=0;
 
 
//PID变量
float kp=10,ki=0,kd=4;  //PID参数
 
 
/**************************************
 * Arduino初始化函数
 * 
 *************************************/
void setup() {
   Motor_Init();//电机端口初始化
   Serial.begin(9600);//开启串口
}
 
 
 
/*********************************************************
 * 函数功能:增量式PI控制器(左轮)
 * 入口参数:当前速度(编码器测量值),目标速度
 * 返回 值:电机PWM 
 * 参考资料: 
 *    增量式离散PID公式:
 *                Pwm-=Kp*[e(k)-e(k-1)]+Ki*e(k)+Kd*[e(k)-2e(k-1)+e(k-2)]
 *                e(k):本次偏差
 *                e(k-1):上一次偏差
 *                e(k-2):上上次偏差
 *                Pwm:代表增量输出
 *    在速度闭环控制系统里面我们只使用PI控制,因此对PID公式可简化为:
 *                Pwm-=Kp*[e(k)-e(k-1)]+Ki*e(k)
 *                e(k):本次偏差
 *                e(k-1):上一次偏差
 *                Pwm:代表增量输出
 *                
 *    注意增量式PID先调I,再调P,最后再调D
 *********************************************************/
 int Incremental_Pi_L(int current_speed,int target_speed){
  static float pwm,bias,last_bias,prev_bias;  //静态变量存在程序全周期:pwm:增量输出,bias:本次偏差,last_bias:上次偏差,prev_bais_:上上次偏差
  bias=current_speed-target_speed;    //计算本次偏差e(k)
  pwm-=(kp*(bias-last_bias)+ki*bias+kd*(bias-2*last_bias+prev_bias));   //增量式PID控制器
  prev_bias=last_bias;  //保存上上次偏差
  last_bias=bias;     //保存上一次偏差
 
 
 
  //PWM 限幅度  Arduino的PWM 最高为255  限制在250
  if(pwm<-250){
    pwm=250;     
  }
  if(pwm>250){
    pwm=250;  
  }
  //Serial.println(pwm);
  return pwm;         //增量输出
 }
 
 
//右轮速度增量式PID控制器
int Incremental_Pi_R(float current_speed,float target_speed){
  static float pwm,bias,last_bias,prev_bias;  //静态变量存在程序全周期:pwm:增量输出,bias:本次偏差,last_bias:上次偏差,prev_bais_:上上次偏差
  bias=current_speed-target_speed;    //计算本次偏差e(k)
  pwm-=(kp*(bias-last_bias)+ki*bias+kd*(bias-2*last_bias+prev_bias));   //增量式PID控制器
  prev_bias=last_bias;  //保存上上次偏差
  last_bias=bias;     //保存上一次偏差
 
  //PWM 限幅度  Arduino的PWM 最高为255限制在250
  if(pwm<-250){
    pwm=250;     
  }
  if(pwm>250){
    pwm=250;  
  }
  //Serial.println(pwm);
  return pwm;         //增量输出
 }
 
 int Incremental_Pi_fL(int current_speed,int target_speed){
  static float pwm,bias,last_bias,prev_bias;  //静态变量存在程序全周期:pwm:增量输出,bias:本次偏差,last_bias:上次偏差,prev_bais_:上上次偏差
  bias=current_speed-target_speed;    //计算本次偏差e(k)
  pwm-=(kp*(bias-last_bias)+ki*bias+kd*(bias-2*last_bias+prev_bias));   //增量式PID控制器
  prev_bias=last_bias;  //保存上上次偏差
  last_bias=bias;     //保存上一次偏差
 
 
 
  //PWM 限幅度  Arduino的PWM 最高为255  限制在250
  if(pwm<-250){
    pwm=250;     
  }
  if(pwm>250){
    pwm=250;  
  }
  //Serial.println(pwm);
  return pwm;         //增量输出
 }
 
 int Incremental_Pi_fR(int current_speed,int target_speed){
  static float pwm,bias,last_bias,prev_bias;  //静态变量存在程序全周期:pwm:增量输出,bias:本次偏差,last_bias:上次偏差,prev_bais_:上上次偏差
  bias=current_speed-target_speed;    //计算本次偏差e(k)
  pwm-=(kp*(bias-last_bias)+ki*bias+kd*(bias-2*last_bias+prev_bias));   //增量式PID控制器
  prev_bias=last_bias;  //保存上上次偏差
  last_bias=bias;     //保存上一次偏差
 
 
 
  //PWM 限幅度  Arduino的PWM 最高为255  限制在250
  if(pwm<-250){
    pwm=250;     
  }
  if(pwm>250){
    pwm=250;  
  }
  //Serial.println(pwm);
  return pwm;         //增量输出
 }
 
 
 
/**************************************************************************(测试完成)
  函数功能:设置双轮工作模式和运动速度
  入口参数:工作模式,左右轮pwm
  返回  值:无
**************************************************************************/
void Set_Pwm(int mode,int speed_L,int speed_R){
 
  if(mode==1){
  //前进模式
  //左电机
  digitalWrite(MotorLpin1,LOW);
  digitalWrite(MotorLpin2,HIGH);
  analogWrite(MotorLpwm,speed_L);
  
  //右电机
  digitalWrite(MotorRpin1,HIGH);
  digitalWrite(MotorRpin2,LOW);
  analogWrite(MotorRpwm,speed_R);
  
  }else if(mode==2){
  //后退模式
  //左电机
  digitalWrite(MotorLpin1,HIGH);
  digitalWrite(MotorLpin2,LOW);
  analogWrite(MotorLpwm,speed_L);
  
  //右电机
  digitalWrite(MotorRpin1,LOW);
  digitalWrite(MotorRpin2,HIGH);
  analogWrite(MotorRpwm,speed_R);
  }else if(mode==3){
  //左转模式
  //左电机
  digitalWrite(MotorLpin1,HIGH);
  digitalWrite(MotorLpin2,LOW);
  analogWrite(MotorLpwm,speed_L);
  
  //右电机
  digitalWrite(MotorRpin1,HIGH);
  digitalWrite(MotorRpin2,LOW);
  analogWrite(MotorRpwm,speed_R);
  
  }else if(mode==4){
  //右转模式
  //左电机
  digitalWrite(MotorLpin1,LOW);
  digitalWrite(MotorLpin2,HIGH);
  analogWrite(MotorLpwm,speed_L);
  
  //右电机
  digitalWrite(MotorRpin1,LOW);
  digitalWrite(MotorRpin2,HIGH);
  analogWrite(MotorRpwm,speed_R);
  
  }
}
 
void Setf_Pwm(int mode,int speed_fL,int speed_fR){
 
  if(mode==1){
  //前进模式
  //左电机
  digitalWrite(MotorfLpin1,LOW);
  digitalWrite(MotorfLpin2,HIGH);
  analogWrite(MotorfLpwm,speed_fL);
  
  //右电机
  digitalWrite(MotorfRpin1,HIGH);
  digitalWrite(MotorfRpin2,LOW);
  analogWrite(MotorfRpwm,speed_fR);
  
  }else if(mode==2){
  //后退模式
  //左电机
  digitalWrite(MotorfLpin1,HIGH);
  digitalWrite(MotorfLpin2,LOW);
  analogWrite(MotorfLpwm,speed_fL);
  
  //右电机
  digitalWrite(MotorfRpin1,LOW);
  digitalWrite(MotorfRpin2,HIGH);
  analogWrite(MotorfRpwm,speed_fR);
  }else if(mode==3){
  //左转模式
  //左电机
  digitalWrite(MotorfLpin1,HIGH);
  digitalWrite(MotorfLpin2,LOW);
  analogWrite(MotorfLpwm,speed_fL);
  
  //右电机
  digitalWrite(MotorfRpin1,HIGH);
  digitalWrite(MotorfRpin2,LOW);
  analogWrite(MotorfRpwm,speed_fR);
  
  }else if(mode==4){
  //右转模式
  //左电机
  digitalWrite(MotorfLpin1,LOW);
  digitalWrite(MotorfLpin2,HIGH);
  analogWrite(MotorfLpwm,speed_fL);
  
  //右电机
  digitalWrite(MotorfRpin1,LOW);
  digitalWrite(MotorfRpin2,HIGH);
  analogWrite(MotorfRpwm,speed_fR);
  
  }
}
 
 
 /**************************************************************************(测试完成)
  函数功能:电机端口初始化,控制芯片引脚拉低
  入口参数:无
  返回  值:无
**************************************************************************/
void Motor_Init(){
  //左电机
  pinMode(MotorLpin1,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorLpin2,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorLpwm,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(MotorLcountA,INPUT); //左轮编码器A引脚
  
  //右电机
  pinMode(MotorRpin1,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorRpin2,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorRpwm,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(MotorRcountA,INPUT); //右轮编码器A引脚
  
  //驱动芯片控制引脚全部拉低
  digitalWrite(MotorLpin1,LOW); //左电机
  digitalWrite(MotorLpin2,LOW);
  digitalWrite(MotorLpwm,LOW);
  digitalWrite(MotorRpin1,LOW); //右电机
  digitalWrite(MotorRpin2,LOW);
  digitalWrite(MotorRpwm,LOW);
 
  //左电机
  pinMode(MotorfLpin1,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorfLpin2,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorfLpwm,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(MotorfLcountA,INPUT); //左轮编码器A引脚
   
  //右电机
  pinMode(MotorfRpin1,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorfRpin2,OUTPUT);  //驱动芯片控制引脚
  pinMode(MotorfRpwm,OUTPUT);   //驱动芯片控制引脚,PWM调速
  pinMode(MotorfRcountA,INPUT); //右轮编码器A引脚
 
  //驱动芯片控制引脚全部拉低
  digitalWrite(MotorfLpin1,LOW); //左电机
  digitalWrite(MotorfLpin2,LOW);
  digitalWrite(MotorfLpwm,LOW);
  digitalWrite(MotorfRpin1,LOW); //右电机
  digitalWrite(MotorfRpin2,LOW);
  digitalWrite(MotorfRpwm,LOW);
}
 
 
 
/***********************************
 * 电机实际速度计算:
 * 公式:
 * 已知参数:
 *     车轮直径65mm,
 *     左边轮子一圈:390脉冲(RISING),
 *     右边轮子一圈:390脉冲(RISING),
 * 单位时间读两个轮子脉冲读取两个轮子脉冲
 ***********************************/
 void Read_Moto_V(){
  unsigned long nowtime=0;
  motorL=0;
  motorR=0;
  nowtime=millis()+50;//读50毫秒
  attachInterrupt(digitalPinToInterrupt(MotorLcountA),Read_Moto_L,RISING);//左轮脉冲开中断计数
  attachInterrupt(digitalPinToInterrupt(MotorfLcountA),Read_Moto_fL,RISING);//左轮脉冲开中断计数
  attachInterrupt(digitalPinToInterrupt(MotorRcountA),Read_Moto_R,RISING);//右轮脉冲开中断计数
  attachInterrupt(digitalPinToInterrupt(MotorfRcountA),Read_Moto_fR,RISING);//前右轮脉冲开中断计数
  while(millis()<nowtime); //达到50毫秒关闭中断
  detachInterrupt(digitalPinToInterrupt(MotorLcountA));//左轮脉冲关中断计数
  detachInterrupt(digitalPinToInterrupt(MotorfLcountA));//左轮脉冲关中断计数
  detachInterrupt(digitalPinToInterrupt(MotorRcountA));//右轮脉冲关中断计数
  detachInterrupt(digitalPinToInterrupt(MotorfRcountA));//右轮脉冲关中断计数
  V_L=((motorL/390)*6.5*PI)/0.05;   //单位cm/s
  V_fL=((motorfL/390)*6.5*PI)/0.05;   //单位cm/s
  V_R=((motorR/390)*6.5*PI)/0.05;   //单位cm/s
  V_fR=((motorfR/390)*6.5*PI)/0.05;   //单位cm/s
  v1=V_L;
  vf1=V_fL;
  v2=V_R;
  vf2=V_fR;
}
 
 
 
/***************************
 * 中断函数:读左轮脉冲
 *
 **************************/
void Read_Moto_L(){
  motorL++;
}
void Read_Moto_fL(){
  motorfL++;
}
 
 
 
/**************************
 * 中断函数:读右轮脉冲
 * 
 *************************/
void Read_Moto_R(){
  motorR++;
}
void Read_Moto_fR(){
  motorfR++;
}
 
 
 
/***************************************
 * Arduino主循环
 * 
 ***************************************/
void loop() {
  Read_Moto_V();//读取脉冲计算速度
  Pwm_L=Incremental_Pi_L(V_L,Target_V_L);//左轮PI运算
  Pwm_fL=Incremental_Pi_fL(V_fL,Target_V_fL);//前左轮PI运算
  Pwm_R=Incremental_Pi_R(V_R,Target_V_R);//右轮PI运算
  Pwm_fR=Incremental_Pi_fR(V_fR,Target_V_fR);//右轮PI运算
  Serial.print(V_L);//直接用串口绘图画出速度曲线
  Serial.print(",");
  Serial.print(V_R);//直接用串口绘图画出速度曲线
  Serial.print(",");
  Serial.print(V_fR);
  Serial.print(",");
  Serial.println(V_fL);
  Set_Pwm(1,Pwm_L,Pwm_R);  //设置左右轮速度
  Setf_Pwm(1,Pwm_fL,Pwm_fR);  //设置左右轮速度
}

由于我们对参数的调节还不是很熟练,以及一个编码器出现了问题,我们并没有完全实现利用PID算法控制小车的运动。而且可能因为机械误差的问题,我们的还不能实现轮子的速度都保持一致。我们预计这两天内会解决问题。

6⃣️为小车增加无线模块进行控制:

我们之前想实现对小车的无线控制,我们了解了几种方案:

1⃣️基于红外的遥控。

2⃣️:基于2.4G的JDY-40和蓝牙以及利用S-BUS传输的航模遥控器的控制。优点:控制距离长,受干扰小。缺点:配置时间长,难以驾驭!!!

基于此我们使用了红外的控制,其它的实现方式会在我们完成PID算法后再进行研究。

#include <IRremote.h>  // 使用IRRemote函数库
///选择///
#define choose 2    //1为通过串口打印码值模式  
                    //2为主函数运行模式
 
 
 
//-------------------------------------------------------------------//
//*******************************************************************//
///
//电机设置/
///
 
#define leftA_PIN 5
#define leftB_PIN 6
#define righA_PIN 9
#define righB_PIN 10
void motor_pinint( );     //引脚初始化
void forward( );          //前进
void back( );             //后退
void turnLeftOrigin( );   //原地左
void turnRightOrigin( );  //原地右
void turnRightforword( ); //右前
void turnLeftforword( );  //左前
void turnLeftback( );     //左后
void turnRightback( );    //右后
void _stop();             //停车
 
//-------------------------------------------------------------------//
//*******************************************************************//
///
//红外遥控/
///
 
const int irReceiverPin = 2;  // 红外接收器的 OUTPUT 引脚接在 PIN2 接口 定义irReceiverPin变量为PIN2接口
IRrecv irrecv(irReceiverPin); // 设置irReceiverPin定义的端口为红外信号接收端口
decode_results results;    // 定义results变量为红外结果存放位置
void rev(void); 
void scan(void);
 
//-------------------------------------------------------------------------//
 
void setup()
{
  Serial.begin(9600); //9600(PC端使用)
  motor_pinint();        //电机引脚初始化
  irrecv.enableIRIn();   // 启动红外解码
 
}
void loop()
{
  if(choose==1) scan();
  else if(choose==2) rev();  
}
 
/*电机引脚初始化*/
void motor_pinint( )
{
  pinMode (leftA_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (leftB_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (righA_PIN, OUTPUT); //设置引脚为输出引脚
  pinMode (righB_PIN, OUTPUT); //设置引脚为输出引脚
  }
/**************************************************
forward子函数——前进子函数
函数功能:控制车前进
**************************************************/
void forward( )
{
  analogWrite(leftA_PIN,180);      
  analogWrite(leftB_PIN,0);         //左轮前进
  analogWrite(righA_PIN,180);      
  analogWrite(righB_PIN,0);         //右轮前进
}
/**************************************************
back子函数——后退子函数
函数功能:控制车后退
**************************************************/
void back( )
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,180);        //左轮后退
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,180);        //右轮后退
}
/**************************************************
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);      //右轮后退
}
/**************************************************
turnRightforword子函数——右前运动子函数
函数功能:控制车右前
**************************************************/
void turnRightforword( )
{
  analogWrite(leftA_PIN,200);      
  analogWrite(leftB_PIN,0);        //左轮快前进
  analogWrite(righA_PIN,120);      
  analogWrite(righB_PIN,0);        //右轮慢前进
}
/**************************************************
turnLeftforword子函数——左前运动子函数
函数功能:控制车左前
**************************************************/
void turnLeftforword( )
{
  analogWrite(leftA_PIN,120);      
  analogWrite(leftB_PIN,0);       //左轮慢前进
  analogWrite(righA_PIN,200);      
  analogWrite(righB_PIN,0);       //右轮快前进
}
/**************************************************
turnRightforword子函数——右后运动子函数
函数功能:控制车右后
**************************************************/
void turnRightback( )
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,200);        //左轮快后退
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,120);        //右轮慢后退
}
/**************************************************
turnLeftforword子函数——左后运动子函数
函数功能:控制车左后
**************************************************/
void turnLeftback( )
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,120);        //左轮慢后退
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,200);        //右轮快后退
}
/**************************************************
stop子函数—停止子函数
函数功能:控制车停止
**************************************************/
void _stop()
{
  analogWrite(leftA_PIN,0);      
  analogWrite(leftB_PIN,0);         //左轮静止不动
  analogWrite(righA_PIN,0);      
  analogWrite(righB_PIN,0);         //右轮静止不动
}
 
void rev(void)
{
  if   (irrecv.decode(&results)) {   // 解码成功,把数据放入results.value变量中
  if   ((results.value==16718055)||(results.value==1033561079))
       {forward( )         ;delay(500);_stop();}//2前进
  else if((results.value==465573243)||(results.value==16730805)||(results.value==304335233)||(results.value==891929274)||(results.value==93040025))
       {back( )            ;delay(500);_stop();}//8后退
  else if((results.value==16724175)||(results.value==814588342)||(results.value==2534850111)||(results.value==16724175))
       {turnLeftforword( ) ;delay(500);_stop();}//1左前
  else if((results.value==16743045)||(results.value==1635910171)||(results.value==16743045))     
       {turnRightforword( );delay(500);_stop();}//3右前
  else if((results.value==1209942246)||(results.value==851901943)||(results.value==16728765)) 
       {turnLeftback( )    ;delay(500);_stop();}//7左后
  else if((results.value==16732845)||(results.value==1623741183))    
       {turnRightback( )   ;delay(500);_stop();}//9右后
  else if((results.value==2351064443)||(results.value==16716015)||(results.value==3640844469)||(results.value==3606423579))    
       {turnLeftOrigin( )   ;delay(250);_stop();}//4原地左转
  else if((results.value==16734885)||(results.value==71952287))    
       {turnRightOrigin( )   ;delay(250);_stop();}//6原地右转
    irrecv.resume();    // 继续等待接收下一组信号
  }if(results.value==0x16) 
  delay(600); //延时600毫秒,做一个简单的消抖
}
void scan(void)
{
 if (irrecv.decode(&results)) {   // 解码成功,把数据放入results变量中
    // 把数据输入到串口
    Serial.print("irCode: ");            
    Serial.print(results.value, DEC); // 显示红外编码
    Serial.print(",  bits: ");           
    Serial.println(results.bits); // 显示红外编码位数
    irrecv.resume();    // 继续等待接收下一组信号
  }if(results.value==0x16)
  digitalWrite(9, HIGH);  
  delay(600); //延时600毫秒,做一个简单的消抖
}

  • 6
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值