被弾センサーのテスト第2弾です。前回はナットドライバーで叩いただけでしたが、今回は実際にエアガンで撃ってみました。
下の写真の様に被弾センサーから約1m離れたところからエアガンで撃ちます。(周りが散らかっていてごめんなさい)
撃った時の被弾センサーについている加速度センサーのZ軸(面に垂直な方向)のデータが以下です。2つの画像は別々の回です。上は1メモリ100ms、下は1メモリ50msです。各々2発弾が当たっています(本当は3発撃っているはずなんだけどな......)。
やはりエアガンを撃つと立ち上がりが急な波形が出来るみたいですね。ただ下のデータの様に絶対値がいつも振り切れるというわけではなさそう。
追記
詳細な波形の形が取れました。
右が1目盛り10msで左が1目盛り1msです。1ms以内にピークまで達するという条件でうまく検出できそうです。
2017年8月16日水曜日
2017年8月14日月曜日
ROSのPublish、Subscribeの遅れの対策
ROSで基本的なPub、Subをしていた時にどうもうまくいかないところがあったのでそれの対策をメモします。重要なところだけを抜き出すと下の様にmsg_pubとmsg_subを作って通信をさせてその遅延を測りました(本当は途中にデータの変換ノードがいくつかあったが)。本来ならいくらかの遅延が発生するだけなのですが、実際には送信受信するデータのずれや遅れが発生しました。
Publish側では、例えばdata0をpublish()しても実際はパブリッシュされず、次のループでdata1をpublish()すると実際はdata0がパブリッシュされるという現象です。
Subscribe側では、受信処理が行われるタイミングが受信してから1秒遅れるという不具合です。$rostopic echo /msg_outで表示されるタイミングよりも遅れて表示が起きます。
ネットを探したりと1時間ほど格闘していたら答えが分かりました。
Publisher側の解決策としては
ros::Publisher msg_pub = n.advertise<std_msgs_Float64>("/msg_out", 1000);
を
ros::Publisher msg_pub = n.advertise<std_msgs_Float64>("/msg_out", 1000, true);
に変更しました。
どうやらpublishをするとソケット通信をするプロセスが裏で立ち上がって、それが通信をするみたいです。しかし、元のスレッドが短い場合はタイミングの問題なのか1つ分をデータを内部でバッファしてしまうみたいです。ros::Publisherの3つ目のオプションであるlatchをtrueにすることでそれを防げます。
Subscliber側の解決策としては
ros::Rate loop_rate(1);
を
ros::Rate loop_rate(100);
に変更しました。
これはなかなか分かりにくい問題で、普通は受信処理はトピックが来たら即実行されると思っていたのですが、実はmain関数のfor文でloop_rate.sleep()している間は受信処理が起きず、スリープが解除されたときにトピックが来たら受信処理をするという仕様の様です。そのためにfor文中で何の処理をしていなくてもloop_rateはある程度細くしなければなりません。
==========msg_pub.c==========
#include "ros/ros.h"
#include "std_msgs/Float64.h"
int main(int argc, char **argv)
{
ros::init(argc, argv, "msg_pub");
ros::NodeHandle n;
ros::Publisher msg_pub = n.advertise<std_msgs_Float64>("/msg_out", 1000);
ros::Rate loop_rate(1);
while (ros::ok()){
std_msgs::Float64 msg=1.0;
msg_pub.publish(msg);
//時間を計測
ros::spinOnce();
loop_rate.sleep();
}
}
==========#####==========
==========msg_sub.c==========
#include "ros/ros.h"
#include "std_msgs/Float64.h"
void msg_callback(const std_msgs::Float64& msg){
//時間を計測
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "msg_sub");
ros::NodeHandle n;
ros::Subscriber msg_sub = n.subscribe("/msg_out", 10, msg_callback);
ros::Rate loop_rate(1);
while (ros::ok()){
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
==========#####==========
Publish側では、例えばdata0をpublish()しても実際はパブリッシュされず、次のループでdata1をpublish()すると実際はdata0がパブリッシュされるという現象です。
Subscribe側では、受信処理が行われるタイミングが受信してから1秒遅れるという不具合です。$rostopic echo /msg_outで表示されるタイミングよりも遅れて表示が起きます。
ネットを探したりと1時間ほど格闘していたら答えが分かりました。
Publisher側の解決策としては
ros::Publisher msg_pub = n.advertise<std_msgs_Float64>("/msg_out", 1000);
を
ros::Publisher msg_pub = n.advertise<std_msgs_Float64>("/msg_out", 1000, true);
に変更しました。
どうやらpublishをするとソケット通信をするプロセスが裏で立ち上がって、それが通信をするみたいです。しかし、元のスレッドが短い場合はタイミングの問題なのか1つ分をデータを内部でバッファしてしまうみたいです。ros::Publisherの3つ目のオプションであるlatchをtrueにすることでそれを防げます。
Subscliber側の解決策としては
ros::Rate loop_rate(1);
を
ros::Rate loop_rate(100);
に変更しました。
これはなかなか分かりにくい問題で、普通は受信処理はトピックが来たら即実行されると思っていたのですが、実はmain関数のfor文でloop_rate.sleep()している間は受信処理が起きず、スリープが解除されたときにトピックが来たら受信処理をするという仕様の様です。そのためにfor文中で何の処理をしていなくてもloop_rateはある程度細くしなければなりません。
==========msg_pub.c==========
#include "ros/ros.h"
#include "std_msgs/Float64.h"
int main(int argc, char **argv)
{
ros::init(argc, argv, "msg_pub");
ros::NodeHandle n;
ros::Publisher msg_pub = n.advertise<std_msgs_Float64>("/msg_out", 1000);
ros::Rate loop_rate(1);
while (ros::ok()){
std_msgs::Float64 msg=1.0;
msg_pub.publish(msg);
//時間を計測
ros::spinOnce();
loop_rate.sleep();
}
}
==========#####==========
==========msg_sub.c==========
#include "ros/ros.h"
#include "std_msgs/Float64.h"
void msg_callback(const std_msgs::Float64& msg){
//時間を計測
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "msg_sub");
ros::NodeHandle n;
ros::Subscriber msg_sub = n.subscribe("/msg_out", 10, msg_callback);
ros::Rate loop_rate(1);
while (ros::ok()){
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
==========#####==========
2017年8月10日木曜日
Raspberry PiとROSでロボット製作(インストール)
前の記事でRaspberry Pi3にUbuntu mate16とRos Kineticをインストールするという話をしました。今回はその方法を具体的に述べていきます。
カメラのパッケージの追加
基本的にロボット関連だと良く使うのでここで入れておきます。
- Ubuntu mate16用のイメージをSDに書き込み
- Raspberry Pi3上でUbuntu mateのセットアップ
- ROSのインストール
準備するもの
- Raspberry Pi3
- micro SDカード(8GB以上)
- Raspberry Pi用の電源アダプタ
- Raspberry Pi用のモニター、キーボード、マウス
- Windows PC
- インターネット回線(Wifi or 有線)
1. Ubuntu mate16用のイメージをSDに書き込み
Device Plusの記事を参考にしています。
- イメージをダウンロード
ダウンロードページにアクセスします。「Ubuntu MATE 16.04.3 LTS」をクリック、その後に一番右の「Raspberry Pi」の部分をクリックします。
下の方にスクロールしてVia Direct Downloadの部分の「Bytemark - ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img.xz」をクリックしましょう。
もしかしたらこの部分は時間がたつと更新されているかもしれません。バージョンが「16」であることが大切です。その時は読み替えを - 解凍
Ubuntu mate16のイメージは「xz」というWindowsでは珍しい圧縮形式をしています。標準では解凍が出来ないので「Lhaplus」等のソフトを使って解凍してください。 - SDの準備、SDのフォーマット
SDカードのフォーマットに使います。セットアップのやり直しをしたりするときに使うのでここの段階でSDFormatterをインストールしておくと良いでしょう。ダウンロードサイトに行きまして、下の方の青い「Windows用ダウンロード」を押して次の画面の一番下の「同意します」を押すとインストーラーがダウンロードできます。それをインストールして起動しましょう。
これでこれからイメージを書き込むSDカードを1度フォーマットします。オプション設定では論理サイズ調整をONにしておくと良いです。 - DDWinでSDに書き込み
イメージをSDカードに書き込みます。DD for Windowsというソフトを使います。ダウンロードページに行きダウンロードのところの最新バージョンをクリックします(おそらくver0.9.9.8のはずです)。zipなので解凍するとフォルダの中には「DDWin.exe」という実行ファイルがありますがこれを右クリックして「管理者として実行」を選択します。ディスク選択でSDカードを選び(おそらくすでに入力されているはずです)、ファイル選択で先ほどダウンロードしたUbuntu mateのイメージ(ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img のような名前をしている)を選択します。始めは.ddiファイルしか選択できないようになっているので、ファイルの選択画面で右下のドロップダウンリストでall filesに変更してください。最後に書き込みを押すと書き込みが開始されます。意外と長く10分ほどかかります。
2.Raspberry Pi3上でUbuntu mateのセットアップ
- Raspberry Pi3の起動
Raspberry Pi3にモニター、キーボード、マウスをつけて電源を挿します。しばらくすると立ち上がります。 - 設定
始めにWifiの設定を聞かれるので、Wifiにつなぐか、Ethernetを接続してください。後の設定は画面の指示通りに行ってください。30分ぐらいかかりますが、設定が終了すると再起動してログイン画面が出てきますのでログインしてください。 - キーボード設定
途中でキーボードの選択画面が出てきます。「日本語」→「OADG 109A」を選択するのが良いです。 - SSHの設定(オプション)
いつかは必要になるのでここでしておきましょう。一番左上のMateのマークからたどってTerminal(Mate端末)を出します。
$sudo raspi-config
で設定画面が出てくるので、Interfacing Options→ssh→Enableで設定します。
3.ROS kineticをインストール
ROS Wikiに書いてある通りです。- リポジトリの登録
$sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
$sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116 - update
$sudo apt-get -y update
($sudo apt-get -y upgrade)やってもよいが時間がかかるのでいつもは飛ばしている - ROSインストール
$sudo apt-get -y install ros-kinetic-desktop
($sudo apt-get install ros-kinetic-desktop-full)←ROSのフルバージョンを入れたいなら代わりにこっちを入力
$apt-cache search ros-kinetic - rosdepのインストール
$sudo rosdep init
$rosdep update - 環境設定
ターミナル起動時にROSにパスを通す必要があるので必要です
$echo "source /opt/ros/kinetic/setup.bash" >> ~/.bashrc
$source ~/.bashrc - rosinstallのインストール
基本的に使わないと思うけど
$sudo apt-get -y install python-rosinstall
カメラのパッケージの追加
基本的にロボット関連だと良く使うのでここで入れておきます。
- $sudo apt-get -y install ros-kinetic-uvc-camer
2017年8月9日水曜日
Raspberry PiとROSでロボット製作(概要)
ROSについて
Raspberry Piは強力なツールです。これを使うことで今までのマイコンでは扱うのが難しかったカメラや無線LANをロボットで簡単に使うことが出来ます。またROSを使うことでプログラムをモジュール化できるので、プログラムの再利用性が格段と上がります。個人的にはROSの利点として以下の点をあげます。
- プログラム間の通信部分が規格化されている
例えば(1)ジョイスティックの入力を読んで、それをもとに(2)タイヤの回転量を決めて、(3)タイヤを制御するというプログラムを書くとします。普通は(1)、(2)、(3)を1つのソースコードで記述して、その間の通信は自分で作ったデータ型を使うでしょう。
これでは例えば(1)のジョイスティックをキーボード入力に変えようとすると、ソースコードを地道に直さなければなりません。
しかしROSではジョイスティックのデータ型等のロボットで使われそうなものはすべて定義されていて、またプログラム間での通信の方法が規格化されています。そのために3つのプログラムを個々のノードに分離でき、前のような状況でもノードを置き換えることで実現できます。 - PC間接続が簡単にできる
例えばロボットのWEBカメラの画像をコントローラーのPCで見たい時には、わざわざMJPEGのストリーマーを起動させる必要があったり、ラジコン化させようとしたときにはコマンドを送るソケット通信をわざわざ書く必要があります。しかしROSではそのようなことをする必要はありません。上記のプログラム間接続の規格というのは実はTCP/IP通信です。同じPCの中でもTCP/IP通信をしているのです。そのために同じPCで(1)WEBカメラの画像を取り込むプログラムと(2)画像を表示するプログラムの2つを使ってWEBカメラの画像を表示するのと同じように、(1)がロボットPCで起動していて、(2)がコントローラーPCで起動することが出来ます。 - 座標の管理が簡単にできる
ROSにはtfという座標管理システムがあります。これを使うことでバグの多い座標管理を簡単に行えます。 - 公開されているパッケージが多い
例えばWEBカメラの画像を取り込むソフトも十分にありますし、ロボットで使うそうなセンサーに対応するプログラムは大体あるみたいです。 - Launchファイルでプログラムを改変できる
通常ロボットのプログラムに変更を加える場合はソースを編集してビルドする必要がありますが、それとは別にLaunchという起動スクリプトでパラメーターを変更することが出来ます。例えば移動速度をいくつかのパターンで試したいときにソースではスクリプトから変数を取得するようにします。そして起動スクリプトで変数をしていして起動します。この方式ではビルドすることなくプログラムを変更することが出来ます。
- インストールが面倒
ROSを使うハードルが高いと言われる最大の原因です。ROSは複雑な移動関係を持つのでインストール時にトラブルが発生しやすいです。 - (特に駆動系統の)ハードウェアを自作する必要がある
これはROSの問題というよりもロボット開発における問題ですが、現在IoTなどが流行っていてUSB接続できるセンサー等が増えています。しかし流通している大体のセンサーはSPIやI2C等の接続の物です。これらはArduinoでは簡単に使えるのですが、PCで使うのには工夫が必要です。またモータードライバも同様でUSB接続の物の無いことは無いのですが産業用で高価であり、これもPCとつなぐには間の通信する部分をArduinoなどで作る必要があります。
Ros on Raspberry Pi
ここからやっとRaspberry Piの話に入ります。Raspberry PiでROSを使う方法はいろいろあります。- Raspbianを使う(Raspberry Pi2、Raspberry Pi3)
Raspbianは標準のOSですがROSをapt-getすることが出来ません。apt-getはdebian系のOSでプログラムを自動でタウンロードできる便器な機能ですが、何故かROSではできません。そのためにソースをgitからダウンロードして、ビルドする必要があります。また追加のパッケージもapt-getできなく、別途gitからソースをダウンロードしなくてはならないのですが、この辺りは慣れた人でも大変らしいです。 - Ubuntu16を使う(Raspberry Pi2)
Raspberry Pi2用のイメージデータがあります。これを使うと普通のデスクトップでROSを使うのと同じように使えます。しかしRaspberry Pi3用のイメージは無く、無理やり2用の物を入れても3の特徴であるWiFiを使うことは面倒です。 - Ubuntu mate16をつかう(Raspberry Pi3)
Ubuntu mateはデスクトップ環境にmateを使ったUbuntu派生ディストリビューションでUbuntuより軽量らしいです。Raspberyy Pi3用のUbuntu mate16イメージが公開されているので、Raspberry Pi3を使うならこれがベストです。また中身はUbuntuと変わらないので、apt-getでのインストールなどUbuntuと同じように使うことが出来ます。
2017年8月7日月曜日
被弾センサーのテスト
前にロボットに取り付けられるエアガンを作りましたが、的が未だありません。適当な板を立てて、当たったら倒れるようにしたいのですが、どうせならエアガンをRapberry Piから操作できるので、Raspberry Piで当たったか検知できるような機構を作りたいと思います。そうするとロボットに載せてエアガンで撃ち合いもできますし。
「ロボでサバゲ」という大会ではアルミ箔を箱状に貼り、弾が当たって破けると箱の中の光センサが反応するという光を使って判定しています。
同じものを作るのは面白くないので、私は加速度センサーを使った方式で試したいと思います。しかし加速度センサーではロボットの振動などのノイズも拾ってみます。そこで今回は的を外枠とゴムでつないで宙づりにして的に加速度センサーを付けてみました。
真ん中にあるのは加速度センサーMNA7361です。このセンサーはアナログ出力で、今回はZ軸(面に垂直)をオシロスコープで見てみます。(横軸は1目盛りが10ms)
的をナットドライバで叩いた時が以下です。飽和しています。
外枠を斜めにナットドライバーで叩いたとき
外枠も思いっきり叩くとそこそこの加速度が掛かってしまいます。しかしよく見るとばねの遅れの分加速度の立ち上がりに1msほどかかっています。
加速度が閾値を超える&立ち上がりが早いの2つの条件で弾が的に当たったことと他の振動を区別できそうです。
「ロボでサバゲ」という大会ではアルミ箔を箱状に貼り、弾が当たって破けると箱の中の光センサが反応するという光を使って判定しています。
同じものを作るのは面白くないので、私は加速度センサーを使った方式で試したいと思います。しかし加速度センサーではロボットの振動などのノイズも拾ってみます。そこで今回は的を外枠とゴムでつないで宙づりにして的に加速度センサーを付けてみました。
的をナットドライバで叩いた時が以下です。飽和しています。
外枠を斜めにナットドライバーで叩いたとき
外枠も思いっきり叩くとそこそこの加速度が掛かってしまいます。しかしよく見るとばねの遅れの分加速度の立ち上がりに1msほどかかっています。
加速度が閾値を超える&立ち上がりが早いの2つの条件で弾が的に当たったことと他の振動を区別できそうです。
2017年8月2日水曜日
MFT2017用の準備
MFT2017まで残り数日となりました。私は展示品の作成などに追われています。ビラなど今まではロボットについて書いていましたが、ロボット以外にも1つ製作物を出すので載せておきます。
ブースはG-07-04です。ぜひお越しください。
ブースはG-07-04です。ぜひお越しください。
登録:
投稿 (Atom)