Quantcast
Channel: demura.net
Viewing all 757 articles
Browse latest View live

ROS演習7-2019:地図作成・自己位置推定(SLAM, AMCL)

$
0
0

この記事は私が金沢工業大学ロボティクス学科で担当している2019年度後学期開講の講義ロボットプログラミングⅡ用です。今回は地図作成(SLAM)と自己位置推定(AMCL)のパッケージを使いロボットにナビゲーションをさせましょう! 本記事を以下の記事を参考にしています。

1. 地図生成

(1) 端末を3つ開き以下のコマンドを実行する。

gazeboシミュレータを起動

  • $ export TURTLEBOT3_MODEL=burger
  • $ roslaunch turtlebot3_gazebo turtlebot3_fmt_world.launch

地図生成のgmappingを起動

  • $ export TURTLEBOT3_MODEL=burger
  • $ roslaunch turtlebot3_slam turtlebot3_slam.launch slam_methods:=gmapping

注:rvizがOpenGL関係のエラーで落ちる場合は、以下の1行を.bashrcの最後に付け加える。

  • export LIBGL_ALWAYS_SOFTWARE=1

(2) 端末を開き、以下のコマンドでロボットを動かし、地図を作る。

  • $ roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch

(3)  端末を開き、以下のコマンドで地図を保存する。mymapは保存する地図名なので適宜変更する。

  • $ mkdir  ~/maps
  • $ rosrun map_server map_saver -f  ~/maps/mymap

 

2. ナビゲーション

一度開いている端末を全部閉じ、ノードを落とす。

(1)  gazeboシミュレータを起動

  • $ export TURTLEBOT3_MODEL=burger
  • $ roslaunch turtlebot3_gazebo turtlebot3_world.launch

(2) 自己位置推定ノードの起動
上で作成した地図を使ってナビゲーションをする。

  • $ export TURTLEBOT3_MODEL=burger
  • $ roslaunch turtlebot3_navigation turtlebot3_navigation.launch map_file:=$HOME/maps/mymap.yaml

(3) (2)のコマンドで rvizも起動するが、rvizを別に起動したい場合は以下のコマンドを使う。

  • $ rviz -d `rospack find turtlebot3_slam`/rviz/turtlebot3_navigation.rviz

(4) ロボット初期位置の設定
上で起動したrviz(上図)の”2D Pose Estimation”をクリックして選択し、下図シミュレータのロボットの向きと位置が合うように、rviz上でロボットの位置と向きを設定する。ロボットの位置にマウスのカーソールを持って行き、ロボットの向きにドラッグすると設定終わり。

(5) ゴールの設定
次にrvizの”2D Nav Goal”をクリックして、初期位置を設定したのと同様に、ゴールの位置と向きを設定する。設定するとロボットが自動で動き出す。

終わり


ROS演習8-2019:ナビゲーションとアクションプログラム

$
0
0

この記事は私が金沢工業大学ロボティクス学科で担当している2019年後学期開講の講義ロボットプログラミングⅡ用です。ROS演習で7はrvizを使いGUIでロボットを動かしましたが、今回はROSのActionLibを使ったアクションプログラムを学びます。以下のチュートリアルも参考にしてください。

ソース

 
// 本プログラムは
// http://wiki.ros.org/ja/navigation/Tutorials/SendingSimpleGoals
// を改変しています。
#include <ros/ros.h>
#include <geometry_msgs/PoseWithCovarianceStamped.h>
#include <move_base_msgs/MoveBaseAction.h>
#include <actionlib/client/simple_action_client.h>

typedef actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> MoveBaseClient;

struct MyPose {
  double x;
  double y;
  double yaw;
};

int main(int argc, char** argv){
  MyPose way_point[] = {{-0.15, -0.54, 0.0 * M_PI}, {1.6, -0.6, M_PI}, 
	                {1.6, 1.5,  0.0 * M_PI},{999, 999, 999}};

  ros::Publisher  pub;

  ros::init(argc, argv, "simple_goal");

  ros::NodeHandle nh;
  pub= nh.advertise<geometry_msgs::PoseWithCovarianceStamped>("initialpose", 2, true);

  // 時間の取得
  ros::Time tmp_time = ros::Time::now();
  //create msg
  geometry_msgs::PoseWithCovarianceStamped initPose;

  // 初期位置の設定 turtlebot3_worldの初期位置が(-2.0, -0.5)なのでそれに設定
  initPose.header.stamp = tmp_time;  //  時間
  initPose.header.frame_id = "map";  //  フレーム
  initPose.pose.pose.position.x = -2.0;
  initPose.pose.pose.position.y = -0.5;
  initPose.pose.pose.position.z =  0;
  initPose.pose.pose.orientation.w = 1.0;

  // パブリッシュ amclパッケージに初期位置を送る
  pub.publish(initPose);
  
  // アクションクライアンを作成。1番目の引数は接続するアクションサーバー名。
  // アクションサーバーが立ち上がっていないとだめ。
  // 2番目の引数はtrueならスレッドを自動的に回す(ros::spin()。
  MoveBaseClient ac("move_base", true);
  // アクションサーバーが起動するまで待つ。引数はタイムアウトする時間(秒)。
  // この例では5秒間待つ(ブロックされる)
  while(!ac.waitForServer(ros::Duration(5.0))){
      ROS_INFO("Waiting for the move_base action server to come up");
  }

  ROS_INFO("The server comes up");
  move_base_msgs::MoveBaseGoal goal;
  // base_link座標系(ロボット座標系)
  goal.target_pose.header.frame_id = "base_link";
  // 現在時刻                                                                       
  goal.target_pose.header.stamp = ros::Time::now();


  int i = 0;
  while (ros::ok()) {
    // ROSではロボットの進行方向がx座標、左方向がy座標、上方向がz座標
    goal.target_pose.pose.position.x =  way_point[i].x;
    goal.target_pose.pose.position.y =  way_point[i].y;
    goal.target_pose.pose.orientation.w = 1; 

    ROS_INFO("Sending goal: No.%d", i+1);
    // サーバーにgoalを送信
    ac.sendGoal(goal);

    // 結果が返ってくるまで30.0[s] 待つ。ここでブロックされる。
    bool succeeded = ac.waitForResult(ros::Duration(30.0));

    // 結果を見て、成功ならSucceeded、失敗ならFailedと表示
    actionlib::SimpleClientGoalState state = ac.getState();

    if(succeeded) {
      ROS_INFO("Succeeded: No.%d (%s)",i+1, state.toString().c_str());
    }
    else {
      ROS_INFO("Failed: No.%d (%s)",i+1, state.toString().c_str());
    }
    i++;  
  }
  return 0;
}
  • packageのディレクトリ毎、圧縮したファイル
  • 展開・ビルド方法
    • $  cp  simple_goal.tar    ~/catkin_ws/src
    • $  cd  ~/catkin_ws/src
    • $  tar  xvf  simple_goal.tar
    • $  cd  ~/catkin_ws
    • $  catkin_make

ハンズオン

  • 上で展開したsimple_goalを次の要領で実行しよう。
    • まず、geditで~/.bashrcを開き、最後の行に以下を追加し保存する。これにより、毎回入力する手間がはぶける。
      •  export TURTLEBOT3_MODEL=burger
    •  まず、端末を開き次のコマンドを実行。
      • $ roslaunch turtlebot3_gazebo turtlebot3_world.launch
    • この地図map.tarファイルをダウンロードして、次のようにホームディレクトリで展開してください。
      • $ cd
      • $ tar xvf maps.tar
      • 展開するとmapsディレクトリができ、その中に、mymap.pgmとmymap.yamlの2つのファイルがあります。pgmファイルは地図画像ファイルで、yamlファイルは設定ファイルです。mymap.yamlファイルの1行目に画像ファイルの場所を指定する必要があります。ダウンロードしたファイルは以下のようにimage: /home/demulab/maps/mymap.pgmになっています。demulabの部分を自分のユーザ名に変更、保存してください。
    • 2個目の端末を開き次のコマンドを実行。
      • $ roslaunch turtlebot3_navigation turtlebot3_navigation.launch map_file:=$HOME/maps/mymap.yaml
    •  3個目の端末を開き、catkin_makeして生成したsimple_goalノードを起動する。
      • $ rosrun simple_goal simple_goal

演 習(レポート2)

 

  • 基本動作
    • Turtlebot3を指定の距離[m]だけ直進して停止するプログラムを作ろう
    • Turtlebot3を指定の角度[°]だけ回転して停止するプログラムを作ろう
    • Turtllebot3を矩形軌道を移動するプログラムを作ろう
  • ウェイポイントナビゲーション
    • 演習6の建物環境(上図)を使いスタート地点からゴールまで進むプログラムを作ろう。
  • デッドレコニング
    • デッドレコニングをcbMyOdom関数に実装しよう。rvizの場合は/odomトピックと値を比較し、gazeboが動く場合はシミュレータ上の真の位置Real Posと比較しよう。

 

ROS演習9-2019: ロボットビジョン (OpenCVとの連携)

$
0
0

この記事は私が金沢工業大学ロボティクス学科で担当している2019年度後学期講義ロボットプログラミングⅡ用です。今回はcv_bridgeを使います。ROSでOpenCVを使いgazeboシミュレータのRGB-Dセンサから取得した画像から赤色の抽出とエッジ抽出を行います。

この記事は、以下のROSチュートリアルと「ROSで始めるロボットプログラミング、小倉著」を参考にしています。

ソース:ROSのチュートリアルと「ROSで始めるロボットプログラミング」をベースに改変しています。

 
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

static const std::string OPENCV_WINDOW = "Image window";

class ImageConverter
{
  ros::NodeHandle nh_;
  image_transport::ImageTransport it_;
  image_transport::Subscriber image_sub_;
  image_transport::Publisher image_pub_;

public:
  // コンストラクタ
 ImageConverter()
    : it_(nh_)
  {
    // カラー画像をサブスクライブ                                                                
    image_sub_ = it_.subscribe("/camera/rgb/image_raw", 1,
      &ImageConverter::imageCb, this);
    // 処理した画像をパブリッシュ                                                                                          
    image_pub_ = it_.advertise("/image_topic", 1);
 }

  // デストラクタ
  ~ImageConverter()
  {
    cv::destroyWindow(OPENCV_WINDOW);
  }

  // コールバック関数
  void imageCb(const sensor_msgs::ImageConstPtr& msg)
  {
    cv_bridge::CvImagePtr cv_ptr, cv_ptr2, cv_ptr3;
 try
    {
      // ROSからOpenCVの形式にtoCvCopy()で変換。cv_ptr->imageがcv::Matフォーマット。
      cv_ptr    = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);
      cv_ptr3   = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::MONO8);
    }
    catch (cv_bridge::Exception& e)
    {
      ROS_ERROR("cv_bridge exception: %s", e.what());
      return;
    }

    cv::Mat hsv_image, color_mask, gray_image, cv_image2, cv_image3;
    // RGB表色系をHSV表色系へ変換して、hsv_imageに格納
    cv::cvtColor(cv_ptr->image, hsv_image, CV_BGR2HSV);

    // 色相(Hue), 彩度(Saturation), 明暗(Value, brightness) 
    // 指定した範囲の色でマスク画像color_mask(CV_8U:符号なし8ビット整数)を生成  
    // マスク画像は指定した範囲の色に該当する要素は255(8ビットすべて1)、それ以外は0                                                      
    cv::inRange(hsv_image, cv::Scalar(150, 100, 50, 0) , cv::Scalar(180, 255, 255, 0), color_mask);
    // ビット毎の論理積。マスク画像は指定した範囲以外は0で、指定範囲の要素は255なので、ビット毎の論理積を適用すると、指定した範囲の色に対応する要素はそのままで、他は0になる。
    cv::bitwise_and(cv_ptr->image, cv_ptr->image, cv_image2, color_mask);
    // グレースケールに変換
    cv::cvtColor(cv_ptr->image, gray_image, CV_BGR2GRAY);
    // エッジを検出するためにCannyアルゴリズムを適用
    cv::Canny(gray_image, cv_ptr3->image, 15.0, 30.0, 3);

    // ウインドウに円を描画                                                
    cv::circle(cv_ptr->image, cv::Point(100, 100), 20, CV_RGB(0,255,0));

    // 画像サイズは縦横1/4に変更
    cv::Mat cv_half_image, cv_half_image2, cv_half_image3;
    cv::resize(cv_ptr->image, cv_half_image,cv::Size(),0.25,0.25);
    cv::resize(cv_image2, cv_half_image2,cv::Size(),0.25,0.25);
    cv::resize(cv_ptr3->image, cv_half_image3,cv::Size(),0.25,0.25);

    // ウインドウ表示                                                                         
    cv::imshow("Original Image", cv_half_image);
    cv::imshow("Result Image", cv_half_image2);
    cv::imshow("Edge Image", cv_half_image3);
    cv::waitKey(3);
 
    // エッジ画像をパブリッシュ。OpenCVからROS形式にtoImageMsg()で変換。                                                            
    image_pub_.publish(cv_ptr3->toImageMsg());
  }
};

int main(int argc, char** argv)
{
  ros::init(argc, argv, "image_converter");
  ImageConverter ic;
  ros::spin();
  return 0;
}

 

 

1.  準備

  • opencv3のパッケージをインストールする。
    • sudo apt install ros-melodic-opecv3
    • sudo apt update
    • sudo apt upgrade
  •  次に、サンプロプログラムをインストールしましょう。以下のファイルを~/catkin_ws/srcの下にコピーする。
  • $ cd ~/catkin_ws/src
  • $ tar xvf cv_bridge_tutorial.tar
  • $ cd ~/catkin_ws
  • $ catkin_make
  • RGB-Dセンサを使うのでTurtlebot3のモデルをwaffleに変更する。geditで~/.bashrcを開き、以下のようにburgerをwaffleに変更する。
    • export TURTLEBOT3_MODEL=waffle

2. 実行

  • $ roslaunch turtlebot3_gazebo turtlebot3_world.launch
  • $ rosrun cv_bridge_tutorial cv_bridge_tutorial
  • 次のコマンドでロボットを動かしてカメラ画像が変わるのを確認しよう
    • $ roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch

 

4.演習

  • シミュレータにコカ・コーラの缶(Coke Can)を挿入して、それを追うプログラムを作ろう
    • コーラ缶を挿入するためにはGazeboのInsertタブをクリックして、その中のCoke Canを選択して、Gazebo上の配置したい場所をクリックするとそこに現れます。
    • コーラ缶の位置を推定する方法はいろいろありますが、ここではマスクをかけた赤い画像の重心を求めることにします。OpenCVで画像の各画素にアクセスする方法は次のリンクを参考にしてください。

終わり

ROS演習10-2019:ロボットアーム

$
0
0

arm2-gazebo

arm2-rviz

この記事は私が金沢工業大学ロボティクス学科で担当している講義ロボットプログラミングⅡ用です。今週はgazeboを使い2自由度のロボットアームを作り、関節を動かします。2自由度ロボットアームのURDFは参考リンクを参照してください。このサンプルでは参考リンクのrrbot.xacroをベースに作っています。

ソース
Turtlebotをテレオペ(遠隔操作)したソースコードをベースに ~/catkin_ws/src/armbot2/src/teleop.cppを作成しました。ジョイント1とジョイント2の目標角度をパブリッシュし、/armbot2/joint_statesトピックをサブスクライブしジョイントの現在値を取得しています。この例では、目標角度に追従するのに時間がかかるのでループ毎に1秒スリープしてから現在値を取得しています。

 
// ~/catkin_ws/src/armbot2/src/teleop.cpp
#include "ros/ros.h"  // rosで必要はヘッダーファイル
#include "std_msgs/Float64.h"
#include "sensor_msgs/JointState.h"
#include "nav_msgs/Odometry.h"

using namespace std;
std_msgs::Float64 tmp_joint1, tmp_joint2;
double pos_x, pos_y, pos_z;

void monitorJointState(const sensor_msgs::JointState::ConstPtr& jointstate)
{
  tmp_joint1.data = jointstate->position[0];
  tmp_joint2.data = jointstate->position[1]; 
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "teleop");  // ノードの初期化
  ros::NodeHandle nh; // ノードハンドラ  
  ros::Publisher  pub_joint1, pub_joint2;  // パブリッシャの作成
  ros::Subscriber sub_joints, sub_sensor;  // サブスクライバの作成

  std_msgs::Float64 target_joint1, target_joint2;

  pub_joint1 = nh.advertise<std_msgs::Float64>("/armbot2/joint1_position_controller/command", 100);
  pub_joint2 = nh.advertise<std_msgs::Float64>
("/armbot2/joint2_position_controller/command", 100);
  sub_joints = nh.subscribe("/armbot2/joint_states", 100, monitorJointState);

  target_joint1.data = 0;
  target_joint2.data = 0;

  while (ros::ok()) { // このノードが使える間は無限ループ
    char key;  // 入力キーの値

    ROS_INFO("[Input] j: Joint1++, f: Joint1--, k: Joint2++, d:Joint2--");
    cin >> key; 
    cout << key << endl;

    switch (key) {
    case 'j': target_joint1.data  +=  5 * M_PI/180.0; break;
    case 'f': target_joint1.data  -=  5 * M_PI/180.0; break;
    case 'k': target_joint2.data  +=  5 * M_PI/180.0; break;
    case 'd': target_joint2.data  -=  5 * M_PI/180.0; break;
    default: ROS_INFO("Input j,f,k,d");
    }
      
    pub_joint1.publish(target_joint1); // 角度を送信    
    pub_joint2.publish(target_joint2);
    ROS_INFO("Targe: Joint1=%f Joint2=%f", target_joint1.data, target_joint2.data);

    usleep(1000*1000); // 制御に時間がかかるので1秒寝て待つ
    ros::spinOnce();   // コールバック関数を呼ぶ
    ROS_INFO("Tmp:Joint1=%f Joint2=%f", tmp_joint1.data,    tmp_joint2.data);
  }
  
  return 0;
}

なお、ジョイントのPIDゲインやコントローラーは以下のファイルに記述されています。詳細については参考リンクをご覧ください。
~/catkin_ws/src/armbot2/config/armbot2_control.yaml

準 備

  • $ sudo apt update
  • $ sudo apt upgrade
  • $ sudo apt install ros-melodic-gazebo-ros-pkgs ros-melodic-gazebo-ros-control
  • $ sudo apt install ros-melodic-gazebo-plugins  ros-melodic-gazebo-ros
  • $ sudo apt install ros-melodic-moveit-*
  • $ sudo apt install ros-melodic-ros-control ros-melodic-ros-controllers  ros-melodic-joint-state-controller ros-melodic-effort-controllers ros-melodic-position-controllers ros-melodic-joint-trajectory-controller
  • $ sudo apt install liburdfdom-tools

プログラムとビルド

  • 以下を~/catkin_ws/src(/home/ユーザ名/catkin_ws/src)にダウンロードする。
  • $ cd  ~/catkin_ws/src
  • $ tar  xvf  armbot2-161208.tar
  • $ cd  ~/catkin_ws
  • $ catkin_make

実 行
端末を2つ開き、次のコマンドを実行する。

  • $ roslaunch  armbot2  armbot2.launch
  • $ rosrun armbot2 armbot2
    • armbot2を実行している端末をクリックし、j, k, f, dコマンドを入力する毎にEnterキーを入力するとロボットアームが動く。各コマンドを入力する度にEnterキーを押さなければ動きません。jは第1関節を正方向、fは負方向、 kは第2関節を正方向、dは負方向に目標角度を5度ずつ変化させる。
  • 成功するとrvizとgazeboの2つのウインドウが開く。そのままではrvizにロボットモデルが表示されないので、次の設定を行う。

rvizの設定

rviz-gazebo

  • 次の操作を行う
    1. (1) Global Option -> Fixed Frameをbase_linkに設定
    2. (2) Addボタンをクリックする
    3. (3) RobotModelを追加する

ノードグラフ

ノードグラフは次のとおり。端末を開き、次のコマンドを実行。

  • $ rqt_graph

rqt_graph

参考リンク

 

VcXsrvのインストールと設定

$
0
0

X Window システムのインストール。WSLはグラフィカルなインタフェース(GUI)が使えないので、GUIを使いROSを動かすためにはX Windowシステムを別にインストールしなければならない。調べたらVcXsrvが無償で良さそうなのでインストールしてみる。

  • ダウンロード。以下のウェブサイトに行き、下図の赤で囲った「Download]をクリックする。2019年10月2日現在のバージョンは1.20.5.1。
    • https://sourceforge.net/projects/vcxsrv/
    • ダウンロードしたexeファイルをダブルクリックする。次のウインドウが開くので「Next」をクリックする。
    • インストールするフォルダーを聞かれるので、デフォルトのまま「Install」をクリックする。
    • セットアップが終わったら「Close」をクリックしてインストールを終了する。
  • X起動
    • デスクトップにできたXLaunchアイコンをダブルクリックする。
    • Select display settingsのウインドウになるのでデフォルトのまま「次へ(N)」をクリックする。
    • Select how to start clientのウインドウになるので、デフオルトのまま「次へ(N)」をクリックする。
    • Extra Settingsのウインドウになるので 以下の図のようにClipboard、Primary Selection、Disable access controlにチェックを入れ、Native openglのチェックを外して「次へ」をクリックする。
    • Finish configurationウインドウになるので、「Save configuration」をクリックして設定ファイルを保存してから「完了」をクリックする。
    • ファイアウォールなどを設定している場合は、次の図のように「Windowsセキュリティの重要な警告」というウインドウが開くので、「アクセスを許可する」をクリックする。
  • Ubuntuの設定
    • スタートメニュー→Ubuntu 16.04からUbuntuターミナルを起動する。
      デスクトップにショートカットを作っておくと便利。
    •  起動したターミナルで以下のコマンドを実行し、必要なパッケージをインストールする。なお、$はプロンプトなので入力しない。
      • $ sudo apt update
      • $ sudo apt upgrade
      • $ sudo apt-get install language-pack-ja -y
      • sudo update-locale LANG=ja_JP.UTF-8
      • $ sudo apt-get install git emacs gedit build-essential firefox dbus -y
    • 環境変数の設定
      • 自分のパソコン画面にLinuxのウインドウアプリケーションが表示されるように以下のコマンドを実行して環境変数を設定する。
        • $ echo 'export DISPLAY=localhost:0.0' >> ~/.bashrc
        • $ source ~/.bashrc

WSL2を試す:Gazeboも動くぞ!

$
0
0

WSL (Windows Subsystem for Linux)で授業のROS教材が動かないので、来年には正式にリリースされるLinuxが完全に動くWSL2試してみる。WSLでは動かなった授業のROS教材も問題なく動いた。この記事はそのメモ。なお、現時点(2019-10-25)ではWSL2とVirtualBox、VMwareは共存できないので注意。

Windows 10のPreview版をインストールしないとWSL2は使えないので、今年度の授業には使えないが、来年度にはリリース版でも動くので使えるだろう。

なお、WSL2のインストールはMicrosoftの以下の記事に従い作業した。


まず、ビルド18917以降にするためにWindows Insiderプログラムに参加する。

  • 以下のリンクからWindows Insider Programに登録する。
  • Windows Insider Programの設定を行う。
    • スタート → 設定 → 更新とセキュリティ → Windows Insider Program
    • 「Windows Insider Programに参加して、Windows10のプレビュービルドを取得し、フィードバックを送信してWindowsの発展にご協力ください。」と聞かれるので「開始」をクリック。
    • 「Windows Insider Programにご参加ください」と聞かれる。アカウントを切り替えたい場合は「アカウントの切り替え」をクリックする。そのままでよい場合は「登録」をクリック。

    • 「Insiderの設定を選択してください」と聞かれるので、「ファスト」を選択し、「確認」をクリックする。する。WSL2をインストールまでは「ファスト」にして、インストール後は「スロー」にする。そうしないと、OS更新プログラムが1週間に1,2回入手し、再起動が必要になるので仕事に支障が出るかもしれない。
    • 「すべての人に、より良いWindowsを」と聞かれるので「確認」をクリック。
    • 「あと1ステップです。。。」と聞かれるので「今すぐ再起動」をクリックする。
  • Windows Preview版のインストール
    • 再起動したら、以下を実行する。
      • スタート → 設定 → 更新とセキュリティ → 更新プログラムのチェック
    • 利用可能な更新プログラムとして、Windows 10 Insider Previewが表示される。ビルド 18917ならWSL2をインストールできる。この場合はバージョン19002.1だった。
    • 更新して以下の手順でバージョンをチェックする。OSビルドが18917以上ならよい。
      • スタート→設定→システム→バージョン情報
  • 仮想マシンプラットフォーム ‘ オプションのコンポーネントを有効にし、WSL を有効にする。
    • 管理者権限でPowerShellを開き以下のコマンドを実行する。PowerShellを開くのはスタートメニューからWindowsPowerShellを選び、右マウスボタンをクリックして「管理者として実行する」を選ぶ。
      • Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform
      • Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
      • 再起動するかと聞かれので「Y」キーを押して再起動する。
  • WSLとUbuntu-18.04のインストール
  •  WSL2の設定
    • 管理者権限でPowerShellを開き、次のコマンドを実行する。
      • wsl -l
    • 僕の環境では、Ubuntu-16.04、Ubuntu-18.04が既にインストールされている。次の困んでUbuntu-18.04をWSL2に設定する。
      • wsl –set-version Ubuntu-18.04 2
    • 次のコマンドで、設定を確認する。Ubuntu-18.04が次のようにVERSION 2になっていればよい。
      • wsl –list –verbose
  • ROS Melodicのインストール
  • ROS での動作確認
    • Windowsのデスクトップで右マウスボタンをクリックして、NVIDIAコントロールパネルを選択し、「優先するグラフィックスプロセッサ」に「高いパフォーマンスNVIDIAプロセッサ」に設定する。
    • VcXsrvを以下の設定で起動する。
      • Select display settingsウインドウ
        • Multiple windowsにチェックを入れ、「次へ(N)」をクリックする。
      • Select how to start clientsウインドウ
        • Start no client にチェックを入れ、「次へ(N)」をクリックする。
      • Extra settingsウインドウ
        • Clipboard、Primary Selection、Disable access controlにチェックを入れる
        • Additional parameter for VcXsrvに”-ac”を入力して、「次へ」をクリックする。
      • Configuration completeウインドウ
        • 「完了」をクリックするとVxSrvが起動する。
    • ROSでの動作確認
      • Ubuntu18.04LTSアイコンをクリックして端末を開き、.bashrcをgeditなどのエディタで以下の4行をファイルの最後に追加して保存する。特に、DISPLAY環境変数がlocalhostでは動かないので注意。
        export TURTLEBOT3_MODEL=burger:0.0
        export DISPLAY=$(grep -m 1 nameserver /etc/resolv.conf | awk '{print $2}'):0.0
        source /opt/ros/melodic/setup.bash
        source ~/catkin_ws/devel/setup.bash

      •  WSLでは動かなかった以下のGazebo上のTurtlebot3をキーボードで動かすサンプルを試す。デスクトップにあるUbuntu18.04LTSアイコンをクリックして端末を開き、以下のリンクを実行して動作を確認した。私の環境ではWSL2では問題なく動作した。めでたし!めでたし!

終わり

Hyper-Vの有効化、無効化

$
0
0

VirtualBox6.0からWSL2と共存できるような記事がありましたが、私の環境ではできませんでした。

そのため、VirtualBoxを使うときには管理者権限でコマンドプロンプトを開き、以下のコマンドでhyper-vをoffにして、WSL2を使うときはhyper-vをonにしています。なお、BCDEditはブート構成データ (BCD) を管理するためのコマンドです。

  • hyper-v 無効化
    • bcdedit /set hypervisorlaunchtype off
  • hyper-v 有効化
    • bcdedit /set hypervisorlaunchtype auto
  • hyper-vの確認
    • bcdedit | find "hypervisorlaunchtype"

終わり

ROS演習2-2019:はじめてのROSプログラミング(catkin build)

$
0
0

この記事は私が金沢工業大学ロボティクス学科で担当している2019年度後学期開講の講義ロボットプログラミングⅡ用です。ROSでHellow Worldと表示するプログラムを作り、ビルドして実行してみましょう。この記事は以下のROS Wikiの記事を参考に、ビルドコマンドとして新しいcatkin buildを使います。catkin_makeコマンドと比較して、パッケージ毎に違う環境(isolated environment)でビルドできたり、並列ビルドできたり、ROSのパスが通っていればどこでもbuildできたり、一つのパッケージだけ簡単にビルドできたりするところが違う優れた特徴があります。

  • catkin_tool
  • ROSパッケージを作る
  • ROSのパッケージをビルドする
  • エラー
    • すでにcatkin_makeでビルドした場合は、~/catkin_wsにあるdevel、buildのディレクトリを消してからcatkin buildし直す必要があります。それでもエラーが出る場合は、ホームディレクトリに.catkin_toolsというフォルダがないかls -aコマンドで確認して、あったらフォルダ毎削除してください。

 


(1) まず、以下のコマンドでcatkinツールをインストールします。
$ sudo apt install python-catkin-tools

(2) セットアップする。なお、sourceコマンドはファイルに書かれたコマンドを現在のシェルで実行するコマンドです。
$ source /opt/ros/melodic/setup.bash
(3) mkdirコマンドでディレクトリを作る。-pのオプションはcatkin_wsディレクトリをない場合はそれを作り、その中にsrcディレクトリを作ってくれる便利なオプション。なお、~はホームディレクトリの意味。
$ mkdir -p ~/catkin_ws
(4) cdコマンドでディレクトリを移動する。
$ cd ~/catkin_ws/src
(4) 次のコマンドでワークスペースを初期化する。
$ catkin init

2. ビルドの方法
ROSではソースコードをビルドするときにcatkin buildコマンドを使います。このコマンドを実行するときは~/catkin_ws以下のディレクトリならどこでも良いところがcatkin_makeと違い便利なところです。
次のコマンドを実行してください。
$ cd ~/catkin_ws
$ catkin build 
実行後にlsコマンドを実行すると、build、develとlogのディレクトリが新たに作成されていることがわかります。

3.  設定
ここで作成したcatkin_wsを有効にするためには以下のコマンドを実行する必要があります。
$ source ~/catkin_ws/devel/setup.bash
毎回、実行するのは面倒なので~/.bashrcの一番最後にテキストエディターgeditで、上のコマンドを付け加え保存しましょう。まず、geditがインストールされていない場合は次のコマンドでインストールしてください。
$ sudo apt install gedit

ホームディレクトリに移動します。
$ cd
次のコマンドでgeditを実行します。
$ gedit .bashrc

.bashrcの中にsource /opt/ros/melodic/setup.bashがない場合は、下のように2行追加してください。

source /opt/ros/melodic/setup.bash
source ~/catkin_ws/devel/setup.bash

保存はgeditの上ツールバー右にある「Save」をクリックします。では、うまく設定されたか、次のコマンドで確認しましょう。
$ source .bashrc
$ echo $ROS_PACKAGE_PATH
つぎのように表示されたら成功です。

失敗した場合は、設定をもう一度実行してください。打ち間違えがないか注意しましょう。

4. パッケージの作成
準備ができたので早速、パッケージを作りましょう。パッケージは次のcatkin_create_pkgコマンドで作ります。依存パッケージはそのパッケージを作るために必要なパッケージです。
catkin_create_pkg <パッケージ名> [依存パッケージ1] [依存パッケージ2] [依存パッケージ3]
helloパッケージを作りましょう!
$ cd ~/catkin_ws/src
$ catkin_create_pkg hello roscpp
上手く作成できたか確認します。
$ cd ~/catkin_ws/src/hello
$ ls
CMakeLIsts.txt, include, package.xml, srcができていれば成功です。
package.xmlに作成者(maintainer)の情報などを書きます。ここでは省略します。ROS Wikiのpackage.xmlを参考にしてください。

5. ソースコードの作成とビルド
$ cd ~/catkin_ws/src/hello/src
$ gedit hello_node.cpp

エディタが開くので以下をソースコードを打ち込み「保存(S)」をクリックして保存する。

geditで~/catkin_ws/src/hello/CMakeLists.txtを開き、134行目のadd_executableで始まる行と147~149行目のtarget_link_librariesで始まる3行のコメントを次のように外して保存する(つまり、#を消す)。

ビルドします。まず、catkin_wsディレクトリへ移動します。
$ cd ~/catkin_ws
今回はhelloノードだけをビルドすればよいのでcatkin buildの後にビルドしたhelloノードを指定します。全パッケージをビルドしたいときはcatkin buildだけでOKです。
$ catkin build hello

6. 実行
以下のroscoreコマンドでMaster(マスター)を実行する。他のノードを実行する前に必要です。
$ roscore
ノードを実行するためにはrosrunコマンドを使います。使い方は次のとおり。
rosrun パッケージ名 実行ファイル名
別の端末を開き、rosrunコマンドでhello_nodeノードを実行する。
なお、hello_nodeは~/catkin_ws/devel/lib/hello/hello_nodeにcatkin buildコマンドで作られたものです。
$ rosrun hello hello_node
次のように表示されたら成功。終わり。お疲れ様!

7.ホームワーク

  • 以下のノードを作成しよう!
    • “I Love KIT”と表示するkitノードを作ろう。ただし、ダブルクォーテーションは表示しなくて良い。
    • キーボードから打たれ文字列をそのまま表示するechoノードを作ろう。ただし、文字列に空白は含まないとものとします。
    • キーボードから打たれた文字列を”I Love”の後につける、loveノードを作ろう。
  •  次のROSチュートリアル(初級)をやろう!

VirtualBoxからUbuntuが起動しないときの対処方法

$
0
0

VirtualBoxからUbuntuが起動しないときの対処方法

  • VirtualBoxを起動し、Ubuntuを立ち上げようとすると次のようなエーラが出た場合、詳細をクリックする。

  • 以下のエラーの場合は、windowsの仮想化システムHyper-Vが問題の場合が多い。

  • スタート→Windowsシステムツール→コントロールパネル→プログラム→プログラムと機能→Windowsの機能の有効化または無効化を選ぶ
  • 以下のように、「Windowsハイパーバイザープラットフォーム」と「仮想マシンプラットフォーム」のチェックを外し、コンピュータを再起動する。
  • 終わり

ROS演習6-2019:Turtlebot3をプログラムで動かそう

$
0
0

ROS演習4の知識を使いTurtlebot3をプログラムで動かします。この演習6は演習7を問題を解くためのヒントとなっています。

まず、Robotクラスを作成し、次のメンバ関数を作成します。

  • 指定速度[m/s]で指定時間[s]だけ直進して停止するメンバ関数
    • void moveForSecond(double linear_vel, double second);
  • 指定速度[m/s]で指定の距離[m]だけ直進して停止する以メンバ関数
    • void Robot::moveToDistance(double linear_vel, double dist);
// my_robot.cpp
#include "ros/ros.h"  // rosで必要はヘッダーファイル
#include <geometry_msgs/Twist.h> // ロボットを動かすために必要
#include <nav_msgs/Odometry.h>
#include <tf/transform_broadcaster.h>
#include <tf/transform_datatypes.h>
#include "unistd.h"

using namespace std;

struct Pose {
    double x; // x座標[m] 進行方向
    double y; // y座標[m]
    double theta; // 姿勢 [rad]
};

class Robot {
private:
    Pose pos; // 位置と姿勢
    geometry_msgs::Twist vel; // 速度
    ros::NodeHandle nh; // ノードハンドラ
    ros::Publisher  pub; // パブリッシャ
    ros::Subscriber  sub_odom; //, sub_vel; // サブスクライバ
public:
    Robot();
    void setLinearVel(double linear_vel); // 並進速度の設定
    void setAngularVel(double angular_vel); // 並進速度の設定
    void setVel(double linear_vel, double angular_vel);
    void odomCallBack(const nav_msgs::Odometry::ConstPtr& msg);
    void moveForSecond(double linear_vel, double s); // 指定速度と時間で移動
    void moveForSecond2(double linear_vel, double s); // 指定速度と時間で移動
    void moveToDistance(double linear_vel, double dist); // 指定速度で指定距離を移動
};


Robot::Robot() {
    pub = nh.advertise("/cmd_vel", 10,this);
    sub_odom = nh.subscribe("/odom", 100, &Robot::odomCallBack, this);
    vel.linear.x  = vel.linear.y =vel.linear.z = 0.0; // 並進速度の初期化
    vel.angular.z = vel.angular.y = vel.angular.x = 0.0; // 回転速度の初期化
}

// 並進速度の設定
void Robot::setLinearVel(double linear_vel) {
    vel.linear.x = linear_vel;
    pub.publish(vel);
}

// 回転速度の設定
void Robot::setAngularVel(double angular_vel) {
    vel.angular.z = angular_vel;
    pub.publish(vel);
}

void Robot::setVel(double linear_vel, double angular_vel = 0) {
    vel.linear.x  = linear_vel;
    vel.angular.z = angular_vel;
    pub.publish(vel);
}

// /odomトピックから位置と姿勢、速度を表示
void Robot::odomCallBack(const nav_msgs::Odometry::ConstPtr& msg) {
    //ROS_INFO("Seq: %d", msg->header.seq);
    //ROS_INFO("/odom Pos (x:%f, y:%f, z:%f)", msg->pose.pose.position.x,msg->pose.pose.position.y, msg->pose.pose.position.z);
    pos.x = msg->pose.pose.position.x;
    pos.y = msg->pose.pose.position.y;
    tf::Quaternion q(msg->pose.pose.orientation.x, msg->pose.pose.orientation.y, msg->pose.pose.orientation.z, msg->pose.pose.orientation.w);
    tf::Matrix3x3 m(q);
    double roll, pitch, yaw;
    m.getRPY(roll, pitch, yaw);
    pos.theta = yaw;

    //ROS_INFO("/odom Pose (roll:%f, pitch:%f, yaw:%f) ", roll, pitch, yaw);
    //ROS_INFO("Vel (Linear:%f, Angular:%f)", msg->twist.twist.linear.x,msg->twist.twist.angular.z);
}

void Robot::moveForSecond(double linear_vel, double s)
{
    setVel(linear_vel); //  指定速度で進む
    ros::Duration(s).sleep(); // s秒間スリープ
    setVel(0); // 停止
}

void Robot::moveForSecond2(double linear_vel, double s)
{
    static ros::Time begin = ros::Time::now();
    static int step = 0;

    ros::Duration diff(0,0); // diff.sec = diff.nsec = 0と同じ
    setVel(linear_vel);

    ros::Rate rate(50);  // ループの頻度を設定
    rate.sleep();

    while (diff < ros::Duration(s)) {
        ros::spinOnce();
        if (step++ == 0) begin = ros::Time::now();

        diff = ros::Time::now() - begin;
        ROS_INFO("ROS diff: %u.%u",diff.sec,diff.nsec);
        rate.sleep();
    }
    setVel(0);
}

void Robot::moveToDistance(double linear_vel, double dist)
{
    double d = 0;
    Pose init_pos = pos;

    setVel(linear_vel);

    ros::Rate rate(50);  // ループの頻度を設定
    while (d < dist) {
        ros::spinOnce();
        d = sqrt((pos.x - init_pos.x) *  (pos.x - init_pos.x)
                 + (pos.y - init_pos.y) *  (pos.y - init_pos.y));
        ROS_INFO("distance=%.3f[m]",d);
        rate.sleep();
    }
    setVel(0);
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "my_robot");

    // ros::init()の前にノードハンドラーを生成するとエラーになるので、
    // クラス化した場合はオブジェクトの生成はinitの後で行うこと。
    Robot robot;

    double v = 0.2; // 速度[m/s]
    double t = 5.0; // 時間[s]

    ROS_INFO("moveSecond:begin");
    robot.moveForSecond2(v, t); // 指定した速度と時間で進む
    ROS_INFO("moveSecond:end");

    ros::Duration(3).sleep(); // 3秒間停止

    double d = 3.0; // 距離[m]
    ROS_INFO("moveToDistance:begin");
    robot.moveToDistance(v, d); // 指定した速度で指定距離を進む
    ROS_INFO("moveToDistance:end");

    return 0;
}

  • 以下ファイルをダウンロードして~/catkin_ws/srcの下にコピーする。
  • ビルドする
    • $ cd ~/catkin_ws/src
    • $ tar xvf my_robot.tar
    • $ cd ~/catkin_ws
    • $ catkin build my_robot
  • gazeboでの実行
    • 端末を2つ開き、各端末で以下のコマンドを実行する。
    • $ roslaunch turtlebot3_gazebo turtlebot3_empty_world.launch
    • $ rosrun my_robot my_robot
    • 実行すると速度0.2[m/s]で5秒間直進し、3秒停止、速度0.2[m/s]で3[m]直進して停止する。

終わり。お疲れ様!

ROS演習9-2019:ナビゲーションとアクションプログラム

$
0
0

この記事は私が金沢工業大学ロボティクス学科で担当している2019年後学期開講の講義ロボットプログラミングⅡ用です。ROS演習8ではrvizを使いGUIでロボットを動かしましたが、今回はROSのActionLibを使ったアクションプログラムを学びます。以下のチュートリアルも参考にしてください。

ソース

 
// 本プログラムは
// http://wiki.ros.org/ja/navigation/Tutorials/SendingSimpleGoals
// を改変しています。
#include <ros/ros.h>
#include <geometry_msgs/PoseWithCovarianceStamped.h>
#include <move_base_msgs/MoveBaseAction.h>
#include <actionlib/client/simple_action_client.h>

typedef actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> MoveBaseClient;

struct MyPose {
  double x;
  double y;
  double yaw;
};

int main(int argc, char** argv){
  MyPose way_point[] = {{-0.15, -0.54, 0.0 * M_PI}, {1.6, -0.6, M_PI}, 
	                {1.6, 1.5,  0.0 * M_PI},{999, 999, 999}};

  ros::Publisher  pub;

  ros::init(argc, argv, "simple_goal");

  ros::NodeHandle nh;
  pub= nh.advertise<geometry_msgs::PoseWithCovarianceStamped>("initialpose", 2, true);

  // 時間の取得
  ros::Time tmp_time = ros::Time::now();
  //create msg
  geometry_msgs::PoseWithCovarianceStamped initPose;

  // 初期位置の設定 turtlebot3_worldの初期位置が(-2.0, -0.5)なのでそれに設定
  initPose.header.stamp = tmp_time;  //  時間
  initPose.header.frame_id = "map";  //  フレーム
  initPose.pose.pose.position.x = -2.0;
  initPose.pose.pose.position.y = -0.5;
  initPose.pose.pose.position.z =  0;
  initPose.pose.pose.orientation.w = 1.0;

  // パブリッシュ amclパッケージに初期位置を送る
  pub.publish(initPose);
  
  // アクションクライアンを作成。1番目の引数は接続するアクションサーバー名。
  // アクションサーバーが立ち上がっていないとだめ。
  // 2番目の引数はtrueならスレッドを自動的に回す(ros::spin()。
  MoveBaseClient ac("move_base", true);
  // アクションサーバーが起動するまで待つ。引数はタイムアウトする時間(秒)。
  // この例では5秒間待つ(ブロックされる)
  while(!ac.waitForServer(ros::Duration(5.0))){
      ROS_INFO("Waiting for the move_base action server to come up");
  }

  ROS_INFO("The server comes up");
  move_base_msgs::MoveBaseGoal goal;
  // base_link座標系(ロボット座標系)
  goal.target_pose.header.frame_id = "base_link";
  // 現在時刻                                                                       
  goal.target_pose.header.stamp = ros::Time::now();


  int i = 0;
  while (ros::ok()) {
    // ROSではロボットの進行方向がx座標、左方向がy座標、上方向がz座標
    goal.target_pose.pose.position.x =  way_point[i].x;
    goal.target_pose.pose.position.y =  way_point[i].y;
    goal.target_pose.pose.orientation.w = 1; 

    ROS_INFO("Sending goal: No.%d", i+1);
    // サーバーにgoalを送信
    ac.sendGoal(goal);

    // 結果が返ってくるまで30.0[s] 待つ。ここでブロックされる。
    bool succeeded = ac.waitForResult(ros::Duration(30.0));

    // 結果を見て、成功ならSucceeded、失敗ならFailedと表示
    actionlib::SimpleClientGoalState state = ac.getState();

    if(succeeded) {
      ROS_INFO("Succeeded: No.%d (%s)",i+1, state.toString().c_str());
    }
    else {
      ROS_INFO("Failed: No.%d (%s)",i+1, state.toString().c_str());
    }
    i++;  
  }
  return 0;
}
  • packageのディレクトリ毎、圧縮したファイル
  • 展開・ビルド方法
    • $  cp  simple_goal.tar    ~/catkin_ws/src
    • $  cd  ~/catkin_ws/src
    • $  tar  xvf  simple_goal.tar
    • $  cd  ~/catkin_ws
    • $  catkin build

ハンズオン

  • 上で展開したsimple_goalを次の要領で実行しよう。
    • まず、geditで~/.bashrcを開き、最後の行に以下を追加し保存する。これにより、毎回入力する手間がはぶける。
      •  export TURTLEBOT3_MODEL=burger
    •  まず、端末を開き次のコマンドを実行。
      • $ roslaunch turtlebot3_gazebo turtlebot3_world.launch
    • この地図map.tarファイルをダウンロードして、次のようにホームディレクトリで展開してください。
      • $ cd
      • $ tar xvf maps.tar
      • 展開するとmapsディレクトリができ、その中に、mymap.pgmとmymap.yamlの2つのファイルがあります。pgmファイルは地図画像ファイルで、yamlファイルは設定ファイルです。mymap.yamlファイルの1行目に画像ファイルの場所を指定する必要があります。ダウンロードしたファイルは以下のようにimage: /home/demulab/maps/mymap.pgmになっています。demulabの部分を自分のユーザ名に変更、保存してください。
    • 2個目の端末を開き次のコマンドを実行。
      • $ roslaunch turtlebot3_navigation turtlebot3_navigation.launch map_file:=$HOME/maps/mymap.yaml
    •  3個目の端末を開き、catkin_makeして生成したsimple_goalノードを起動する。
      • $ rosrun simple_goal simple_goal
  • 演 習(レポート2:ROS演習7-2019の演習と同じ)
    • 準備
    •  基本動作
      1. Turtlebot3を指定速度[m/s]で直進する以下のメンバ関数を作ろう。
        • void Robot::moveAtSpeed(double linear_vel)
      2. Turtlebot3を指定角速度[rad/s]で回転する以下のメンバ関数を作ろう。
        • void Robot::turnAtSpeed(double ang_vel)
      3. Turtlebot3を指定速度[m/s]で指定の距離[m]だけ直進して停止する以下のメンバ関数を作ろう。
        • void Robot::moveToDistance(double linear_vel, double dist)
      4. Turtlebot3を指定角速度[°/s]で指定の角度[°]だけ回転して停止する以下のメンバ関数を作ろう。
        • void Robot::turnToAngle(double ang_vel, double angle)
      5. Turtlebot3を指定位置(ロボット座標系)へ移動する以下のメンバ関数を作ろう。なお、ROSの座標系なのでロボットの進行方向がx、左方向がy軸の正方向です。
        • void Robot::moveToPoint(double x, double y)
    • ウェイポイントナビゲーション
      • スタート地点からゴールまで進むプログラムを作ろう。ロボットが通過するウェイポイントとその地点での姿勢を配列として実装しなさい。ロボットはウェイポイントで停止してもしなくても良いが、指定された姿勢を取ること。
    • デッドレコニング
      • デッドレコニングをcbMyOdom関数に実装しよう。rvizの場合は/odomトピックと値を比較し、gazeboが動く場合はシミュレータ上の真の位置Real Posと比較しよう。
  • ヒント
    • Gazeboを起動するとTurtlebot3に速度指令を送らなくても滑って動く場合があります。その場合は次のパラメータを変更してみてください。
      • turtlebot3/turtlebot3_description/urdf/turtlebot3_burger.gazebo.xacro
        • 11,12, 21,22行目パラメータ摩擦係数mu1,mu2を0.1から1以下の大きな値。
          • <mu1>1.0</mu1>
            <mu2>1.0</mu2>
        • mu1, mu2を変化させてもスリップする場合はkp, kdのパラメータを変えましょう。gazeboは動力学計算にODEを使っており、ODEのdt(時間ステップ)、erp、cfmとは次の関係があります。
          • kp = erp/ (dt* cfm)
          • kd = (1.0- erp)/cfm
        • kp, kd, dtからerp, cfmを求める式
          • erp = dt * kp / (dt * kp + kd)
          • cfm = 1.0 / (dt * kp + kd)

終わり

ROS: Turtlebot2をKineticで動かす

$
0
0

Turtlebot2をROS Kineticで動かした時のメモ。Turtlebot2はRoboCup@Home Educationリーグでデファクトスタンダードの存在ですが、最近は開発元のYujin Roboticsからはあまりサポートされていないようです。

Turtlebot2関連パッケージのインストール

  • sudo apt install ros-kinetic-turtlebot ros-kinetic-turtlebot-apps ros-kinetic-turtlebot-interactions ros-kinetic-kobuki-ftdi ros-kinetic-ar-track-alvar-msgs ros-kinetic-turtlebot-simulator
  • ros-kinetic-rocon-remoconとros-kinetic-rocon-qt-library, turtlebot_simulationパッケージはaptで取得できないので以下のコマンドで取得する。
    • $ ~/catkin_ws/src
    • $ git clone https://github.com/roboticsin-concert/rocon_qt_gui.git
    • $ git clone https://github.com/turtlebot/turtlebot_simulator.git
  • catkin_makeでpyrcc4, pyrcc5がないと怒られるので次のパッケージをインストル
    • $ sudo apt install pyqt4-dev-tools
    • $ sudo apt-get install pyqt5-dev-tools
  • ビルド
    • $ cd ~/catkin_ws
    • $ catkin_make

Kobukiのセットアップ

  • $ source  /opt/ros/kinetic/setup.bash
  • $ rosrun kobuki_ftdi create_udev_rules

Hokuyo Lidar設定

  • TurtlebotパッケージではHokuyo Lidar (UTM-30LX)の設定がないので追加する。
    /opt/ros/kinetic/share/turtlebot_description/urdf/turtlebot_properties.urdf.xacroに以下のコードを一番下の</robot>の上に追加する。なお、コピペするとurdf の読み込みでエラーになるので、手で入力するか、以下のファイルを解凍してオリジナルのurdfディレクトリと置き換えてください。
<!-- Urg Lidar -->
  <joint name="laser" type="fixed">
    <origin xyz="0.13 0.00 0.1" rpy="0 0 0" />
    <parent link="base_link" />
    <child link="base_laser_link" />
  </joint>

  <link name="base_laser_link">
    <visual>
      <geometry>
        <box size="0.06 0.06 0.07" />
      </geometry>
      <material name="Black" />
    </visual>
    <inertial>
      <mass value="0.000001" />
      <origin xyz="0 0 0" />
      <inertia ixx="0.0001" ixy="0.0" ixz="0.0"
        iyy="0.0001" iyz="0.0"
        izz="0.0001" />
    </inertial>
  </link>
  •  /opt/ros/kinetic/share/turtlebot_bringup/launch/3dsensor.launchの次の部分を変更する。
    変更前:
     <arg name="scan_topic" default="scan"/>

    変更後:

     <arg name="scan_topic" default="kinect_scan"/>
     <node name="laser_driver" pkg="urg_node" type="urg_node"> <param name="frame_id" value="base_laser_link" /></node>
  • /opt/ros/kinetic/share/turtlebot_navigation/param/cosmap_common_params.yamlの31行目のmin_obstacle_heightを0.05,32行目のmax_obstacle_heightを1.2に変更する.Hokuyo Lidarを低い位置に取り付けるため.この設定をしないと障害物回避をしないので悩むことになる.この設定では高さ0.05[m]以上1.2[m]以下の障害物を回避する。それ以外は回避しない。ロボットの高さやセンサの取り付け位置でこの値を変更する。
     
     scan:
        data_type: LaserScan
        topic: scan
        marking: true
        clearing: true
        min_obstacle_height: 0.05
        max_obstacle_height: 1.2
    
  • urg nodeをインストールする。
    • $ sudo apt-get install ros-kinetic-urg-node
  • udevの設定:一般ユーザはデフォルトではHokuyo Lidarのデバイスファイル/dev/ttyACM0にアクセスできないので以下のコマンドでアクセスできるようにできる。
        • $ sudo chmod u+rw /dev/ttyACM0
      • これを毎回実行するのは面倒なのでudevを設定する。
      • udevデータベースからデバイスの情報を取得
        $ udevadm info -n /dev/ttyACM0
        各デバイスに固有な情報を探します。ここでは、idVendorとidProductを使います。lsusbコマンドでidを調べることができる。
        /etc/udev/60-cdc_acm.rulesというファイルを作成します。
        中身は次のとおりです。なお、cdc_acmはUSBのドライバ名です。ここではarduinoもコンピュータに接続されているとします。接続されていない場合はttyACM1が含まれている行を削除してください。コンピュータを再起動するとデバイス名が固定され、ファイルにアクセスできるはずです。
     
    KERNEL=="ttyACM*", ATTRS{{idProduct}=="0000", SYMLINK+="ttyACM_URG", MODE="0666"
    KERNEL=="ttyACM*", ATTRS{idVendor}=="2a03", ATTRS{idProduct}=="0043", SYMLINK+="ttyACM_ARDUINO", MODE="0666"
    

Turtlebot2起動

  • 以下のコマンドでTurtlebot2を起動する。うまくいったらピロピロピロと音がする。鳴らない場合はTurtlebot2とPCとの接続がうまくいっていないのでUSBケーブルなどを挿し直す。
  • $ roslaunch turtlebot_bringup minimal.launch

キーボードによる遠隔操作

  • 以下のコマンドでキーボードによりTurtlebot2を遠隔操作できる。iキーで前進、uキーで左折、oキーで右折、kで停止、jで左回転、lで右回転、,で行進。
  • $ roslaunch turtlebot_teleop keyboard_teleop.launch

コントローラによる遠隔操作

  • $ roslaunch turtlebot_bringup minimal.launch
  • $ roslaunch turtlebot_teleop  ps3_teleop.launch
    • このコマンドでPS3, PS4のコントローラでどちらとも遠隔操作可能です。
  • 操作方法
    • PSボタンを押しながら左ジョイスティックを動かす

以上

ROS演習10-2019: ロボットビジョン (OpenCVとの連携)

$
0
0

この記事は私が金沢工業大学ロボティクス学科で担当している2019年度後学期講義ロボットプログラミングⅡ用です。今回はcv_bridgeを使います。ROSでOpenCVを使いgazeboシミュレータのRGB-Dセンサから取得した画像から赤色の抽出とエッジ抽出を行います。

この記事は、以下のROSチュートリアルと「ROSで始めるロボットプログラミング、小倉著」を参考にしています。

ソース:ROSのチュートリアルと「ROSで始めるロボットプログラミング」をベースに改変しています。

 
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

static const std::string OPENCV_WINDOW = "Image window";

class ImageConverter
{
  ros::NodeHandle nh_;
  image_transport::ImageTransport it_;
  image_transport::Subscriber image_sub_;
  image_transport::Publisher image_pub_;

public:
  // コンストラクタ
 ImageConverter()
    : it_(nh_)
  {
    // カラー画像をサブスクライブ                                                                
    image_sub_ = it_.subscribe("/camera/rgb/image_raw", 1,
      &ImageConverter::imageCb, this);
    // 処理した画像をパブリッシュ                                                                                          
    image_pub_ = it_.advertise("/image_topic", 1);
 }

  // デストラクタ
  ~ImageConverter()
  {
    cv::destroyWindow(OPENCV_WINDOW);
  }

  // コールバック関数
  void imageCb(const sensor_msgs::ImageConstPtr& msg)
  {
    cv_bridge::CvImagePtr cv_ptr, cv_ptr2, cv_ptr3;
 try
    {
      // ROSからOpenCVの形式にtoCvCopy()で変換。cv_ptr->imageがcv::Matフォーマット。
      cv_ptr    = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);
      cv_ptr3   = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::MONO8);
    }
    catch (cv_bridge::Exception& e)
    {
      ROS_ERROR("cv_bridge exception: %s", e.what());
      return;
    }

    cv::Mat hsv_image, color_mask, gray_image, cv_image2, cv_image3;
    // RGB表色系をHSV表色系へ変換して、hsv_imageに格納
    cv::cvtColor(cv_ptr->image, hsv_image, CV_BGR2HSV);

    // 色相(Hue), 彩度(Saturation), 明暗(Value, brightness) 
    // 指定した範囲の色でマスク画像color_mask(CV_8U:符号なし8ビット整数)を生成  
    // マスク画像は指定した範囲の色に該当する要素は255(8ビットすべて1)、それ以外は0                                                      
    cv::inRange(hsv_image, cv::Scalar(150, 100, 50, 0) , cv::Scalar(180, 255, 255, 0), color_mask);
    // ビット毎の論理積。マスク画像は指定した範囲以外は0で、指定範囲の要素は255なので、ビット毎の論理積を適用すると、指定した範囲の色に対応する要素はそのままで、他は0になる。
    cv::bitwise_and(cv_ptr->image, cv_ptr->image, cv_image2, color_mask);
    // グレースケールに変換
    cv::cvtColor(cv_ptr->image, gray_image, CV_BGR2GRAY);
    // エッジを検出するためにCannyアルゴリズムを適用
    cv::Canny(gray_image, cv_ptr3->image, 15.0, 30.0, 3);

    // ウインドウに円を描画                                                
    cv::circle(cv_ptr->image, cv::Point(100, 100), 20, CV_RGB(0,255,0));

    // 画像サイズは縦横1/4に変更
    cv::Mat cv_half_image, cv_half_image2, cv_half_image3;
    cv::resize(cv_ptr->image, cv_half_image,cv::Size(),0.25,0.25);
    cv::resize(cv_image2, cv_half_image2,cv::Size(),0.25,0.25);
    cv::resize(cv_ptr3->image, cv_half_image3,cv::Size(),0.25,0.25);

    // ウインドウ表示                                                                         
    cv::imshow("Original Image", cv_half_image);
    cv::imshow("Result Image", cv_half_image2);
    cv::imshow("Edge Image", cv_half_image3);
    cv::waitKey(3);
 
    // エッジ画像をパブリッシュ。OpenCVからROS形式にtoImageMsg()で変換。                                                            
    image_pub_.publish(cv_ptr3->toImageMsg());
  }
};

int main(int argc, char** argv)
{
  ros::init(argc, argv, "image_converter");
  ImageConverter ic;
  ros::spin();
  return 0;
}

 

 

1.  準備

  • opencv3のパッケージをインストールする。
    • sudo apt install ros-melodic-opecv3
    • sudo apt update
    • sudo apt upgrade
  •  次に、サンプロプログラムをインストールしましょう。以下のファイルを~/catkin_ws/srcの下にコピーする。
  • $ cd ~/catkin_ws/src
  • $ tar xvf cv_bridge_tutorial.tar
  • $ cd ~/catkin_ws
  • $ catkin_make
  • RGB-Dセンサを使うのでTurtlebot3のモデルをwaffleに変更する。geditで~/.bashrcを開き、以下のようにburgerをwaffleに変更する。
    • export TURTLEBOT3_MODEL=waffle

2. 実行

  • $ roslaunch turtlebot3_gazebo turtlebot3_world.launch
  • $ rosrun cv_bridge_tutorial cv_bridge_tutorial
  • 次のコマンドでロボットを動かしてカメラ画像が変わるのを確認しよう
    • $ roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch

 

4.演習

  • シミュレータにコカ・コーラの缶(Coke Can)を挿入して、それを追うプログラムを作ろう
    • コーラ缶を挿入するためにはGazeboのInsertタブをクリックして、その中のCoke Canを選択して、Gazebo上の配置したい場所をクリックするとそこに現れます。
    • コーラ缶の位置を推定する方法はいろいろありますが、ここではマスクをかけた赤い画像の重心を求めることにします。OpenCVで画像の各画素にアクセスする方法は次のリンクを参考にしてください。

終わり

FUTURE CONVENIENCE STORE CONTEST

$
0
0

東京ビッグサイトで開催されるWorld Robot Summit 2019のFuture Convenience Store Contestにロボティクス学科出村研究室Happy Robotチームが出場しています。競技は12/19(木)~21(土)。国際ロボット展と併設されていますので十分楽しめると思います。もし、来られる場合は21(土)がお勧めです。Happy Robotチーム競技予定は次のとおりです。

会場:東京ビッグサイト南4ホール

日時:
12月19日(木)
11:30~11:55 接客タスク
15:00~15:25 接客タスク

12月20日(金)
11:00~11:30 トイレ清掃タスク
15:00~15:25 陳列廃棄タスク

12月21日(土)
11:00~11:30 トイレ清掃タスク
15:00~15:25 陳列廃棄タスク

詳細については以下のリンクをご覧ください。

  • https://f-csc.org/2019-wrs-fcsc/

ROS演習7-2019:デッドレコニングを実装しよう!

$
0
0

今回はTurtlebot3にデッドレコニングを実装します。

  • デッドレコニング説明資料
  • ROSの座標系
    • ROSではロボットの進行方向がx軸、左方向がy軸、上方向がz軸の正方向です。回転方向は反時計周りが正(0~π[rad])、時計回りが負(0~-π[rad])となります。
  • テンプレートファイル
// ファイル名 my_odom3.cpp
#include <ros/ros.h>  // rosで必要はヘッダーファイル
#include <geometry_msgs/Twist.h> // ロボットを動かすために必要
#include <nav_msgs/Odometry.h>
#include <tf/transform_broadcaster.h>
#include <tf/transform_datatypes.h>
#include <gazebo_msgs/ModelStates.h> 
#include <sensor_msgs/JointState.h>
#include 

using namespace std;

// コールバック関数。並進、回転速度の表示。
void cbVel(const geometry_msgs::Twist::ConstPtr& vel) {
  cout << "Linear :" << vel->linear.x << endl;
  cout << "Angular:" << vel->angular.z << endl; } 

// /odomトピックから位置posと姿勢poseを表示 
void cbOdom(const nav_msgs::Odometry::ConstPtr& msg) { 
  ROS_INFO("Seq: %d", msg->header.seq);
  ROS_INFO("/odom Pos (x:%f, y:%f, z:%f)", msg->pose.pose.position.x,msg->pose.pose.position.y, msg->pose.pose.position.z);

  tf::Quaternion q(msg->pose.pose.orientation.x, msg->pose.pose.orientation.y, msg->pose.pose.orientation.z, msg->pose.pose.orientation.w);  
  // tf::Quaternion q(quat.x, quat.y, quat.z, quat.w);
  tf::Matrix3x3 m(q);
  double roll, pitch, yaw;
  m.getRPY(roll, pitch, yaw);

  ROS_INFO("/odom Pose (roll:%f, pitch:%f, yaw:%f) ", roll, pitch, yaw);
  ROS_INFO("Vel (Linear:%f, Angular:%f)", msg->twist.twist.linear.x,msg->twist.twist.angular.z);
												  
}

// /gazebo/model_statesトピックから真の位置Pos(x,y,z)と姿勢Pose(roll, pitch ,yaw)を表示
void cbModelStates(const gazebo_msgs::ModelStates::ConstPtr& msg)
{
  ROS_INFO("Real Pos (x:%f, y:%f, z:%f)", msg->pose[1].position.x,msg->pose[1].position.y, msg->pose[1].position.z);

  tf::Quaternion q(msg->pose[1].orientation.x, msg->pose[1].orientation.y, msg->pose[1].orientation.z, msg->pose[1].orientation.w);  
  // tf::Quaternion q(quat.x, quat.y, quat.z, quat.w);
  tf::Matrix3x3 m(q);
  double roll, pitch, yaw;
  m.getRPY(roll, pitch, yaw);

  ROS_INFO("Real Pose (roll:%f, pitch:%f, yaw:%f) ", roll, pitch, yaw);
												  
}

// cbMyOdom:この関数に自分のオドメトリを実装しよう!
// /joint_statesトピックから左右のjoint(車輪回転軸)の位置(回転角度)[rad]を表示
// 参考:Turtlebot3の車輪直径0.066 [m]
void cbMyOdom(const sensor_msgs::JointState::ConstPtr& jointstate)
{
  double wheel_right_joint_pos = jointstate->position[0]; // 右車軸の位置[rad]
  double wheel_left_joint_pos  = jointstate->position[1]; // 左車軸の位置[rad]

  // 車軸の位置は積算される
  ROS_INFO("Whell Pos (r:%f, l:%f)", wheel_right_joint_pos,wheel_left_joint_pos);
}




int main(int argc, char **argv)
{
  ros::init(argc, argv, "my_odom3");
  ros::NodeHandle nh;

  //subscriberの作成。トピック/cmd_velを購読する。
  ros::Subscriber sub  = nh.subscribe("/cmd_vel", 10, cbVel);
  ros::Subscriber sub2 = nh.subscribe("/odom", 100, cbOdom);
  ros::Subscriber sub3 = nh.subscribe("/gazebo/model_states", 100, cbModelStates);
  ros::Subscriber sub4 = nh.subscribe("/joint_states", 100, cbMyOdom);
  
  
  // コールバック関数を繰り返し呼び出す。
  ros::Rate rate(100);

  while (ros::ok()) {

    
    ros::spinOnce();
    rate.sleep();
  }
  return 0;
}
  • 以下ファイルをダウンロードして~/catkin_ws/srcの下にコピーする。
  • ビルドする
    • $ cd ~/catkin_ws/src
    • $ tar xvf my_odom3.tar
    • $ cd ~/catkin_ws
    • $ catkin build
  • rvizでの実行
    • 端末を3つ開き、各端末で以下のコマンドを実行する。
    • $ roslaunch turtlebot3_fake turtlebot3_fake.launch
    • $ roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch
    • $ rosrun my_odom3  my_odom3
  • gazeboでの実行
    • 端末を3つ開き、各端末で以下のコマンドを実行する。
    • $ roslaunch turtlebot3_gazebo turtlebot3_empty_world.launch
    • $ roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch
    • $ rosrun my_odom3  my_odom3
    • 以下のコマンドでノードとトピックの関係を見てみましょう。
      • $ rqt_graph
    • 以下のように表示されれば成功です。

 

演  習

  • 準 備
    • ホームディレクトリの名前が日本語の場合はコマンド操作がやりづらいので以下のコマンドで英語に変更する。以下のウインドウが開くので[UpdateNames]をクリックすると英語名に変わる。
      • $ LANG=C xdg-user-dirs-gtk-update

    • $ cd
    • fmt_world-2.tarをクリックしてダウンロードし~/Downloadsの中に保存。
    • $ cd Downloads
    • $ tar xvf  fmt_world-2.tar
    • $ cd fmt_world
    • $ cp turtlebot3_fmt_world.launch  ~/catkin_ws/src/turtlebot3_simulations/turtlebot3_gazebo/launch
    • $ cp  fmt.world  ~/catkin_ws/src/turtlebot3_simulations/turtlebot3_gazebo/worlds
    • $ cp -r fmt ~/.gazebo/models
    • $ roslaunch turtlebot3_gazebo turtlebot3_fmt_world.launch
    • 下のような建物とロボットが表示されたら終わり。右奥のボールがゴール。
  • 演 習(レポート2)
    • 準備
    •  基本動作
      1. Turtlebot3を指定速度[m/s]で直進する以下のメンバ関数を作ろう。
        • void Robot::moveAtSpeed(double linear_vel)
      2. Turtlebot3を指定角速度[rad/s]で回転する以下のメンバ関数を作ろう。
        • void Robot::turnAtSpeed(double ang_vel)
      3. Turtlebot3を指定速度[m/s]で指定の距離[m]だけ直進して停止する以下のメンバ関数を作ろう。
        • void Robot::moveToDistance(double linear_vel, double dist)
      4. Turtlebot3を指定角速度[°/s]で指定の角度[°]だけ回転して停止する以下のメンバ関数を作ろう。
        • void Robot::turnToAngle(double ang_vel, double angle)
      5. Turtlebot3を指定位置(ロボット座標系)へ移動する以下のメンバ関数を作ろう。なお、ROSの座標系なのでロボットの進行方向がx、左方向がy軸の正方向です。
        • void Robot::moveToPoint(double x, double y)
    • ウェイポイントナビゲーション
      • スタート地点からゴールまで進むプログラムを作ろう。ロボットが通過するウェイポイントとその地点での姿勢を配列として実装しなさい。ロボットはウェイポイントで停止してもしなくても良いが、指定された姿勢を取ること。
    • デッドレコニング
      • デッドレコニングをcbMyOdom関数に実装しよう。rvizの場合は/odomトピックと値を比較し、gazeboが動く場合はシミュレータ上の真の位置Real Posと比較しよう。
  • ヒント
    • Gazeboを起動するとTurtlebot3に速度指令を送らなくても滑って動く場合があります。その場合は次のパラメータを変更してみてください。
      • turtlebot3/turtlebot3_description/urdf/turtlebot3_burger.gazebo.xacro
        • 11,12, 21,22行目パラメータ摩擦係数mu1,mu2を0.1から1以下の大きな値。
          • <mu1>1.0</mu1>
            <mu2>1.0</mu2>
        • mu1, mu2を変化させてもスリップする場合はkp, kdのパラメータを変えましょう。gazeboは動力学計算にODEを使っており、ODEのdt(時間ステップ)、erp、cfmとは次の関係があります。
          • kp = erp/ (dt* cfm)
          • kd = (1.0- erp)/cfm
        • kp, kd, dtからerp, cfmを求める式
          • erp = dt * kp / (dt * kp + kd)
          • cfm = 1.0 / (dt * kp + kd)

終わり


RealSense D435が落ちる

$
0
0

RealSense D435をUbuntu16.04で使用しているが研究室ではごくまれに落ちる程度であったが、競技会場にきて頻繁に落ちてしまいロボットが全然動かないまずい状態になった。ネットで検索したところ、以下の記事が参考になった。結論は出ていないようだが、RealSenseは2A程度流れる。通常のUSBケーブルだと0.9A程度しか流せないので3Aまで流せるものに変えると良いようだ。

以下はそのときの対処メモ。まず、RealSenseのファームウェアを最新版(5.12.1)にアップデートした。状況は改善されたがされでも時々落ちるので、今までHubに接続していたRealSenseを直接PCに接続するように変更した。ロボットアームのセンタにつける関係で2.5m以上のUSBケーブルが欲しかったが店になかったので、USBケーブル2m (Type A->Type C)も3.0Aまで流せる以下の物と延長ケーブル、空きポートがなかったので7ポートのUSBハブを購入して換装した。今のところ落ちていない。

    • 簡単にまとめると。
      1. RealSenseをコンピュータに接続する
      2. intel-realsense-dfu.exeをダブルクリックする
      3. 以下のウインドウが開くので、1を入力してEnterキーを押す

      4. 以下のウインドウが開くので、1を入力してEnterキーを押す

      5. 以下のようにEnter path and filename (e.g. C:\documents\newFirmware.bin): と表示されるのでファームウェアのファイル名を入力する。ここでは同じフォルダに入れたのでフルパスではなく相対パスで次のように入力した。
      .\Signed_Image_UVC_5_9_2_0.bin

      なお、User Guide の11ページ⑦に以下のような説明がある。
      Type the full file path with firmware filename included and press [ENTER]

ここで、full file pathというのは、ドライブ名から始めてすべてのディレクトリ(フォルダ)名を指定すること。Windows環境なのでドライブ名を入れる。なお、ディレクトリ名が日本語でうまくいかない場合はCドライブの直下などに移動すると良い。

6. アップデータが終了したらQを入力して終了する。

以上

ROS: Roomba 800 の掃除機能を使いたい

$
0
0

Roomba 800 の掃除機能をROSで使いたいときのメモ。Roomba用のパッケージとしては以下のcreate_autonomyを使っている。

しかし、掃除機能を実現するブラシを動かすモータをON/OFFできない。研究室のM2学生榎本君がドライバを少し改造したのでその方法を紹介する。

  • ca_driver/src/create_driver.cppの以下の3点を変更する。
  1. UdevでRoombaを設定している場合は、エラーになる可能性があるため以下を変更する。
//priv_nh_.param<std::string>("dev", dev_, "/dev/ttyUSB0");
↓
priv_nh_.param<std::string>("dev", dev_, "/dev/roomba");

2. サブスクライバが定義されているすぐ上の行に以下を追加する。

brush_sub_ = nh.subscribe("brush", 1, &CreateDriver::brushCallback, this);

3. callback関数が定義されているすぐ上に以下の関数を追加する。

void CreateDriver::brushCallback(const std_msgs::BoolConstPtr& msg)
{
  if(msg->data==1){
    robot_->setAllMotors(1,1,1);
  }
  else{
    robot_->setAllMotors(0,0,0);
  }
}
  • ca_driver/include/ca_driver/create_driver.hの変更は以下の2点

1.callback関数が宣言されているすぐ上に以下のcallbackの宣言を追加する。

void brushCallback(const std_msgs::BoolConstPtr& msg);

2.Subscriberが定義されているすぐ上にsubscriberの宣言を追加

ros::Subscriber brush_sub_;
  • catkin buildでビルトする。/brushトピックにstd_msgs/Bool型 data: trueを送るとブラシモータがON、data: falseを送るとOFFになる。rostopicコマンドを使うと次になる。
# Brush ON
rostopic pub /brush std_msgs/Bool "data: true"

# Brush OFF
rostopic pub /brush std_msgs/Bool "data: false"

以上

Voyager 18.04:インストールと設定

$
0
0

フランス製のLinuxディストリビューションVoyager16.04LTSはXubuntuベースでデザインが洗練されているので使っている。サポートが2020年4月までなのでVoyager 18.04にアップデートした。

  • ダウンロード
  • インストールUSBメディアの作成
    • ダウンロードしたイメージファイルを使いUSBインストールメディアを作成する。ここではLinuxで作成する手順を示す。Voyagerのイメージファイルは1.8GBなので2GB以上のUSB Flash Memoryを用意する。最近はコンビニで8GBなら1000円程度で購入できる。
    • USB Flash MemoryをPCに挿入する
    • USBメモリがマウントさえていると作業できないのでアンマウントする。ファイルマネージャーでもよいし、以下のコマンドでもできる。
      • $ df
        • /dev/sda1 1796960 1796960 0 100% /media/user/Voyager 18.04.2
        • 上のように表示されている場合は/dev/sda1がマウントされている。
      • $ sudo  umount  デバイス名 
        • 上の例ではデバイス名は/dev/sda1
      • $ df
        • /dev/sda1は表示されていないことを確認する。
    • イメージファイルをddコマンドを使いUSBメモリに書き込む
      • $dd if=イメージファイル of=USBメモリのデバイス名  bs=ブロックサイズ
        • この例では以下になる
        • イメージファイル:/home/ユーザ名/Downloads/Voyager-18.04.2-amd64.iso
        • デバイス名:/dev/sda    (sda1ではないので注意)
        • ブロックサイズ:4096   (デフォルトは512。4096は私のファイルシステムのブロックサイズ)
  • インストール
    • BIOSの設定を変更して、USBメモリからブートできるようにしてVoyager18.04.2をインストールする。方法はXubuntuと全く同じ。
  • 設定
    •  日本語化
      • Settings->Language Support
        「The language support is not installed completely」と表示されるので、[Install]をクリック
      • Settings->Language Support
        • Install/Remove Languages -> Japanese
        • Keyboard Input method system -> fcitx
      • 再起動すると日本語を使えるようになる。
    • Conkyの文字化けを直す
      • 日本語フォントを設定して日本語化もできるが、デザイン的に英語が合うので、英語で表示する。
      • この記事のとおり実施
      • メニュー->設定->セッションと起動->自動開始アプリケーションのConky Controlを選択してEditをクリックする。コマンドに以下に変更する。つまり、言語環境を英語にする。
        • ALLh -c “sleep 5;LC_ALL=C sh ~/.scripts/Conky/DemConky.sh;”
    •  すぐ必要なソフトのインストール
      • $ sudo apt install git emacs25 
    • CAPS LOCKとCTRLキーの入れ替える
      • /etc/default/keyboardのXKBOPTIONS=”ctrl:nocaps”と変更する。
    • ログイン画面に写真を入れる
      • 入れたい写真の画像ファイルを~/.faceにコピーする。これだけ。

以上

 

Razer Blade 15 環境設定メモ (Xubuntu18.04.2, Cuda10.2)

$
0
0

Razer Blade 15 (2018)にxubuntu18.04.2, Cuda10.2をインストールしたときのメモ。発売から約1年半経つが未だに色褪せないカッコ良さ。ただ、少々重い。

  • 環境
    • Razer Blade 15
      (CPU: Intel i7-8750H, Memory:16GB, GPU: Nvidia 1070 Max-Q Design, Memory: 8GB)
    • xubuntu 18.04.2 (USBメモリでインストールし、upgrade後は18.04.3)
    • Kernel 5.0.0-37-generic
  •   準備
    • NVIDIAのドライバをインストールしていないので、起動するとIntelのGPUでXが起動する。Ctlr+Alt+F1でXを落としてから以下のコマンドを実行する。
      • $ sudo apt update
      • $ sudo apt upgrade
      • $ sudo service lightdm stop
  •  NVIDIAドライバのインストール
    • Xが落ちている状態で以下のコマンドを実行してインストールする。
      • $ sudo add-apt-repository ppa:graphics-drivers/ppa
      • $ sudo apt update
      • 以下のコマンドで推奨ドライバのバージョンを確認する。私の場合は、nvidia-driver-440がrecommendedだった。
        • $ ubuntu-drivers devices
      • $ sudo apt install nvidia-driver-440  nvidia-settings
    • 再起動
      • $ sudo reboot
    • 以下のコマンドでGPUが有効化確認する。
      • $ nvidia-smi
  •  NVIDIAのウェブサイトからCuda10.2をインストール
    • Select Target Platformで以下を選択
      • Operating system: Linux
      • Architecture: x86_64
      • Distribution: ubuntu
      • Version: 18.04
      • Install type: dev(local)
    • 以下のインストール方法の説明が表示されるので、以下のコマンドを実行してインストールする。
      • $ wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin
      • $ sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600
      • $ wget http://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda-repo-ubuntu1804-10-2-local-10.2.89-440.33.01_1.0-1_amd64.deb
      • $ sudo dpkg -i cuda-repo-ubuntu1804-10-2-local-10.2.89-440.33.01_1.0-1_amd64.deb
      • $ sudo apt-key add /var/cuda-repo-10-2-local-10.2.89-440.33.01/7fa2af80.pub
      • $ sudo apt update
      • $ sudo apt -y install cuda
    • .bashrcに以下を追加し、CUDAのパスを通す
      • export PATH=/usr/local/cuda-10.2/bin${PATH:+:${PATH}}
  • NVIDIAのウェブからcuDNNのインストール
    • nvidiaのdeveloperに登録しないとダウンロードできないので登録してログインする。
    • Download cuDNN v7.6.5 for CUDA10.2をクリック
    • cuDNN v7.6.5 for Runtime Library for Ubuntu18.04 (Deb)とcuDNN v7.6.5 Developer Library for Ubuntu18.04 (Deb)をダウンロードして以下のコマンドでインストールする。
      • $ sudo dpkg -i libcudnn7_7.6.5.32-1+cuda10.2_amd64.deb
      • $ sudo dpkg -i libcudnn7-dev_7.6.5.32-1+cuda10.2_amd64.deb
  • OpenCV3.4.9のインストール
  • ROS Melodicのインストール

終わり

Ubuntu18.04: OpenCV3.4.9 (CUDA10.2)のインストール

$
0
0

Ubuntu18.04にOpenCV3.4.9をGPU搭載のラップトップ用にソースからビルドしインストールしたときのメモ。GPUを使いたいのでソースからビルドした。インストール方法は以下のリンクの手順を参考にした。

環境

  • Laptop
    • Razer Blade 15
      (CPU: Intel i7-8750H, Memory:16GB, GPU: Nvidia 1070 Max-Q Design, Memory: 8GB)
  • Linux
    • Voyager 18.04.3 (xubuntu18.04.3)
    • Kernel 5.0.0.-37-generic
    • gcc/g++ 7.4.0
    • CUDA 10.2
    • python3.6

準備

  • $ sudo apt install build-essential ccache
  • $ sudo apt install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev tesseract-ocr libtesseract-dev
  • $sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev 
  • $ sudo apt-get install libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libgtk2.0-dev libgtk-3-dev libpng-dev libjpeg-dev libopenexr-dev libtiff-dev libwebp-dev
  •  python3関連のインストール
    • $ sudo apt install python3-dev python3-numpy
    • $ sudo apt install python3-pip
  • python2関連のインストール(オプション)
    • $ sudo apt install python-dev python-numpy

ソースコードのダウンロード

  • $ cd
  • $ mkdir src
  • $ cd src
  • 以下をクリックしてopencv-3.4.9を~/srcにダウンロードする。
  • $ unzip opencv-3.4.9.zip
  • $ ln -s opencv-3.4.9  opencv
  •  以下をクリックしてopencv_contrib-3.4.9をダウンロードする。
  • $ unzip opencv_contrib-3.4.9.zip
  • $ ln -s opencv_contrib-3.4.9 opencv_contrib

ソースのビルド

  • $ cd ~/src/opencv
  • $ mkdir build
  • $ cd build
  • $ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D OPENCV_EXTRA_MODULES_PATH=~/src/opencv_contrib/modules -D BUILD_NEW_PYTHON_SUPPORT=ON -D WITH_V4L=ON -D WITH_VTK=ON -D INSTALL_C_EXAMPLES=ON -D PYTHON3_EXECUTABLE=/usr/bin/python3.6  -D PYTHON_INCLUDE_DIR=/usr/include/python3.6 -D PYTHON_INCLUDE_DIR2=/usr/include/x86_64-linux-gnu/python3.6m -D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.6m.so -D PYTHON3_NUMPY_INCLUDE_DIRS=/usr/include/python3.6m/numpy -D INSTALL_PYTHON_EXAMPLES=ON -D BUILD_EXAMPLES=ON -D ENABLE_FAST_MATH=1 -D CUDA_FAST_MATH=1 -D WITH_CUBLAS=1 -D WITH_OPENGL=ON -D WITH_CUDA=ON -D CUDA_ARCH_BIN="6.1" -D CUDA_ARCH_PTX="6.1"  -DBUILD_opencv_cudacodec=OFF ..
  • $ make -j$(nproc)
    • 私の環境では、コンパイルが終わるまで20分ぐらいかかった。

インストール

  • $ sudo make install
  • $ sudo /bin/bash -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf'
  • $ sudo  ldconfig

テスト

  • CUDAを有効にしてソースからビルドしたので、gpuを使うexample_gpu_opticalflowを試す。
  • $ cd ~/src/opencv/build
  • $ cp -aur ~/src/opencv/samples/data  .
  • $ cd ~/src/opencv/build/bin
  • $ ./example_gpu_opticalflow
  • 端末に下のような結果とウインドウが表示されれば成功。私の環境ではウインドウが重なっていたので、移動して並べた結果。お疲れ様!
    • Usage : ./example_gpu_optical_flow <frame0> <frame1>
      Brox : 0.146902 sec
      LK : 0.0252506 sec
      Farn : 0.0109897 sec
      TVL1 : 0.205551 sec

 

Viewing all 757 articles
Browse latest View live