VS-RC003→Arduinoのシリアル解読


以前挫折してほったからしになっていた案件。
ArduinoとVS-RC003の安定したシリアル通信について、突然思い立ってリベンジ中です。

前回の挫折からもう3年も経っているのが驚きです。
ブログではあまり書いてきませんでしたが言語の勉強はチクチクと進めており、C言語、RASPBERRY PI、ROS、LINUX、PYTHONなどの入門書を2冊ぐらいずつ読んだところです。入門書ばかりで何も身にはついていませんが、少しは理解力が向上していると信じたいです。




今回のリベンジでは純粋にソフトウェアのことに集中できるよう、万全を期してArduino MEGAを購入しました。
Arduino MEGAはやや高いのですがハードウェアシリアルを複数扱うことができます。
ハードウェアシリアルが複数あることで、115200のスピードでVS-RC003とのシリアル通信の実験をしながら、
同時にUSB経由でPCでモニンタリングもできるというわけです!
ハードウェアの限界に悩まされなければ、あとはソフトの話なのでパズルゲームのように楽しめるはず・・・です。




ArduinoからVS-RC003に命令を書き込む場合には、115200のスピードのシリアルで文字列を一方的に送りつければ済む話です。あとは安定性をアップさせるための仕掛けをいれれば大丈夫でしょう。

一方、読み取りの方はグッと難易度があがります。
今回はシリアルの読み取りから攻略してみます。




読み取りにはクリアすべきいろいろな難題があります。

・VS-RC003は送った命令をエコーバックしてくるが、データとの区別はどうするか?
・Arduinoが扱えるシリアルデータは1バイトずつだが、文字列のシリアルパケットをどう受け取るか?
・リトルエンティアンのビックエンディアンへの入れ替えは?
・ASCIIコードから16進数への変換は?
・16進数から10進数への変換は?

などなど。絡まったテグスを解きほぐすように、順番に解決していく必要があります。




さっそく、VS-RC003の信号をArduinoで読み取るためのスケッチを書いて見ました。
シリアル仕様マニュアルの例にもある電圧の読み取りに挑戦です。
作業の途中経過がわかるよう、

・読み取った信号
・該当箇所のデータをビッグエンディアンに変更したもの
・それを10進数に置き換えたもの
・さらに換算し、電圧の数値として読み取れるように直したもの

のそれぞれを表示するようにしてみました。




実際のコードです。


// VS-RC003のシリアルを読み取るプログラム作例
// rコマンドで読み出し命令を出し、結果を変数VSmsgsに入れて表示する。
// 例では、r 2009dc 04で電圧を読み取る。
// 2009dc 02 00 xx yy が読み出されるが、xx yy の部分が、該当の電圧データとなる。
// また、リトルエンディアンからビッグエンティアンへ、
// さらにアスキーコードの16進数を数値に変換し、10進数に換算する。
// ArduinoのTX,RX(MEGAなら18,19番ピン、LeonardoやMICROなら1,0番ピン)を
// VS-RC003のRX,TXにそれぞれ配線する。5VとGNDもそれぞれ接続する。
// ※ UNO系等ではハードウェアシリアル(Serial1.begin())が使えないので注意。

int vcc1, vcc2, vcc3, vcc4;// 換算用の変数を宣言。
bool ERR;// 読み取りエラーのフラグ用変数を宣言。

void setup() {
Serial.begin(115200); // 115200bpsでPCモニタ用ポートを開く
Serial1.begin(115200);// 115200bpsでVS-RC003通信用ポートを開く
}

void loop() {
char VSmsgs[64];// 読み取ったシリアルを入れる配列を宣言。
Serial1.println("r 2009dc 04");//電圧を読み込む命令
delay(30);//このディレイが小さすぎると失敗しやすい。
if (Serial1.available() > 0 ) {
int i = 0; //文字配列カウンタ
int CRcounter = 0; //CR記号カウンタ。これが2回出たら1パケット終了。
int SHcounter = 0; //#記号カウンタ。これの2回目から本データ取得。(それまではエコーバックの文字列ということ。)
while (1) {
char data = Serial1.read();
VSmsgs[i] = data; //文字配列に文字を一個入れる。
i ++;
if (data == 0x23) { //#文字が出てきたら#カウンタを加算。
SHcounter ++;
if (SHcounter >= 2) {
i = 0; //#カウンタが2になったら、コールバック終了なので改めてデータを取る。
}
}
if (data == 0x0D) { //改行文字が出てきたらCRカウンタを加算。
CRcounter ++;
if (CRcounter >= 2) { //2回目の改行文字が出てきたら、データ取得完了し、換算と表示処理へ。
VSmsgs[i] = 0x00;//データにヌル終端を追加
Serial.println(VSmsgs);//取得データを表示。
Serial.print("Big endian : ");//以下、該当の電圧データをエンディアンを交換して表示する。
Serial.print(VSmsgs[16]);
Serial.print(VSmsgs[17]);
Serial.print(" ");
Serial.print(VSmsgs[13]);
Serial.println(VSmsgs[14]);
Serial.print("ASCII to HEX to DEC : ");

//以下、取得したASCIIコードを16進数に換算していく。
//その際、範囲にない文字であれば、エラーフラグを立てる。
if (VSmsgs[16] <= 0x2f) {//取得した文字が0よりも前の文字であればエラー。
ERR = 1;
}
else if (VSmsgs[16] >= 0x67) {//取得した文字がfよりも後の文字であればエラー。
ERR = 1;
}
else if (VSmsgs[16] >= 0x41) {
vcc1 = VSmsgs[16] - 0x57;//取得した文字がa以上であれば10からの数字に換算。
} else
{
vcc1 = VSmsgs[16] - 0x30;//それ以外であれば、0から9の数字に換算。
}

if (VSmsgs[17] <= 0x2f) {
ERR = 1;
}
else if (VSmsgs[17] >= 0x67) {
ERR = 1;
}
else if (VSmsgs[17] >= 0x41) {
vcc2 = VSmsgs[17] - 0x57;
} else
{
vcc2 = VSmsgs[17] - 0x30;
}

if (VSmsgs[13] <= 0x2f) {
ERR = 1;
}
else if (VSmsgs[13] >= 0x67) {
ERR = 1;
}
else if (VSmsgs[13] >= 0x41) {
vcc3 = VSmsgs[13] - 0x57;
} else
{
vcc3 = VSmsgs[13] - 0x30;
}

if (VSmsgs[14] <= 0x2f) {
ERR = 1;
}
else if (VSmsgs[14] >= 0x67) {
ERR = 1;
}
else if (VSmsgs[14] >= 0x41) {
vcc4 = VSmsgs[14] - 0x57;
} else
{
vcc4 = VSmsgs[14] - 0x30;
}

Serial.print(vcc1, DEC);//ビッグエンディアンに変更後の16進数を並べる。
Serial.print(" ");
Serial.print(vcc2, DEC);
Serial.print(" ");
Serial.print(vcc3, DEC);
Serial.print(" ");
Serial.println(vcc4, DEC);
Serial.print("VCC : ");
int vcc = vcc1 * 4096 + vcc2 * 256 + vcc3 * 16 + vcc4;//16進数を10進数に換算する。
Serial.print(vcc, DEC);//結果の数値を表示する。
Serial.println();
Serial1.flush();
break;
if (ERR = 1) {//取得データにエラーが出ていればエラーと表示する。
Serial.println("*** READ ERROR!! ***");
ERR = 0;
delay (100);
}
}
}
}
}
Serial.println();
delay (1);
}


実行結果は、PCシリアルモニタで見ると


2009dc 02 00 3c 0e
Big endian : 0e 3c
ASCII to HEX to DEC : 0 14 3 12
VCC : 3644

2009dc 02 00 33 0e
Big endian : 0e 33
ASCII to HEX to DEC : 0 14 3 3
VCC : 3635

2009dc 02 00 29 0e
Big endian : 0e 29
ASCII to HEX to DEC : 0 14 2 9
VCC : 3625
・・・


のような感じになります。
たぶん、結果の換算もうまくいっていると思います。

スケッチ文はかなり雑で下手くそですが、とりあえず基本ができてきたと思います。
これをベースに、使える関数にしていきたいと思います。
スポンサーサイト

テーマ : 自然科学
ジャンル : 学問・文化・芸術

コメントの投稿

非公開コメント

プロフィール

二名川(ニナガワ)

Author:二名川(ニナガワ)
ホビーロボットをレトロゲームが発展したものと捉えて楽しく遊び倒します。
子供が夢を見ている時間帯に稼働します。

宣伝:電子出版しました。
「コンソロイド ガイドブック」
46107_CONSOLOID_GUID_FACE_200.jpg





■作成中の機体
汎用ヒト型決戦遊具 ~RX計画~
RX-7.5 ゼロタンク
RRf-0.6 ゼニィ
RXM-7.9 ゼムネス
RX-7.5R 量産型ゼロタンク
RX-7.5Fp ファミタンク仮設1号
RX-7.7 ゼロキャノン
RX-7.8 ゼログレイ
SMS-0.1 ゼロライナー
以下続く

ブログ内検索
最近の記事
最近のコメント
カテゴリ
月別アーカイブ
リンク