えいあーるれいの技術日記

ROS2やM5 Stack、Ubuntuについて書いています

SPI接続Ethernetモジュールを使ってmicro-ros-arduinoを動かす(STM32F4・Arduino・ROS2)

1年(実装してからは2年)くらい放置していたmicro-ROSの記事です。


STM32マイコンとSPI接続のEthernetチップ「W5100」を接続してmicro-ROSで通信させてみました。

STM32F446REとSTM32L432KCで動作確認したのでArduino_Core_STM32がサポートしていれば動きます。

github.com

STM32F7系でサポートされているEthernet以外でも動くようになると、ボードの選択肢が増えて便利だと思います。

ARM CoreかつArduinoプラットフォームでサポートされていればコンパイルは通りそうですが、RaspberryPi picoはリンカー関連、Arduino R4はEthernetとの通信がうまくいっておらず断念しました😢


以前のmicro-ROSの記事

ar-ray.hatenablog.com

ar-ray.hatenablog.com

ar-ray.hatenablog.com


micro-ROSとは

micro-ROSはマイクロコントローラを接続するためのプロジェクトで、rclcをベースにPub-Sub接続を実現します。 サポートされているボードやIDEがとても広いです。

micro-ROS自体にはノード探索機能が搭載されていないため、micro-ROS-agentをホスト側に用意してそこに接続する必要があります。

SPI-Ethernetチップ「W5100」

W5100はSPI接続が可能なEthernet処理チップです。複雑な処理が必要なTCP/IPUDP処理を単純な命令およびそのコールバックで済ませることができ、Arduino + ネットワーク接続を実現することができます。チップ自体は600円程度で購入できます。

今回は、Switch-Scienceで購入したものを使用します。

WIZnetイーサネットHAT — スイッチサイエンス

この製品はPico用のシールドとなっており、Picoと一体になっているモデルも購入しています。

W5100S-EVB-Pico — スイッチサイエンス


環境構築

Ethernetライブラリ

STM32のネイティブEthernet用のライブラリはSTM32Ethernetですが、SPI接続のW5100は別のライブラリが必要です。

github.com

ArduinoのデフォルトEthernetライブラリやSTM32DuinoのEthernetライブラリは使わないでください。

配線については、SPIの4線と電源として3.3V・GNDを接続します。


開発環境にはPlatformIO (arduino) を使用します。

コンパイラを一括で設定できるので、開発環境を固定できない趣味開発との相性が抜群にいいです。

依存関係の記述(STM32)

L432とF446どちらでも使えます。

;; ==============================
;; STM32L4, F4 SPI-Ethernet Model
;; ==============================
[env:nucleo]
platform = ststm32
framework = arduino

;; L432
board = nucleo_l432kc
board_build.f_cpu = 80000000L
board_build.mcu = stm32l432kcu6

;; F446
; board = nucleo_f446re
; board_build.f_cpu = 180000000L
; board_build.mcu = stm32f446re

monitor_speed = 115200
upload_speed = 115200
upload_device = /dev/ttyACM0

lib_deps =
;; microros ---------------------------------------------------------------
    https://github.com/NITKK-ROS-Team/micro_ros_arduino.git#humble_custom
    https://github.com/NITKK-ROS-Team/micro_ros_arduino_simpler.git#main

    https://github.com/WIZnet-ArduinoEthernet/Ethernet.git

build_flags =
    -L ./.pio/libdeps/pico/micro_ros_arduino/src/cortex-m4/
    -l microros


Arduinoコード

bool型のメッセージをsubしてtrueを送ったらマイコン内でカウントアップしてintデータをpubするプログラムです。

#include <Arduino.h>

// executor ------------------
#include <micro_ros_arduino.h>

#include <stdio.h>
#include <rcl/rcl.h>
#include <rcl/error_handling.h>

#include <rclc/rclc.h>
#include <rclc/executor.h>

rclc_executor_t executor;
rclc_support_t support;
rcl_allocator_t allocator;
rcl_node_t node;

# message -----------------------
#include <std_msgs/msg/bool.h>
#include <std_msgs/msg/int32.h>

rcl_publisher_t publisher;
std_msgs__msg__Int32 msg_int32;

rcl_subscription_t subscription;
std_msgs__msg__Bool msg_bool;

// timer ----------------------
rcl_timer_t timer;

int counter = 0;

// subscription callback ("/bool_data", "std_msgs/msg/bool") 
void bool_callback(const void *msgin)
{
  const std_msgs__msg__Bool *_msg = (const std_msgs__msg__Bool *)msgin;
  counter += _msg->data;
}

// timer callback (10ms) 
void timer_callback(rcl_timer_t *timer, int64_t last_call_time)
{
  (void)last_call_time;
  (void)timer;

  msg_int32.data = counter;
  rcl_publish(&publisher, &msg_int32, NULL);
}

// setup micro_ros_arduino ===============================================
void setup()
{
#if !defined(STM32L4xx)
#error "This example is only for STM32L4xx"
#endif

  byte arduino_mac[] = {0xAA, 0xBB, 0xCC, 0xEE, 0xDD, 0xFF};
  IPAddress arduino_ip(192, 168, 0, 10);
  IPAddress agent_ip(192, 168, 0, 5);
  int agent_port = 2000;
  int cs = 6;

  set_microros_native_ethernet_udp_transports(arduino_mac, arduino_ip, 2, agent_ip, cs);
  get_default_allocator();
  rclc_init("uros_node", "ns");
  init_executor(2);


  // rclc-publisher-subscriber-timer ======================================
  rclc_publisher_init_default(&publisher, &node, ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32), "int32_data");

  rclc_create_timer_and_add(&timer, 10, timer_callback);
  rclc_create_subscription_and_add(&subscription, ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Bool), &msg_bool, &bool_callback, "bool_data");
}

// loop micro_ros_arduino ===============================================
void loop()
{
  rclc_delay(10);
}


コンピュータ側の設定

コンピュータはx86のものを使ってください。(MacやRaspberryPi OSだとうまくうごかないかもしれないです)


コンピュータ側のEhernetポートはデフォルトでついているものでもUSBで拡張したものでもいいです。

まず、マイコンと接続するEthernetソケットのIPアドレスagent_ip と同じにします。(この場合は 192.168.0.5

IPアドレスを設定したら、マイコンとPCをLANケーブルで接続します。CAT5e対応とかであれば問題ないと思います。

dockerでmicro-ros-agentを動かします。

docker run -it --rm -v /dev:/dev --privileged --net=host microros/micro-ros-agent:humble udp4 --port 2000

fastrtpsで DOMAIN_ID=0 の設定を忘れないでください!


Arduino UNO R4

Arduino UNO R4でも使ってみます。


Arduino UNO R4にはWi-FiモデルがあるのでEthernet対応の必要性は微妙ですが、USB-Serialでとりあえず動かせることを確認しました。

www.switch-science.com

感謝🙏


micro_ros_arduino_simplerへの組み込みも終わっており、platformioで ARDUINO_ARCH_RENESAS フラグを立てればUSB-SerialもEthernetコンパイルは通ります。

micro-ros-arduinoのUSB-Serialはうまく動くようになりました。

一方、EthernetはまさかのMACアドレスの設定が失敗するトラブルで断念。

Arduino UNO R4向けの設定とWiFiS3をlib_ignoreに含めるよう先程のplatformio.iniに変更すればビルドができるようになります。

実は、Arduino UNO R4とSPI通信の相性は悪いようで、UNO R3より性能低下するとの話題も上がっているようです😢

Uno R4 Poor SPI Performance - #5 by fat16lib - UNO R4 Minima - Arduino Forum

誰か助けてー