Add camera spawning functionality and update world configuration

This commit is contained in:
Даниил Грабарь
2026-04-13 17:37:24 +03:00
parent 2dfa8f1c94
commit cd450a3476
7 changed files with 118 additions and 32 deletions
+34
View File
@@ -125,6 +125,40 @@ def _runtime_setup(context, *args, **kwargs):
"rotation": str(settings.digital_twin.webots.rotation), "rotation": str(settings.digital_twin.webots.rotation),
"controller_timer": str(settings.digital_twin.webots.controller_timer), "controller_timer": str(settings.digital_twin.webots.controller_timer),
} }
# TODO пример работы, необходимо правильно интегрировать в структуру проекта и удалить из-за избыточности
# example_camera_urdf = """<?xml version="1.0"?>
# <robot name="example_camera_robot">
# <link name="example_camera_link"/>
# <webots>
# <device reference="example_camera" type="Camera">
# <ros>
# <topicName>/example_camera/image_raw</topicName>
# <updateRate>30</updateRate>
# <alwaysOn>True</alwaysOn>
# <frameName>example_camera_link</frameName>
# </ros>
# </device>
# </webots>
# </robot>
# """
# from webots_ros2_driver.webots_controller import WebotsController
# example_camera_driver = WebotsController(
# robot_name="example_camera_robot",
# parameters=[
# {
# "robot_description": example_camera_urdf,
# "use_sim_time": True,
# "set_robot_state_publisher": False,
# }
# ],
# respawn=True,
# )
# setup += [example_camera_driver]
else: else:
controller_args = { controller_args = {
"robot_name": settings.robot.name, "robot_name": settings.robot.name,
@@ -0,0 +1,4 @@
# Пример использования параметров камеры
name: D455_TOP
translation: "-0.25 0 0.79"
rotation: "0 0 1 0"
@@ -1,29 +0,0 @@
# Формат каждой записи:
# ros_topic_name: имя топика в ROS2
# gz_topic_name: имя топика в Gazebo (можно опустить если совпадает)
# ros_type_name: тип сообщения ROS2
# gz_type_name: тип сообщения Gazebo
# direction: GZ_TO_ROS / ROS_TO_GZ / BIDIRECTIONAL
- ros_topic_name: /clock
gz_topic_name: /clock
ros_type_name: rosgraph_msgs/msg/Clock
gz_type_name: gz.msgs.Clock
direction: GZ_TO_ROS
lazy: false
# Состояния джойнтов из Gazebo в ROS2
- ros_topic_name: /joint_states
gz_topic_name: /world/empty/model/iiwa7/joint_state
ros_type_name: sensor_msgs/msg/JointState
gz_type_name: gz.msgs.Model
direction: GZ_TO_ROS
lazy: false
# TF из Gazebo в ROS2 (поза модели в мире)
- ros_topic_name: /tf
gz_topic_name: /model/iiwa7/pose
ros_type_name: tf2_msgs/msg/TFMessage
gz_type_name: gz.msgs.Pose_V
direction: GZ_TO_ROS
lazy: false
+2 -1
View File
@@ -8,7 +8,8 @@ robot:
digital_twin: digital_twin:
webots: webots:
world: pkg://iiwa_description/worlds/iiwa.wbt # world: pkg://iiwa_description/worlds/iiwa.wbt
world: pkg://iiwa_description/worlds/simple_world.wbt
transform: "-0.25 0 0.79" transform: "-0.25 0 0.79"
rotation: "0 0 1 0" rotation: "0 0 1 0"
controller_timer: "50" controller_timer: "50"
@@ -32,6 +32,15 @@
</ros> </ros>
</device> </device>
<device reference="example_camera" type="Camera">
<ros>
<topicName>/camera_example/color</topicName>
<updateRate>30</updateRate>
<alwaysOn>True</alwaysOn>
<frameName>example_camera</frameName>
</ros>
</device>
<device reference="camera_depth" type="RangeFinder"> <device reference="camera_depth" type="RangeFinder">
<ros> <ros>
<topicName>/camera/depth</topicName> <topicName>/camera/depth</topicName>
+13 -2
View File
@@ -7,8 +7,8 @@ EXTERNPROTO "https://raw.githubusercontent.com/cyberbotics/webots/R2025a/project
WorldInfo { WorldInfo {
} }
Viewpoint { Viewpoint {
orientation -0.20135401485081894 0.14705590432610455 0.9684168119700772 1.9104172436184537 orientation -0.28913430413481667 0.20676337530925004 0.9346926023047372 1.96317584288795
position 2.126114183750861 -6.172386590547907 2.2530769187603243 position 2.0700764329273156 -5.621201880809646 3.39425616182994
} }
TexturedBackground { TexturedBackground {
} }
@@ -17,3 +17,14 @@ TexturedBackgroundLight {
RectangleArena { RectangleArena {
floorSize 5 5 floorSize 5 5
} }
Robot {
translation -1.26 0 0.77
children [
Camera {
name "example_camera"
}
]
name "example_camera_robot"
controller "<extern>"
}
@@ -0,0 +1,56 @@
from dataclasses import dataclass
import rclpy
from rclpy.node import Node
from rclpy.task import Future
from webots_ros2_msgs.srv import SpawnNodeFromString
from rclpy.executors import ExternalShutdownException
@dataclass(frozen=True)
class CameraSpawnParams:
camera_name: str
translation: str
rotation: str
class CameraSpawner(Node):
def __init__(self, camera_params: CameraSpawnParams):
super().__init__("camera_spawner")
self._camera_params = camera_params
self._urdf_template = self._generate_camera_urdf()
self._proto_template = self._generate_camera_proto()
# self.cli = self.create_client(
# SpawnNodeFromString, "/Ros2Supervisor/spawn_node_from_string"
# )
# while not self.cli.wait_for_service(timeout_sec=10):
# self.get_logger().warning(
# "service /Ros2Supervisor/spawn_node_from_string not available, waiting again..."
# )
# data = 'Camera { name "camera" translation 0 0 1.5 rotation 1 0 0 -1.5708 }'
# req = SpawnNodeFromString.Request(data=data, check_fields=True)
# self.get_logger().info(f"Calling spawn service for camera")
# future = self.cli.call_async(req)
# future.add_done_callback(self._response_callback)
# def _response_callback(self, future: Future):
# try:
# response = future.result()
# self.get_logger().info("Camera spawned successfully")
# except Exception as e:
# self.get_logger().error(f"Service call failed: {e}")
def _generate_camera_proto(self) -> str:
...
def _generate_camera_urdf(self) -> str:
...