Isaac Sim + ROS2联合仿真
学习如何将Isaac Sim与ROS2深度集成,实现传感器数据发布、控制指令订阅和多节点协同仿真。
Isaac Sim ROS2 联合仿真 传感器 控制
Isaac Sim + ROS2联合仿真
Isaac Sim与ROS2的深度集成是其核心优势之一。本文讲解如何搭建联合仿真环境,实现传感器数据发布和控制指令订阅。
配置ROS2桥接
from isaacsim.core import World
from isaacsim.ros2 import ROS2Bridge
world = World()
# 初始化ROS2桥接
ros_bridge = ROS2Bridge(
world=world,
node_name="isaac_sim_ros2"
)
# 启动桥接
ros_bridge.start()
发布传感器数据
相机图像发布
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import rclpy
class CameraPublisher:
def __init__(self, ros_bridge, camera):
self.camera = camera
self.bridge = CvBridge()
# 创建发布者
self.publisher = ros_bridge.create_publisher(
Image, "/camera/color/image_raw", 10
)
# 创建深度图发布者
self.depth_publisher = ros_bridge.create_publisher(
Image, "/camera/depth/image_rect", 10
)
def publish(self):
"""发布相机数据"""
# RGB图像
rgb = self.camera.get_rgb()
rgb_msg = self.bridge.cv2_to_imgmsg(rgb, encoding="rgb8")
self.publisher.publish(rgb_msg)
# 深度图
depth = self.camera.get_depth()
depth_msg = self.bridge.cv2_to_imgmsg(depth, encoding="32FC1")
self.depth_publisher.publish(depth_msg)
# 使用
camera_pub = CameraPublisher(ros_bridge, camera)
while simulation_app.is_running():
world.step(render=True)
camera_pub.publish()
激光雷达发布
from sensor_msgs.msg import LaserScan, PointCloud2
class LidarPublisher:
def __init__(self, ros_bridge, lidar):
self.lidar = lidar
self.scan_pub = ros_bridge.create_publisher(
LaserScan, "/scan", 10
)
self.cloud_pub = ros_bridge.create_publisher(
PointCloud2, "/point_cloud", 10
)
def publish(self):
# 获取点云
points = self.lidar.get_point_cloud()
# 转换为LaserScan(2D切片)
scan_msg = self._points_to_laserscan(points)
self.scan_pub.publish(scan_msg)
# 发布完整点云
cloud_msg = self._points_to_pointcloud2(points)
self.cloud_pub.publish(cloud_msg)
def _points_to_laserscan(self, points):
"""将3D点云转换为2D激光扫描"""
msg = LaserScan()
msg.header.frame_id = "lidar_frame"
# 提取Z=0附近的点
z_mask = np.abs(points[:, 2]) < 0.1
points_2d = points[z_mask, :2]
# 转换为极坐标
ranges = np.linalg.norm(points_2d, axis=1)
angles = np.arctan2(points_2d[:, 1], points_2d[:, 0])
# 排序
sorted_indices = np.argsort(angles)
msg.ranges = ranges[sorted_indices].tolist()
msg.angle_min = float(angles[sorted_indices[0]])
msg.angle_max = float(angles[sorted_indices[-1]])
msg.angle_increment = float(np.mean(np.diff(angles[sorted_indices])))
return msg
订阅控制指令
from geometry_msgs.msg import Twist
from std_msgs.msg import Float64MultiArray
class ControlSubscriber:
def __init__(self, ros_bridge, robot):
self.robot = robot
# 订阅速度指令(差速驱动)
self.cmd_sub = ros_bridge.create_subscription(
Twist, "/cmd_vel", self.cmd_vel_callback, 10
)
# 订阅关节指令(机械臂)
self.joint_sub = ros_bridge.create_subscription(
Float64MultiArray, "/joint_commands",
self.joint_callback, 10
)
def cmd_vel_callback(self, msg):
"""处理速度指令"""
linear_vel = msg.linear.x
angular_vel = msg.angular.z
# 转换为轮子速度
left_wheel_vel = linear_vel - angular_vel * 0.1
right_wheel_vel = linear_vel + angular_vel * 0.1
self.robot.set_wheel_velocities(left_wheel_vel, right_wheel_vel)
def joint_callback(self, msg):
"""处理关节指令"""
joint_positions = np.array(msg.data)
self.robot.set_joint_positions(joint_positions)
# 使用
control_sub = ControlSubscriber(ros_bridge, robot)
完整的联合仿真示例
def main():
# 初始化
world = World()
setup_scene(world)
# 初始化ROS2
rclpy.init()
ros_bridge = ROS2Bridge(world, "isaac_sim_node")
ros_bridge.start()
# 创建发布者和订阅者
camera_pub = CameraPublisher(ros_bridge, camera)
lidar_pub = LidarPublisher(ros_bridge, lidar)
control_sub = ControlSubscriber(ros_bridge, robot)
# 仿真循环
while simulation_app.is_running():
world.step(render=True)
# 发布传感器数据
camera_pub.publish()
lidar_pub.publish()
# 处理ROS回调
rclpy.spin_once(ros_bridge.node, timeout_sec=0)
# 清理
ros_bridge.stop()
rclpy.shutdown()
simulation_app.close()
if __name__ == "__main__":
main()
在另一个终端运行ROS2节点
# 启动ROS2导航节点
ros2 launch nav2_bringup navigation_launch.py
# 查看话题
ros2 topic list
# 发布速度指令
ros2 topic pub /cmd_vel geometry_msgs/Twist \
"{linear: {x: 0.5}, angular: {z: 0.0}}"
FAQ
Isaac Sim和ROS2版本如何匹配?
Isaac Sim 4.2支持ROS2 Humble。确保使用匹配的ROS2版本。
传感器数据发布频率低怎么办?
增加仿真步长或减少渲染分辨率。也可以在单独的线程中发布传感器数据。
如何调试ROS2话题?
使用ros2 topic echo /topic_name查看数据,或用RViz2可视化。