環境
この記事は以下の環境で動いています。
項目 | 値 |
---|---|
CPU | Core i5-8250U |
Ubuntu | 22.04 |
ROS2 | Humble |
SQLite | 3.37.2 |
概要
ROS2はパラメーター等データの読み取りは仕組みがあるのですが、不揮発にデータを保存する標準的な仕組みはありません。
ROS2の多くのノード(例:slamのmap情報の保存)ではファイル書き出しをして行っています。しかしプランニングのユーザーデータなど細々した情報が多く、それぞれをファイル書き出しすると管理が大変です。
ここではSQLiteのデータベースを使ってROS2実行中の情報を不揮発に保存することを目指します。sqliteはROS2のrosbagのファイル形式としても使われている形式です。
SQLite
データベースというとサーバーで動く物を想像しますが、SQLiteはローカルで動くデータベースで、ライブラリの形で提供されます。SQL構文でデータの操作を行うことが出来ます。
SQLiteをコマンドで使う
SQliteファイルを作る。
sqlite3をインストールします。
sudo apt install sqlite3
sqliteを実行することで
$ sqlite3 data.db
SQLite version 3.37.2 2022-01-06 13:25:41
Enter ".help" for usage hints.
sqlite> # <- SQLのコマンドを打てる。Ctrl+Dで抜ける
$ ls
data.db
- sqlite3コマンドの引数でファイルを指定します。存在しない場合はファイルを生成します。
-
sqlite>
というプロンプトが出るのでここでSQLコマンドを打ち込みます。Ctrl+Dで抜けます。
table作成、行の挿入、内容の確認
sqlite> CREATE TABLE DataList (name, count);sqlite> INSERT INTO DataList VALUES("hoge",10);
sqlite> SELECT * FROM DataList;
hoge|10
sqlite> INSERT INTO DataList VALUES("fuga",20);
sqlite> SELECT * FROM DataList;
hoge|10
fuga|20
- RDBとは、簡単にいえばExcelのような表形式のデータをコマンドで扱えるものです。
-
CREATE TABLE
で新たな表を作れます。かっこの中は列の設定です。多くのSQLデータベースでは型の指定が必須ですが、SQLiteでは型名の指定は不要です。 -
INSERT INTO
ではデータの行を追加します。 -
SELECT
ではデータの中身を見ることが出来ます。
SQLiteをsqlitebrowserで使う
sqlite3コマンドだけでデータを操作するのはつらいところ、sqlitebrowserを使うとGUIで操作が出来ます。
sudo apt install sqlitebrowser
sqlitebrowser
「Open DataBase」のボタンで先ほどの「data.db」ファイルを選択します。
するとファイルの中身が表示して「Brows Data」タブを開くとデータベースが表示されます。
GUI上の表に入力することで、データを変更することもできます。データは「Write Change」ボタンを押したときにファイルに書き込まれます。
SQLiteをc++から使う
ソースコード
#include <sqlite3.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
sqlite3 *db = NULL;
if (sqlite3_open("data.db", &db) != SQLITE_OK)
{
printf("%s[%s]\n", __func__, sqlite3_errmsg(db));
return -1;
}
if (sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS CountList (name PRIMARY KEY, count);", NULL, NULL, NULL) != SQLITE_OK){
printf("%s[%s]\n", __func__, sqlite3_errmsg(db));
return -1;
}
if (sqlite3_exec(db, "INSERT OR IGNORE INTO CountList VALUES ('boot', 0);", NULL, NULL, NULL) != SQLITE_OK){
printf("%s[%s]\n", __func__, sqlite3_errmsg(db));
return -1;
}
if (sqlite3_exec(db, "UPDATE CountList SET count = count + 1 WHERE name == 'boot'", NULL, NULL, NULL) != SQLITE_OK){
printf("%s[%s]\n", __func__, sqlite3_errmsg(db));
return -1;
}
printf("Done\n");
return 0;
}
-
CREATE TABLE
でテーブルを作成します。-
IF NOT EXISTS
はテーブルが無い時だけ作成します。これをつけないと、テーブルがあるときにエラーになります。 -
PRIMARY KEY
はその行の値がユニークになる制約を加えます。
-
-
INSERT INTO
はテーブルにレコード(行)を追加します。- これだけだと
PRIMARY KEY
の制約があるために2回目以降の実行でエラーになってしまいます。OR IGNORE
をつけるとPRIMARY KEY
の制約に反する時は無視します。
- これだけだと
-
UPDATE
コマンドではname = boolのレコードでcountをインクリメントします。
ビルド&実行
source /opt/ros/humble/setup.bash
cd ros2_ws
colcon build
$ ros2 run sqlite_lecture sample1
Done
$ ros2 run sqlite_lecture sample1
Done
$ ros2 run sqlite_lecture sample1
Done
$ sqlite3 data.db
SQLite version 3.37.2 2022-01-06 13:25:41
Enter ".help" for usage hints.
sqlite> SELECT * FROM CountList;
boot|3
3回実行すると、bootの値は3になります。