1. 程式人生 > >Arduino小程式——超聲波避障遙控小車

Arduino小程式——超聲波避障遙控小車

之前偶然間瞭解到Arduino,腦子一熱果斷入手一套簡單的小車開發套件,後來由於忙些其他的東西,就把它丟在角落裡吃灰了……上個月正好表妹過生日,決定弄一弄也算準備一個誠意滿滿的小禮物了;這也是第一次接觸硬體程式設計,也算是個小挑戰。

由於只是入門級別的套件,像超聲波,舵機,直流電機等配件的程式碼都是現成的,只需要配置開發環境,寫自己的小車執行邏輯就行了,忍不住吐槽一下黑心商家的配件,各種問題搞得開發過程中莫名其妙的被坑……

安裝好開發軟體,把開發板接入電腦就可以寫程式碼了,開發板接入電腦後先看看埠號:

然後開發軟體中記得選擇對應的埠,不然無法燒錄程式。

新建一個專案,發現自動生成2個函式:

void setup()函式是初始化函式,裡面的語句只會執行一次,一般用來設定硬體的引腳;void loop()函式是程式執行函式,裡面的語句會重複執行(有點類似createjs的Ticker類),下面貼一個簡單LED燈閃爍程式碼。

void setup(){
  pinMode(11, OUTPUT); //將11號引腳上拉輸出
}

void loop(){
  digitalWrite(11,HIGH); //設定11號引腳位高電平
  delay(1000);
  digitalWrite(11,LOW); //設定11號引腳為低電平
  delay(1000); // 閃爍時間間隔為1S
}

寫完程式碼需要先編譯再燒錄到開發板裡才能看到效果,有些複雜的配件需要監控返回值,比如超聲波要看返回檢測到障礙物的距離,紅外遙控要看返回按鍵的鍵值,這就要用到串列埠監視器了;寫好程式碼,每次按下紅外遙控器,串列埠監視器會返回鍵值:

Serial.print(results.value);//返回當前按鍵值

注意串列埠監視器下面的波特率要和我們設定的一致。

Serial.begin(9600);

使用自帶的開發介面寫程式碼很不習慣,可以在首選項裡設定使用外部編輯器,這樣軟體會把開發頁面鎖死,只能通過其他編輯器寫程式碼了,這裡我用sublime text(語言選擇C++程式碼才會高亮顯示)。

下面貼個全部原始碼,留個備份:

#include <Servo.h>
#include <IRremote.h>

long control;
boolean car_automatic_move = false;
boolean car_trajectory = false;

//紅外避障模組
// long SL;
//紅外接收模組
int RECV_PIN = 11;//管腳
//舵機
int servopin = 10;

IRrecv irrecv(RECV_PIN);
decode_results results;

long unsigned  int return_decode() {
  if (irrecv.decode(&results)) {
    irrecv.resume();
    Serial.print(results.value);//返回當前按鍵值
    return results.value;
  }
  else
  {
    return 0;
    irrecv.resume();
  }
}

void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT);
  pinMode(4, INPUT);
  pinMode(7, INPUT);
  pinMode(8, INPUT);
  pinMode(A0, INPUT);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  irrecv.enableIRIn();//初始化紅外遙控
}

void loop() {
  // SL = digitalRead(A0);//左避障管腳

  // if (car_automatic_move && SL == 0) {//左避障觸發
  //   car_forward();
  // }

  control = return_decode();
  if (control == 16712445) {//前進
    car_forward();
    delay(500);
    car_stop();

  } else if (control == 16720605) {//後退
    car_back();
    delay(500);
    car_stop();
  } else if (control == 16769055) {// -
    car_left();
    delay(150);
    car_stop();
  } else if (control == 16754775) {// +
    car_right();
    delay(150);
    car_stop();
  } else if (control == 16761405) {//暫停
    car_stop();
    car_automatic_move = false;
  } else if (control == 16748655) {//EQ
    car_automatic_move = true;
  } else if (control == 16750695) {//100+
  } else if (control == 16756815) {//200+
  } else if (control == 16738455) {//0 原地打轉
    car_left();
  } else if (control == 16753245) {//CH-
    servopulse(servopin, 180);
  } else if (control == 16769565) {//CH+
    servopulse(servopin, 0);
  } else if (control == 16736925) {//CH
    servopulse(servopin, 65);
  }
  // car_line();
  car_automatic();
}


void car_forward() {//前進
  analogWrite(3, 0);
  analogWrite(5, 255);
  analogWrite(6, 255);
  analogWrite(9, 0);
}
void car_back() {//後退
  analogWrite(3, 255);
  analogWrite(5, 0);
  analogWrite(6, 0);
  analogWrite(9, 255);
}
void car_stop() {//停車
  analogWrite(3, 0);
  analogWrite(5, 0);
  analogWrite(6, 0);
  analogWrite(9, 0);
}
void car_left() {//左轉
  analogWrite(3, 255);
  analogWrite(5, 0);
  analogWrite(6, 255);
  analogWrite(9, 0);
}
void car_right() {//右轉
  analogWrite(3, 0);
  analogWrite(5, 255);
  analogWrite(6, 0);
  analogWrite(9, 255);
}
void car_line() {//紅外循跡
  if (car_trajectory) {
    if (digitalRead(4)) {//左探頭
      Serial.print("left");
    }
    if (digitalRead(2)) {//右探頭
      Serial.print("right");
    }
  }
}


long speedF;
long speedL;
long speedR;
// 超聲波檢測距離
int ardublockUltrasonicSensorCodeAutoGeneratedReturnCM(int trigPin, int echoPin) {
  long duration;
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(20);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  duration = duration / 59;
  return duration;
}
//定義一個脈衝函式
void servopulse(int servopin, int myangle) {
  int  pulsewidth, count;
  for (count = 0; count < 25; count++)
  {
    pulsewidth = (myangle * 11) + 500; //將角度轉化為500-2480的脈寬值
    digitalWrite(servopin, HIGH); //將舵機介面電平至高
    delayMicroseconds(pulsewidth);//延時脈寬值的微秒數
    digitalWrite(servopin, LOW); //將舵機介面電平至低
    delay(20 - pulsewidth / 1000);
  }
}
// 測量前方距離
int range_F() {
  speedF = ardublockUltrasonicSensorCodeAutoGeneratedReturnCM(7, 8) ;
  Serial.print("speedF:");
  Serial.println(speedF);
  return speedF;
}

// 自動行駛
void car_automatic() {
  if (car_automatic_move) {
    car_forward();
    if (range_F() <= 18) {
      car_stop();
      car_automatic_move = false;
      delay(300);
      servopulse(servopin, 20);
      if (range_F() > 18) { //檢測右方距離
        servopulse(servopin, 65);
        car_right();
        delay(120);
        car_automatic_move = true;
      } else if (range_F() <= 18) { //檢測右方距離
        delay(300);
        servopulse(servopin, 110);
        if (range_F() > 18) { //檢測左方距離
          servopulse(servopin, 65);
          car_left();
          delay(120);
          car_automatic_move = true;
        } else if (range_F() <= 18) { //檢測左方距離
          car_back();
          servopulse(servopin, 65);
          delay(120);
          car_right();
          delay(120);
          car_automatic_move = true;
        }
      }
    }
  }
}

本來要寫紅外避障模組的,可惜有一個紅外避障配件是壞的,而且紅外感應器“怕太陽光”,即使沒有直接被陽光直射到,白天在室內也可能被太陽熱輻射影響到紅外訊號,避障變成“智障”……一個直流電機也有問題,只有設定電流引數255才會工作,所以無法調整小車的行駛速度,再次吐槽一下黑心商家……