MultiWiiにArduinoからRC信号をシリアル送信してのコントロール

本来は簡単にPPM信号でRCデータを入力しようと企んでいたのですが、LED-Arreyを搭載しようとした所どうしてもTLC5940を積みたくなり…。そうすると、タイマーが使えなくなり、同時に割り込みも使えなくなり、PPM入力が不安定なdelay関数やmicros()を使わないといけなくなってしまうためしょうがなく置き換のため検討。たかだか、LEDの点灯のために安定した送信が可能なタイマーを使ったPPM信号を捨ててmicros()関数とか使って飛行を不安定にしたくない。だとすると、BTのデータ受信時に使っているプログラム内でそのままデータをシリアル送信してあげたほうがはるかに効率が良かろうということでの検証です。

MultiWiiの2.1以降には「Multiwii serial protocol」などというものが実装されているようでこれを使ってのPC信号の入力が可能ですのでこれを使ってテストします。

信号の形式:$M>[data length]

[data][checksum]

ヘッダコード:’$”M’
データの向き:'<‘ or ‘>’
データ長(data length):コマンドで送信するデータ長(8ビット1文字換算)
コード(code):指示コード(詳細は以下「Multiwii Serial Protocol Code」参照
データ(data):「データ長」で指定した数のパラメータ
チェックサム(checksum):データ長からデータ迄を順次XORした値の下位8ビット
※:コード(code)に関しては、MultiWiiプログラム内の「Serial.ino」に情報があるので参照

今回のテスト構成はシリアル通信でのコントロールが可能かを試すだけなのでBluetoothでのコントロールは考えずに簡単にします。

(ATMegaはシリアルデータを中継する途中でRCコントロールデータを追加送信します)

色々とデータの送受信が可能なのですが、飛行中に制御したいパラメタはそんなに必要ないと思われるしIMU周りのデータは取得しても取得時間のズレから使えなそうな予感がします。 などと考えまして、基本的にはRCコントロールチャンネルのデータを投げっぱなしにすることで簡単かつ軽量に仕上げます。

■接続イメージ

クリップボード

■コード


// RC Control
int lastRCSend;
static int16_t rcData[8];  // interval [1000;2000]

// Debug
#define LED_PIN 13 // debug

// initialize
void setup() {

  // initialize serial:
  Serial.begin(115200);
  Serial1.begin(115200);

  // initialize PIN_MODE
  #if defined(LED_PIN)
    pinMode(LED_PIN, OUTPUT);
  #endif
}
// main loop
void loop() {

  // MCU-FCU SerialTransmit
  uint8_t length_Rx = Serial.available();
  uint8_t str_box_Rx[length_Rx-1];
  for(uint8_t i = 0; i &lt; length_Rx; i++){
    str_box_Rx[i]=Serial.read();
  }
  Serial1.write(str_box_Rx,length_Rx);

  // MCU-FCU SerialReceive
  uint8_t length_Tx = Serial1.available();
  uint8_t str_box_Tx[length_Tx-1];

  for(uint8_t i = 0; i &lt; length_Tx; i++) {
    str_box_Tx[i]=Serial1.read();
  }
  Serial.write(str_box_Tx,length_Tx);

  // RC Control Data Send
  if ((millis() % 100) == 0){
    for(uint8_t i=0;i&lt;8;i++) {
      rcData[i] = random(1000,2000);
    }
    sendrcData();
  }

  // Debug LED Print
  #if defined(LED_PIN)
    if ((millis() % 1000) == 0){
      digitalWrite(LED_PIN,!digitalRead(LED_PIN));
    }
  #endif
}

// *******************************************************
// Interrupt driven UART transmitter - using a ring buffer
// *******************************************************
#define TX_BUFFER_SIZE 32

static volatile uint8_t headTX,tailTX;
static uint8_t bufTX[TX_BUFFER_SIZE];

// Multiwii Serial Protocol 0
#define MSP_SET_RAW_RC           200   //in message          8 rc chan

static uint8_t checksum;
static uint8_t cmdMSP;

void headSerial_Tx(uint8_t s) {
  serialize8('$');
  serialize8('M');
  serialize8('&lt;');
  checksum = 0; // start calculating a new checksum
  serialize8(s);
  serialize8(cmdMSP);
}
void tailSerial_Tx() {
  serialize8(checksum);
  UartSendData();
}
void sendrcData(){
  cmdMSP = MSP_SET_RAW_RC;
  headSerial_Tx(16);
  for(uint8_t i=0;i&lt;8;i++) serialize16(rcData[i]);
  tailSerial_Tx();
}
void serialize16(int16_t a) {
  serialize8((a   ) &amp; 0xFF);
  serialize8((a&gt;&gt;8) &amp; 0xFF);
}

void serialize8(uint8_t a) {
  uint8_t t = headTX;
  if (++t &gt;= TX_BUFFER_SIZE) t = 0;
  bufTX[t] = a;
  checksum ^= a;
  headTX = t;
}

void UartSendData() {
  while(headTX != tailTX) {
    if (++tailTX &gt;= TX_BUFFER_SIZE) tailTX = 0;
    uint8_t* p = bufTX+tailTX;
    Serial1.write(p,1);
  }
}

今回のテストコードはRCコントロールチャンネル8chに対してランダムに生成した数値(1000-2000)の値を送信するプログラムとしています。(MultiWiiの「Serial.ino」から必要な部分だけ抜き出して修正)
※:実際の飛行コードに関してはPS3のコントローラーからのデータをBluetoothで受信して値を変換した上で数値データを入力します。

組み合わせてあげれば動くようになると思われますので結果を元にして回路構成と基板のレイアウトを考えていきたいと思います。最大の問題は基板に全部回路が乗るのか?と言うことなのですが、最悪、基板2枚重ねとして機能を一部サブボードに移行ですかね…。

■参考情報

MultiWii ? View topic – New Multiwii Serial Protocol

マルチコプター MultiWii Ver2.1通信プロトコル対応 プログラムの開発

  1. コメントはまだありません。

  1. トラックバックはまだありません。

 
%d人のブロガーが「いいね」をつけました。