【Carla + ROS2 control vehicle movement】

Carla + ROS2 control vehicle movement

Background

This simple tutorial for receive the commands via ROS2 Topic and self-defined message to control vehicle behavior. This framework can be used to your scenario. I will write the problem I met, hope it have some referenced meanings to you.
My scenario setting is that a vehicle radical move, for testing the braking algorithm to avoid collision .

environment:
ubuntu22.04
ROS2 humble
Carla0.9.15

Code snippets

1、configure ROS2
write self-defined msg to control vehicle and return vehicle status, simple example as follow:
YourPublishMsg.msg

std_msgs/Header header
float32 vehicle_speed

YourSubscriptionMsg.msg

std_msgs/Header header
bool brake
  1. main code
    Perhaps some dependence isn’t necessary, I cut it from my whole project, you can throw it, so I’m not sure this snippet can running without error. Your ROS2 work space should has two packages, one is the message, another is your realize program. Remember configure your CMakeLists.txt, package.xml or setup.py. If some wrong happen, a great possibility refer the environment configure.
import carla
import rclpy
import random
import math
import threading
from rclpy.time import Time  
from std_msgs.msg import Header

from rclpy.executors import MultiThreadedExecutor   
from YourPackageName.msg import YourSubscriptionMsg,YourPublishMsg
from rclpy.node import Node

class CarlaControl(Node):
    def __init__(self):
        super().__init__('NodeName')
        self.clock = self.get_clock() 
        self.publisher_speed = self.create_publisher(YourPublishMsg, "TopicName", 10)
        self.subscription = self.create_subscription(YourSubscriptionMsg,"TopicName",self.subscription_callback,10)  
        self.subscription  # prevent unused variable warning
		# you can choose one of the method of control
        self.ego_control = carla.VehicleControl()
        self.ego_ackermann_control = carla.VehicleAckermannControl()
        self.ego_ackermann_control.speed = 2.77777 # the unit of measurement is m/s
        self.ego_ackermann_control.acceleration = 6.0 # m/s^2 
        self.is_autopilot = True

    def simulation(self):
        client = carla.Client('localhost', 2000)
        client.set_timeout(2.0)
        traffic_manager = client.get_trafficmanager()
        world = client.load_world("Town02") # I am used to testing with small map
        try:
            original_settings = world.get_settings()
            settings = world.get_settings()
			# Synchronous mode + fixed time-step.
            traffic_manager.set_synchronous_mode(True)
            settings.fixed_delta_seconds = delta # every simulated second including 1/fixed time-step frame
            settings.synchronous_mode = True
            world.apply_settings(settings)

            blueprint_library = world.get_blueprint_library()
 			vehicle_bp = blueprint_library.find('vehicle.tesla.model3') 
            ego_vehicle_transform = random.choice(world.get_map().get_spawn_points())
            ego_vehicle = world.spawn_actor(vehicle_bp, ego_vehicle_transform)
            actor_list.append(ego_vehicle)
            
            traffic_manager.ignore_vehicles_percentage(ego_vehicle, 100) # ignore the vehicle collision , second parameter is percentage
            traffic_manager.ignore_lights_percentage(ego_vehicle, 100) # ignore the traffic lights
            traffic_manager.set_desired_speed(ego_vehicle,18) # the unit of measurement is km/h
            
            while True:
                world.tick() 
                ego_vehicle.set_autopilot(self.is_autopilot)

				# if receive the brake message, colse the autopilot, use normal control or ackermancontrol to stop vehicle running. 
                if self.is_autopilot == False: 
                    # ego_vehicle.apply_control(self.ego_control)
                    ego_vehicle.apply_ackermann_control(self.ego_ackermann_control)

                # publish and print the speed 
                ret_speed = self.publish_and_display_speed(ego_vehicle)
                
                spectator = world.get_spectator()
                transform = ego_vehicle.get_transform()
                spectator_transform = carla.Transform(transform.location + carla.Location(z=30), carla.Rotation(pitch=-90, yaw=270, roll=0.0))
                spectator.set_transform(spectator_transform)
        finally:
            world.apply_settings(original_settings)
            traffic_manager.set_synchronous_mode(False)
            for actor in actor_list:
                actor.destroy()

    def subscription_callback(self, control):  

        self.get_logger().info(f'I heard: {control.braking}') 
        if control.braking == True: 
            self.is_autopilot = False # Close the autopilot model
            # self.ego_control.throttle = 0.0
            # self.ego_control.brake = 1.0    
            # target speed is 0 with the -6 acceleration.
            self.ego_ackermann_control.speed = 0.0
            self.ego_ackermann_control.acceleration = -6.0
        else:
            self.is_autopilot = True

    def publish_and_display_speed(self,vehicle):
        v = vehicle.get_velocity() #carla.Vector3D - m/s
        speed_kmh = 3.6 * math.sqrt(v.x**2 + v.y**2 + v.z**2) # km/h
        # create your feedback message,intializw the items.
        vehicle_status =  YourPublishMsg()
        vehicle_status.header = Header(stamp=self.clock.now().to_msg(), frame_id=" ")
        vehicle_status.vehicle_speed = speed_kmh  
        self.publisher_speed.publish(vehicle_status)
        self.get_logger().info(f'vehicle Speed:   {speed_kmh:15.0f} km/h')
        return speed_kmh

    def destroy_node(self):
        super().destroy_node()
    
    def spin(self):
        rclpy.spin(self, self.executor)

def main(args=None):
    rclpy.init(args=args)
    node = CarlaControl()
    try:
        # Create a multiple thread excutor for run simulation thread. 
        executor = MultiThreadedExecutor()  
        executor.add_node(node)
        spin_thread = threading.Thread(target=node.spin)
        spin_thread.start()
        node.simulation()

    except KeyboardInterrupt:
        pass
    finally:
        node.destroy_node()
        rclpy.shutdown()
        spin_thread.join()

Issue recording

1、When I use ros2 topic echo XX to check my topic publish, I found out it hint "The message type ‘XXX’ is invalid. for solve it, source install/setup.bash in you ROS2 work space path

2、Assign the time-stamp wrong:

vehicle_status.header.stamp = self.clock.now() File
“/opt/ros/humble/local/lib/python3.10/dist-packages/std_msgs/msg/_header.py”,
line 133, in stamp
assert \ AssertionError: The ‘stamp’ field must be a sub message of type ‘Time’

answer: https://robotics.stackexchange.com/questions/96084/timestamp-message-ros2-python.
self.clock.now().to_msg() to solve it.

3、I found out the program can’t enter the subscription callback, check the program structure, my original main function like this,

  rclpy.init(args=args)
  node = CarlaControl()
  try:
      rclpy.spin(node)
  except KeyboardInterrupt:
      pass
  finally:
      node.destroy_node()
      rclpy.shutdown()

I guess it’s because the spin() didn’t run, I found a article prove my assumption.

subscribe一个topic之后,并不会直接进入callback函数, 而是往下执行,直到遇见了ros::spin()。这也就是说,
ros::spin()后面的内容不会执行,除非ros::ok() return
false(用户按下ctrl+c,或者调用了ros::shutdown()函数)。还有就是,如果程序中没有ros::spin(),
那么就永远不会进入callback函数了。

from https://www.cnblogs.com/chrislzy/p/14933825.html

So, I use while loop to make my simulation work, simulation() as a class function in the Node class. then node = CarlaControl() make the node work. hence, the rclpy.spin(node) never run -> didn’t enter subscription function.
Solution:
use multiple thread to run simulation. I get this idea from the calra-ros-bridge example. If you want to know more, provide this program pathcarla-ros-bridge/src/ros-bridge/carla_manual_control/src/carla_manual_control/carla_manual_control.py

在这里插入图片描述
And the ROS2 executors tutorials as follow:
https://docs.ros.org/en/humble/Concepts/Intermediate/About-Executors.html

I mention the calra-ros-bridge, but why I didn’t use it.
First of all, the real-time capability is very important, the interface provide by the calra-ros-bridge went through more packaged, I thought the running speed will slower then the original ros interface.
Second, this function is simple, no need to research how to use calra-ros-bridge 😃.
And I’m not sure, but when I building the calra-ros-bridge, it remind me the version is not correct, seems it just support under the Carla 0.9.13 version.

Thank you for your attention. bye.
原创请勿转载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值