ロボット開発に必須とも言えるROS(Robot Operating System)ですが、Raspberry PiやArduinoと組み合わせて手軽に試すことができます。OSとついていますが、実際にはRaspbianやUbuntu Mate上で動作するミドルウェアと言えます。

前回はPub/Subを簡単に試してみましたが、今回はサーボモータを動かす実験をしてみます。

前回はパブ/サブまでやりました

プログラミング言語としてPythonを用いますので、C言語のようにコンパイルもいらず、手軽に試せることでしょう。

OSはUbuntu Mateで

ROSをRaspbianにインストールするドキュメントもあるのですが、試してみた限りでは最後の起動で失敗してしまいました。そのため、前回と同様に今回もUbuntu Mate 18.04を使っています。特に問題はないと思いますが、ライブラリのバージョンなどが多少異なる可能性があります。Raspbianの場合、ROSを一つずつコンパイルしないといけないですが、Ubuntu Mateの場合はパッケージ管理から簡単にインストールできるのも大きな利点です。

Download | Ubuntu MATE

ROSインストールから初期セットアップまでは下記コマンドになります。詳しくは前回の記事を参考にしてください。

$ sudo apt-get update
$ sudo apt-get upgrade -y
$ sudo add-apt-repository universe
$ sudo add-apt-repository multiverse
$ sudo add-apt-repository restricted
$ 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://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
$ sudo apt-get -y update
$ sudo apt-get -y upgrade
$ sudo dpkg -i --force-all /var/cache/apt/archives/linux-firmware-raspi2_1.20190215-0ubuntu0.18.04.1_armhf.deb
$ sudo apt-get upgrade
$ sudo apt install ros-melodic-desktop-full -y
$ sudo rosdep init
$ rosdep update
$ echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc
$ source ~/.bashrc
$ sudo apt-get -y install python-rosinstall
$ mkdir -p ~/catkin_ws/src
$ cd ~/catkin_ws/src
$ catkin_init_workspace
$ cd ~/catkin_ws
$ catkin_make
$ echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc
$ source ~/.bashrc
$ roscore

パッケージを作成する

今回もまずPub/Subの仕組みを作りますので、ja/ROS/Tutorials/WritingPublisherSubscriber(python) – ROS Wikiに沿って進めていきます。まずパッケージを作ります。パッケージの作り方についてはja/ROS/Tutorials/CreatingPackage – ROS Wikiを参考にします。

$ cd ~/catkin_ws/src
$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
$ roscd beginner_tutorials

Pythonスクリプト用のディレクトリを作成

Pythonスクリプトを格納するディレクトリを作成します。

$ mkdir scripts
$ cd scripts

スクリプトを配置する

テンプレートになるスクリプトをダウンロードします。

$ wget https://raw.github.com/ros/ros_tutorials/indigo-devel/rospy_tutorials/001_talker_listener/talker.py
$ chmod +x talker.py
$ wget https://raw.github.com/ros/ros_tutorials/indigo-devel/rospy_tutorials/001_talker_listener/listener.py
$ chmod +x listener.py

コードを見ると分かりますが、talker.pyが現在時刻を発信(Publish)し、listener.pyがその発信を購読しているという仕組みです。

ビルドする

このコードを確実にデプロイするため、 catkin_make を実行します。

$ cd ~/catkin_ws
$ catkin_make

実行する

では試しに実行してみます。まず購読側を実行します。

$ rosrun beginner_tutorials listener.py

次に発信側を実行します。

$ rosrun beginner_tutorials talker.py

そして、購読側のログに以下のように流れれば問題ありません。

[ INFO] 1251943144.400553000: Received [Hello there! This is message [1]]
[ INFO] 1251943144.600712000: Received [Hello there! This is message [2]]

サーボモータのコードに変更する

では続いてこのtalker.pylistener.pyをサーボモータを動かすコードに変えてみたいと思います。talker.pyからサーボモータの値を送信し、listener.pyはその値にモータを動かすという仕組みです。

pigpiodのインストール

サーボモータを動かす際にはGPIOを使いますので、pigpiodをインストールします。

$ sudo apt-get install pigpio python-pigpio python3-pigpio -y
$ sudo systemctl enable pigpiod
$ sudo systemctl start pigpiod

Publish側のコード

Publish(発信)側のコードです。サーボモータの動作範囲である 500〜2500 の値を100ずつ増加させたり、逆に減らしたりします。発信できるのは文字列のみなので、str関数を使って数字を文字列にしています。

#!/usr/bin/env python
import rospy
from std_msgs.msg import String

def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    rate = rospy.Rate(10) # 10hz
    i = 500
    plus = True
    while not rospy.is_shutdown():
        msg = str(i)
        rospy.loginfo(msg)
        pub.publish(msg)
        rate.sleep()
        if plus:
            i += 100
        else:
            i -= 100
        if i == 2500:
            plus = False
        if i == 500:
            plus = True

if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException:
        pass

Subscribe側のコード

Subscribe(購読)側のコードです。こちらは送られてきた文字列を数字にして、その値をサーボモータに適用しているだけです。サーボモータはGPIOの23番ピンを使っています。

#!/usr/bin/env python
import rospy
import pigpio
from std_msgs.msg import String
SERVO_PIN = 23
pi = pigpio.pi()

def callback(data):
    rospy.loginfo(rospy.get_caller_id() + 'I heard %s', data.data)
    p_width = int(data.data)
    pi.set_servo_pulsewidth(SERVO_PIN, p_width)

def listener():
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber('chatter', String, callback)
    rospy.spin()
if __name__ == '__main__':
    listener()

デモ

実際に動かしているところです。

このようにROSのPub/Subを使うことで、モジュールの独立性が高まったり、複数のモジュールを同時に操作できるようになります。発信側ではサーボモータの数字を指定するだけで、pigpioを読み込む必要もありません。

まとめ

ROSを使えばセンサーに依存したコードを排除したり、再利用性の高いノードを開発できるようになります。コールバックやPub/Subを使った方式なので、値や状態変化によって動作するロボットを開発するのが簡単になるでしょう。ぜひRaspberry Piと一緒に試してみてください。

ja – ROS Wiki


0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *