1
1

備忘録 ラズパイ5 ROS2 ⑧ Ubuntu Desktop 24.04LTSでROS2環境 C++ その4 bme280.cpp 温度

Last updated at Posted at 2024-08-01

 前回までに、topicを使ったPublisherとSubscriverのとてもベーシックなプログラムを作り、動かしました。
 ここでは、温度を計測するPublisherを作ります。Subscriverはそのまま使います。

環境

  • Raspberry Pi 5 8GB
  • 追加ボード;NVMe Base for Raspberry Pi 5 (NVMe Base by Pimoroni)
  • Crucial クルーシャル P2シリーズ 500GB 3D NAND NVMe PCIe M.2 SSD CT500P2SSD8
  • 初期;RaspberryPi OS Desktop 64bit (Debian version: 12 (bookworm) Release date: March 15th 2024)
  • 現在;Ubuntu Desktop 24.04LTS(64-bit)
  • ROS2 HumbleではなくJazzy

Windows10で、検索窓にcmdと入れ、コマンドプロンプトを起動します。
 sshでログインします(第1回参照)。必要ならupdateします。

C:\Users\yoshi>ssh yoshi.local

温度を測るセンサBME280を接続する

 I2CデバイスでつないだボッシュのBME280は、I2C経由でデータを読む方法とデバイス・ドライバを登録してiioアプリが読み出した測定データを読む方法があります。
 /boot/firmware/READMEに書かれたラズパイのWebサイトに行っても、ラズパイのOS(bookworm)の/boot/firmware/READMEに書かれたセンサ類の情報が見つかりません。ものは試しで、bookwormと同じ手順で組み込んでみました。
 i2cdetectが使えるように、i2c-toolsをインストールします。

C:\Users\yoshi>ssh yoshi.local
yoshi@yoshi:~$ sudo apt install i2c-tools

 接続です。I2CバスにStemma QT/Qwiicコネクタで増設します。使っているセンサ・ボードはAdafruit製です。

lps22-bme280-a.png

 0x76ではなく、0x77に見つけてきました。

yoshi@yoshi:~$ i2cdetect -y 1
    0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- 77

 sudo nano /boot/config.txtを立ち上げ、最後の行に、次の1行を追加します。

dtoverlay = i2c-sensor,bme280,addr=0x77

リブート(restart)します。UUという表記に代わっているので、デバイス・ドライバが組み込まれたことが確認できました。

yoshi@yoshi:~$ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- UU

デバイス・ドライバが組み込まれたので、テキスト・ファイルで測定結果が常に更新されているので読み出します。

yoshi@yoshi:~$  ls /sys/bus/i2c/devices/
1-0077  i2c-1  i2c-11  i2c-12
yoshi@yoshi:~$  ls /sys/bus/i2c/devices/1-0077/iio:device0/
in_humidityrelative_input               in_pressure_oversampling_ratio  name     subsystem
in_humidityrelative_oversampling_ratio  in_temp_input                   of_node  uevent
in_pressure_input                       in_temp_oversampling_ratio      power    waiting_for_supplier
yoshi@yoshi:~$ cat /sys/bus/i2c/devices/i2c-1/1-0077/iio:device0/in_temp_input
26330
yoshi@yoshi:~$ cat /sys/bus/i2c/devices/i2c-1/1-0077/iio:device0/in_pressure_input
101.508132812
yoshi@yoshi:~$ cat /sys/bus/i2c/devices/i2c-1/1-0077/iio:device0/in_humidityrelative_input
60806

 温度は千倍になっているので、26.33℃、気圧はPaなので、1015.08132812hPa、湿度は千倍になっているので、60.806%です。
 ラズパイのOS(bookworm)の場合とまったく同じです。

温度を取得するプログラム

 catで読みだしていたテキスト・ファイルを、プログラムで読み出します。

yoshi@yoshi:~/ros2_ws$ nano  works/src/bme280/readTemp.cpp

readTemp.cpp
#include <iostream>
#include <fstream>       //  ファイル入出力用
#include <cstdlib>       //  exit()用
using namespace std;

int main(void)
{
    ifstream ifs;            //  ifstream の変数(インスタンス)を生成.

    ifs.open("/sys/bus/i2c/devices/i2c-1/1-0077/iio:device0/in_temp_input"); 
    //  ファイルを開く.fopen() に相当
    if( ! ifs ) {            //  ファイルが開けない場合の処理
        cerr << "File open error ! " << endl;
        exit(1);
    }

    char data[32];       //  データを読み込むバッファ
    ifs >> data;          //  ifs から入力
    float temp = stof(data);
    cout << temp/1000.0 << endl;    //  確認のため画面に出力

    ifs.close();          //  ファイルを閉じる.fclose()に相当.
    return 0;
}

 コンパイルし、実行します。

yoshi@yoshi:~/ros2_ws$ g++ -o out works/src/bme280/bme288.cpp
yoshi@yoshi:~/ros2_ws$ ./out
28.35

 関数にしました。

readTemp.cpp
 #include <iostream>
#include <fstream>       //  ファイル入出力用
#include <cstdlib>       //  exit()用
using namespace std;

float readTemp(){
   ifstream ifs;            //  ifstream の変数(インスタンス)を生成.

    ifs.open("/sys/bus/i2c/devices/i2c-1/1-0077/iio:device0/in_temp_input");    
    //  ファイルを開く.fopen() に相当
    if( ! ifs ) {            //  ファイルが開けない場合の処理
        cerr << "File open error ! " << endl;
        exit(1);
    }

    char data[32];       //  データを読み込むバッファ
    ifs >> data;          //  ifs から入力
    float temp = stof(data);
    ifs.close();          //  ファイルを閉じる.fclose()に相当.
    return (float)(temp/1000.0);
}

int main(void)
{
    cout << readTemp();
}

 実行すると、温度を表示します。

温度をpublishする。msgは文字列

 温度を読み出す事例を見つけたのですが、今の私の力では、理解できませんでした。

 前回までのディレクトリ構造です。srcのなかに、bme280ディレクトリを作り、bme280.cppで、プログラムを保存します。プログラムは、前回のpub.cppに、readTemp()関数を組み込んだ形にしました。

$ cd ros2_ws
tree

└── works
  ├── CMakeLists.txt
  ├── include
  │   └── works
  ├── package.xml
  └── src
      ├── exec_sample
      │   └── main.c
      ├── pub
      │   └── pub.cpp
      └── sub
          └── sub.cpp
yoshi@yoshi:~/ros2_ws$ mkdir works/src/bme280
yoshi@yoshi:~/ros2_ws$ nano  works/src/bme280/bme280.cpp
bme280.cpp
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
#include <stdio.h>
#include <iostream>
#include <fstream>       //  ファイル入出力用
#include <cstdlib>       //  exit()用
using namespace std;

float readTemp(){
   ifstream ifs;            //  ifstream の変数(インスタンス)を生成.
    ifs.open("/sys/bus/i2c/devices/i2c-1/1-0077/iio:device0/in_temp_input");
    //  ファイルを開く.fopen() に[>
    if( ! ifs ) {            //  ファイルが開けない場合の処理
        cerr << "File open error ! " << endl;
        exit(1);
    }
    char data[32];       //  データを読み込むバッファ
    ifs >> data;          //  ifs から入力
    float temp = stof(data);
    ifs.close();          //  ファイルを閉じる.fclose()に相当.
    return (float)(temp/1000.0);
}

int main(int argc, char **argv)
{
  printf("start publish bme280\n");
  rclcpp::init(argc, argv);
  auto node = rclcpp::Node::make_shared("publish_bme280_temp");
  auto publisher = node->create_publisher<std_msgs::msg::String>("greeting", 1);

  rclcpp::WallRate loop(1);
  while (rclcpp::ok()) {
    auto msg = std_msgs::msg::String();
    msg.data = "Hello, world " + std::to_string(readTemp());
    publisher->publish(msg);
    loop.sleep();
  }

  rclcpp::shutdown();
  return 0;
}

 CMakeLists.txtを修正します。

 yoshi@yoshi:~/ros2_ws$ nano works/CMakeLists.txt
CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(works)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
 add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_components REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(sub src/sub/sub.cpp)

ament_target_dependencies(sub rclcpp std_msgs)

install(
 TARGETS sub
 DESTINATION lib/${PROJECT_NAME}
 )

add_executable(bme280 src/bme280/bme280.cpp)

ament_target_dependencies(bme280 rclcpp std_msgs)

install(
 TARGETS bme280
 DESTINATION lib/${PROJECT_NAME}
 )

ament_package()

 colcon buildでビルドしたものを登録します。まえに作ったsubscriberのsubを起動します。

yoshi@yoshi:~/ros2_ws$ source ~/ros2_ws/install/setup.bash
yoshi@yoshi:~/ros2_ws$ ros2 run works sub

 もう一つターミナルを立ち上げます。今回作ったpublisherのbme280を起動します。

ssh yoshi.local

yoshi@yoshi:~/ros2_ws$ source ~/ros2_ws/install/setup.bash
yoshi@yoshi:~/ros2_ws$ ros2 run works bme280
start publish bme280

 subが動いているターミナルの最初の付近の様子です。実行中にBME280を指でつまんでいます。

yoshi@yoshi:~/ros2_ws$ source ~/ros2_ws/install/setup.bash
yoshi@yoshi:~/ros2_ws$ ros2 run works sub
start subscribe test
[INFO] [1722152136.834887788] [yoshi_subscriber]: Hello, world 28.420000
[INFO] [1722152137.835059203] [yoshi_subscriber]: Hello, world 28.420000
[INFO] [1722152138.835054433] [yoshi_subscriber]: Hello, world 28.420000
[INFO] [1722152139.835027311] [yoshi_subscriber]: Hello, world 28.420000
[INFO] [1722152140.835045820] [yoshi_subscriber]: Hello, world 28.420000
[INFO] [1722152141.835054939] [yoshi_subscriber]: Hello, world 29.370001
[INFO] [1722152142.835063540] [yoshi_subscriber]: Hello, world 30.180000
[INFO] [1722152143.835096604] [yoshi_subscriber]: Hello, world 30.670000
[INFO] [1722152144.835049742] [yoshi_subscriber]: Hello, world 31.000000
[INFO] [1722152145.835071232] [yoshi_subscriber]: Hello, world 31.260000
[INFO] [1722152146.835029426] [yoshi_subscriber]: Hello, world 31.450001
[INFO] [1722152147.835083157] [yoshi_subscriber]: Hello, world 31.580000
[INFO] [1722152148.835062833] [yoshi_subscriber]: Hello, world 31.290001
[INFO] [1722152149.835103249] [yoshi_subscriber]: Hello, world 31.100000
[INFO] [1722152150.835075518] [yoshi_subscriber]: Hello, world 30.980000

 ディレクトリの様子です。

└── works
    ├── CMakeLists.txt
    ├── include
    │   └── works
    ├── package.xml
    └── src
        ├── bme280
        │   ├── bme280.cpp
        │   └── readTemp.cpp
        ├── exec_sample
        │   └── main.c
        ├── pub
        │   └── pub.cpp
        └── sub
            └── sub.cpp

可視化

ラズパイのターミナルで可視化ツールを動かします。

$ source /opt/ros/jazzy/setup.bash
$ rqt_graph

 rqt_graphの左上にあるリフレッシュ・アイコンをクリックしたのが次の画面です。

Screenshot from 2024-07-28 16-45-29.png


備忘録 ラズパイ5 ROS2

① ハードの用意とUbuntu Desktop 24.04LTS

② Ubuntu Desktop 24.04LTSでROS2環境 rqt_graphとturtlesim

③ Ubuntu Desktop 24.04LTSでROS2環境 Python その1 responder(セットアップ)

④ Ubuntu Desktop 24.04LTSでROS2環境 Pythonその2responder(コーディングと実行;失敗)

⑤ Ubuntu Desktop 24.04LTSでROS2環境 C++ その1 セットアップ main.c

⑥ Ubuntu Desktop 24.04LTSでROS2環境 C++ その2 セットアップ pub.cpp rqt_graph

⑦ Ubuntu Desktop 24.04LTSでROS2環境 C++ その3 セットアップ sub.cpp rqt_graph

⑧ Ubuntu Desktop 24.04LTSでROS2環境 C++ その4 bme280.cpp 温度

⑨ Ubuntu Desktop 24.04LTSでROS2環境 C++ その5 bme280_3.cpp 温度、湿度、気圧

⑩ Ubuntu Desktop 24.04LTSでROS2環境 C++ その6 VL53L1X.cpp 距離センサ


1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1