ROS講座96 カスタムmbedでrosserial+platformioを使う


環境

この記事は以下の環境で動いています。

項目
CPU Core i5-8250U
Ubuntu 16.04
ROS Kinetic
PlatformIO 3.6.0

インストールについてはROS講座02 インストールを参照してください。
またこの記事のプログラムはgithubにアップロードされています。ROS講座11 gitリポジトリを参照してください。

概要

ロボットの下回りの特にアクチュエーターは自作をする必要があるのが現状です。今回はmbedを用います。Arduinoほどはメジャーではありませんが、Arduinoで使われるAVRよりもIOなどの性能が高いARMベースのコアを使ったマイコンプラットフォームです。この記事では

  • カスタムmbedボードの作り方
  • mbed用のソースコードのオフラインでのビルド
  • カスタムmbedに書き込む方法
  • mbedでrosserialを使う方法

を説明します。

カスタムmbedボードの作り方

青mbedが一番メジャーですが、ロボット用としては自分で基板を起こしたくなります。そんな時はICだけを買って自分で基板を作りましょう。

接続 ピン番号
3.3V 10, 12, 19, 28, 42, 54, 71, 84, 96
GND 11, 15, 31, 41, 55, 72, 83, 97
水晶 22, 23
リセットIC 17

書き込みにはシリアル通信を使います。USBシリアル変換を使うとよいです。RTSとDTRはリセット&bootモードに入る設定を行うものです。

USBシリアル LPC1768
TxD 99
RxD 98
RTS 53
DTR 17

mbed用のソースコードをオフラインでのビルド

platformioを用いてビルドをすることができます。platformio boards|grep lpc1768でplatformioでlpc1768が対応推しているか見れます。(結果はlpc1768 LPC1768 96MHz 512KB 64KB NXP mbed LPC1768ともう一行出る)

初期設定
roscd hard_lecture/platformio/mbed01 #プロジェクトのディレクトリに移動
platformio init -b lpc1768

ソースコードを編集します。これのプログラムはオンラインのコンパイラと同様に書けます。

hard_lecture/platformio/mbed01/src/main.cpp
#include "mbed.h"
#define SRSG_LED0 P0_16
#define SRSG_TX0 P0_2
#define SRSG_RX0 P0_3

DigitalOut l0(SRSG_LED0);
Serial pc(SRSG_TX0,SRSG_RX0);

int main() {
  pc.baud(1000000);
  while (true) {
    l0 = !l0;
    wait(500);
    pc.printf("hellow mbed!\n");
  }
}

最後にコンパイルです。

ビルドの実行
platformio run

これでhard_lecture/platformio/mbed01/.pioenvs/lpc1768/firmware.binにビルド済みのバイナリが生成されます。

カスタムmbedに書き込む方法

通常のmbedならplatformioでuploadオプションを付けると自動でダウンロードしてくれますが、カスタムmbedではそうはいきません。lpc21ispで書き込みを行います。

lpc21ispのインストール
sudo apt-get install lpc21isp

/dev/ttyUSB0にカスタムmbed用のライターがついているとします。

lpc21ispの書き込み
roscd hard_lecture/platformio/mbed01/.pioenvs/lpc1768/ 
sudo lpc21isp -control -bin firmware.bin /dev/ttyUSB0 115200 12000

わざわざ別のコマンドを打つのは面倒ですので、すべてplatformio runでやってくれるように設定を変えましょう。

hard_lecture/platformio/mbed01/platformio.iniに追加
[env:lpc1768]
platform = nxplpc
board = lpc1768
framework = mbed

targets = upload                        # デフォルトで書き込みを行う
extra_scripts =  pre:lpc21isp_script.py # カスタム書き込みコマンドのロード
upload_protocol = custom                # 標準ではなくカスタムの書き込みを行う
upload_port = /dev/ttyUSB0              # 書き込み先のポートの設定

以下のファイルを追加します。

hard_lecture/platformio/mbed01/lpc21isp_script.py
Import("env")

print("load lpc21")

env.Replace(
    UPLOADCMD="lpc21isp -control -bin $SOURCE $UPLOAD_PORT 115200 12000"
)

これでplatformio runでコンパイルから書き込みまですべてをおこなえます。

mbedでrtosライブラリを使う

強力なmbedのライブラリとしてrtosがあります(逆にこれがないとプログラムがだいぶ難しい)。これは標準の設定だとplatformioでは使えません。

hard_lecture/platformio/mbed02/src/main.cpp
#include "mbed.h"
#include "rtos.h"

#define SRSG_LED0 P0_16
#define SRSG_LED1 P0_15
#define SRSG_LED2 P0_17
#define SRSG_LED3 P0_18

DigitalOut l0(SRSG_LED0);
DigitalOut l1(SRSG_LED1);
DigitalOut l2(SRSG_LED2);
DigitalOut l3(SRSG_LED3);

void blink1(void) {
    while (1) {
        l1=!l1;
        Thread::wait(1000);
    }
}
void blink2(void) {
    while (1) {
        l2=!l2;
        Thread::wait(1000);
    }
}

int main() {
    Thread thread1;
    thread1.start(blink1);
    Thread thread2;
    thread2.start(blink2);
    while (true) {
        l0 = !l0;
        Thread::wait(500);
    }
}

この状態でplatformio runをするとエラーになります。設定ファイルに書き加える必要があります。

hard_lecture/platformio/mbed02/platformio.ini
[env:lpc1768]
platform = nxplpc
board = lpc1768
framework = mbed
build_flags = -D PIO_FRAMEWORK_MBED_RTOS_PRESENT #この行を追加

これでplatformio runのビルドが通ります。

mbedでrosserialを使う方法

platformioワークスペースの作成

面倒なのでmbed01をコピーしてmbed03にします。

ライブラリの生成

ライブラリの生成のために以下が必要になります。

sudo apt-get install ros-kinetic-rosserial-mbed

以下のコマンドで生成します。ライブラリは<platformioワークスペース>/libに入れます。

roscd hard_lecture/platformio/mbed03/lib/
rosrun rosserial_mbed make_libraries.py ./

ros_lib以下には多数のファイルディレクトリが生成されます。ファイルは全て必要ですが、ディレクトリはBufferedSerialrosrosserial_msg、ソース中でincludeしているパッケージ以外は消去しても構いません。

ソースコード

文字を1秒単位でpublishする、msgをsubscribeするとLEDが点灯するというものです。LEDハP0_16につながっているとします。

hard_lecture/platformio/mbed03/src/main.cpp
#include <mbed.h>
#include <ros.h>
#include <std_msgs/Empty.h>
#include <std_msgs/String.h>

DigitalOut led = P0_16;

ros::NodeHandle  nh;

std_msgs::String str_msg;
ros::Publisher chatter("chatter", &str_msg);

void messageCb( const std_msgs::Empty& toggle_msg) {
  led=1;
  wait(0.2);
  led=0;
}
ros::Subscriber<std_msgs::Empty> sub("led", &messageCb );

int main() {

  nh.getHardware()->setBaud(115200);
  nh.initNode();
  nh.advertise(chatter);
  nh.subscribe(sub);

  while (1) {
    str_msg.data = "hello world!";
    chatter.publish( &str_msg );
    nh.spinOnce();
    wait_ms(1000);
  }
}

コンパイル&書き込み

roscd hard_lecture/platformio/mbed03/lib/
platformio run

実行

どうやらubuntuのデフォルトのUSB設定ではRST、DTRの設定のせいでこれらをlpc1768とつないでいると、通常の起動時でもbootモードに入って動かなくなってしまいます。動作時はこの2本の信号は物理的に切り離す必要があります。

1つ目のターミナル
roscore
2つ目のターミナル
rosrun rosserial_python serial_node.py _port:=/dev/ttyACM0 _baud:=115200

これでrostopic list/chatter/ledが見えます。後は普通のrosと同じように使うことができます。

参考

platformioでmbedを使う
lpc21isp
bin->hex変換ツール?
mbedシリアル書き込み
platformio mbedオプション
rosserial mbed

目次ページへのリンク

ROS講座の目次へのリンク