空飛ぶロボットのつくりかた

ロボットをつくるために必要な技術をまとめます。ロボットの未来についても考えたりします。

catkin_make徹底理解

catkinワークスペース

STEP1

  1. ROS_PACKAGE_PATHの確認、設定
  2. $ mkdir ~/test_catkin_ws/src
  3. $ cd ~/test_catkin_ws/src
  4. $ catkin_init_workspace

ここで、~/test_catkin_ws/src にCMakeKist.txtが作成される

STEP2

  1. cd ~/test_catkin_ws
  2. catkin_make

ここで、buildとdevelができる

  • buildとは

    • catkinパッケージを構成するためにCMakeを呼び出し、さまざまな処理を行う場所でビルドスペースと呼ばれる
  • develとは

    • 生成される目的コードをインストールする前に作業を行うスペースであり、開発スペースと呼ばれる

develや/opt/ros/indigoの中に設定ファイル.bashがある

  • /opt/ros/indigo設定読み込み

    • コアパッケージへのパスが反映
  • devel設定読み込み

パッケージ作成

ROSパッケージをビルドするには

  1. CMakeList.txt
  2. package.xml

が必要

$ catkin_create_pkg <package_name> [depend1] [depend2] ...
ex: catkin_create_pkg test_package roscpp rospy std_msgs

こうすることで、依存関係がpackage.xmlに追加される

  • 同じパッケージがある場合は$ROS_PACKAGE_PATHに記載の順番で呼ばれる

コードの変更、修正時

  1. package.xml
  2. CMakeLists.txt

を修正

package.xml

  • 現在のパッケージの名前や、ほかのパッケージとの依存関係、コンパイル時のフラグなどの基本情報が定義

  • 大事なタグ

<build_depend>
現在のパッケージをインストールする前に、先にインストールする必要のあるパッケージの名前を指定する
<run_depend>
現在のパッケージを実行する際に必要とするほかのパッケージの名前や現在のパッケージが依存するランタイムライブラリ名などを指定する
<test_depend>
現在のパッケージの機能テストを行う際に依存するパッケージ名を指定する
<buildtool_depend>
現在のパッケージを構築する際に使用されるシステムツールを指定する
一般的にはcatkin
<export>
現在のパッケージをコンパイルする際に必要となるフラグやヘッダファイル、ライブラリなどのパス情報を指定する

CMakeLists.txt

  • CMakeビルドシステムに使われる設定ファイル
  • このファイルの中にはターゲットを生成する際に必要なツールや関連するライブラリおよび生成方法などを記述する。CMakeでビルドするときに、このファイルを参照してターゲットを生成する

記述する内容

  1. . 関連するほかのcatkinパッケージ名

    ex: find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs)
    
  2. . メッセージ・サービス・アクションジェネレータ

    ex: add_message_files(
        FILE Message1.msg)
    
  3. . メッセージ・サービス・アクションのデータタイプの生成

    ex: generate_message(DEPENDENCIES std_msgs)
    
  4. . パッケージの構築情報

    ex: catkin_package(~)
    
  5. . 構築するターゲットの指定

    ex: add_executable(~)
    
  6. . インストール方法

    ex: install(~)
    
  7. . テスト項目

    ex: catkin_add_gtest(~)
    
  8. . メタパッケージの記述

単一のパッケージのみビルドしたい場合

catkin_make --pkg <package name>

myenigma.hatenablog.com

ROSを勉強している方々のブログまとめ

お世話になっております。

大感謝。全部目を通したい。

rosとは

参考

ROSの概念

[ROSロボットプログラミング] ROSで使われる専門用語 - Qiita

わかりやすいチュートリアル

ROS Tutorials — ROS Tutorials 0.5.1 documentation

ブログまとめ

ros-robot.blogspot.jp

myenigma.hatenablog.com

karaage.hatenadiary.jp

www.youtalk.jp

BRILLIANTSERVICE TECHNICAL BLOG: ROS

cryborg.hatenablog.com

crafty-as-a-fox.tumblr.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

ロボットとお話しよう2(音声でラジコン操作)

robonchu.hatenablog.com

の続き

[Raspberry Pi]USBマイクと音声認識ソフトJuliusを使って音声認識を試す(2) : 工作と競馬

[Raspberry Pi]USBマイクと音声認識ソフトJuliusを使って音声認識を試す(3) ~ フルカラーLEDを音声で操作 ~ : 工作と競馬

をとても参考にさせていただきました。 感謝です。

目標

声を使ってラジコンを操作

準備

dictation-kit-v4.3.1-linuxからmodelファイルをコピーしてこれから作業するフォルダにおく

手順

  1. teleop.dic(utf-8で作成)ファイルの作成
    右   m i g i
    左   h i d a r i
    前   m a e
    後ろ    u sh i r o
    停止    t e i sh i
    
  2. juliusの設定ファイルのteleop.jconfの作成
    -w teleop.dic       #単語辞書ファイル
    #-v model/lang_m/bccwj.60k.htkdic  #N-gram、または文法用の単語辞書ファイルを指定$
    -h model/phone_m/jnas-tri-3k16-gid.binhmm #使用するHMM定義ファイル
    -hlist model/phone_m/logicalTri   #HMMlistファイルを指定する
    -n 5        #n個の文仮説数が見つかるまで検索を行う
    -output 1     #見つかったN-best候補のうち、結果として出力する個数
    -input mic #-demo     #マイク使用
    -zmeanframe
    -rejectshort 600  #検出された入力が閾値以下なら棄却
    #-charconv euc-jp utf8 #入出力エンコード指定(内部euc-jp, 出力utf-8)
    -lv 1000    #入力の振幅レベルの閾値(0~32767)
    
  3. juliusを起動するシェルスクリプトrun_teleop.shの作成
    #! /bin/sh
    export ALSADEV=“plughw:1,0”
    julius -C teleop.jconf -demo -input alsa -nostrip -module > /dev/null &
    echo $!
    sleep 3
    
  4. juliusから送られるコマンドを受け取りarduinoに送る

以下com_julius_arduino.pyを作成。 これを実行すると音声入力に対し、cmd_velがpubされる。

#!/usr/bin/python
# coding:utf-8

import rospy
from sensor_msgs.msg import Joy
from geometry_msgs.msg import Twist

import socket
import subprocess
import xml.etree.ElementTree as ET
 
HOST = "localhost"
PORT = 10500

teleop_cmd = [
    u"右" , \
    u"左" , \
    u"前" , \
    u"後ろ" , \
    u"停止" 
    ]

class RosSet(object):
    def __init__(self):
        rospy.init_node('voice_twist')
        self.twist_pub = rospy.Publisher('cmd_vel', Twist, queue_size=100)
        self.twist = Twist() 

    def sendCmd(self, cmdName):
        if cmdName==u"前":
            self.twist.linear.x = 10
            self.twist.angular.z = 0
        elif cmdName==u"後ろ":
            self.twist.linear.x = -10
            self.twist.angular.z = 0
        elif cmdName==u"右":
            self.twist.linear.x = 0
            self.twist.angular.z = -10
        elif cmdName==u"左":
            self.twist.linear.x = 0
            self.twist.angular.z = 10
        elif cmdName==u"停止":
            self.twist.linear.x = 0
            self.twist.angular.z = 0 
        rospy.loginfo(self.twist)
        self.twist_pub.publish(self.twist)

def main():
    rosset = RosSet()
    p = subprocess.Popen(["sh run_teleop.sh"], stdout=subprocess.PIPE, shell=True)
    pid = p.stdout.read() # juliusのプロセスIDを取得
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect((HOST, PORT))
    try:
        data = ""
        while 1:
            if "</RECOGOUT>\n." in data:
                root = ET.fromstring('<?xml version="1.0"?>\n' + data[data.find("<RECOGOUT>"):].replace("\n.", ""))
                for whypo in root.findall("./SHYPO/WHYPO"):
                    if whypo.get("WORD") in teleop_cmd:
                        # 判別した言葉を表示する
                        print whypo.get("WORD")
                        rosset.sendCmd(whypo.get("WORD"))
                    else:
                        print "Unknown"
                data = ""
            else:
                try:
                    data = data + client.recv(1024)
                except:
                    print "ps kill."
                    p.kill() #
                    subprocess.call(["kill " + pid], shell=True) 
                    client.close()
                    break
    
    except KeyboardInterrupt:
        print "KeyboardInterrupt occured."
        p.kill() #
        subprocess.call(["kill " + pid], shell=True)
        client.close()
   
if __name__ == "__main__":
    main()

参考:

www.feijoa.jp

rosとarduinoでラジコンをつくる(arduino+pcをxbeeでつなぐ)

Xbeeのセットアップ

robonchu.hatenablog.com

に追加で、baud rateを57600に変更。9600のままだとうまくいかなかった。 以下参照。

baud rate parameter in rosserial_python arduino - ROS Answers: Open Source Q&A Forum

手順

  1. くるまにmotor shield付きarduinoを設置

  2. 以下の準備を行う

    robonchu.hatenablog.com

    robonchu.hatenablog.com

  3. XbeeをPCとarduinoに設置

  4. ターミナル4

    $ sudo chmod 777 /dev/ttyUSB0(or/ttyACM0)
    

  5. ターミナル4
    $ rosrun rosserial_python serial_node.py /dev/ttyACM0 _baud:=57600
    
  6. joy stickの十字キーでくるまを操作!

rosとarduinoでラジコンをつくる(pc側)

joy stickでコマンドを送り、arduinoにros経由で信号を送る

pythonでjoy stickのコマンドを受け取り(sub)送る(pub)コードを書く

手順

  1. ターミナル1

    $ roscore

  2. ターミナル2

    $ rosrun joy joy_node

  3. ターミナル3

以下のpythonコードを実行

$ python joy_twist.py
import rospy
from sensor_msgs.msg import Joy
from geometry_msgs.msg import Twist

class JoyTwist(object):
    def __init__(self):
        self._joy_sub = rospy.Subscriber('joy', Joy, self.joy_callback, queue_size=1)
        self._twist_pub = rospy.Publisher('cmd_vel', Twist, queue_size=100)
        self.operation = [0.0, 0.0, 0.0]

    def joy_callback(self, joy_msg):
        self.operation[0] = joy_msg.axes[0]
        self.operation[1] = joy_msg.axes[1]

if __name__ == '__main__':
    rospy.init_node('joy_twist')
    rate = rospy.Rate(10) # 10hz
    joy_twist = JoyTwist()
    twist = Twist()
    
    while not rospy.is_shutdown():
        twist.linear.x = joy_twist.operation[1]
        twist.angular.z = joy_twist.operation[0]
        rospy.loginfo(twist)
        joy_twist._twist_pub.publish(twist)
        rate.sleep()

Joy Stick Library

Access joysticks/game controllers from Python in Linux via the joystick driver. See https://www.panda3d.org/forums/viewtopic.php?f=8&t=16767 · GitHub

evdev 0.1.1 : Python Package Index

rosとarduinoでラジコンをつくる(arduino側)

めちゃくちゃ手抜き笑

rosでcmd_velを受け取って(subscribe)、arduinoのモーターを動かす

準備

手順

  • 以下からモーターシールドのライブラリインストール

Library Install | Adafruit Motor Shield | Adafruit Learning System

  • rosserial-arduinoを使えるようにする

    1. rosserial_arduinoをインストール
      $ sudo apt-get install ros-indigo-rosserial-arduino  ros-indigo-rosserial
      
    2. ros_libディレクトリをArduinoのsketchbook/libraries下に生成
      $ cd sketchbook/libraries
      $ rosrun rosserial_arduino make_libraries.py .
      
  • Arduinoに以下のsketchを書き込み

#include <AFMotor.h>

int Vl,Vr,kl,kr;

#include <ros.h>
#include <std_msgs/String.h>
#include <geometry_msgs/Twist.h>
ros::NodeHandle  nh;

//モーターボードの3,4を使用しているため
AF_DCMotor motor3(3, MOTOR12_64KHZ); // create motor #3, 64KHz pwm
AF_DCMotor motor4(4, MOTOR12_64KHZ); // create motor #4, 64KHz pwm


void MotorCmdCallback(const geometry_msgs::Twist& msg){
//  Vl = msg.linear.x+0.13/2*msg.angular.z;
//  Vr = msg.linear.x-0.13/2*msg.angular.z;
//  Vl = kl*Vl;
//  Vr = kr*Vr;

  if (msg.linear.x>0){
    motor3.run(FORWARD);      // forward
    motor4.run(FORWARD);
    }
  else if (msg.linear.x<0){
    motor3.run(BACKWARD);     // backward
    motor4.run(BACKWARD);
  }
  else if (msg.angular.z>0){
    motor3.run(FORWARD);      // turn right
    motor4.run(BACKWARD);
    }
  else if (msg.angular.z<0){
    motor3.run(BACKWARD);     // turn left
    motor4.run(FORWARD);
    }
  else{
    motor3.run(RELEASE);      // stopped
    motor4.run(RELEASE);      
    }
}

ros::Subscriber<geometry_msgs::Twist> sub("cmd_vel", MotorCmdCallback);


void setup() {
  //Serial.begin(9600);           // set up Serial library at 9600 bps
  //Serial.println("Motor test!");//↑rosserialはserial.beginをコメントアウトしないと使用できない(XCTUの設定で回避可能?)
  
  motor3.setSpeed(200);     // set the speed to 200/255
  motor4.setSpeed(200);     // set the speed to 200/255

  nh.initNode();
  nh.subscribe(sub);
  
}

void loop() {
  nh.spinOnce();
  delay(1);
}

ロボットの認識をつくろう(Tensorflowをつかう)

物体認識をtensorflowを使って行う。

OTLさんが既にrosで動かしてくれていた↓

ROS勉強記録: rostensorflow (というには程遠いけど一応動く一般物体認識ROSノード)作ってみた