LIFE LOG(ここにはあなたのブログ名)

あつあつ備忘録

ソフトやハード、時にはメカの備忘録をまとめていきます

【C++】仮引数を受け取るコンストラクタ

f:id:AtsuyaKoike:20190524095847p:plain:w300

  • コンストラクタ関数には引数を渡すことができる

study48.cpp

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;

class strtype {
    char *p;
    int len;
public:
    strtype( char * );
    ~strtype();
    void show();
};

strtype::strtype( char *ptr ) {
    len = strlen( ptr );
    p = ( char *) malloc( len + 1 );
    if ( !p ) {
        cout << "メモリ割り当てエラー" << endl;
        exit(1);
    }
    strcpy( p, ptr );
}

strtype::~strtype() {
    cout << "pを開放する" << endl;
    free( p );
}

void strtype::show() {
    cout << p << " - 長さ:" << len << endl;
}

int main() {
    strtype s1("This is a test."), s2("I like C++.");
    s1.show();
    s2.show();

    return 0;
}

コンパイル

$ g++ -o study48 study48.cpp 

実行

$ ./study48 
This is a test. - 長さ:15
I like C++. - 長さ:11
pを開放する
pを開放する

引用・参考はこちら

f:id:AtsuyaKoike:20190524100759j:plain:w200
独習C++ 第4版 https://www.amazon.co.jp/dp/4798119768

【C++】コンストラクタ関数とデストラクタ関数

f:id:AtsuyaKoike:20190524095847p:plain:w300

  • コンストラクタ関数
    • クラス名と同じ。
    • スタックの索引値を設定することができる
    • オブジェクト作成時に実行される
  • デストラクタ関数
    • オブジェクトが破棄されるときに呼び出される
      • mainでオブジェクトが生成されていたとしたら、mainを抜けるとき
    • 例えばオブジェクト生成時にメモリを割り当てた場合は、メモリを開放する
    • コンストラクタ関数の名前の頭に「~」をつけたものがデストラクタ関数

study41.cpp

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;

#define SIZE 255

class strtype {
    char *p;
    int len;
public:
    strtype();
    ~strtype();
    void set( char * );
    void show();
};

strtype::strtype() {
    p = ( char * ) malloc(SIZE);
    if ( !p ) {
        cout << "メモリ割り当てエラー" << endl;
        exit(1);
    }
    *p = '\0';
    len = 0;
}

strtype::~strtype() {
    cout << "pを開放する" << endl;
    free(p);
}

void strtype::set( char *ptr ) {
    if ( strlen( ptr ) >= SIZE ) {
        cout << "文字列が大きすぎる" << endl;
        return;
    }
    strcpy( p, ptr );
    len = strlen( p );
}

void strtype::show() {
    cout << p << " - 長さ:" << len << endl;
}

int main() {
    strtype s1, s2;
    s1.set( "This is a test." );
    s2.set( "I like C++." );
    s1.show();
    s2.show();

    return 0;
}

コンパイル

$ g++ -o study41 study41.cpp 

Warningがでますが、今回は気にしないということで。

実行

$ ./study41 
This is a test. - 長さ:15
I like C++. - 長さ:11
pを開放する
pを開放する

引用・参考はこちら

f:id:AtsuyaKoike:20190524100759j:plain:w200
独習C++ 第4版 https://www.amazon.co.jp/dp/4798119768

【C++】オーバーロード

f:id:AtsuyaKoike:20190524095847p:plain:w300

  • 関数オーバーロードの主な用途として、コンパイル時ポリフォーリズムを行うことが挙げられる
  • 1つの名前をオーバーロードすることで、複数あるデータの方の種類などに対応できる
    • 関数をたくさん作り、それぞれ別の名前をつける必要がない

study29.cpp

#include <iostream>
using namespace std;

int myabs( int );
long myabs( long );
double myabs( double );

int main() {
    cout << "-10の絶対値:" << myabs(-10) << endl << endl;
    cout << "-10Lの絶対値:" << myabs(-10L) << endl << endl;
    cout << "-10.01の絶対値:" << myabs(-10.01) << endl << endl;
}

int myabs( int n ) {
    cout << "整数用のmyabs()" << endl;
    return n<0 ? -n : n;
}

long myabs( long n ) {
    cout << "長整数用のmyabs()" << endl;
    return n<0 ? -n : n;
}

double myabs( double n ) {
    cout << "倍精度浮動小数点数用のmyabs()" << endl;
    return n<0 ? -n : n;
}

コンパイル

g++ -o study29 study29.cpp

実行

$ ./study29
整数用のmyabs()
-10の絶対値:10

長整数用のmyabs()
-10Lの絶対値:10

倍精度浮動小数点数用のmyabs()
-10.01の絶対値:10.01

引用・参考はこちら

f:id:AtsuyaKoike:20190524100759j:plain:w200
独習C++ 第4版 https://www.amazon.co.jp/dp/4798119768

【C++】クラスの作成

f:id:AtsuyaKoike:20190524095847p:plain:w300

概要

  • 1つのクラスに対して複数のオブジェクトを作ることができる。
  • 今回はstackクラスに対して、s1とs2という名前でオブジェクトを作成する。
  • オブジェクト同士は干渉しない

study21.cpp

#include <iostream>
using namespace std;

#define SIZE 10

// 文字列の保存
class stack {
    char stck[SIZE];
    int tos;
    public:
        void init();
        void push( char ch );
        char pop();
};

void stack::init() {
    tos = 0;
}
void stack::push( char ch ) {
    if ( tos == SIZE ) {
        cout << "スタックはいっぱいです";
        return;
    }
    stck[tos] = ch;
    tos++;
}

char stack::pop() {
    if ( tos == 0 ) {
        cout << "スタックは空です";
        return 0;
    }
    tos--;
    return stck[tos];
}

int main() {
    stack s1, s2;
    int i;

    s1.init();
    s2.init();
    s1.push('a');
    s2.push('x');
    s1.push('b');
    s2.push('y');
    s1.push('c');
    s2.push('z');

    for ( i=0; i<3; i++ ) cout << "s1をポップする:" << s1.pop() << endl;
    for ( i=0; i<3; i++ ) cout << "s2をポップする:" << s2.pop() << endl;

    return 0;
}

コンパイル

g++ -o study21 study21.cpp 

実行

s1をポップする:c
s1をポップする:b
s1をポップする:a
s2をポップする:z
s2をポップする:y
s2をポップする:x

引用・参考はこちら

f:id:AtsuyaKoike:20190524100759j:plain:w200
独習C++ 第4版 https://www.amazon.co.jp/dp/4798119768

【C++】オブジェクト指向プログラミング

f:id:AtsuyaKoike:20190524095847p:plain:w300

カプセル化

  • プログラムコードとプログラムコードが扱うデータを一体化して、外部の干渉から両者を保護するための仕組み。
  • 実際にはprivateやpublicといった機能を使用する。publicはprivateの制御インターフェースを提供されるっために使われる。

ポリモーフィズム

継承

  • 1つのオブジェクトがほかのオブジェクトの性質を獲得するプロセスのこと。
    • オブジェクトは特定の性質を汎用セットとして受け継いだ上で、そのオブジェクトの機能を独自に追加できる。
  • 例えば、家は「建物」という汎用クラスの一部、「建物」は「建築物」というクラスの一部、そして「建築物」は汎用的な「人工物」のクラスの一部
    • どのクラスえも、小クラスは親クラスが持つ性質をすべて継承し、独自の性質を追加して定義

引用・参考はこちら

f:id:AtsuyaKoike:20190524100759j:plain:w200
独習C++ 第4版 Amazon CAPTCHA

【ROS】tfを用いた座標変換

f:id:AtsuyaKoike:20190421152613p:plain
画像元

tfとは

  • 座標系管理システム
  • ROSでは順運動学の問題にtfを使用している

tfの特徴

  1. 時間動機ができる
  2. 分散システムが使える
  3. rvizとの連携が強力

以下のようなものを作る場合には必須

  • 自立移動ロボット
  • 複数の関節を持つロボットアーム
  • 3次元物体の認識プログラム
$ roslaunch pr2_gazebo pr2_empty_world.launch 
$ cd catkin_ws/src/
$ git clone https://github.com/OTL/ez_utils.git
$ cd ../
$ catkin_make
$ rosrun rviz rviz

表示させるものをいい感じに選択する(下の画像の左メニューを参考に)
f:id:AtsuyaKoike:20190515155542p:plain:w600



f:id:AtsuyaKoike:20190515160255p:plain:w400
そして、TFの「head_plate_frame」と「I_gripper_led_frame」にチェックを入れる

f:id:AtsuyaKoike:20190515160441p:plain:w600
するとこのように、必要なものだけを表示させることができる

相対関係を取得する

  • /head_plate_frameが頭
  • /I_gripper_led_frameが左手先

tf_echoでこれらのフレーム間の相対位置を調べることができる

$ rosrun tf tf_echo /head_plate_frame /l_gripper_led_frame
At time 817.691
- Translation: [0.756, 0.188, -0.271]
- Rotation: in Quaternion [-0.002, -0.391, 0.000, 0.920]
            in RPY (radian) [-0.005, -0.803, 0.003]
            in RPY (degree) [-0.286, -46.031, 0.167]

そして、look_hand.pyを作成する

#!/usr/bin/env python
import rospy
import tf2_ros
from ez_utils.ez_joints import EzJoints

if __name__ == "__main__":
    rospy.init_node( 'pr2_look_left_hand' )
    tf_buffer = tf2_ros.Buffer()
    tf_listener = tf2_ros.TransformListener( tf_buffer )
    
    # make EzJoints instance and this topic to Publish
    head = EzJoints( '/head_traj_controller' )
    left_arm = EzJoints( '/l_arm_controller' )
    
    yaw_angle = 0.0 # init
    pitch_angle = 0.0 # init
    rate = rospy.Rate(10.0)
    while not rospy.is_shutdown():
        try:
            trans = tf_buffer.lookup_transform( 'head_plate_frame', 'l_gripper_led_frame', rospy.Time() )
            
            # decide angle
            yaw_angle = trans.transform.translation.y / 1
            pitch_angle = -trans.transform.translation.z / 1
            
            print trans.transform.translation
            head.set_positions( [yaw_angle, pitch_angle] ) # Send angle
        except ( tf2_ros.LookupException, tf2_ros.ConnectivityException, tf2_ros.ExtrapolationException ):
            rospy.logwarn( 'tf not found' )
        rate.sleep()
  • 4行目:EzJointsを使うとPR2の関節を簡単に動かすことができる
  • 8、9行目:TFのデータを蓄えるバッファを作成し、引数にしてTransformListenerを作り、tf_listenerに代入する。このtf_listenerを使用してTFの機能にアクセスする
  • 20行目:指定したフレーム間の相対関係を取得する。rospy.Time()は取得可能な最新の時間。また、この関数lookup_transformは失敗すると例外を投げるため、try, exceptで例外処理をする
$ chmod 755 look_hand.py 
$ rosrun ros_start look_hand.py
$ rosrun rqt_ez_publisher rqt_ez_publisher 

f:id:AtsuyaKoike:20190515172135p:plain

  1. topicを選択
  2. スライダを増やすために+をクリックする

これで上の画像のようになる。



f:id:AtsuyaKoike:20190515172243p:plain:w600
この時、PR2このように顔が手の方向を向いていることが分かる。

【ROS】rviz・rqt_plot

f:id:AtsuyaKoike:20190421152613p:plain
画像元

rviz

ROSの可視化といえばrviz

$ rosrun rviz rviz

で起動


Turtlebotのシミュレータを使用してみる

$ sudo apt-get install -y ros-kinetic-turtlebot-gazebo
$ source ~/.bashrc
$ roslaunch turtlebot_gazebo turtlebot_world.launch

f:id:AtsuyaKoike:20190514164017p:plain:w600

$ roslaunch turtlebot_gazebo amcl_demo.launch 
$ rosrun rviz rviz
  1. 左下のAddをクリック
  2. RobotModelを選択

f:id:AtsuyaKoike:20190514164135p:plain:w600
すると、TurtleBotが表示される

  1. Addをクリックし、ByTopicタブを選択
  2. /mapのmapを選択し、OKをクリック

f:id:AtsuyaKoike:20190514164444p:plain:w600
この地図は予め製作されたもので、Gazeboの画面と比較すると同じようになっていることが分かる。
次に/camera/depth/pointsを追加する。

  1. AddからBy topicを選択し、/camera/depth/pointのPointCloud2を選択する

f:id:AtsuyaKoike:20190514164931p:plain:w600
次にKinectのセンサ情報をロボットの現在位置に重ねる

  1. /odom/Odometry
  2. /move_base/NavfnROS/plan/path

を追加する。

f:id:AtsuyaKoike:20190514165233p:plain:w600
赤い矢印がロボットモデルに重ねて表示される
この画面で、左のメニューのOdometryを開きCovarianceのチェックを外す

このようにrvizではPublishされているTopicから表示したいTopicを選択すると3次元的に表示させることができる
要するに、rostopic echoで表示される文字列がrvizで可視化できる


また、rvizでは出力だけでなく入力もできる

f:id:AtsuyaKoike:20190514174634p:plain:w600
上のメニューの2D Nav Goalを選択し、

f:id:AtsuyaKoike:20190514174754p:plain:w600
このように矢印をひっぱりると

f:id:AtsuyaKoike:20190514174830p:plain:w600
このように赤い矢印が表示される。


f:id:AtsuyaKoike:20190514175424p:plain:w600
別の角度で実行してみると、緑の線が出ていることも分かる。

赤い矢印が履歴として表示され、緑の細い線(/move_base/navfnROS/plan)がロボットがどこに移動使用しているのかを表している。

rqt

rqt_ez_publisherを使う

Topicをスライダーなどを使ってpublishできる

$ sudo apt-get isntall ros-kinetic-rqt-ez-publisher
$ roscore
$ rosrun turtlelesim turtlesim_node
$ rosrun rqt_ez_publisher rqt_ez_publisher 

f:id:AtsuyaKoike:20190514181125p:plain:w600
そして、/turtle1/cmd_velを選択

f:id:AtsuyaKoike:20190514181304p:plain:w600

  • 画面を最大化するとスライダーを動かしやすくなる
  • このGUIで亀を動かすことができる
  • スライダを動かすたびにMessageがpublishされる

rqt_plotを使ってみる

$ rqt_plot 

f:id:AtsuyaKoike:20190514181745p:plain:w600
Topic名と変数を繋いで書くことでPlotしたい要素を指定

f:id:AtsuyaKoike:20190515104135p:plain:w600
リアルタイムで描画される