Arduinoでラジコンカーの電装を作った際に得た知見を共有します。

PWM信号を読み取る`pulseIn`を使うとその間他の処理が止まってしまい動作がぎこちなくなってしまいますが、今回は複数のPWM信号を処理しながら他の動作をスムーズに行えるよう、パルス読み取り関数を自前で実装しました。

今回作ったもの

複数のスイッチ切替に対し素早いレスポンスで反応、点灯点滅の処理もスムーズ。

今回作ったものの構成

・ラジコン受信機 (Corona R6SF 等)

操作したいCh数に合わせてください。今回は電飾関係の操作に3ch使いたかったので、ラジコンカーのステアリングとスロットルの2chを足しても余裕がある6chの受信機を使っています。

・ Arduino Uno

繋ぐLEDの個数等に合わせて変えてください。

受信機の各Chの信号線をArduinoの任意のpinに繋いでいます。

プロポから受信した複数のパルス信号を非同期で処理するコード

標準で用意されているpulseIn関数でPWMを処理することもできますが、この処理をしている間ほかの処理がストップしてしまいます。

ヘッドライトの点灯ぐらいであれば問題ないですが、ウィンカー点滅の処理等を同時に行いたい場合、カクついてしてしまうので自前でパルス信号を非同期で読み取る処理を実装しています。

下記にソースコードの例を示します。

`readPulseWidth(CH3_PIN, 0);`このコードでパルス幅を読み

`calcPosition(pwm3, 0)`この関数で各chのプロポのスイッチのポジションを特定しています。

厳密な計測ではない為、1ループ中の処理が多くなると実際のパルス幅よりも長い結果が格納されるので、各ポジションの切り替えはパルス幅がある程度ブレても大丈夫なように作る必要があります。

/* 受信用設定 */
// 受信ピン
#define CH5_PIN A5
#define CH4_PIN A4
#define CH3_PIN A3
// パルスの閾値
#define HIGH_PWM 2000
#define MIDDLE_PWM 1550
#define LOW_PWM 970
#define TOLERABLE 100
#define LOW_TOLERABLE 120
#define HIGH_POS 2
#define MIDDLE_POS 1
#define LOW_POS 0
// 受信信号格納
static int ch_positions[3] = {0, 0, 0};
static unsigned long pulse_rise_time[3];
static int last_state[3];

// 点灯タイミング計測用変数
long last_delay_time = 1;

void setup() {
  pinMode(CH3_PIN, INPUT);
  pinMode(CH4_PIN, INPUT);
  pinMode(CH5_PIN, INPUT);
}

void loop() {
  unsigned long start_time = micros();  // 1ループあたりの遅延時間計測用変数

  /* 受信信号の計測と保存 */
  int pwm3 = readPulseWidth(CH3_PIN, 0);
  int pwm4 = readPulseWidth(CH4_PIN, 1);
  int pwm5 = readPulseWidth(CH5_PIN, 2);
  calcPosition(pwm3, 0);
  calcPosition(pwm4, 1);
  calcPosition(pwm5, 2);

  /* ここに点灯処理を書く */


  /* 点滅タイミング非同期制御用、1ループ当たりの遅延時間計測 */
  unsigned long end_time = micros();
  last_delay_time = end_time - start_time;
}


/* パルスを計測する */
unsigned long readPulseWidth(int pin, int index) {
  unsigned int current_state = digitalRead(pin);  // HighLowを読む
  unsigned long pulse_width = 0;  // パルス幅を格納する変数

  // 信号立ち上がり時に、立ち上がりの時刻をpulse_rise_timeに格納
  if (last_state[index] == LOW && current_state == HIGH) {
    pulse_rise_time[index] = micros();
  }

  // 信号立ち下がり時に、パルス幅を計測しpulse_widthに格納
  if (last_state[index] == HIGH && current_state == LOW) {
    unsigned long pulse_fall_time = micros();
    pulse_width = pulse_fall_time - pulse_rise_time[index];
  }

  last_state[index] = current_state;
  return pulse_width;
}
プロポのスイッチを操作し受信したPWM信号を表示しているところ。パルス幅がブレるのでポジション推定のコードに工夫が必要。

電飾の操作

上記コードの通り各スイッチのポジションが推定できればあとは通常のLEDを点灯させる回路とコードを組むと完成です。

ここで注意したいのはArduino Unoの場合、各pinの電流が20mAを超えないように抵抗をいれることとpin数が限られているので同系統のLEDをまとめるように回路を組むことです。

今回ですと、ポジションライト、ハイビーム、ロービームを左右で結線し、3pinのみ使用しています。1つのLEDに対して1pin使ってしまうとpinが足りなくなってしまうのでご注意ください。

まとめ

今回はArduinoを使ってラジコンカー用の電飾を作りました。

このように、Arduinoを使うことで市販のライトユニットよりも安い費用で、複雑な点灯制御もできます。

皆さんもぜひ、挑戦してみてください。

以上です。



ギャップロを運営しているアップフロンティア株式会社では、一緒に働いてくれる仲間を随時、募集しています。 興味がある!一緒に働いてみたい!という方は下記よりご応募お待ちしております。
採用情報をみる