技術

Arduinoのシリアル通信のボーレート

最近、HiLetgo Mini USB Nano V3.0 ATmega328P CH340G 5V 16M マイクロコントローラーボード Arduinoと互換という中国製のArduino Nanoクローンを入手しました。
中国からの発送となるため到着に2週間くらいかかったんですけども330円というめちゃ安価格で普通に動作するので満足しております。

それはさておき、同時に以下の2製品、赤外線受信モジュールと赤外線送信モジュールも入手し、Arduinoで学習リモコンみたいなものを作成しました。
HiLetgo 38kHz 赤外線受信機モジュール IR レシーバー Arduino 電子建物知能ロボット [並行輸入品]
HiLetgo 赤外線送信機モジュール IR 赤外線センサー Arduino 電子建物知能ロボット LED表示 [並行輸入品]

こんな感じ

ソースはここ

https://github.com/peta-okechan/irecho
(IRremoteというArduinoのライブラリを使っています)

仕組みとしてはPC(Pythonスクリプト)からシリアル通信でArduinoに赤外線信号の受信 or 送信のコマンドを送信する感じです。
Arduinoで受信した赤外線信号のデータをPCに保存したり、PCに保存した赤外線信号のデータをArduinoに送ったりすることで学習リモコンとして機能するようになってます。

問題点

でまぁ安定して動作はするのですが、赤外線信号の生データをシリアル通信でやりとりするのでそのへんがボトルネックになってしまいました。
受信、つまり学習は基本最初の1回やれば済むのであまり気にならないんですけども、送信に時間がかかると結構不便です。
私が学習させたリモコンの場合だと送信に1秒くらいかかるので、例えばテレビのリモコンの複数のボタンを連続してパパパッと操作するような場合のリアルリモコンの使い勝手とくらべると、非常に使いづらい感じです。

これは生データをシリアル通信でやりとりしてるのが原因なので、デコードされたデータを扱うようにすると解決できると思います。
IRremoteには生データだけでなくデコードされたデータを扱う仕組みもあるので、というかデコードされたデータを扱うのが主目的なライブラリなので、対応はそう難しくはないはずです。
ちなみにデコードされたデータというのは、例えばNEC方式の信号の12345(32bitデータ)みたいな感じになりますので、この場合1信号で5バイトあれば十分に表現できることになります。
生データだと私が学習させたリモコンの場合、1信号あたり32bit整数68個分くらいで、単純計算で272バイトになりますので、デコード済みデータと比べると50倍以上のサイズになります。
さらに今回デバッグのしやすさを考慮して生データを整数じゃなくてカンマ区切りの文字列として送信してますので300バイト以上になってます。
各整数が3~5桁に収まってるのでこの程度で済んでますけど、かなり無駄が多いです。

後々デコードされたデータを扱うよう変更するとして、現状の仕様のままでシリアル通信の速度を変えたらどのくらい処理速度に変化があるか気になったので測ってみました。
計測に使ったスクリプトはこんな感じ。

#!/usr/bin/env python
# coding=utf-8

import subprocess
import timeit


def main():
    command = [
        'python', 'irecho.py', 'send', '--serial-port', 'COM3', '--name', 'ue',
    ]
    result = timeit.timeit(
        '''subprocess.run(
            command, stdout=subprocess.PIPE, stderr=subprocess.PIPE
        )''',
        'import subprocess',
        number=10,
        globals={'command': command}
    )
    print(result)

if __name__ == '__main__':
    main()

送信処理を10回行ってその合計時間を表示します。
追記: これ最初のimport subprocessはいらないですねw

これを元のソースを書き換えながら2400bpsから230400bpsまで計測した結果が以下です。

2400bps 31.465807555238776秒
4800bps 16.709830173437872秒
9600bps 10.859490425279164秒
14400bps 6.955400712758374秒
19200bps 5.69991770016631秒
28800bps 4.4919952482775秒
38400bps 3.902442195295795秒
57600bps 3.2598146828225234秒
76800bps 2.9445462580185318秒
115200bps 2.5869034925160372秒
230400bps 51.266840769779044秒

元が9600bpsだったんですけども10回の送信処理で約10秒でやはり1回の送信処理あたり1秒くらいかかってた事が分かります。
2400bpsから19200bpsまではボーレートに応じて結構速くなる感じですけども、シリアル通信以外の処理がボトルネックの主要因になりはじめると思われる19200bps以降はあんまり速くならない感じですね。
230400bpsでグラフが跳ね上がってますけども、これはシリアル通信に失敗してPC側のスクリプトとArduinoがうまく連携出来なくなり、タイムアウトが発生するまで止まってしまうせいでしょう。
Arduino側のソースで送信時のタイムアウト時間は5秒としてますので、10回の処理で約51秒かかったということは10回全てタイムアウトしてるものと思います。

115200bpsが一番速いんですけども通信の安定性という点で少し心配なのでひとつ下の76800bpsにしてみました。
思ったより効果が高かったので根本解決するまえにボーレートを上げてしばらく使ってみたいと思います。

コメントを残す

メールアドレスが公開されることはありません。



※画像をクリックして別の画像を表示