Программа движения робота

Мы разобрались, как управлять роботом и получать данные о его положении в симуляторе turtlesim. Давайте рассмотрим программу, которая заставит робота проехать 3 метра и остановиться. На базе этой программы вам будет необходимо выполнить зачетное домашнее задание.

import rospy, math

from turtlesim.msg import Pose
from geometry_msgs.msg import Twist

class Turtle():

    def __init__(self):

        rospy.on_shutdown(self.shutdown)
        self.pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)
        rospy.Subscriber("turtle1/pose", Pose, self.pose_callback)
        self.pose = None

    def shutdown(self):
        self.pub.publish(Twist())    

    def pose_callback(self, pose):
        self.pose = pose        

    def wait_turtle(self):
        while self.pose is None:
            rospy.loginfo('Wait turtle')
            rospy.sleep(0.1)



    def move_forward(self, dist):

        start_pose = self.pose
        move_dist = 0
        cmd_vel = Twist()

        while not rospy.is_shutdown():

            move_dist = self.getMoveDist(start_pose, self.pose)

            if (move_dist < dist):                    
                cmd_vel.linear.x = 1
                self.pub.publish(cmd_vel)
            else:
                cmd_vel.linear.x = 0
                self.pub.publish(cmd_vel)
                return  

            rospy.sleep(0.2)


    def getMoveDist(self, start_pose, current_pose):

        move_dist = math.sqrt(math.pow(start_pose.x - current_pose.x,2) + math.pow(start_pose.y - current_pose.y,2))
        rospy.loginfo("Dist :%s", move_dist)
        return move_dist


rospy.init_node('move_forward')
rospy.loginfo("Start Node")

turtle = Turtle()   
turtle.wait_turtle()
turtle.move_forward(3)

Программа выглядит уже сложнее и больше, чем мы видели раньше. Но такая программа уже больше похоже на те, какие реально работают на роботах.

Алгоритм программы по сути довольно простой. Если у нас есть координаты, то зная текущую и стартовую координаты, мы можем вычислить расстояние, которое проехала черепаха. Если расстояние меньше требуемого, то продолжать ехать. Если больше, то остановиться и выйти. Но есть нюансы реализации.

Конструктор класса - создание Издателя для управления перемещением робота и подписка на данные Одометрии.

rospy.on_shutdown(self.shutdown)
self.pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)
rospy.Subscriber("turtle1/pose", Pose, self.pose_callback)
self.pose = None

Новый для нас метод. Он нам нужен для правильного завершения программы. Мы говорим, что если мы решили отключиться от ROS, то нужно вызвать метод класса shutdown

rospy.on_shutdown(self.shutdown)

Вызвать такой метод необходимо, чтобы остановить робота. Иначе программа завершится, а робот может продолжить свое движение, это будет неожидаемым поведением.

Также мы инициализировали переменную, в которой собираемся хранить текущее положение робота.

self.pose = None

Функция "отключения" робота. Мы создаем пустой объект Twist. И отправляем его через Издателя. Пустой Twist содержит все нулевые скорости, поэтому робот остановится.

def shutdown(self):
    self.pub.publish(Twist())

Функция обратного вызова, мы просто сохраним положение в атрибуте класса pose, потом мы будем использовать эту переменную для расчета пройденного расстояния.

def pose_callback(self, pose):
    self.pose = pose

Метод, который позволит нашей программе работать правильно.

def wait_turtle(self):
    while self.pose is None:
        rospy.loginfo('Wait turtle')
        rospy.sleep(0.1)

По ходу выполнения нашей программы нам важно, чтобы в самом начале работы мы знали положение робота. Но у нас может быть ситуация, что программа уже запустилась и готова рассчитать расстояние, а мы еще не получили "первый" callback с данными положения робота.

Поэтому нам необходима функция, которая позволит работать программе только после того, как мы получили первые данные о положении робота.

Сама главная функция "ехать вперед на расстояние dist"

def move_forward(self, dist):

    start_pose = self.pose
    move_dist = 0
    cmd_vel = Twist()

    while not rospy.is_shutdown():

        move_dist = self.getMoveDist(start_pose, self.pose)

        if (move_dist < dist):                    
            cmd_vel.linear.x = 1
            self.pub.publish(cmd_vel)
        else:
            cmd_vel.linear.x = 0
            self.pub.publish(cmd_vel)
            return  

        rospy.sleep(0.2)

Логика работы этой функции описана в самом алгоритме программы. Мы сохраняем точку старту, и раз в rospy.sleep(0.2) в цикле рассчитываем расстояние self.getMoveDist и принимаем решение, что делать: ехать дальше или выходить из метода.

# Установить линейную скорость по оси робота X 1 м/с
cmd_vel.linear.x = 1
# Обнулит скорость
cmd_vel.linear.x = 0

Функция getMoveDist производит расчет пройденного расстояния робота по теореме Пифагора. На вход мы передаем стартовую и текущую координату, а функция выдает расстояние между двумя этими точками.

    def getMoveDist(self, start_pose, current_pose):

        move_dist = math.sqrt(math.pow(start_pose.x - current_pose.x,2) + math.pow(start_pose.y - current_pose.y,2))
        rospy.loginfo("Dist :%s", move_dist)
        return move_dist

Ну и запуск нашей программы

turtle = Turtle()   
turtle.wait_turtle()
turtle.move_forward(3)

Мы создаем объект turtle. Ожидаем получения первых данных о положении робота, едем на 3 метра.

results matching ""

    No results matching ""