无法在 ROS Gazebo 中发布到 /cmd_vel

问题描述 投票:0回答:1

我目前正在做 RRT* 路径规划作业,我无法将turtlesim3 Gazebo 的速度发布到 /cmd_vel。我可以看到节点已在 rqt_graph 中连接,但当我回显该主题时,没有弹出任何内容。我可以使用 teleop 和终端控制机器人。我可以看到节点已在 rqt_graph 中连接,但当我回显该主题时,没有任何内容弹出。我可以使用 teleop 和终端控制机器人。

#!/usr/bin/env python3
import matplotlib.pyplot as plt
import random
import math
import copy
import rospy
import time
import numpy as np
from numpy import genfromtxt
from numpy import array
from sensor_msgs.msg import NavSatFix
from sensor_msgs.msg import Imu
from std_msgs.msg import String
from geometry_msgs.msg import Vector3Stamped
from geometry_msgs.msg import Twist
from geometry_msgs.msg import Pose2D
from nav_msgs.msg import Path
from geometry_msgs.msg import PoseStamped
from std_msgs.msg import Float32MultiArray

show_animation = True

class RRT():
    """
    Class for RRT Planning
    """
    
    def __init__(self, start, goal, obstacles,
                 randArea, expandDis=1.0, goalSampleRate=5, maxIter = 500):
        """
        Setting Parameter

        start: Start Position [x, y]
        goal: Goal Position [x, y]
        obstacles: Obstacle Positions [[x, y, size], ...]
        randArea: Random Sampling Area [min, max]
        """
        self.start = Node(start[0], start[1])
        self.end = Node(goal[0], goal[1])
        self.minrand = randArea[0]
        self.maxrand = randArea[1]
        self.expandDis = expandDis
        self.goalSampleRate = goalSampleRate
        self.maxIter = maxIter
        self.obstacles = obstacles

    def Planning(self, animation=True):
        """
        Path planning

        animation: flag for animation on or off
        """
        self.nodeList = [self.start]
        while True:
            # Random Sampling
            if random.randint(0, 100) > self.goalSampleRate:
                rnd = [random.uniform(self.minrand, self.maxrand), random.uniform(self.minrand, self.maxrand)]
            else:
                rnd = [self.end.x, self.end.y]

            # Find nearest node
            nind = self.GetNearestListIndex(self.nodeList, rnd)

            # Expand tree
            nearestNode = self.nodeList[nind]
            theta = math.atan2(rnd[1] - nearestNode.y, rnd[0] - nearestNode.x)

            newNode = copy.deepcopy(nearestNode)
            newNode.x += self.expandDis * math.cos(theta)
            newNode.y += self.expandDis * math.sin(theta)
            newNode.parent = nind

            if not self.__CollisionCheck(newNode, self.obstacles):
                continue

            self.nodeList.append(newNode)
            print("Node list length:", len(self.nodeList))

            # Check goal
            dx = newNode.x - self.end.x
            dy = newNode.y - self.end.y
            d = math.sqrt(dx * dx + dy * dy)
            if d <= self.expandDis:
                print("Goal reached!")
                break

            if animation:
                self.DrawGraph(rnd)

        path = [[self.end.x, self.end.y]]
        lastIndex = len(self.nodeList) - 1
        while self.nodeList[lastIndex].parent is not None:
            node = self.nodeList[lastIndex]
            path.append([node.x, node.y])
            lastIndex = node.parent
        path.append([self.start.x, self.start.y])

        return path

    def DrawGraph(self, rnd=None):
        """
        Draw Graph
        """
        plt.clf()
        if rnd is not None:
            plt.plot(rnd[0], rnd[1], "^k")
        for node in self.nodeList:
            if node.parent is not None:
                plt.plot([node.x, self.nodeList[node.parent].x], [
                         node.y, self.nodeList[node.parent].y], "-g")

        for (ox, oy, size) in self.obstacles:
            plt.plot(ox, oy, "ok", ms=30 * size)

        plt.plot(self.start.x, self.start.y, "xr")
        plt.plot(self.end.x, self.end.y, "xr")
        plt.axis([-10, 10, -10, 10])
        plt.grid(True)
        plt.pause(0.01)

    def GetNearestListIndex(self, nodeList, rnd):
        dlist = [(node.x - rnd[0]) ** 2 + (node.y - rnd[1]) ** 2 for node in nodeList]
        minind = dlist.index(min(dlist))
        return minind

    def __CollisionCheck(self, node, obstacles):
        for (ox, oy, size) in obstacles:
            dx = ox - node.x
            dy = oy - node.y
            d = math.sqrt(dx * dx + dy * dy)
            if d <= size:
                return False  # Collision

        return True  # Safe


class Node():
    """
    RRT Node
    """
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.parent = None


# Variable to store robot's current position
current_position = [0, 0]  # Initial position of the robot

def topic2_callback(msg):
    """
    Callback function for receiving robot's position from /topic2
    This function updates the robot's position with data from Float32MultiArray.
    """
    global current_position

    # Assuming msg.data contains the position as [x, y]
    current_position = msg.data
    print(f"Received robot position: {current_position}")


def goal_pose_callback(msg):
    """
    Callback function for receiving goal pose via /goal_pose topic.
    """
    print(f"Received new goal position: ({msg.x}, {msg.y})")
    start_position = current_position[:2]  # Start position from current robot position
    rand_area = [-15, 15]  # Define the random sampling area for the planner
    
    # Load obstacles from file
    f = open("/home/ercan/catkin_ws/src/localization_ekf/obstacles.txt", "r")
    obstacles = []
    for i in range(8):    
        x = int(f.readline())
        y = int(f.readline())
        cap = int(f.readline())
        obstacles.append((int(x), int(y), int(cap)))
    f.close()

    # Plan the path using RRT
    rrt = RRT(start=start_position, goal=[msg.x, msg.y], randArea=rand_area, obstacles=obstacles)
    path = rrt.Planning(animation=show_animation)

    # Draw the final path
    if show_animation:
        rrt.DrawGraph()
        plt.plot([x for (x, y) in path], [y for (x, y) in path], '-r')
        plt.grid(True)
        plt.show()

    # Return the path
    follow_path(path, pub, rate)


def follow_path(path, pub, rate):
    """
    Function to follow the generated path using a simple control approach
    """
    # Robot speed and control parameters
    linear_speed = 0.5
    angular_speed = 1.0

    for i in range(1, len(path)):
        x1, y1 = path[i - 1]
        x2, y2 = path[i]

        # Calculate the distance and angle to the next waypoint
        distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
        angle = math.atan2(y2 - y1, x2 - x1)

        # Initialize the Twist message
        twist = Twist()

        while distance > 0.1:  # Continue moving until the robot reaches the waypoint
            # Calculate the angle difference
            angle_to_goal = math.atan2(y2 - current_position[1], x2 - current_position[0])
            angle_diff = angle_to_goal - current_position[2]

            # Normalize the angle difference to the range [-pi, pi]
            angle_diff = (angle_diff + math.pi) % (2 * math.pi) - math.pi

            # Adjust velocities based on distance and angle difference
            if abs(angle_diff) > 0.1:
                twist.linear.x = 0.0  # Stop moving forward if we need to rotate
                twist.angular.z = angular_speed * angle_diff  # Rotate towards the goal
            else:
                twist.linear.x = linear_speed  # Move forward
                twist.angular.z = 0.0  # Stop rotating

            pub.publish(twist)
            rate.sleep()

            # Update current position (for simulation purposes, assuming we update it here)
            current_position[0] += twist.linear.x * 0.1  # Update x based on linear speed
            current_position[1] += twist.linear.x * 0.1  # Update y based on linear speed
            distance = math.sqrt((x2 - current_position[0]) ** 2 + (y2 - current_position[1]) ** 2)

    twist.linear.x = 0
    twist.angular.z = 0
    pub.publish(twist)  # Stop the robot when finished


def main():
    # Initialize the ROS node
    rospy.init_node('motion_planning_node')

    # Create a publisher to send /cmd_vel messages
    pub = rospy.Publisher('/cmd_vel', Twist, queue_size=10)
    rate = rospy.Rate(10) # 10hz
    # Print waiting message before goal input
    print("Waiting for goal position input...")

    # Subscribe to the /goal_pose topic to get the goal position
    rospy.Subscriber('/goal_pose', Pose2D, goal_pose_callback)

    # Subscribe to the /topic2 topic to get the robot's current position
    rospy.Subscriber('/topic2', Float32MultiArray, topic2_callback)

    rospy.spin()


if __name__ == '__main__':
    main()

我认为问题是由代码的放置或顺序引起的,但我无法找到解决方案。 谢谢

python ros gazebo-simu
1个回答
0
投票

这种使用变量的方法不起作用,而且实际上会导致错误。如果您这样做,您的

pub
应该是文件顶部的全局变量。那么它不应该作为函数 arg 传递,而应该直接在以下函数中使用:

#!/usr/bin/env python3
import matplotlib.pyplot as plt
import random
import math
import copy
import rospy
import time
import numpy as np
from numpy import genfromtxt
from numpy import array
from sensor_msgs.msg import NavSatFix
from sensor_msgs.msg import Imu
from std_msgs.msg import String
from geometry_msgs.msg import Vector3Stamped
from geometry_msgs.msg import Twist
from geometry_msgs.msg import Pose2D
from nav_msgs.msg import Path
from geometry_msgs.msg import PoseStamped
from std_msgs.msg import Float32MultiArray

show_animation = True
pub = rospy.Publisher('/cmd_vel', Twist, queue_size=10)

class RRT():
    ....

另一个问题是这会导致运行时错误。因此,如果上述节点没有死亡,则意味着您还有另一个问题。您的

/goal_pose
主题未发布到,或者发布到该主题的消息与您当前的位置相同。

© www.soinside.com 2019 - 2024. All rights reserved.