OGIMOノート ~家族のためのモノづくり~

8歳の娘と、6歳の息子(脳性麻痺)を持った父親エンジニアの備忘録。自作の電子工作おもちゃ/リハビリ器具/ロボット関係の製作記録、勉強記録を残していきます

息子向けポータブルモリビリティを改造してみた② (デバイス間通信ソフトなど)

前回のおさらい

前回記事で記載した通り、息子などの電動乗り物への搭乗機会を増やすため、子供用電動乗り物「mottoy」を改造してみました。
ogimotokin.hatenablog.com

今回は前回で書ききれなかったソフトウェアの話を簡単にします。

ソフト構成の考え方

今回のMottoy改造の様に「コントロール部」と「モータ部」に異なるマイコンに分かれている場合、そのマイコン間で通信のやりとりが必要になってきます。そのため、その通信メッセージのルールを決めてやる必要があります。この検討で大事なのは、「今後に接続デバイスを増やす事を想定して拡張しやすくしておくか」という拡張性と、「いかに複雑にしすぎず分かりやすいルールにするか」という開発速度とのバランスです。
f:id:motokiinfinity8:20181104043251j:plain

業務や商用で検討する場合、出来る限り通信エラー耐性を上げるために
フッタに「チェックサム(伝送エラー)」やら「信頼性を上げるためのハンドシェイク」等様々な耐性強化の工夫を入れるものですが、
開発時間の限られる個人製作物においてその細かい箇所に時間をかける事自体が本質ではないため、必要最低限の絞り込みを実施した感じです。
「あれこれ悩む前にまずはざっと作ってみる」
こういう判断も、ラピットプロト開発ならではかな、と思います。

この辺りは色々と賛否両論あると思いますし、私も自分のやり方が正解とは思っていないので、是非とも有識者・玄人の皆様のやり方をご教示頂けるとありがたいです( ^^) _



独自通信メッセージルールの例

という訳で、今回のやりたい事を実現するための「独自伝送メッセージルール」を定義してみました。

今回は、操作デバイスから「モビリティの移動したい方向」を伝える独自ルールになります。

■モビリティ移動方向
(コマンド名:MDC/Mobility Direction Control)

型は Byte (unsigned char)型

1byte   : 0x2 (STX:テキスト開始文字 )
2-4byte : 命令固有文字 "MDC" ASCIIで表示
5-6byte : 前方方向の速度 "+9": 前進 ~ "+0":停止 ~ "-9":後退
7-8byte : 旋回方向の速度 "+9": 左旋回 ~ "+0":停止 ~ "-9":右旋回
9byte  : 選択ジョイコン ("0" : ジョイコン、"1": バイクコントローラ)
10-11byte  : 予備 ("0x0")
12byte : 0x3 (ETX:テキスト終了文字)

これだけでは分かりにくいので、一例をあげます。

例) コントローラから、『最大速度で前進』する場合、以下の12byteを転送します。

[1byte] 2 : STX
[2byte] 77 : M
[3byte] 68 : D
[4byte] 67 : C
[5byte] 43 : +
[6byte] 57 : 9 (前進)
[7byte] 43 : +
[8byte] 48 : 0 (旋回なし)
[9byte] 48 : 0 (ジョイスティック)
[10byte] 48 : 0
[11byte] 48 : 0
[12byte] 3 : ETX


英語&数字&記号はASCIIコードで表現できるので、その値を伝送するイメージです。
変換表は以下のサイトを参考ください。

ASCII文字コード - IT用語辞典


独自ルールを決める上で気にすべきは、「メッセージの先頭&終わりをどうやって判別させるか」です。
バイスの送信側はかならず一定間隔でメッセージ先頭からデータを投げますが、受信側は必ずしもきっちりメッセージ先頭から取れるとは限りません。受信側が別の処理をするのを頑張っていた場合、受信バッファ(郵便受けのポストの様なもの)が溢れてしまいメッセージが途中で切れてしまう事は実使用上でありえます。
なので、「どこまでが一つのメッセージなのか判別できる様にする仕組み」は最低限必要かなぁ、と思います。
判別のさせ方は色々ありますが、私は『普通の文字通信では絶対に使わない値を先頭/末尾に置く』というやり方がよいかな、と思い、ASCII制御コードであるSTX/ETXを使いました。

伝送メッセージルールの応用

上記のメッセージルールを共通にしておけば、モビリティ側とコントローラ側を自由に組み合わせる事が可能です!
例えば、今は『モビリティ』を 『ジョイスティック』&『段ボールトイコン』から操作できますが、これに別の第三のコントローラを作ってもすぐにモビリティが動かせるし、
また別の新しい二輪ロボットを作った場合でも、すぐにこの3つのコントローラがすべて対応してくれる訳です!リソースのない個人開発に置いては、なかなかの効率化ですね♪
f:id:motokiinfinity8:20181123200648j:plain

ちなみに、無線の場合はWifi(UDP)通信、有線の場合はUART通信(Serial)で、同じプロトコルが使いまわせられるので、超便利!!

ソースコード

以下のGithubに置きました。色々と汚いコードですが、ご参考までに。

① モビリティ(Mottoy)側
github.com

ジョイスティックコントローラ側
github.com

Nintendo Labo バイクトイコン側
github.com

更に参考まで、UDP送信側とUDP受信側のコードを抜粋

UDP送信側
#define CMD_SIZE  12

loop{
    省略
    
    String  m_buf = "";
    m_buf.concat("MDC");  // CMD命令設定

     //前方方向速度
     if(g_stick_pos >= 3) m_buf.concat("+9");
     else if(g_stick_pos >= -1) m_buf.concat("+0");
     else m_buf.concat("-9");

      //旋回方向速度
      if((g_stick_pos+8) % 4 == 1) m_buf.concat("+9");
      else if((g_stick_pos+8) % 4 == 0) m_buf.concat("+0");
      else m_buf.concat("-9");  
  
      m_buf.concat("0");  // ジョイコントローラモード 

     byte wifi_buf[CMD_SIZE-2];
     m_buf.getBytes(wifi_buf, CMD_SIZE-2);
     sendWiFi(wifi_buf);
}

/////////////////////////////
// Wifi送信処理
/////////////////////////////
void sendWiFi(uint8_t byteData[]) {
  uint8_t stx = 0x2;
  uint8_t etx = 0x3;
  if (Udp.beginPacket(HostIP,  WifiPort)) {
    Udp.write(&stx,1); //STX送信  
    Udp.write(byteData,CMD_SIZE-2);
    Udp.write(&etx,1); //ETX送信
    Udp.endPacket();
  }
}
UDP受信側
#define CMD_SIZE  12

uint8_t WiFibuff[CMD_SIZE];

loop(){
  中略
    Udp.read(WiFibuff, CMD_SIZE);
    Udp.flush();

    if(WiFibuff[0] == 0x2){
          String s_buf = String((char*)WiFibuff);
          cmd_msg = (s_buf.substring(1,4));
          vel_msg = (s_buf.substring(4.8));
          running_mode = (s_buf.substring(8,9)).toInt();
   }
}

まとめ

今回は、「モビリティ部」と「コントローラ部」の通信メッセージについて、少し書いてみました。今回は「移動させたい方向を指示するだけ」のシンプルなメッセージですが、当然ながら細かい速度量等を設定できるメッセージも別途設定しようと思っています。(アナログジョイスティックの傾き量に応じてモビリティの速度を変える等)
この様に、個人製作物で設計思想を統一しておくのは、今後モノをたくさん作っていった時に威力を発揮するかなぁ、と思います。自分が作ったモノ同士での新たなコラボレーションが簡単にできたり、色々と楽しそう!