【Arduino玩具】东张西望的避障车


简介

通过舵机的左右旋转来控制超声波模块的测量区域。障碍物出现时, 即探测到的距离小于10cm时,底盘会朝着远离障碍物的方向转动。


演示

【Arduino玩具】东张西望的避障车


BOM

Arduino UNO x 1
超声波测距模块(HC-SR04) x 1
舵机(SG 90) x 1
红色LED x 1
履带式底盘,含两个减速电机(Pololu Zumo) x 1
马达驱动版(Zumo Shield V1.3) x 1


接线

在这里插入图片描述


Arduino IDE 代码

舵机的操控使用了 ATmega328P 的 timer-2, 代码稍微复杂一些。因为马达驱动板的库文件 <ZumoShield.h> 使用的是 timer -1,会与 <Servo.h> 冲突。如果使用其它不需要库文件的马达驱动的话,代码会简单很多,例如 L298N。

/* 
Obstacle Avoidace 避障车
Last Edited: March.18th.2021 by Mun Kim(老金)
Contact: [email protected]
*/

#include <Wire.h>           
#include <ZumoShield.h>  //马达驱动板需要的库文件     
ZumoMotors motors;

#define Echo  2  //HC-SR04 Echo pin//超声波测距模块的“回声”引脚接 D2
#define Trig  3  //HC-SR04 Trig pin//超声波测距模块的“激发”引脚接 D3
#define SERVO 11 //Servo pin//舵机接 D11或 D3,因为要使用 timer-2
#define LED   5  //LED pin//LED接 D5


uint16_t volatile servoTime = 0;
uint16_t volatile servoHighTime = 3000; // Pulse width in units of 0.5us//高电平持续时间
 boolean volatile servoHigh = false;    

float distance;                         //distance measured by HC-SR04//超声波模块探测到的距离 

void setup(){
    
    
  Serial.begin(9600);
  pinMode(Trig, OUTPUT); pinMode(Echo, INPUT); pinMode(LED, OUTPUT);
  servoInit();
}
 
void loop(){
    
    
    //Drive Forward//前进*******************************************************************************************
    motors.setLeftSpeed(100);   motors.setRightSpeed(100); //0-25

    //Look Right//向右看*********************************************************************************************
    servoSetPosition(1000);                                      //Send 1000us pulses to servo//1000us的脉冲,转动舵机
    distance = MeasureDistance();                                //HC-SR04//超声波模块测距
    
    while (distance <10 ) {
    
                                          //turn left, till the obstacle is more than 10cm away
      motors.setLeftSpeed(-100); motors.setRightSpeed( 100);     //底盘向左转动,直到障碍物处于10cm开外                               
      digitalWrite(LED, HIGH);                                   
      distance = MeasureDistance();}
    
    digitalWrite(LED, LOW); 
    delay(700);                                                  //for stable HC-SR04 readings
                                                                 //700ms毫秒的延迟貌似会让超声波模块的读数稳定一些
   //Look Forward//向前看********************************************************************************************
   servoSetPosition(1500);  
    distance = MeasureDistance();
    while (distance <15) {
    
      
      motors.setLeftSpeed(-100);   motors.setRightSpeed( 100); 
      digitalWrite(LED, HIGH); 
      distance = MeasureDistance();}
      digitalWrite(LED, LOW); 
    delay(700);
    
    //Look Forward//向右看********************************************************************************************
    servoSetPosition(2000); 
      distance = MeasureDistance();
      while(distance <10) {
    
      
      motors.setLeftSpeed( 100);   motors.setRightSpeed(-100);
      digitalWrite(LED, HIGH);
      distance = MeasureDistance();}
      digitalWrite(LED, LOW); 
     delay(700);

    //Look Forward//向前看********************************************************************************************
     servoSetPosition(1500); 
    distance = MeasureDistance();
    while (distance <15 ) {
    
      
      motors.setLeftSpeed( 100);   motors.setRightSpeed(-100); 
      digitalWrite(LED, HIGH);
      distance = MeasureDistance();}
      digitalWrite(LED, LOW); 
    delay(700);
}

//Functions//函数****************************************************************************************************

float MeasureDistance(){
    
     //测距
     float d;
     digitalWrite(Trig, LOW);  delayMicroseconds(2);
     digitalWrite(Trig, HIGH); delayMicroseconds(10);
     digitalWrite(Trig, LOW);
     d = (pulseIn(Echo, HIGH) / 2) * 343/10000; //测距公式,"d" 的单位是 "cm"
     Serial.println(d);
     return d; } 

//在Timer 2 达到 OCR2A 并重置后启动ISR
ISR(TIMER2_COMPA_vect){
    
                   //Timer/Counter2 Compare Match A//中断向量
  servoTime += OCR2A + 1;
  static uint16_t highTimeCopy = 3000;
  static uint8_t interruptCount = 0;
  if(servoHigh){
    
    
    if(++interruptCount == 2){
    
    
      OCR2A = 255;}
    if(servoTime >= highTimeCopy){
    
      //Servo引脚处在高电平状态
      digitalWrite(SERVO, LOW);     //做一个下降沿
      servoHigh = false;
      interruptCount = 0;}
    } 
  else{
    
                                 //Servo引脚处在低电平状态
    if(servoTime >= 40000){
    
        
      highTimeCopy = servoHighTime;
      digitalWrite(SERVO, HIGH);    //做一个上升沿
      servoHigh = true; servoTime = 0; interruptCount = 0;
      OCR2A = ((highTimeCopy % 256) + 256)/2 - 1;}
  }
}
 
void servoInit(){
    
    
  digitalWrite(SERVO, LOW); pinMode(SERVO, OUTPUT);
  //开启CTC模式,Timer 2 会增加到 OCR2A 然后重置,造成中断
  TCCR2A = (1 << WGM21);
  TCCR2B = (1 << CS21);            //0.5us分辨率
  TCNT2 = 0; OCR2A = 255;          
  TIMSK2 |= (1 << OCIE2A);         // 开启 timer compare interrupt.
  sei();                           // 开启中断
}
 
void servoSetPosition(uint16_t highTimeMicroseconds){
    
    
  TIMSK2 &= ~(1 << OCIE2A);        // 关闭 timer compare interrupt.
  servoHighTime = highTimeMicroseconds * 2;
  TIMSK2 |= (1 << OCIE2A);         // 开启 timer compare interrupt.
}

参考

  1. 中断处理教程
  2. ATmega328P 数据手册
  3. Polulu Zumo 底盘,驱动版手册

猜你喜欢

转载自blog.csdn.net/robotixworkshop/article/details/115291738
今日推荐