jquery

2019年3月30日 星期六

Arduino 自走車(智能小車)超音波偵測碰撞 改良無法走直線(2)

使用紅外線進行控制,進行了左右輪調速,並加入超音波碰撞偵測
拿廠商給的程式改的
超音波偵測感測器為 HC-SR04

//------------------------------------程式碼開始---------------------------------------------
#include //红外線函式庫
int RECV_PIN = A4;//宣告紅外線 PIN腳
IRrecv irrecv(RECV_PIN);  //創建一個紅外線
decode_results results;//這個用來解析你的紅外線是哪一牌
int on = 0;//标志位
unsigned long last = millis();

//底下為超音波偵測器的設定,超音波裝置有主要二個PIN腳,echo 和trig
int echo=7;
int trig=12;
int distance=0;    //用來記錄超音波裝置偵測到的距離
int dangerDistance=30;  //自訂危險距離,我設30, 也就是偵測到小於三十公分,自走車強制停止前進,避免撞牆
//-------------------

long run_car = 0x00FF629D;//按键CH
long back_car = 0x00FFA857;//按键+
long left_car = 0x00FF22DD;//按键<<
long right_car = 0x00FFC23D;//按键>||
long stop_car = 0x00FF02FD;//按键>>|
long left_turn = 0x00ffE01F;//按键-
long right_turn = 0x00FF906F;//按键EQ
//==============================
int Left_motor_go=8;     //左馬達前進(IN1)
int Left_motor_back=9;     //左馬達後退(IN2)

int Right_motor_go=10;    // 右馬達前進(IN3)
int Right_motor_back=11;    // 右馬達後退(IN4)

int runCount=0;

void setup()
{
  //初始化馬達的IO方式
  pinMode(Left_motor_go,OUTPUT); // PIN 8 (PWM)
  pinMode(Left_motor_back,OUTPUT); // PIN 9 (PWM)
  pinMode(Right_motor_go,OUTPUT);// PIN 10 (PWM)
  pinMode(Right_motor_back,OUTPUT);// PIN 11 (PWM)
  pinMode(13, OUTPUT);////端口模式,输出
   pinMode(trig, OUTPUT);
  pinMode(echo,INPUT);
  Serial.begin(9600);    //波特率9600
  irrecv.enableIRIn(); // Start the receiver
}

void Distance_test(){
  //底下為超音波測距離的標準寫法
  digitalWrite(trig,LOW);
  delayMicroseconds(2);
  digitalWrite(trig,HIGH);
  delayMicroseconds(10);  //最小為10,小於此值,偵測易失敗
  digitalWrite(trig, LOW);
  float Fdistance = pulseIn(echo, HIGH);  // 讀取返回時間(單位:微秒)
  Fdistance= Fdistance/58;       //除以58等於公分,  Y米=(X秒*344)/2
  // X秒=( 2*Y米)/344 ==》X秒=0.0058*Y米 ==》公分=微秒/58
  distance = Fdistance;
  }
void Distance_display(){
  Serial.print("Distance is: ");
  Serial.println(distance);
 
  }
void brake()         //停車
{
  digitalWrite(Right_motor_go,LOW);
  digitalWrite(Right_motor_back,LOW);
  digitalWrite(Left_motor_go,LOW);
  digitalWrite(Left_motor_back,LOW);
  runCount=0;
  //delay(time * 100);//執行時間,可以调整
}
 
void run()     // 前進
{
  
   if(runCount ==0){
   analogWrite(Right_motor_go,250);
   runCount=1;
   }else{
    digitalWrite(Right_motor_go,HIGH);
    }
  // digitalWrite(Right_motor_go,HIGH);  // 右馬達前進
   digitalWrite(Right_motor_back,LOW);   
  //analogWrite(Right_motor_go,200);//PWM比例0~255调速,如果左右輪不平均(例如無法走直線),可以改用此函數,調整值即可
  //analogWrite(Right_motor_back,0);
  digitalWrite(Left_motor_go,LOW);  // 左馬達前進
  digitalWrite(Left_motor_back,HIGH);

  //analogWrite(Left_motor_go,0);//PWM比例0~255调速,
  //analogWrite(Left_motor_back,200);
  //delay(time * 100);   //執行時間,可以调整
}



void left()         //左轉(左輪不動,右輪前進)
{
  digitalWrite(Right_motor_go,HIGH);    // 右馬達前進
  digitalWrite(Right_motor_back,LOW);
  //analogWrite(Right_motor_go,200);
  //analogWrite(Right_motor_back,0);//PWM比例0~255调速
  digitalWrite(Left_motor_go,LOW);   //左輪後退
  digitalWrite(Left_motor_back,LOW);
  //analogWrite(Left_motor_go,0);
  //analogWrite(Left_motor_back,0);//PWM比例0~255调速
  //delay(time * 100);    //執行時間,可以调整
}

void spin_left()         //左轉(左輪後退,右輪前進)
{
  digitalWrite(Right_motor_go,HIGH);    // 右馬達前進
  digitalWrite(Right_motor_back,LOW);
  //analogWrite(Right_motor_go,200);
  //analogWrite(Right_motor_back,0);//PWM比例0~255调速
  digitalWrite(Left_motor_go,HIGH);   //左輪後退
  digitalWrite(Left_motor_back,LOW);
  //analogWrite(Left_motor_go,200);
  //analogWrite(Left_motor_back,0);//PWM比例0~255调速
  //delay(time * 100);    //執行時間,可以调整
}

void right()        //右轉(右輪不动,左輪前進)
{
  digitalWrite(Right_motor_go,LOW);   //右电机後退
  digitalWrite(Right_motor_back,LOW);
  //analogWrite(Right_motor_go,0);
  //analogWrite(Right_motor_back,0);//PWM比例0~255调速
  digitalWrite(Left_motor_go,LOW);//左馬達前進
  digitalWrite(Left_motor_back,HIGH);
  //analogWrite(Left_motor_go,0);
 // analogWrite(Left_motor_back,200);//PWM比例0~255调速
 // delay(time * 100);    //執行時間,可以调整
}

void spin_right()        //右轉(右輪後退,左輪前進)
{
  digitalWrite(Right_motor_go,LOW);   //右电机後退
  digitalWrite(Right_motor_back,HIGH);
  //analogWrite(Right_motor_go,0);
  //analogWrite(Right_motor_back,200);//PWM比例0~255调速
  digitalWrite(Left_motor_go,LOW);//左馬達前進
  digitalWrite(Left_motor_back,HIGH);
  //analogWrite(Left_motor_go,0);
  //analogWrite(Left_motor_back,200);//PWM比例0~255调速
  //delay(time * 100);    //執行時間,可以调整
}

void back()          //後退
{
  digitalWrite(Right_motor_go,LOW);  //右輪後退
  digitalWrite(Right_motor_back,HIGH);
  //analogWrite(Right_motor_go,0);
  //analogWrite(Right_motor_back,150);//PWM比例0~255调速
  digitalWrite(Left_motor_go,HIGH);  //左輪後退
  digitalWrite(Left_motor_back,LOW);
  //analogWrite(Left_motor_go,150);
  //analogWrite(Left_motor_back,0);//PWM比例0~255调速
  //delay(time * 100);     //執行時間,可以调整  
}

void dump(decode_results *results)
{
  int count = results->rawlen;
  if (results->decode_type == UNKNOWN)
  {
    //Serial.println("Could not decode message");
    brake();
  }
//輸出你使用的遙控器的編碼,但此段程式會影響程式執行速度,除了測試之外建議註解掉
/*
  else
  {

    if (results->decode_type == NEC)
    {
      Serial.print("Decoded NEC: ");
    }
    else if (results->decode_type == SONY)
    {
      Serial.print("Decoded SONY: ");
    }
    else if (results->decode_type == RC5)
    {
      Serial.print("Decoded RC5: ");
    }
    else if (results->decode_type == RC6)
    {
      Serial.print("Decoded RC6: ");
    }
    Serial.print(results->value, HEX);
    Serial.print(" (");
    Serial.print(results->bits, DEC);
    Serial.println(" bits)");
  
  }
  Serial.print("Raw (");
  Serial.print(count, DEC);
  Serial.print("): ");

  for (int i = 0; i < count; i++)
  {
    if ((i % 2) == 1)
    {
      Serial.print(results->rawbuf[i]*USECPERTICK, DEC);
    }
    else
    {
      Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC);
    }
    Serial.print(" ");
  }
  Serial.println("");
*/
}

void loop()
{
  Distance_test();
  delay(100);
  if(distance < dangerDistance){
    brake();
    }
  //Distance_display();
  if (irrecv.decode(&results)) //解碼
  {
    // If it's been at least 1/4 second since the last
    // IR received, toggle the relay
    if (millis() - last > 250) //確定接收到訊號
    {
      on = !on;//標記位置反
      digitalWrite(13, on ? HIGH : LOW);//收到訊號後閃一下LED
    //  dump(&results);//解碼紅外線訊號,看是哪一家(sony,NEC...)
    }
  
    if (results.value == run_car )//按键CH
      run();//前進
    if (results.value == back_car )//按键+
      back();//後退
    if (results.value == left_car ){//按键<<
      left();//左轉
      delay(300);
      brake();
    }
    if (results.value == right_car ){//按键>||
      right();//右轉
      delay(300);
      brake();
      }
    if (results.value == stop_car )//按键>>|
      brake();//停車
    if (results.value == left_turn )//按键-
      spin_left();//左旋轉
    if (results.value == right_turn )//按键EQ
      spin_right();//右旋轉
   
    last = millis();    
    irrecv.resume(); // Receive the next value
  }
}

2019年3月28日 星期四

Arduino, Raspberry pi 自走車(智能小車) 無法走直線(1)

為了迎接未來物聯網的時代,身為一個軟體工程師的我也開始學起IOT
在芒茫網海搜尋後,敗入了一台Arduino自走車,
紅外線避障+藍芽版本的一台才650塊新台幣 ,為了讓運費划算一點
買了樹莓派3 B+(含電源、殼、hdmi線),這個比台灣便宜很多,台幣1300左右,台灣這樣買要破二千

買來興高采列的組起小車



但組完之後發現這傢伙沒辦法走直線....等等,這是不是有什麼誤會Orz
一台車耶,沒辦法走直線

再上網問狗之後,發現這個不是個案

網路上找到的問題點
 1.馬達有公差,,即使二顆馬達全力輸出,,轉速也不可能一模一樣
 2.Arduino是單晶片,速度不快所導致

這二個問題點都可以透過調整馬達的速度(PWM)進行改善。

但除此之外呢?  沒有其它辦法嗎

因為據我觀察這台車的結果,給我的直覺就是
他是先啟動其中一輪所導致的

這台車是按下直走後,往左邊轉了約30度後再走直線

往左邊轉就是右輪先啟動,那程式裡剛好就是右輪先走
rightWheel()
leftWheel()

在這個情形下,先啟動的那邊會先走當然不奇怪,自然就歪一邊

所以身為專業的軟體工程師,我直覺的就想到, 用fork() 做multithread不就好了...?
 做法很容易
1. 啟動右輪進背景
2. 馬上暫停右輪約1/3秒 (為了等左輪啟動)
3.啟動左輪

但白痴如我,單晶片不支援多工

所以...身為一個專業的軟體工程師,我決定改車....

我就像軌道車那樣,用一顆馬達做四輪傳動就好了

就憑你這種小車也想玩我,我操!!!