ROS サービスの具体的なアプリケーション 無人車両におけるサービス通信メカニズム

1 はじめに

通信メカニズムでは、このServiceサービスを以前に紹介しました:一般に、 ROS 通信メカニズムのサービス (Service) のアプリケーションは、
通信処理が比較的単純ないくつかのシナリオに適しています。サービス: 電圧データの発行、LED ライトのオン/オフ、ブザーのオン/オフ、左右のモーターの速度制御。

サーバー: サービスを提供するノードは、リクエストを処理するコールバック関数を定義します
クライアント: リクエストを提供するノードは、ローカル プロキシを通じてサービスを呼び出します。

ワークスペースやパッケージの作成過程は無視していますので、興味のある方はROSの新しいワークスペース(workspace)とパッケージ(package)のコンパイル練習(C++の例)をご覧ください。

2. 自動運転車への応用

2.1. ディレクトリ

まず、メッセージ、サービス、ノード ファイルとは何かを理解しましょう。

cd ~/workspace/catkin_ws/src
ls jetbotmini_msgs/msg
ls jetbotmini_msgs/srv
ls jetbot_ros/scripts

以下のスクリーンショット:

2.2. ノードの起動

次に、 ROSMASTERを直接開き、無人車両のノードを起動し、無人車両のサービス通信メカニズムをより明確に理解するためにメイン コードを投稿します。

roscore
rosrun jetbot_ros jetbotmini_driver.py

さて、これで自動運転車と通信できるようになりました

2.3. トピックの表示

まずはトピックを見てみましょう: rostopic リスト

/rosout
/rosout_agg
/電圧

ここでわかるように、 電圧 に関するトピックがあります。 


2.4. サービスの表示

次に、提供されるサービスのリストに注目してみましょう: rosservice list

/ブザー
/LEDBLUE
/LEDGREE
/モーター
/サーボ
/driver_node/get_loggers
/driver_node/set_logger_level
/rosout/get_loggers
/rosout/set_logger_level 

サービスリストにはブザー、LEDライト、モーター、ステアリングギアなどのサービスが含まれており、次にコマンドラインを通じてこれらのサービスを操作して自動運転車と通信します。
サービスの定義は非常に簡単です。詳しく見てみましょう

2.5. ブザー

コマンドを入力します: rossrv show ブザー

入力タイプと出力タイプは 3 本の小さな水平線で区切られています --- 

[jetbotmini_msgs/Buzzer]:
int32 ブザー
---
bool 結果

ブザーをオンにする: rosservice call /Buzzer "buzzer: 1"
result: True #これが戻り値です
。ブザーをオフにする: rosservice call /Buzzer "buzzer: 0"
result: True 

2.6. ステアリングギア

コマンドを入力します: rossrv show Servo 

[jetbotmini_msgs/Servo]:
int32 servoid
int32 angle
---
bool result

私の無人車両には、以下に示すように 2 つのサーボ インターフェイス S1 と S2 があります。

サーボ 1 角度 90: rosservice 呼び出し /Servo 1 90
結果: True
サーボ 2 角度 90: rosservice 呼び出し /Servo 2 90
結果: True 

サーボパラメータを確認します: rosservice args サーボ
サーボイド角度

サーボ 1 が 30 度回転します: rosservice call /Servo 1 30

もちろん、パラメータが複数ある場合は、パラメータ名の書き方を指定して辞書形式で実行することもでき、より直感的です:
rosservice call /Servo "{'servoid': 1, 'angle': 30}" 

2.7. LEDライト

LEB の青色ライトをオンにします: rosservice call /LEDBLUE 1結果:以下に示すように
True :

緑色の LED ライトをオンにします: rosservice call /LEDGREE 1結果:以下に示すように 
True :

一緒にライトアップ: 

2.8. モーター(モーター) 

Motorのデータ型構造を表示します: rossrv show Motor

[jetbotmini_msgs/Motor]:
float32 rightspeed
float32 leftspeed
---
bool 結果 

モーターのパラメーターを表示します。motor : rosservice args Motor

右の速度 左の速度

[rightspeed]: [-1, 1]、右のモーター速度。逆回転の場合は 0 未満、正回転の場合は 0 より大きくなります。
[leftspeed]: [-1, 1]、左モーター速度。逆回転の場合は 0 未満、正回転の場合は 0 より大きくなります。

左モーター (モーターホイール) 50% 速度、右モーター 80% 速度: rosservice 呼び出し /Motor 0.5 0.8 

利用可能なトピックを確認してください: rostopic リスト 

/rosout
/rosout_agg
/電圧 

トピック メッセージを視覚的に表示します: rosrun rqt_topic rqt_topic は
次のとおりです。電圧トピックのチェック ボックスをクリックして確認します。 

このように、電圧が10.67V、周波数が0.03Hzであることが直感的にわかります(30秒ごとに更新) 

3、jetbotmini_driver.py

このノードのコードに注目してみましょう。このノードには上で定義したさまざまなサービスが含まれているため、メッセージとサービスをインポートします。

from jetbotmini_msgs.msg import *
from jetbotmini_msgs.srv import *

Jetbotmini_msgs.msgJetbotmini_msgs.srvは自動的に生成されます メッセージの定義についても以前に紹介しました 興味がある場合は、ROS 通信メカニズムのトピック (Topics) の公開と購読、およびカスタム メッセージの実装が
行われます。 Python に基づいて、バージョンは対応する場所に生成されます。たとえば、次のディレクトリにいます
~/workspace/catkin_ws/devel/lib/python2.7/dist-packages/jetbotmini_msgs は、msgおよびsrv
で生成されますフォルダー。以下のスクリーンショット:


次に、 jetbotmini_driver.pyファイルに戻ります。ソース コードは次のとおりです。 

#!/usr/bin/env python3
# encoding: utf-8
import rospy
import random
import threading
from time import sleep
from jetbotmini_msgs.msg import *
from jetbotmini_msgs.srv import *
import RPi.GPIO as GPIO # Raspberry Pi 的GPIO库
import smbus

bus = smbus.SMBus(1) # 使用编号为1的总线,用于I2C通信
ADDRESS = 0x1B
Led_G_pin = 24 # 引脚编号
Led_B_pin = 23
Key1_pin = 8
GPIO.setmode(GPIO.BCM) # BCM模式是指使用Broadcom SOC通道编号的方式
GPIO.setup(Led_G_pin, GPIO.OUT, initial=GPIO.HIGH) # 引脚设置为输出模式,初始化为高电平
GPIO.setup(Led_B_pin, GPIO.OUT, initial=GPIO.HIGH)
GPIO.setup(Key1_pin, GPIO.IN) #输入模式,可以读取引脚的状态

print("Starting now!")

class transbot_driver:
    def __init__(self):
        rospy.on_shutdown(self.cancel)
        self.srv_Buzzer = rospy.Service("/Buzzer", Buzzer, self.Buzzercallback)
        self.srv_Servo = rospy.Service("/Servo", Servo, self.Servocallback)
        self.srv_LEDBLUE = rospy.Service("/LEDBLUE", LEDBLUE, self.LEDBLUEcallback)
        self.srv_LEDGREE = rospy.Service("/LEDGREE", LEDGREE, self.LEDGREEcallback)
        self.srv_Motor = rospy.Service("/Motor", Motor, self.Motorcallback)
        self.volPublisher = rospy.Publisher("/voltage", Battery, queue_size=10)

    def cancel(self):
        self.srv_Buzzer.shutdown()
        self.srv_Servo.shutdown()
        self.srv_LEDBLUE.shutdown()
        self.srv_LEDGREE.shutdown()
        self.srv_Motor.shutdown()
        self.volPublisher.unregister()
        GPIO.cleanup()
        rospy.loginfo("Close the robot...")
        rospy.sleep(1)

    def pub_data(self):
        # 发布电池电压
        while not rospy.is_shutdown():
            sleep(30)
            AD_value = bus.read_i2c_block_data(ADDRESS,0x00,2)
            voltage = ((AD_value[0] << 8) + AD_value[1]) * 13.3 / 1023.0
            battery = Battery()
            battery.Voltage = voltage
            self.volPublisher.publish(battery)

    def Buzzercallback(self, request):
        #蜂鸣器控制,服务器回调函数
        if not isinstance(request, BuzzerRequest): return
        bus.write_byte_data(ADDRESS,0x06,request.buzzer)
        sleep(0.01)
        bus.write_byte_data(ADDRESS,0x06,request.buzzer)
        response = BuzzerResponse()
        response.result = True
        return response

    def Servocallback(self, request):
        # 控制舵机
        if not isinstance(request, ServoRequest): return
        bus.write_i2c_block_data(ADDRESS,3,[request.servoid,request.angle])
        sleep(0.01)
        bus.write_i2c_block_data(ADDRESS,3,[request.servoid,request.angle])
        response = ServoResponse()
        response.result = True
        return response

    def LEDBLUEcallback(self, request):
        # 控制蓝色LED
        if not isinstance(request, LEDBLUERequest): return
        if request.ledblue == 1:
            GPIO.output(Led_B_pin, GPIO.LOW)
        elif request.ledblue == 0:
            GPIO.output(Led_B_pin, GPIO.HIGH)
        response = LEDBLUEResponse()
        response.result = True
        return response

    def LEDGREEcallback(self, request):
        # 控制绿色LED
        if not isinstance(request, LEDGREERequest): return
        if request.ledgree == 1:
            GPIO.output(Led_G_pin, GPIO.LOW)
        elif request.ledgree == 0:
            GPIO.output(Led_G_pin, GPIO.HIGH)
        response = LEDGREEResponse()
        response.result = True
        return response

    def Motorcallback(self, request):
        # 控制马达,速度小于0就反方向
        if not isinstance(request, MotorRequest): return
        if request.leftspeed < 0:
            request.leftspeed = -request.leftspeed
            leftdir = 0
        else:
            leftdir = 1
        if request.rightspeed < 0:
            request.rightspeed = -request.rightspeed
            rightdir = 0
        else:
            rightdir = 1
        bus.write_i2c_block_data(ADDRESS,0x01,[leftdir,int(request.leftspeed*255),rightdir,int(request.rightspeed*255)])
        sleep(0.01)
        bus.write_i2c_block_data(ADDRESS,0x01,[leftdir,int(request.leftspeed*255),rightdir,int(request.rightspeed*255)])
        response = MotorResponse()
        response.result = True
        return response

if __name__ == '__main__':
    rospy.init_node("driver_node", anonymous=False)
    try:
        driver = transbot_driver()
        driver.pub_data()
        rospy.spin()
    except:
        rospy.loginfo("Final!!!")

最初にいくつかの関連動作を初期化し、GPIO をBCMモードに設定し、次にピン番号に従って高レベルに初期化します。モードは出力モードなので、高レベルと低レベルに従って LED ライトを制御できます。明るさを制御したい場合は、 PWMパルス幅変調方式cancel関数のGPIO.cleanup()はピンを元の状態に戻し、すべてのピンを解放して出力を停止し、電気的損傷や火災を回避することに注意してください。
残りはいくつかのコールバック関数であり、主に一部の書き込みと判定操作が行われ、これらのコールバック関数を通じて対応するコンポーネントを操作できます。

このセクションは主に、Service サービスの実際の操作を実行し、通信メカニズムの 1 つとしてのその使用方法と、実際のその特定のアプリケーションを統合することについて説明します。
このコードには、GPIO の一般的な入出力に関するいくつかの知識ポイントが含まれています。興味がある場合は、
JetsonNano ボードの RPi.GPIO インターフェイスの物理図と機能の紹介を確認してください。

おすすめ

転載: blog.csdn.net/weixin_41896770/article/details/134264461
おすすめ