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

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

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

インストールについては[ROS講座02 インストール](https://qiita.com/srs/items/e0e0a9dc3f94c2d3348e)を参照してください。
またこの記事のプログラムはgithubにアップロードされています。[ROS講座11 gitリポジトリ](https://qiita.com/srs/items/25a56a6abda41dcf396e)を参照してください。

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

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

を説明します。

# カスタムmbedボードの作り方
[青mbed](https://os.mbed.com/platforms/mbed-LPC1768/)が一番メジャーですが、ロボット用としては自分で基板を起こしたくなります。そんな時は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 |

![lpc1768.png](https://qiita-image-store.s3.amazonaws.com/0/254442/e03c4707-347c-b9d2-b303-5e77825999ec.png)

書き込みにはシリアル通信を使います。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`ともう一行出る）

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

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

```c++: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");
  }
}
```

最後にコンパイルです。

```shell:ビルドの実行
platformio run
```

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

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

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

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

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

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

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

```shell: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では使えません。

```c++: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`をするとエラーになります。設定ファイルに書き加える必要があります。

```ini: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にします。

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

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

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

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

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

## ソースコード

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

```c++: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);
  }
}
```

## コンパイル＆書き込み

```shell
roscd hard_lecture/platformio/mbed03/lib/
platformio run
```

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

```shell:1つ目のターミナル
roscore
```

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

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

# 参考
[platformioでmbedを使う](https://qiita.com/stastaka/items/a6a50dbbb2933bd78bdd)
[lpc21isp](http://www.postcard.st/nosuz/tech/2014/01/13-80)
[bin->hex変換ツール？](https://daichiahl.wordpress.com/2016/01/23/ubuntu%E3%81%A7stm32-arm%E3%83%9E%E3%82%A4%E3%82%B3%E3%83%B3%E3%81%AE%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%82%92%E6%95%B4%E3%81%88%E3%82%8B/)
[mbedシリアル書き込み](https://os.mbed.com/users/okini3939/notebook/flash-program/)
[platformio mbedオプション](https://docs.platformio.org/en/latest/frameworks/mbed.html)
[rosserial mbed](http://wiki.ros.org/rosserial_mbed/Tutorials/rosserial_mbed%20Setup)

# 目次ページへのリンク
[ROS講座の目次へのリンク](https://qiita.com/srs/items/5f44440afea0eb616b4a)