#DJI RoboMaster S1のCANプロトコル解析
鋭意RoboMasterS1をROSで操作できるように進めていますが、今回はいま絶賛解析中のCANのプロトコルについて続編を書きたいと思います。
##前回のおさらい
前回DJI RoboMaster S1に使用されているCANの通信はおかしなことになっていて、各ユニットごとにCAN IDが割り振られ、そのIDでCAN-BUSを専有してバースト転送しているということがわかりました。
どうやらDJI Roninシリーズのジンバルも外部からの制御にCAN通信を使用しており、これを流用したのかもしれません。(にしても、もうちょっとなんとかならないものか)
CANの規格としてはCAN 2.0BでBitrateは1Mbpsで使用されておりCAN IDは
0x201〜0x204、0x211〜0x216となっていました。
そしてデータの構造はとてもシンプルで、トイドローンのTelloやRoboMasterの大会で使用されているジャッジシステムなどと同様のコマンド形式になっていることがわかりました。
ヘッダ | メッセージ長 | 固定値 | CRC8 | データバイト列 | CRC16 |
---|---|---|---|---|---|
0x55 | 0xXX | 0x04 | CRC8 | Data[] | CRC16 |
今回、RoboMaster S1に搭載されているIntelligent Controllerのフリをして、コマンドを乗っ取ることで制御を奪ってしまいます。
Intelligent Controllerが出力しているCAN IDは物理的にIntelligent Controllerを切り離すことで、わかりますので、ID = 0x201ということが判明しました。
##コマンドの種類を特定する
通常はCANにのせるコマンドは、常に同じものを定常的に送信し、そのBitの変化で指示を与えることが通例なのですが、ここでもDJIは恐ろしいことにCAN-BUSに流すコマンドを定常的に流すものと、ブラスターなどの指示が来た時だけ流すコマンドの2種類存在していました。また、指示が来た時だけ流すコマンドで、別ユニットからACKと思しきコマンドが返ってくるものもありました。
なぜこのように2種類のコマンドを用意することがよろしくないかというと、例えばブラスターを連続で発射するなどの指示が来た時に、その時だけ流すものが想定外にCAN-BUS負荷を上げて、他のコマンドを送信したいのに送信できなくなるなど、CAN-BUSの負荷が急に高くなり他の通信がブロッキングされる時間が長くなってしまうことが考えられます。
これは自動車や、産業用機器などのミッションクリティカルなシステムでは大きな問題となるため、CAN-BUSの負荷は常に一定にするように管理するのが通例です。DJIさんは産業機器スペックのCANを採用と宣伝していましたが、あまり好ましくない使い方といえるでしょう。ただ、逆手に取ればCANは複数のセンサーなどを制御する際には非常に扱いやすいので、RoboMaster S1のようなミッションクリティカルでないシステムで用いる場合は、管理を放棄することで、とても楽に高品質なシステムが組めるということで採用したのかもしれません。
話がそれてしまいましたが、この定常的に流すものと、指示に従って間欠的に流される2種類のコマンドの存在が確認できました。
その中で先ほど書いたメッセージの構造は更に、以下のようになっているとわかりました。
ヘッダ | メッセージ長 | 固定値 | CRC8 | コマンドの種類 | コマンドの種類 | コマンドカウンタ下位Byte | コマンドカウンタ上位Byte | データバイト列 | CRC16 |
---|---|---|---|---|---|---|---|---|---|
0x55 | 0xXX | 0x04 | CRC8 | 0xXX | 0xXX | Count | Count | Data[] | CRC16 |
はじめはメッセージ長でコマンドを分類しようと試みたのですが、同じメッセージ長で異なる指示となっている場合もあり、コマンドの種類のバイト列が存在することに気づきました。
また、コマンドの種類はたとえばLEDの点灯など種類が同じものは近い数値になっていたりしていました。
また、コマンドカウンタに関しては、先ほど出てきたACKを返す場合などの場合送信されてきたカウンタ値をコピーして返すようです。また、複数のコマンドでカウンタ値を共有している場合もあるようです。その場合、コマンドの種類の2Byte目が変化していました。またブラスターのコマンド送信後に、返ってくるACKのコマンド種類のバイトが反転しているということも確認できました。(どういう意味かは不明)
##解析できたコマンド
いろいろコマンドはわかってきたので、主要なコマンドについてまとめておきたいと思います。
メッセージ長 | コマンドの種類 | コマンドの意味(推定) | 送信周期(推定) |
---|---|---|---|
0x1B | 0x09C3 | スマホからのジョイスティックによるコマンド指示 | 10msec |
0x0E | 0x09C3 | 機体速度(スマホからセットできる) | 指示による |
0x0F | 0x0904 | スマホの画面をタッチしているかしていないか(制御OK/NG) | 指示による |
0x1A | 0x0918 | LED発光指示 | 指示による |
0x0E | 0x0917 | ブラスター指示(多分発射) | 指示による |
0x16 | 0x0917 | ブラスター指示(多分発射) | 指示による |
意味のわからないコマンドは他にもいろいろあるのですが、とりあえず真似して送れば Controllerのフリはできるかなあと思っていたりします。
前回Intelligent Controllerありで、ROSから制御できていたのは、Intelligent Controllerの上記の指示が来た際に、スマホのジョイスティックコマンドを書き換えていたからでした。また課題になった点として、RoboMaster S1がスマホのタッチの有無を見ていて、スマホをタッチし続けていないと自動で停止してしまうという点でしたが、こちらも、「タッチしていない」というコマンドを「タッチしている」というコマンドに書き換えることで制御に成功しました。
まだまだ、ブラスターの角度のデータなど解析できていることもあるのですが、今回はこのくらいにしておきたいと思います。これはかなり人海戦術的なところもあるので、みなさまご協力お願いいたします。
##RoboMaster S1を用いて自律走行プラットフォームを作る
こんな感じで解析を進めていくことで、Intelligent Controllerをなくしていくことで、以下のようなシステムを構築しようと企んでいます。
こちらで活動していますので、ご興味ある方はご協力よろしくおねがいします。
https://github.com/RoboMasterS1Challenge/robomaster_s1_can_hack