📈
C++ matplotlib-cpp / gunplotの使い方
海洋ロボコンをやってた人です。
今回はC++の描画ライブラリの導入を、備忘録として記載しておきます。
以下箇条書きになりますが、何卒宜しくお願い致します。
動作環境は以下です。
- OS: Ubuntu 22.04
- Python 3.11
追記事項があれば、別途記載します。
1: matplotlib-cpp
まずはmatplotlib-cppの紹介。C++で使用するにはライブラリの準備とPython系のインストールなどが必要です。
1.1: Input
- matplotlibのcpp版の準備
クローンし以下のパスへ配置するところまで進めておきます。
/usr/local/include/matplotlib-cpp
- 必要なモジュールのインストール
matplotlibに必要なpythonモジュールをインストール
terminal
sudo apt install python3.11-dev
sudo apt install -y python3-matplotlib
python3-numpy
1.2: Implementation
CMakeLists.txtでPythonモジュールをインクルードできるように指定
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(plot_test)
# Default to C99
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()
# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
# Find the Python 3.10 package
find_package(Python3 REQUIRED COMPONENTS Development)
include_directories(${Python3_INCLUDE_DIRS})
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# Include Python headers
add_executable(
matplot_test src/matplot.cpp
)
target_link_libraries(matplot_test ${Python3_LIBRARIES})
2軸ロボットアームの順運動学を解き、その結果をmatplotlibへ描画するプログラムにしてみます。
2軸ロボットアームの各リンクの長さを
matplot.cpp
#include "matplotlib-cpp/matplotlibcpp.h"
#include <vector>
#include <cmath>
namespace plt = matplotlibcpp;
// 2軸アームの順運動学を計算
std::pair<std::vector<double>, std::vector<double>> forward_kinematics(
const std::vector<double>& theta1,
const std::vector<double>& theta2,
double l1,
double l2
) {
std::vector<double> x, y;
for (size_t i = 0; i < theta1.size(); ++i) {
double x_i = l1 * cos(theta1[i]) + l2 * cos(theta1[i] + theta2[i]);
double y_i = l1 * sin(theta1[i]) + l2 * sin(theta1[i] + theta2[i]);
x.push_back(x_i);
y.push_back(y_i);
}
return {x, y};
}
int main() {
// アームの長さ
double l1 = 1.0;
double l2 = 1.0;
// theta1, theta2の範囲を細かく分割
int num_points = 20;
std::vector<double> theta1, theta2;
for (int i = 0; i < num_points; ++i) {
theta1.push_back(M_PI/2 * i / num_points);
theta2.push_back(M_PI/2 * i / num_points);
}
// 順運動学を計算
auto [x, y] = forward_kinematics(theta1, theta2, l1, l2);
// 軌跡を描画
plt::plot(x, y, "r-"); // 軌跡
plt::scatter(x, y); // 軌跡のポイント
// 各軸の部分を別々に描画
for (size_t i = 0; i < theta1.size(); ++i) {
std::vector<double> x_segment = {0, l1 * cos(theta1[i]), x[i]};
std::vector<double> y_segment = {0, l1 * sin(theta1[i]), y[i]};
plt::plot(x_segment, y_segment, "b-");
}
// プロットを表示
plt::title("2-Axis Robot Arm Trajectory");
plt::xlabel("X");
plt::ylabel("Y");
plt::show();
return 0;
}
1.3: Verification
2: gnuplot
matplotlib-cppと比較し、準備が簡単。一方で描画のためのファイル準備などが必要。
2.1: Input
gnuplotの基礎は以下を熟知すればOK
ディレクトリは以下になります。
folder_tree
|--- CMakeLists.txt
|--- build
| |--- test.gp
| |--- test
| |--- test.txt
|--- folder_tree.md
|--- src
| |--- test.cpp
2.2: Implementation
gnuplot_test.cpp
#include <iostream>
#include <cmath>
#include <vector>
#include <string.h>
class Test {
public:
Test();
double o_i_[2] = {};
void update(double time);
private:
std::string fname = "./test.txt";
FILE *fp = fopen(fname.c_str(), "w");
};
Test::Test(){
o_i_[0] = -0.2;
o_i_[1] = 0.0;
}
void Test::update(double time){
fprintf(fp, "%f, %f, %f\n", time, o_i_[0], o_i_[1]);
std::cout << "Step " << time << ": Output0 = " << o_i_[0] << ", Output1 = " << o_i_[1] << std::endl;
}
int main() {
Test test;
double time;
double dt = 0.01; // Hz / (2 * 10)
double sim_time = 100.0;
int num_step = static_cast<int>(sim_time/dt);
for(int i=0; i<num_step; i++){
time = i*dt;
test.update(time);
}
return 0;
}
build下へ.gpファイルを作成する
test.gp
plot [0:10][-0.2:0.2] \
'test.txt' using 1:2 with lines,\
'test.txt' using 1:3 with lines linestyle 3,\
2.3: Verification
terminal
gnuplot
load "test.gp"
以上です。
Likeいただけると大変励みになりますので、よろしくお願いいたします。
Discussion