Arduino智能小车——调速篇

Arduino智能小车——调速篇

Arduino智能小车系列教程时空门:

  1. Arduino智能小车——拼装篇 点击跳转
  2. Arduino智能小车——测试篇 点击跳转
  3. Arduino智能小车——调速篇 点击跳转
  4. Arduino智能小车——超声波避障 点击跳转
  5. Arduino智能小车——蓝牙小车 点击跳转
  6. Arduino智能小车——循迹篇 点击跳转
  7. Arduino智能小车——小车测速 点击跳转

  在这一篇我们将对小车的行进速度进行调整,将驱动模块的作用发挥出来。首先大家要了解PWM这个概念。

PWM

  脉宽调制(PWM)基本原理:控制方式就是对逆变电路开关器件的通断进行控制,使输出端得到一系列幅值相等的脉冲,用这些脉冲来代替正弦波或所需要的波形。也就是在输出波形的半个周期中产生多个脉冲,使各脉冲的等值电压为正弦波形,所获得的输出平滑且低次谐波少。按一定的规则对各脉冲的宽度进行调制,即可改变逆变电路输出电压的大小,也可改变输出频率。

  通俗一点讲那,就是当如果我们想输出5V电压时,只需一直输出高电平即可;当我们想输出3.75V电压时,那我们就需要在一个周期内(一个高电平和一个低电平为一个周期)3.75÷5=75%时间输出高电平,25%时间输出低电平;同理,如果想输出2.5V电压时,我们需要在一个周期内50%时间输出高电平,50%时间输出低电平。

  Arduino UNO开发板上只有带有“~”表示的引脚才具有PWM功能,因此我们在控制驱动时可以使用这几个引脚。 ##驱动模块接线   在前面的[教程](http://blog.csdn.net/qq_16775293/article/details/77438499)中已经讲过如果想控制驱动的输出时,需要对驱动的“ENA”“ENB”进行控制,因此我们需要将图中被选中部分的两个跳线帽拔掉。并将“ENA”连接Arduino UNO开发板的“5”引脚,“ENB”连接“6”引脚。

代码测试

int leftCounter=0,  rightCounter=0;
unsigned long time = 0, old_time = 0; // 时间标记
unsigned long time1 = 0; // 时间标记
float lv,rv;//左、右轮速度

#define STOP        0
#define FORWARD     1
#define BACKWARD    2
#define TURNLEFT    3
#define TURNRIGHT   4
#define CHANGESPEED 5

int leftMotor1 = 16;
int leftMotor2 = 17;
int rightMotor1 = 18;
int rightMotor2 = 19;
bool speedLevel=0;

int leftPWM = 5;
int rightPWM = 6;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600); 
  attachInterrupt(0,RightCount_CallBack, FALLING);
  attachInterrupt(1,LeftCount_CallBack, FALLING);

  pinMode(leftMotor1, OUTPUT);
  pinMode(leftMotor2, OUTPUT);
  pinMode(rightMotor1, OUTPUT);
  pinMode(rightMotor2, OUTPUT);
  pinMode(leftPWM, OUTPUT);
  pinMode(rightPWM, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  SpeedDetection();
 
  if(Serial.available()>0)
  {
    char cmd = Serial.read();
    
    Serial.print(cmd);
    motorRun(cmd);
    if(speedLevel)  //根据不通的档位输出不同速度
    {
      analogWrite(leftPWM, 120);
      analogWrite(rightPWM, 120);
    }
    else
    {
      analogWrite(leftPWM, 250);
      analogWrite(rightPWM, 250);
    }
  }  
}
/*
 * *速度计算
 */
bool SpeedDetection()
{
  time = millis();//以毫秒为单位,计算当前时间 
  if(abs(time - old_time) >= 1000) // 如果计时时间已达1秒
  {  
    detachInterrupt(0); // 关闭外部中断0
    detachInterrupt(1); // 关闭外部中断1
    //把每一秒钟编码器码盘计得的脉冲数,换算为当前转速值
    //转速单位是每分钟多少转,即r/min。这个编码器码盘为20个空洞。
    Serial.print("left:");
    lv =(float)leftCounter*60/20;//小车车轮电机转速
    rv =(float)rightCounter*60/20;//小车车轮电机转速
    Serial.print("left:");
    Serial.print(lv);//向上位计算机上传左车轮电机当前转速的高、低字节
    Serial.print("     right:");
    Serial.println(rv);//向上位计算机上传左车轮电机当前转速的高、低字节
    //恢复到编码器测速的初始状态
    leftCounter = 0;   //把脉冲计数值清零,以便计算下一秒的脉冲计数
    rightCounter = 0;
    old_time=  millis();     // 记录每秒测速时的时间节点   
    attachInterrupt(0, RightCount_CallBack,FALLING); // 重新开放外部中断0
    attachInterrupt(1, LeftCount_CallBack,FALLING); // 重新开放外部中断0
    return 1;
  }
  else
    return 0;
}
/*
 * *右轮编码器中断服务函数
 */
void RightCount_CallBack()
{
  rightCounter++;
}
/*
 * *左轮编码器中断服务函数
 */
void LeftCount_CallBack()
{
  leftCounter++;
}
/*
 * *小车运动控制函数
 */
void motorRun(int cmd)
{
  switch(cmd){
    case FORWARD:
      Serial.println("FORWARD"); //输出状态
      digitalWrite(leftMotor1, HIGH);
      digitalWrite(leftMotor2, LOW);
      digitalWrite(rightMotor1, HIGH);
      digitalWrite(rightMotor2, LOW);
      break;
     case BACKWARD:
      Serial.println("BACKWARD"); //输出状态
      digitalWrite(leftMotor1, LOW);
      digitalWrite(leftMotor2, HIGH);
      digitalWrite(rightMotor1, LOW);
      digitalWrite(rightMotor2, HIGH);
      break;
     case TURNLEFT:
      Serial.println("TURN  LEFT"); //输出状态
      digitalWrite(leftMotor1, HIGH);
      digitalWrite(leftMotor2, LOW);
      digitalWrite(rightMotor1, LOW);
      digitalWrite(rightMotor2, HIGH);
      break;
     case TURNRIGHT:
      Serial.println("TURN  RIGHT"); //输出状态
      digitalWrite(leftMotor1, LOW);
      digitalWrite(leftMotor2, HIGH);
      digitalWrite(rightMotor1, HIGH);
      digitalWrite(rightMotor2, LOW);
      break;
     case CHANGESPEED:
      Serial.println("CHANGE SPEED"); //输出状态
      if(speedLevel)  //接收到换挡命令的时候切换档位
        speedLevel=0;
      else
        speedLevel=1;
      break;
     default:
      Serial.println("STOP"); //输出状态
      digitalWrite(leftMotor1, LOW);
      digitalWrite(leftMotor2, LOW);
      digitalWrite(rightMotor1, LOW);
      digitalWrite(rightMotor2, LOW);
  }
}

  由于之前设计不太合理,占用了太多的PWM引脚,因此在代码里对控制小车电机的引脚做了点小改动,如下所示

int leftMotor1 = 5;	
int leftMotor2 = 6;
int rightMotor1 = 7;
int rightMotor2 = 8;

现在改为

int leftMotor1 = 16;	
int leftMotor2 = 17;
int rightMotor1 = 18;
int rightMotor2 = 19;

改完代码大家记得要把对应的接线也改过来哦!!
在前面的宏定义中加入换挡的定义#define CHANGESPEED 5

#define STOP        0
#define FORWARD     1
#define BACKWARD    2
#define TURNLEFT    3
#define TURNRIGHT   4
#define CHANGESPEED 5

Arduion的PWM引脚需要和正常引脚一样,在void setup()函数中初始化为输出模式

pinMode(leftPWM, OUTPUT);
pinMode(rightPWM, OUTPUT);

在小车的控制状态函数void motorRun(int cmd)中添加多一个选择项,用来切换速度。

case CHANGESPEED:
      Serial.println("CHANGE SPEED"); //输出状态
      if(speedLevel)  //接收到换挡命令的时候切换档位
        speedLevel=0;
      else
        speedLevel=1;
      break;

在主函数void loop()中添加PWM输出的函数,analogWrite(pin, value)函数中“pin”代表使用的引脚,“value”代表输出PWM值的大小,范围是0~255。

if(speedLevel)  //根据不通的档位输出不同速度
    {
      analogWrite(leftPWM, 120);
      analogWrite(rightPWM, 120);
    }
    else
    {
      analogWrite(leftPWM, 250);
      analogWrite(rightPWM, 250);
    }

修改蓝牙串口助手

  在串口助手中,将“按键1”修改为“换挡”键,蓝牙串口助手的使用方法和使用详细的修改过程可以参考前面的《Arduino智能小车——蓝牙小车》教程,修改后效果如下:

结束语

  大家快连接蓝牙,测试下我们的变速小车吧。大家有兴趣的话可以使用蓝牙串口助手上面的滑动条来控制小车速度,不妨下去试试吧~

欢迎各位有兴趣的朋友加入Q群1:789127261点评、交流

  • 143
    点赞
  • 850
    收藏
    觉得还不错? 一键收藏
  • 76
    评论
以下是一个简单的循迹小车代码,其中包含了调速功能: ```C++ int leftMotor = 5; // 左电机引脚 int rightMotor = 6; // 右电机引脚 int leftSensor = 2; // 左循迹传感器引脚 int rightSensor = 3; // 右循迹传感器引脚 int speed = 100; // 初始速度 void setup() { pinMode(leftMotor, OUTPUT); pinMode(rightMotor, OUTPUT); pinMode(leftSensor, INPUT); pinMode(rightSensor, INPUT); } void loop() { // 如果左右均检测到黑线,直走 if (digitalRead(leftSensor) == LOW && digitalRead(rightSensor) == LOW) { analogWrite(leftMotor, speed); analogWrite(rightMotor, speed); } // 如果左边检测到黑线,向右转 else if (digitalRead(leftSensor) == LOW) { analogWrite(leftMotor, speed / 2); analogWrite(rightMotor, speed); } // 如果右边检测到黑线,向左转 else if (digitalRead(rightSensor) == LOW) { analogWrite(leftMotor, speed); analogWrite(rightMotor, speed / 2); } // 如果左右均未检测到黑线,停车 else { analogWrite(leftMotor, 0); analogWrite(rightMotor, 0); } } // 通过串口监视器调整速度 void serialEvent() { String input = Serial.readStringUntil('\n'); int newSpeed = input.toInt(); if (newSpeed > 0 && newSpeed <= 255) { speed = newSpeed; } } ``` 在上面的代码中,我们使用 `analogWrite()` 函数来控制电机的转速,而不是使用 `digitalWrite()` 函数,这样可以实现电机的调速功能。在 `setup()` 函数中,我们将左右电机和循迹传感器的引脚声明为输出和输入。在 `loop()` 函数中,我们使用 `digitalRead()` 函数来读取循迹传感器的值,根据传感器的值控制小车的运动方向和速度。最后,我们使用 `serialEvent()` 函数通过串口监视器来调整小车的速度,只需要将一个介于 0 到 255 之间的数字发送到串口,小车的速度就会相应地改变。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值