2020年2月9日 星期日

[R/C] 用 Arduino 讀取 R/C Recever 訊號

使用遙控器搖桿可以很容易操控遙控車、船,但遙控器每一個頻道只能控制(對應)一個動作,同時操控兩個頻道也只能控制(對應)兩個動作。



坦克車左側和右側各有 1 只馬達,我們可以使用遙控器的左、右搖桿來控制坦克車的行走方向。如果想用單一搖桿來控制坦克車的行走方向,好像沒辦法做到,更別說是要去控制麥克納姆輪車可以獨立運作的 4 個輪子了。

有鑑於此,我們想出一個解決的辦法,就是利用 Arduino 讀取接收器的訊號後,做一些整合式的處理(註1),然後再下指令給馬達驅動模組或其它周邊模組作動。

註1:此處所謂的整合式處理,是指把一個以上的訊號指定為一組指令。例如我們想用一只搖桿(有2個頻道的訊號)控制麥克納姆輪車(4個馬達)的行進方向。

本章僅在說明如何解譯搖控接收器的訊號,如何將訊號作整合式應用會另篇說明。


電路接線

Arduino       R/C Recever
5V               VCC
GND           GND
D2               Channel 1




程式

#define THROTTLE_SIGNAL_IN 0 // INTERRUPT 0 = DIGITAL PIN 2 - use the interrupt number in attachInterrupt
#define THROTTLE_SIGNAL_IN_PIN 2 // INTERRUPT 0 = DIGITAL PIN 2 - use the PIN number in digitalRead

#define NEUTRAL_THROTTLE 1500 // this is the duration in microseconds of neutral throttle on an electric RC Car

volatile int nThrottleIn = NEUTRAL_THROTTLE; // volatile, we set this in the Interrupt and read it in loop so it must be declared volatile
volatile unsigned long ulStartPeriod = 0; // set in the interrupt
volatile boolean bNewThrottleSignal = false; // set in the interrupt and read in the loop
// we could use nThrottleIn = 0 in loop instead of a separate variable, but using bNewThrottleSignal to indicate we have a new signal
// is clearer for this first example

void setup()
{
  // tell the Arduino we want the function calcInput to be called whenever INT0 (digital pin 2) changes from HIGH to LOW or LOW to HIGH
  // catching these changes will allow us to calculate how long the input pulse is
  attachInterrupt(THROTTLE_SIGNAL_IN,calcInput,CHANGE);

  Serial.begin(9600);
}

void loop()
{
 // if a new throttle signal has been measured, lets print the value to serial, if not our code could carry on with some other processing
 if(bNewThrottleSignal)
 {

   Serial.println(nThrottleIn); 

   // set this back to false when we have finished
   // with nThrottleIn, while true, calcInput will not update
   // nThrottleIn
   bNewThrottleSignal = false;
 }

 // other processing ...
}

void calcInput()
{
  // if the pin is high, its the start of an interrupt
  if(digitalRead(THROTTLE_SIGNAL_IN_PIN) == HIGH)
  {
    // get the time using micros - when our code gets really busy this will become inaccurate, but for the current application its
    // easy to understand and works very well
    ulStartPeriod = micros();
  }
  else
  {
    // if the pin is low, its the falling edge of the pulse so now we can calculate the pulse duration by subtracting the
    // start time ulStartPeriod from the current time returned by micros()
    if(ulStartPeriod && (bNewThrottleSignal == false))
    {
      nThrottleIn = (int)(micros() - ulStartPeriod);
      ulStartPeriod = 0;

      // tell loop we have a new signal on the throttle channel
      // we will not update nThrottleIn until loop sets
      // bNewThrottleSignal back to false
      bNewThrottleSignal = true;
    }
  }
}


觀察訊號數據

Step1 打開 Serial Monitor,並將鮑率調到 9600。

Step2 輕輕搖動遙控器上面的搖桿,觀察 Selial Monitor 內的數值(註2)。置中時約為 1500,側邊時約為 1250 和 1750。

註2:如果搖桿置中時數值不為 1500,您可以使用遙控器上面的微調按鍵將它調整到接近 1500。



參考網頁

Instructables https://www.instructables.com/id/Rc-Controller-for-Better-Control-Over-Arduino-Proj/