見出し画像

プロポ「MC-8」をArduinoやRaspberry Pi Pico/Pico2で使うためのプログラム

 近藤科学の8チャンネルのプロポ「MC-8」。これをマイコンボードで使う場合のサンプル。このプログラムでは計測されたパルス幅がシリアルモニタに出力される。パルス幅を基にモーターを制御すれば、あっという間に自作ラジコンの出来上がり。
 プロポ「MC-8」やレシーバー「MR-8」の詳しい仕様については『マルチコントローラーMC-8+MR-8をマイコンボードで使用する』の参照を推奨する。
 ※以下のプログラムは全て動作未確認です。いかなる損害が発生しようと私は一切責任を負いません。


attachInterrupt関数不使用版(while文)

 汎用性を高めるためにattachInterrupt関数を使わずに制作した。Arduino IDEでプログラムが書き込める様々なマイコンボードと互換性があるはずだ。同期処理ではないため、実感できてしまうほどの遅延(15ms * 8 = 120ms ?)が発生する。
  パルス幅の測定にはwhile文が使われている。pulseIn関数を使用するよりもプログラムは助長なものになってしまう。while文とpulseIn関数のどちらがより高速な処理なのかは不明。有識者求む。

/*
谷口 左千夫による近藤科学製プロポ「MC-8」をArduinoやRaspberry Pi Pico/Pico2で使うためのプログラム
attachInterrupt関数不使用
while文
ライセンス:CC0
*/

//ピンの指定

//近藤科学製プロポ「MC-8」のレシーバー このプログラムではCH-A~Hの8本すべてのチャンネルを使用する
//左スティック
const int chA = 0;  //上下
const int chB = 1;  //左右
const int chE = 4;  //押し込み
//右スティック
const int chC = 2;  //上下
const int chD = 3;  //左右
const int chF = 5;  //押し込み
//左右10段階のスイッチ
const int chG = 6;  //左
const int chH = 7;  //右

/*
パルス幅の仕様
CH-A~D:890-1496-2100(μs)
CH-E/F:1496-1995(μs)
CH-G/H:997-1496-1995(μs)
*/

void setup() {
  pinMode(chA, INPUT);
  pinMode(chB, INPUT);
  pinMode(chC, INPUT);
  pinMode(chD, INPUT);
  pinMode(chE, INPUT);
  pinMode(chF, INPUT);
  pinMode(chG, INPUT);
  pinMode(chH, INPUT);
  Serial.begin(9600);  // 9600bpsでポートを開く
}

unsigned long pulseStart[30];  //パルスの開始時間を記録 インデックスにピン番号が対応する
unsigned long pulse[30];       //パルス幅を記録 インデックスにピン番号が対応する

void loop() {
  //パルス幅を計測
  pulseCheck(chA);
  pulseCheck(chB);
  pulseCheck(chC);
  pulseCheck(chD);
  pulseCheck(chE);
  pulseCheck(chF);
  pulseCheck(chG);
  //シリアルモニタ
  Serial.print("chA = ");
  Serial.print(pulse[chA]);
  Serial.print(" chB = ");
  Serial.print(pulse[chB]);
  Serial.print(" chC = ");
  Serial.print(pulse[chC]);
  Serial.print(" chD = ");
  Serial.print(pulse[chD]);
  Serial.print(" chE = ");
  Serial.print(pulse[chE]);
  Serial.print(" chF = ");
  Serial.print(pulse[chF]);
  Serial.print(" chG = ");
  Serial.print(pulse[chG]);
  Serial.print(" chH = ");
  Serial.println(pulse[chH]);
}

/*
パルス幅を調べる関数
引数「pin」にはピン番号を入れる
*/
void pulseCheck(int pin) {
  while (digitalRead(pin) == HIGH)
    ;  //LOWになる(パルスが終了する)まで待つ
  while (digitalRead(pin) == LOW)
    ;                          //HIGHになる(パルスが開始する)まで待つ
  pulseStart[pin] = micros();  //パスルの開始時間を記録
  while (digitalRead(pin) == HIGH)
    ;                                       //LOWになる(パルスが終了する)まで待つ
  pulse[pin] = micros() - pulseStart[pin];  //パルス幅 = パスルの終了時間「micros()」 - パスルの開始時間「pulseStart[pin]」
}

attachInterrupt関数不使用版(pulseIn関数)

 汎用性を高めるためにattachInterrupt関数を使わずに制作した。Arduino IDEでプログラムが書き込める様々なマイコンボードと互換性があるはずだ。同期処理ではないため、実感できてしまうほどの遅延(15ms * 8 = 120ms ?)が発生する。
 パルス幅の測定にはpulseIn関数が使われている。pulseIn関数を使用するとwhile文に比べより簡潔になる。while文とpulseIn関数のどちらがより高速な処理なのかは不明。有識者求む。

/*
谷口 左千夫による近藤科学製プロポ「MC-8」をArduinoやRaspberry Pi Pico/Pico2で使うためのプログラム
attachInterrupt関数不使用
pulseIn関数
ライセンス:CC0
*/

//ピンの指定

//近藤科学製プロポ「MC-8」のレシーバー このプログラムではCH-A~Hの8本すべてのチャンネルを使用する
//左スティック
const int chA = 0;  //上下
const int chB = 1;  //左右
const int chE = 4;  //押し込み
//右スティック
const int chC = 2;  //上下
const int chD = 3;  //左右
const int chF = 5;  //押し込み
//左右10段階のスイッチ
const int chG = 6;  //左
const int chH = 7;  //右

/*
パルス幅の仕様
CH-A~D:890-1496-2100(μs)
CH-E/F:1496-1995(μs)
CH-G/H:997-1496-1995(μs)
*/

void setup() {
  pinMode(chA, INPUT);
  pinMode(chB, INPUT);
  pinMode(chC, INPUT);
  pinMode(chD, INPUT);
  pinMode(chE, INPUT);
  pinMode(chF, INPUT);
  pinMode(chG, INPUT);
  pinMode(chH, INPUT);
  Serial.begin(9600);  // 9600bpsでポートを開く
}

unsigned long pulse[30];  //パルス幅を記録 インデックスにピン番号が対応する

void loop() {
  //パルス幅を計測
  pulse[chA] = pulseIn(chA, HIGH);
  pulse[chB] = pulseIn(chB, HIGH);
  pulse[chC] = pulseIn(chC, HIGH);
  pulse[chD] = pulseIn(chD, HIGH);
  pulse[chE] = pulseIn(chE, HIGH);
  pulse[chF] = pulseIn(chF, HIGH);
  pulse[chG] = pulseIn(chG, HIGH);
  pulse[chH] = pulseIn(chH, HIGH);
  //シリアルモニタ
  Serial.print("chA = ");
  Serial.print(pulse[chA]);
  Serial.print(" chB = ");
  Serial.print(pulse[chB]);
  Serial.print(" chC = ");
  Serial.print(pulse[chC]);
  Serial.print(" chD = ");
  Serial.print(pulse[chD]);
  Serial.print(" chE = ");
  Serial.print(pulse[chE]);
  Serial.print(" chF = ");
  Serial.print(pulse[chF]);
  Serial.print(" chG = ");
  Serial.print(pulse[chG]);
  Serial.print(" chH = ");
  Serial.println(pulse[chH]);
}

attachInterrupt関数使用版

 同期処理を行うため遅延は最小限であり、スムーズな動作が可能となる。しかし、これが利用できるマイコンボードは比較的限られてしまう。
 なんか発狂しそう。もっときれいな書き方ないのかな..

/*
谷口 左千夫による近藤科学製プロポ「MC-8」をArduinoやRaspberry Pi Pico/Pico2で使うためのプログラム
attachInterrupt関数使用
ライセンス:CC0
*/

//ピンの指定

//近藤科学製プロポ「MC-8」のレシーバー このプログラムではCH-A~Hの8本すべてのチャンネルを使用する
//左スティック
const int chA = 0;  //上下
const int chB = 1;  //左右
const int chE = 4;  //押し込み
//右スティック
const int chC = 2;  //上下
const int chD = 3;  //左右
const int chF = 5;  //押し込み
//左右10段階のスイッチ
const int chG = 6;  //左
const int chH = 7;  //右

/*
パルス幅の仕様
CH-A~D:890-1496-2100(μs)
CH-E/F:1496-1995(μs)
CH-G/H:997-1496-1995(μs)
*/

volatile unsigned long pulseStart[30];  //パルスの開始時間を記録 インデックスにピン番号が対応する
volatile unsigned long pulse[30];       //パルス幅を記録 インデックスにピン番号が対応する

void setup() {
  pinMode(chA, INPUT);
  pinMode(chB, INPUT);
  pinMode(chC, INPUT);
  pinMode(chD, INPUT);
  pinMode(chE, INPUT);
  pinMode(chF, INPUT);
  pinMode(chG, INPUT);
  pinMode(chH, INPUT);
  //割り込み
  attachInterrupt(chA, interruptChA, CHANGE);
  attachInterrupt(chB, interruptChB, CHANGE);
  attachInterrupt(chC, interruptChC, CHANGE);
  attachInterrupt(chD, interruptChD, CHANGE);
  attachInterrupt(chE, interruptChE, CHANGE);
  attachInterrupt(chF, interruptChF, CHANGE);
  attachInterrupt(chG, interruptChG, CHANGE);
  attachInterrupt(chH, interruptChH, CHANGE);
  Serial.begin(9600);  // 9600bpsでポートを開く
}

void loop() {
  //シリアルモニタ
  Serial.print("chA = ");
  Serial.print(pulse[chA]);
  Serial.print(" chB = ");
  Serial.print(pulse[chB]);
  Serial.print(" chC = ");
  Serial.print(pulse[chC]);
  Serial.print(" chD = ");
  Serial.print(pulse[chD]);
  Serial.print(" chE = ");
  Serial.print(pulse[chE]);
  Serial.print(" chF = ");
  Serial.print(pulse[chF]);
  Serial.print(" chG = ");
  Serial.print(pulse[chG]);
  Serial.print(" chH = ");
  Serial.println(pulse[chH]);
}

/*
割り込み時に実行される関数
パルス幅を配列「pulse」に記録する
*/
void interruptChA() {
  if (digitalRead(chA) == HIGH) pulseStart[chA] = micros();                   //パルスの開始時間を記録
  else if (digitalRead(chA) == LOW) pulse[chA] = micros() - pulseStart[chA];  //終了時間(現在の時間)からパルスの開始時間を減算することでパルス幅を求めて記録
}
void interruptChB() {
  if (digitalRead(chB) == HIGH) pulseStart[chB] = micros();                   //パルスの開始時間を記録
  else if (digitalRead(chB) == LOW) pulse[chB] = micros() - pulseStart[chB];  //終了時間(現在の時間)からパルスの開始時間を減算することでパルス幅を求めて記録
}

void interruptChC() {
  if (digitalRead(chC) == HIGH) pulseStart[chC] = micros();                   //パルスの開始時間を記録
  else if (digitalRead(chC) == LOW) pulse[chC] = micros() - pulseStart[chC];  //終了時間(現在の時間)からパルスの開始時間を減算することでパルス幅を求めて記録
}
void interruptChD() {
  if (digitalRead(chD) == HIGH) pulseStart[chD] = micros();                   //パルスの開始時間を記録
  else if (digitalRead(chD) == LOW) pulse[chD] = micros() - pulseStart[chD];  //終了時間(現在の時間)からパルスの開始時間を減算することでパルス幅を求めて記録
}
void interruptChE() {
  if (digitalRead(chE) == HIGH) pulseStart[chE] = micros();                   //パルスの開始時間を記録
  else if (digitalRead(chE) == LOW) pulse[chE] = micros() - pulseStart[chE];  //終了時間(現在の時間)からパルスの開始時間を減算することでパルス幅を求めて記録
}
void interruptChF() {
  if (digitalRead(chF) == HIGH) pulseStart[chF] = micros();                   //パルスの開始時間を記録
  else if (digitalRead(chF) == LOW) pulse[chF] = micros() - pulseStart[chF];  //終了時間(現在の時間)からパルスの開始時間を減算することでパルス幅を求めて記録
}
void interruptChG() {
  if (digitalRead(chG) == HIGH) pulseStart[chG] = micros();                   //パルスの開始時間を記録
  else if (digitalRead(chG) == LOW) pulse[chG] = micros() - pulseStart[chG];  //終了時間(現在の時間)からパルスの開始時間を減算することでパルス幅を求めて記録
}
void interruptChH() {
  if (digitalRead(chH) == HIGH) pulseStart[chH] = micros();                   //パルスの開始時間を記録
  else if (digitalRead(chH) == LOW) pulse[chH] = micros() - pulseStart[chH];  //終了時間(現在の時間)からパルスの開始時間を減算することでパルス幅を求めて記録
}

おまけ

 スティックの仕様について

図1 プロポ「MC-8」のPWMの変化

いいなと思ったら応援しよう!