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

　前回までに、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でログインします（第１回参照）。必要なら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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/c0ab0e08-fd94-1dcb-4154-ba49eff954ae.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
 ```

https://www.isc.meiji.ac.jp/~be00085/2023ji2/cppintro/index.html

```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は文字列
 　温度を読み出す事例を見つけたのですが、今の私の力では、理解できませんでした。

 https://github.com/longhongc/ros2-practice-example/blob/main/sensors/src/temp.cpp

 　前回までのディレクトリ構造です。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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/b67f3ccd-e739-f798-91fb-5343bc9f89fa.png)


-----------------
<h2>備忘録　ラズパイ5 ROS2</h2>

[①　ハードの用意とUbuntu Desktop 24.04LTS](https://qiita.com/jamjam/items/9ad621bda6ab2e1d325b)

[②　Ubuntu Desktop 24.04LTSでROS2環境　rqt_graphとturtlesim](https://qiita.com/jamjam/items/b7bed8ec9ff68426ac8d)

[③　Ubuntu Desktop 24.04LTSでROS2環境　Python その１ responder（セットアップ）](https://qiita.com/jamjam/items/d124c662813085bc69e3)

[④　Ubuntu Desktop 24.04LTSでROS2環境　Pythonその２responder（コーディングと実行；失敗）](https://qiita.com/jamjam/items/d488e2e4fa88d9882626)

[⑤　Ubuntu Desktop 24.04LTSでROS2環境　C++ その1 セットアップ main.c](https://qiita.com/jamjam/items/4bba331c08805ccda0a8)

[⑥　Ubuntu Desktop 24.04LTSでROS2環境　C++ その2 セットアップ pub.cpp rqt_graph](https://qiita.com/jamjam/items/51eeb26400517883aa59)

[⑦　Ubuntu Desktop 24.04LTSでROS2環境　C++ その3 セットアップ sub.cpp rqt_graph](https://qiita.com/jamjam/items/50f3bc352e4cd0a7959d)

[⑧　Ubuntu Desktop 24.04LTSでROS2環境　C++ その4 bme280.cpp 温度](https://qiita.com/jamjam/items/f64eaae91fefed4eac34)

[⑨ Ubuntu Desktop 24.04LTSでROS2環境　C++ その5 bme280_3.cpp 温度、湿度、気圧](https://qiita.com/jamjam/items/edb799ec88bdfba29c4c)

[⑩ Ubuntu Desktop 24.04LTSでROS2環境　C++ その6 VL53L1X.cpp 距離センサ](https://qiita.com/jamjam/items/21074d7ed830926d7ff4)

--------------

https://qiita.com/jamjam/items/692568361dde688fad16