2016年8月7日日曜日

mbed rtosの注意点

rtosの副作用

mbed rtos (mbed os じゃないよ)は非常に強力なライブラリなのですが、mbedの根本的なところに作用するらしく、副作用が結構あるのでその注意点を書いておきます。(前の記事と一部かぶってますが)
  • rtosライブラリはライブラリをimportするだけで作用が始まる。
    includeしなくてもライブラリをimportするだけで下に書く副作用が起こります。これは結構はまるので注意
  • Serialとの併用は不可
    シリアル通信を行うライブラリであるSerialは内部でFIFO(stream)を使っているのですがそれがrtosと相性が悪いみたいです。変わりにRawSerialを使いましょう。いくつかの注意点がありますが、大体Serialと同じように使えます。
  • main関数が始まる前に threadをはじめてはいけない
    公式のどこにも書いていなくて僕がだいぶ悩まされた現象です。たとえば自作のC++ライブラリのクラスのコンストラクタでthreadを開始するようなコードを書き、main.cのグローバル領域でそのクラスを宣言したとします。その場合main関数が始まる(rtosを使った場合mainもthread扱いになります)前に自作クラスのthreadが始まることになります。
    この動作を行うとプログラムがフリーズします。どういう原理かは知りませんが。

SerialとRawSerialの違い

rtosとSerialの相性が悪いからRawSerialを使えと公式リファレンスに書いてありますが、RawSerialがどのようなものかのリファレンスが皆無なのでここで説明します。
  • 基本的にはSerialと同じ
    初期化はSerial name(tx, rx)でbaud()やformat()もSerialと同じように動きます。また割り込み関連も同じように動きます。
  • write()とread()は実装されていない
    上記の2つが実装されていないので、複数バイトの操作は1バイトずつの書き込み、読み込み関数であるputc()、getc()を複数回呼び出すという方法で実装します。ただし送信に関してはprintfは実装されているのでそれで代用できます。
  • バッファーは16バイト(LPC1768の場合)
    Serialではソフト的にバッファリングされているのでそこそこの大きさのバッファーが効いていますが(具体的に何バイトか知らない)RawSerialではソフトウェアバッファーは無く、ハードウェアバッファーのみです。LPC1768は送信受信共に16バイトあります。
    送信ではprintf()やputc()で16バイトよりも多く送信した場合、各API中で16バイトの送信が終了するまで待ってそれから残りのデータを送信します。つまりprintf()は16バイト以下の送信の場合は一瞬で実行が終わりますが17バイト以上の送信になる場合は16バイトの送信を待つウェイトが入るので一気に時間がかかります。
    受信は単純でバッファーに16バイトたまった後に新しくデータが来た場合は破棄されます。

Class内で自分のクラスメソッドを割り込み、スレッドに登録する方法

こんな面倒なことするかと思いますが、これができるとクラスを宣言するだけで裏でIO周りの処理を自動でやってくれるというクラスが作れるので地味に便利です。説明するよりもコードを乗せるほうが簡単なので相します。コメントで説明を書きます。
Class MyClass{
public:
    Myclass(PinName tx_pin, PinName rx_pin):com(tx_pin, rx_pin){
    }
    init(){
        com.attach(this, &MyClass::mythread, Serial::TxIrq);
        threadp = new Thread(&MyClass::mythread,this);
   
    }
    static void mythread(void const *argument){
        SRSLink*instance = (SRSLink*)argument;
        instance->com.write(0x00);
        /*処理*/
    }
    myisr(){
        /*処理*/
    }
    RawSerial com;
    Thread *threadp;
   
}

ビジーウェイトの扱い

以下のようなプログラムを実行した場合を考えます。

void thread1(void const *args) {
    LED1!=LED1;
    Thread::wait(100);
}
main(){
    Thread thread(thread1);


    while(true){
        LED0=!LED0:
        wait(100);
    }
}
thread1は0.1秒(=100ms)ごとにLED1をトグルさせるコードに見えます。一方main関数のほうも0.1秒ごとにLED0をトグルさせるみたいですが、このコードは良いのでしょうか。mainのwait(100)がThread::wait(100)ならRTOSの入門にありそうなコードですね。
Thread::waitはそのスレッドをInActiveにして他のスレッドに制御を渡し、時間が来たらRTOSから通知を受けて処理を再開する関数です。一方waitは処理を他に渡さずにwaitをするビジーウェイトです。
上記の説明を鵜呑みにするとLED0のトグルだけが起こって、LED1のトグルは起こらないように思えますが、実際はLED0とLED1ともにトグルが起こります。これはビジーウェイトしているmain関数を一定時間おきにRTOS本体が割り込みをかけて中断させ他の処理を行っているからです。
mbed rtosで動かしたところ5ms程度おきに強制的にこの処理が行われていました。
今回はthread1は100msと長いウェイトだったので影響は無いですが、これが1msのwaitだったり、シグナル起動だったりすると実行タイミングが思ったようにいきません。rtosを使うプログラムでは、ビジーウェイトを入れないようにしましょう。

Maker Faire Tokyo 2016 に行ってきました。

久しぶりのビックサイト 最後に来たのは何年前かな。もともと行きたいとは思っていましたが、出展応募して外れたところ招待券が送られてきたので行きました。臨海地域はりんかい線かゆりかもめが必要なので微妙に交通費がかかるんだよな。
色々と面白い作品やネットで見たことがあるという作品を直に見れたので満足。良く使っている会社が大体出展していた(しかも友達が働いていた……)。
個人的に気に入った作品を紹介します。1つ目は飛ぶお金ちょっと写真がぼやけていますが、お札が羽ばたきます。シュールだね。
 もうひとつはロボットプロレス。形としてはRoboOneのロボットのようなものです。右側のロボットは良いつくりをしていて。手のつめをうまく使い相手を掬い上げることができて、その動きは豪快でした。
 そのうち自分も出展したいな。

2016年6月19日日曜日

6脚歩行ロボット改良型 3脚でのテスト

3年前に6脚歩行ロボットを作り歩行まで出来たのですが、つくりやシステムが雑だったためにそれ以上の開発は無理と考えて、作り直しをしていました。今回作業が進み3脚でのテストが成功したので記します。
脚部ユニットは 前にこのブログに載せた物です。これを3つ使って立ち、本体を平行移動させています。次は歩行だ。

動画も入れます。1つ目がx、y、z軸での平行移動。PCのスライダーで10f/sで入力して線形補完をしてで動作しています。2つ目はz軸の移動で2f/sで入力で台形加速をしています。
PCとの通信レートは低いのですが、コントローラー側で1kf/sで補完しているので結構滑らかに動きます。


2016年6月18日土曜日

pyserial on linuxでのbaurateのバグ

Linux上でpythonを使ってシリアル通信をしていたのですが、ボーレートの設定についてはまったので書いておきます。
pyserialでシリアル通信を設定するとき

self.ser = serial.Serial()
self.ser.port="/dev/ttyUSB0"
self.ser.boudrate=1000000
self.ser.open()

とかけますが、open()にバグがあり、ボーレートが9600の固定になります。

self.ser = serial.Serial("/dev/ttyUSB0", 1000000)



と書くとボーレートを変更することが出来ます。
またシリアルターミナルとしてscreenというコマンドがあるのですが、こいつは古典的な標準ボーレート(9600、115200とか)しか対応していません。コンソールは開きますがボーレートは9600になります。
これで2日間無駄にした。

2016年5月28日土曜日

自作mbed新型

汎用の自作mbedの新型が出来たので紹介します。写真左が旧型、右が新型です。旧型は幅1100milで作っていたのですが、これだとブレッドボードには刺せるのですが、ジャンパーがさせないので意味は無く、900milで作り直しました。
ほとんど青mbedと同じサイズです。
回路図はこちら

青mbedとの違いは、interfaceICが無くなって(よって6pinのシリアルで書き込み)、ボタンがリセット以外に4つ、LEDが8つ、USBとEthernetのピンが無くなって、CAN(トランシーバーは内蔵)x2、シリアルx4、SPI、IIC、アナログ入力x6、GPIOx12というIOマシマシの構成になっています。

2016年5月27日金曜日

自作mbed用USB書き込み器

自作mbedを書き込むのに秋月のUSBシリアル変換ケーブルとユニバーサル基板で作った変換基板を通して書き込んでいたのですが、良く使うので基板から起こしてみました。
上の基板がFT231Xを使ったUSBシリアル変換基板で下がADuM1401を使ったアイソレーターです。事故が起きたときにPCが壊れないように電源を分離しています。

USBシリアル変換

アイソレーター

5ピン、6ピンにRTS、DTRをつなげているために書き込み時に自動でブートモードに入ります。

レッグコントローラーが完成

今回作っている6足歩行ロボットですが、この足には結構色々な機能が付いています。挙げると
  • サーボモーター(KRS4031)x3のコントロール
  • ファンのコントロール
  • 足先の荷重センサの読み取り
  • フルカラーLEDの点灯
  • 本体とのCAN通信
6足あるので、全体としてはこれの6倍の量のタスクがあるのですが、これを1つのマイコンでやろうとするとおそらく性能をオーバーします。そこで各足にマイコンボードを付けてそれでその足の分の処理をしています。
前にあげた足の動作テストの動画では足の内側に緑色の基板が着いていたはずですが、それの実装が完了して動作テストが終わったのでここに載せておきます。
上の2ピンコネクタがファン、6ピンコネクタが足先のセンサ・LED、3ピンのコネクタはサーボモーターで4ピンが本体とのCAN通信です。何も刺さっていないコネクタは書き込み用です。