STM32F767ZIでROSserial_stm32を使う

　タイトルの通り，ROSserial_stm32を利用してSTM32F767ZIとROSで通信を行います。似たような記事はネット上にいくつかあるのですが，何ヵ所か詰まった部分があるので個人的なメモも兼ねて書いていこうと思います。
　前提としてUbuntu20.04にROS-noeticとCubeIDEをインストールしておいてください。

# ターミナルでの作業
## ROSserialなどのインストール

　ROSserialをインストールします。
```
$ sudo apt-get install ros-noetic-rosserial
```
　rosserial_stm32をSrcにcloneします。
```
$ cd ~/catkin_ws/src
$ git clone https://github.com/yoneken/rosserial_stm32
$ cd ..
$ catkin_make
```

## roslibの生成

　exampleのchatterを適当な場所にコピーして，そこにroslibを生成します。
```
$ roscd rosserial_stm32
$ cd src/ros_lib/examples
$ cp -r chatter ~/Documents
$ cd ~/Documents/chatter
```
　そのフォルダ内で以下のコードを実行します。一番後ろの`.`を忘れないでください。
```
$ rosrun rosserial_stm32 make_libralies.py .
```
　この時、選択肢が出てきたら2を選択します。
<details><summary>エラーが出た場合はこちらも参考に</summary><div>

```
/usr/bin/env:'python':そのようなファイルやディレクトリはありません
```
と表示された場合は
```
$ sudo apt-get install python-is-python3
```
もしくは
```
$ sudo apt update
$ sudo apt upgrade
```
で改善するかも。
</div></details>

　最後にInc内のcppファイルをSrcに移動させておきましょう。
```
$ mv Inc/duration.cpp Inc/time.cpp Src
```

# CubeIDEでの作業
　次にCubeIDEを開き、`File`→`New`→`STM32 Project`と順番にクリックします。
　STM32F767ZIのボードを選択してから`Next>`→適当なプロジェクト名を入力→`Finish`とし，プロジェクトを生成します。

## .iocファイルの設定
### ピン設定
`PB8`ピンを`USART3_TX`に設定し、ユーザーラベルを`VCP_TX`に，
`PB9`ピンを`USART3_RX`に設定し、ユーザーラベルを`VCP_RX`にしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3231080/5321f5a0-4e04-c151-7ca8-582b6798f159.png)



### USART3の設定
`Connectivity`の`USART3`の設定を変更します。

|Mode|Asynchronous|
---|---

 - Parameter Settings

|Baud Rate|57600|
---|---
 - NVIC Settings
`USART3 global interrupt`をチェックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3231080/c79f22f8-2a87-ee30-cfb4-378b54592df7.png)

 - DMA Settings
`Add`→`USART3TX`として，`Priority`を`High`に変更します。
`Add`→`USART3RX`として，`Priority`を`High`，`Mode`を`Circular`に変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3231080/e4076d54-d30f-bed9-3cf5-0a87acd2539a.png)


### TIM2の設定

|ClockSource|InternalClock|
---|---

### Clock Configurationの設定
`HCLK(MHz)`をある程度大きな値にします（64MHzで動作確認済み）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3231080/f6ebf399-9c9b-33bc-e83e-9218c443997c.png)






## ソースコード関連の作業

　先程コピーしたChatterの`Inc`と`Src`をコピーして，今回作成したCubeIDEのプロジェクトの`Core`フォルダ内に貼り付けます。
　できたらCubeIDEに戻って，上のスタンプマークから`GenerateCode`しましょう。

### プロジェクト設定の変更
　`Project Explorer`に表示されているプロジェクト名を右クリックして
`properties`→`C/C++General`→`File Types`と進み，`Use project settings`にチェックを入れます。
　`New...`をクリックして，

Pattern:`*.h`
Type:　`C++ Header File`

を追加します。`Apply and Close`から閉じましょう。

　同様にプロジェクト名を右クリックして`Convert to C++`をクリックします。

### STM32Hardware.hの修正
`Core/Inc/Stm32Hardware.h`を修正します。
 - 38行目
```
#define STM32F3xx
↓　　　　↓　　　　↓　変更する
#define STM32F7xx
```
 - 52行目
```
extern UART_HandleTypeDef huart2;
↓　　　　↓　　　　↓　　　　↓　　　　↓　変更する
extern UART_HandleTypeDef huart3;
```
 - 69行目
```
huart(&huart2), rind(0), twind(0), tfind(0){
↓　　　　↓　　　　↓　　　　↓　　　　↓　　　　↓　変更する
huart(&huart3), rind(0), twind(0), tfind(0){
```
 - 107行目
```
HAL_UART_Transmit_DMA(huart, &(tbuf), twind);
↓　　　　↓　　　　↓　　　　↓　　　　↓　　　　↓　変更する
HAL_UART_Transmit_DMA(huart, tbuf, twind);
```


### main.cの修正
　以下のように変更します。
```
/*USER CODE BEGIN Include*/
#include "mainpp.h"
/*USER CODE END Include*/
```







### mainpp.cppの変更
　今回はROSから送られてきた文章をそのままオウム返しするコードを書きます。
<details><summary>コード全文</summary><div>

```cpp
#include <mainpp.h>
#include <ros.h>
#include "std_msgs/String.h"

ros::NodeHandle nh;

void callback(const std_msgs::String&);

std_msgs::String str_msg
ros::Publisher f7_pub("f7_data", &str_msg);
ros::Subscriber<std_msgs::String> ros_sub("ros_data", &callback);

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
  nh.getHardware()->flush();
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
  nh.getHardware()->reset_rbuf();
}

void setup(void)
{
  nh.initNode();
  nh.advertise(f7_pub);
  nh.subscribe(ros_sub);
}

void loop(void)
{
  nh.spinOnce();
}

void callback(const std_msgs::String& ros_data){
	f7_pub.publish(&ros_data);
}
```
</div></details>

　ビルドできたらマイコンに書き込みましょう。

# テスト
　初回は以下のコマンドを打ってください。
```
$ sudo adduser $USER dialout
```
　通常はここからです。すべて別のターミナルで起動します。
```
$ roscore
$ rosrun rosserial_python serial_node.py _port:=/dev/ttyACM0
$ rostopic pub -r 2 /ros_data std_msgs/String "data: 'hello world!'"
$ rostopic echo /f7_data 
```
![ros_serial.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3231080/1745484c-6fd5-d426-03ea-738723c372c2.png)
　(画像右上)`rostopic echo`で受信できていますね！


　ちなみに送受信のデータ量を増やしたければ`Inc/ros.h`の`typedef`の部分をいじれば良いっぽいです。
```
typedef NodeHandle_<STM32Hardware, MAX_SUBSCRIBEARS, MAX_PUBLISHERS, INPUT_SIZE, OUTPUT_SIZE> NodeHandle;
```
`MAX_SUBSCRIBEARS`はサブスクライバーの最大数,
`MAX_PUBLISHERS`はパブリッシャーの最大数,
`INPUT_SIZE`は最大受信データサイズ,
`OUTPUT_SIZE`は最大送信データサイズです。
# 終わり
　f303などでは割とすんなり動いたのですが，f7だとなかなかうまくいかなかず結構苦労したので，この記事が同じく苦労している人の助けになればと思います。なおcan通信と同時に行うとエラーが発生する？ので解決待ち。