diff --git a/gazebo_ctrl.py b/gazebo_ctrl.py
new file mode 100644
index 0000000..a7ea00b
--- /dev/null
+++ b/gazebo_ctrl.py
@@ -0,0 +1,169 @@
+import rospy
+from gazebo_msgs.srv import (GetLinkProperties, GetModelProperties,
+ GetModelPropertiesResponse, GetModelState,
+ GetModelStateResponse, GetWorldProperties)
+from std_srvs.srv import Empty
+
+
+class GazeboROSController:
+ def __init__(self):
+ rospy.init_node('gazebo_ros_controller', anonymous=True)
+ self.model_info = None
+
+ def get_model_names(self) -> list:
+ rospy.wait_for_service('/gazebo/get_world_properties')
+ try:
+ get_world_properties = rospy.ServiceProxy(
+ '/gazebo/get_world_properties', GetWorldProperties)
+ world_properties = get_world_properties()
+ return world_properties.model_names
+ except rospy.ServiceException as e:
+ rospy.logerr(f"Service call failed: {e}")
+ return []
+
+ def get_model_state(self, model_names: list = None) -> dict:
+ """
+ 获取模型的状态。
+ 如果model_names为空,返回所有模型的状态,否则返回指定模型的状态。
+ """
+ if not model_names or len(model_names) == 0:
+ model_names = self.get_model_names()
+ print(f"Getting state for models: {model_names}")
+ model_states = {}
+ for name in model_names:
+ rospy.wait_for_service('/gazebo/get_model_state')
+ try:
+ get_model_state = rospy.ServiceProxy(
+ '/gazebo/get_model_state', GetModelState)
+ state = get_model_state(name, '')
+ model_states[name] = state
+ except rospy.ServiceException as e:
+ rospy.logerr(f"Service call failed for model {name}: {e}")
+ model_states[name] = None
+ return model_states
+
+ def get_model_properties(self, model_names: list = None) -> dict:
+ """
+ 获取模型的属性。
+ 如果model_names为空,返回所有模型的属性,否则返回指定模型的属性。
+ """
+ if not model_names or len(model_names) == 0:
+ model_names = self.get_model_names()
+ print(f"Getting properties for models: {model_names}")
+ model_properties = {}
+ for name in model_names:
+ rospy.wait_for_service('/gazebo/get_model_properties')
+ try:
+ get_model_properties = rospy.ServiceProxy(
+ '/gazebo/get_model_properties', GetModelProperties)
+ properties = get_model_properties(name)
+ model_properties[name] = properties
+ except rospy.ServiceException as e:
+ rospy.logerr(f"Service call failed for model {name}: {e}")
+ model_properties[name] = None
+ return model_properties
+
+ def get_link_properties(self, link_full_name: str) -> dict:
+ """
+ 获取指定链接的属性。
+ """
+ rospy.wait_for_service('/gazebo/get_link_properties')
+ try:
+ get_link_properties = rospy.ServiceProxy(
+ '/gazebo/get_link_properties', GetLinkProperties)
+ properties = get_link_properties(link_full_name)
+ return properties
+ except rospy.ServiceException as e:
+ rospy.logerr(f"Service call failed for link {link_full_name}: {e}")
+ return None
+
+ def format_model_state(self, state: GetModelStateResponse) -> dict:
+ return {
+ 'pose': {
+ 'position': {
+ 'x': state.pose.position.x,
+ 'y': state.pose.position.y,
+ 'z': state.pose.position.z
+ },
+ 'orientation': {
+ 'x': state.pose.orientation.x,
+ 'y': state.pose.orientation.y,
+ 'z': state.pose.orientation.z,
+ 'w': state.pose.orientation.w
+ }
+ },
+ 'twist': {
+ 'linear': {
+ 'x': state.twist.linear.x,
+ 'y': state.twist.linear.y,
+ 'z': state.twist.linear.z
+ },
+ 'angular': {
+ 'x': state.twist.angular.x,
+ 'y': state.twist.angular.y,
+ 'z': state.twist.angular.z
+ }
+ }}
+
+ def format_model_properties(self, properties: GetModelPropertiesResponse) -> dict:
+ return {
+ 'parent_model_name': properties.parent_model_name,
+ 'canonical_body_name': properties.canonical_body_name,
+ 'body_names': properties.body_names,
+ 'geom_names': properties.geom_names,
+ 'joint_names': properties.joint_names,
+ 'child_model_names': properties.child_model_names,
+ 'is_static': properties.is_static
+ }
+
+ def format_model_info(self, model_name: str, state: GetModelStateResponse, properties: GetModelPropertiesResponse) -> dict:
+ return {
+ 'name': model_name,
+ 'state': self.format_model_state(state),
+ 'properties': self.format_model_properties(properties)
+ }
+
+ def get_model_info_f(self, model_names: list = None) -> list:
+ """
+ 获取模型的详细信息,包括状态和属性。
+ 如果model_names为空,返回所有模型的信息,否则返回指定模型的信息。
+ 返回值已经格式化为list-dict形式。
+ """
+ if not model_names or len(model_names) == 0:
+ model_names = self.get_model_names()
+ print(f"Getting info for models: {model_names}")
+ model_info = []
+ states = self.get_model_state(model_names)
+ properties = self.get_model_properties(model_names)
+ for name in model_names:
+ m_state = states[name]
+ m_properties = properties[name]
+ info = self.format_model_info(name, m_state, m_properties)
+ model_info.append(info)
+ return model_info
+
+ def get_model_state_f(self, model_names: list = None) -> list:
+ """
+ 获取模型的状态。
+ 如果model_names为空,返回所有模型的信息,否则返回指定模型的信息。
+ 返回值已经格式化为list-dict形式。
+ """
+ if not model_names or len(model_names) == 0:
+ model_names = self.get_model_names()
+ print(f"Getting info for models: {model_names}")
+ model_info = []
+ states = self.get_model_state(model_names)
+ for name in model_names:
+ m_state = states[name]
+ info = self.format_model_state(m_state)
+ info['name'] = name
+ # 获取箱子质量
+ if name == 'block':
+ info['mass'] = self.get_block_mass()
+ model_info.append(info)
+ return model_info
+
+if __name__ == '__main__':
+ controller = GazeboROSController()
+ import json
+ print(json.dumps(controller.get_model_state_f(['block'])))
diff --git a/http_server.py b/http_server.py
new file mode 100644
index 0000000..4dfb597
--- /dev/null
+++ b/http_server.py
@@ -0,0 +1,73 @@
+import dataclasses
+import socket
+
+import flask
+import werkzeug.serving
+
+
+@dataclasses.dataclass
+class HttpHost():
+ """
+ HTTP主机信息
+ """
+ hostname: str
+ port: int
+
+ def __post_init__(self):
+ if not self.hostname:
+ raise ValueError("Hostname cannot be empty")
+ if not (0 <= self.port <= 65535):
+ raise ValueError(f"Invalid port: {self.port}")
+
+class HttpRPCServer():
+ """
+ 来自ability-sdk-python的http服务器。
+ HTTP RPC服务端实现。
+ 使用add_route方法添加路由,重写类以实现自定义功能。
+ """
+
+ def __init__(self):
+ self._server = None
+ self._app = flask.Flask(__name__)
+
+ def add_route(self, uri: str, handler, methods: list):
+ """
+ 添加HTTP路由,handler应符合Flask视图函数的规范。
+ """
+ if not callable(handler):
+ raise ValueError("Handler must be a callable function")
+ self._app.add_url_rule(uri, view_func=handler, methods=methods)
+
+ def start(self, hostname: str = "0.0.0.0", port: int = None):
+ """
+ 启动并以阻塞方式提供服务。
+ """
+ if self._server:
+ raise RuntimeError("Server is already running")
+ self.host = HttpHost(
+ hostname=hostname, port=port if port else self.find_free_port())
+ self._server = werkzeug.serving.make_server(
+ self.host.hostname, self.host.port, self._app, threaded=True)
+ self._server.serve_forever()
+
+ def stop(self):
+ """
+ 停止服务。
+ """
+ if self._server:
+ self._server.shutdown()
+ self._server.server_close()
+ self._server = None
+
+ def find_free_port(self):
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
+ s.bind(("127.0.0.1", 0))
+ return s.getsockname()[1]
+
+class GazeboSimHttpServer(HttpRPCServer):
+ """
+ Gazebo仿真环境的HTTP服务器。
+ """
+
+ def __init__(self):
+ super().__init__()
\ No newline at end of file
diff --git a/main.py b/main.py
new file mode 100755
index 0000000..d4e2e28
--- /dev/null
+++ b/main.py
@@ -0,0 +1,63 @@
+import math
+import os
+import subprocess
+import tempfile
+
+import rospy
+from gazebo_msgs.srv import SpawnModel
+from geometry_msgs.msg import Point, Pose, Quaternion
+from tf.transformations import quaternion_from_euler
+
+
+class GazeboWorldManager:
+ def __init__(self):
+ rospy.init_node('gazebo_world_manager')
+ self.spawn_service = rospy.ServiceProxy(
+ '/gazebo/spawn_urdf_model', SpawnModel)
+
+ def spawn_apriltag_marker(self, model_name, tag_id, x=0, y=0, z=1):
+ """生成 AprilTag 标记模型"""
+
+ xacro_file = "/home/leju/gazebo_world_manager/scene/grasp-box/models/fixed_tag.xacro"
+
+ try:
+ # 添加包路径到 ROS_PACKAGE_PATH
+ ros_package_path = os.environ.get('ROS_PACKAGE_PATH', '')
+ custom_path = '/home/leju/gazebo_world_manager'
+ if custom_path not in ros_package_path.split(':'):
+ os.environ['ROS_PACKAGE_PATH'] = f"{custom_path}:{ros_package_path}" if ros_package_path else custom_path
+
+ # 转换为 URDF
+ urdf_content = subprocess.check_output([
+ 'rosrun', 'xacro', 'xacro', xacro_file, f'tag_id:={tag_id}'
+ ]).decode('utf-8')
+
+ # 设置位姿
+ pose = Pose(
+ position=Point(x=x, y=y, z=z),
+ orientation=Quaternion(*quaternion_from_euler(0, 0, 0))
+ )
+
+ # 生成模型
+ rospy.wait_for_service('/gazebo/spawn_urdf_model')
+ response = self.spawn_service(
+ model_name=model_name,
+ model_xml=urdf_content,
+ robot_namespace='',
+ initial_pose=pose,
+ reference_frame='world'
+ )
+
+ if response.success:
+ rospy.loginfo(f"Successfully spawned {model_name}")
+ else:
+ rospy.logerr(
+ f"Failed to spawn {model_name}: {response.status_message}")
+ except subprocess.CalledProcessError as e:
+ rospy.logerr(f"Failed to convert xacro to urdf: {e}")
+
+
+if __name__ == '__main__':
+ manager = GazeboWorldManager()
+ manager.spawn_apriltag_marker('mk', 0, 1, 1, 1.4)
+ # rospy.spin()
diff --git a/package.xml b/package.xml
new file mode 100644
index 0000000..39909fa
--- /dev/null
+++ b/package.xml
@@ -0,0 +1,14 @@
+
+
+ gazebo_world_manager
+ 0.0.0
+ The gazebo_world_manager package
+
+ user
+ TODO
+
+ catkin
+ rospy
+ gazebo_msgs
+ geometry_msgs
+
\ No newline at end of file
diff --git a/scene/grasp-box/launch.sh b/scene/grasp-box/launch.sh
new file mode 100755
index 0000000..84ccfa4
--- /dev/null
+++ b/scene/grasp-box/launch.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+# 启动仿真程序
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/materials/apriltag_0.material b/scene/grasp-box/models/apriltag/materials/apriltag_0.material
new file mode 100644
index 0000000..774adef
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/materials/apriltag_0.material
@@ -0,0 +1,18 @@
+material AprilTag/Marker0
+{
+ technique
+ {
+ pass
+ {
+ ambient 1.0 1.0 1.0 1.0
+ diffuse 1.0 1.0 1.0 1.0
+ specular 0.0 0.0 0.0 1.0
+ texture_unit
+ {
+ texture textures/tag36h11-0.png
+ filtering trilinear
+ scale 1.0 1.0
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/materials/apriltag_1.material b/scene/grasp-box/models/apriltag/materials/apriltag_1.material
new file mode 100644
index 0000000..af11b15
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/materials/apriltag_1.material
@@ -0,0 +1,18 @@
+material AprilTag/Marker1
+{
+ technique
+ {
+ pass
+ {
+ ambient 1.0 1.0 1.0 1.0
+ diffuse 1.0 1.0 1.0 1.0
+ specular 0.0 0.0 0.0 1.0
+ texture_unit
+ {
+ texture textures/tag36h11-1.png
+ filtering trilinear
+ scale 1.0 1.0
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/materials/apriltag_2.material b/scene/grasp-box/models/apriltag/materials/apriltag_2.material
new file mode 100644
index 0000000..7a3d440
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/materials/apriltag_2.material
@@ -0,0 +1,18 @@
+material AprilTag/Marker2
+{
+ technique
+ {
+ pass
+ {
+ ambient 1.0 1.0 1.0 1.0
+ diffuse 1.0 1.0 1.0 1.0
+ specular 0.0 0.0 0.0 1.0
+ texture_unit
+ {
+ texture textures/tag36h11-2.png
+ filtering trilinear
+ scale 1.0 1.0
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/materials/apriltag_3.material b/scene/grasp-box/models/apriltag/materials/apriltag_3.material
new file mode 100644
index 0000000..2a95322
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/materials/apriltag_3.material
@@ -0,0 +1,18 @@
+material AprilTag/Marker3
+{
+ technique
+ {
+ pass
+ {
+ ambient 1.0 1.0 1.0 1.0
+ diffuse 1.0 1.0 1.0 1.0
+ specular 0.0 0.0 0.0 1.0
+ texture_unit
+ {
+ texture textures/tag36h11-3.png
+ filtering trilinear
+ scale 1.0 1.0
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/materials/apriltag_4.material b/scene/grasp-box/models/apriltag/materials/apriltag_4.material
new file mode 100644
index 0000000..8681bff
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/materials/apriltag_4.material
@@ -0,0 +1,18 @@
+material AprilTag/Marker4
+{
+ technique
+ {
+ pass
+ {
+ ambient 1.0 1.0 1.0 1.0
+ diffuse 1.0 1.0 1.0 1.0
+ specular 0.0 0.0 0.0 1.0
+ texture_unit
+ {
+ texture textures/tag36h11-4.png
+ filtering trilinear
+ scale 1.0 1.0
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/materials/apriltag_5.material b/scene/grasp-box/models/apriltag/materials/apriltag_5.material
new file mode 100644
index 0000000..63a6971
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/materials/apriltag_5.material
@@ -0,0 +1,18 @@
+material AprilTag/Marker5
+{
+ technique
+ {
+ pass
+ {
+ ambient 1.0 1.0 1.0 1.0
+ diffuse 1.0 1.0 1.0 1.0
+ specular 0.0 0.0 0.0 1.0
+ texture_unit
+ {
+ texture textures/tag36h11-5.png
+ filtering trilinear
+ scale 1.0 1.0
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/materials/apriltag_6.material b/scene/grasp-box/models/apriltag/materials/apriltag_6.material
new file mode 100644
index 0000000..9e6d0c0
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/materials/apriltag_6.material
@@ -0,0 +1,18 @@
+material AprilTag/Marker6
+{
+ technique
+ {
+ pass
+ {
+ ambient 1.0 1.0 1.0 1.0
+ diffuse 1.0 1.0 1.0 1.0
+ specular 0.0 0.0 0.0 1.0
+ texture_unit
+ {
+ texture textures/tag36h11-6.png
+ filtering trilinear
+ scale 1.0 1.0
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/materials/apriltag_7.material b/scene/grasp-box/models/apriltag/materials/apriltag_7.material
new file mode 100644
index 0000000..7d8d608
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/materials/apriltag_7.material
@@ -0,0 +1,18 @@
+material AprilTag/Marker7
+{
+ technique
+ {
+ pass
+ {
+ ambient 1.0 1.0 1.0 1.0
+ diffuse 1.0 1.0 1.0 1.0
+ specular 0.0 0.0 0.0 1.0
+ texture_unit
+ {
+ texture textures/tag36h11-7.png
+ filtering trilinear
+ scale 1.0 1.0
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/materials/apriltag_8.material b/scene/grasp-box/models/apriltag/materials/apriltag_8.material
new file mode 100644
index 0000000..ffdd672
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/materials/apriltag_8.material
@@ -0,0 +1,18 @@
+material AprilTag/Marker8
+{
+ technique
+ {
+ pass
+ {
+ ambient 1.0 1.0 1.0 1.0
+ diffuse 1.0 1.0 1.0 1.0
+ specular 0.0 0.0 0.0 1.0
+ texture_unit
+ {
+ texture textures/tag36h11-8.png
+ filtering trilinear
+ scale 1.0 1.0
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/materials/apriltag_9.material b/scene/grasp-box/models/apriltag/materials/apriltag_9.material
new file mode 100644
index 0000000..461404c
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/materials/apriltag_9.material
@@ -0,0 +1,18 @@
+material AprilTag/Marker9
+{
+ technique
+ {
+ pass
+ {
+ ambient 1.0 1.0 1.0 1.0
+ diffuse 1.0 1.0 1.0 1.0
+ specular 0.0 0.0 0.0 1.0
+ texture_unit
+ {
+ texture textures/tag36h11-9.png
+ filtering trilinear
+ scale 1.0 1.0
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/materials/textures/april_36h11-0.png b/scene/grasp-box/models/apriltag/materials/textures/april_36h11-0.png
new file mode 100644
index 0000000..5aa3965
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/april_36h11-0.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/april_36h11-1.png b/scene/grasp-box/models/apriltag/materials/textures/april_36h11-1.png
new file mode 100644
index 0000000..adbbb84
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/april_36h11-1.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/april_36h11-2.png b/scene/grasp-box/models/apriltag/materials/textures/april_36h11-2.png
new file mode 100644
index 0000000..aaa5f0e
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/april_36h11-2.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/april_36h11-3.png b/scene/grasp-box/models/apriltag/materials/textures/april_36h11-3.png
new file mode 100644
index 0000000..aed9f95
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/april_36h11-3.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/april_36h11-4.png b/scene/grasp-box/models/apriltag/materials/textures/april_36h11-4.png
new file mode 100644
index 0000000..559447d
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/april_36h11-4.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/tag36h11-0.png b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-0.png
new file mode 100644
index 0000000..01d4fca
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-0.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/tag36h11-1.png b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-1.png
new file mode 100644
index 0000000..51962f3
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-1.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/tag36h11-2.png b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-2.png
new file mode 100644
index 0000000..59ef498
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-2.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/tag36h11-3.png b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-3.png
new file mode 100644
index 0000000..5be8b45
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-3.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/tag36h11-4.png b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-4.png
new file mode 100644
index 0000000..0b90b48
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-4.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/tag36h11-5.png b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-5.png
new file mode 100644
index 0000000..4406fe6
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-5.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/tag36h11-6.png b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-6.png
new file mode 100644
index 0000000..e5cdb0e
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-6.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/tag36h11-7.png b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-7.png
new file mode 100644
index 0000000..bea714e
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-7.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/tag36h11-8.png b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-8.png
new file mode 100644
index 0000000..3a76de1
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-8.png differ
diff --git a/scene/grasp-box/models/apriltag/materials/textures/tag36h11-9.png b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-9.png
new file mode 100644
index 0000000..20e8d6e
Binary files /dev/null and b/scene/grasp-box/models/apriltag/materials/textures/tag36h11-9.png differ
diff --git a/scene/grasp-box/models/apriltag/urdf/apriltag.xacro b/scene/grasp-box/models/apriltag/urdf/apriltag.xacro
new file mode 100644
index 0000000..df7f37e
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/urdf/apriltag.xacro
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ __default__
+
+ false
+
+
+
+
+
diff --git a/scene/grasp-box/models/apriltag/urdf/apriltag_cube.xacro b/scene/grasp-box/models/apriltag/urdf/apriltag_cube.xacro
new file mode 100644
index 0000000..86d0f44
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/urdf/apriltag_cube.xacro
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/urdf/block.urdf.xacro b/scene/grasp-box/models/apriltag/urdf/block.urdf.xacro
new file mode 100644
index 0000000..1b5cd41
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/urdf/block.urdf.xacro
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+ 1e6
+ 100
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+ 1e6
+ 100
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+ 1e6
+ 100
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/urdf/grab_box_table.xacro b/scene/grasp-box/models/apriltag/urdf/grab_box_table.xacro
new file mode 100644
index 0000000..385a449
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/urdf/grab_box_table.xacro
@@ -0,0 +1,263 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gazebo/Wood
+ 0.5
+ 0.5
+ 1000000.0
+ 100.0
+ 0.001
+ 1.0
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gazebo/Wood
+ 0.5
+ 0.5
+ 1000000.0
+ 100.0
+ 0.001
+ 1.0
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gazebo/Wood
+ 0.5
+ 0.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/urdf/standalone_cube.xacro b/scene/grasp-box/models/apriltag/urdf/standalone_cube.xacro
new file mode 100644
index 0000000..5b4c735
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/urdf/standalone_cube.xacro
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gazebo/Wood
+ 0.5
+ 0.5
+ 1000000.0
+ 100.0
+ 0.001
+ 1.0
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gazebo/Wood
+ 0.5
+ 0.5
+ 1000000.0
+ 100.0
+ 0.001
+ 1.0
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gazebo/Wood
+ 0.5
+ 0.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scene/grasp-box/models/apriltag/urdf/table_apriltag_y.xacro b/scene/grasp-box/models/apriltag/urdf/table_apriltag_y.xacro
new file mode 100644
index 0000000..069ba48
--- /dev/null
+++ b/scene/grasp-box/models/apriltag/urdf/table_apriltag_y.xacro
@@ -0,0 +1,262 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gazebo/Wood
+ 0.5
+ 0.5
+ 1000000.0
+ 100.0
+ 0.001
+ 1.0
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gazebo/Wood
+ 0.5
+ 0.5
+ 1000000.0
+ 100.0
+ 0.001
+ 1.0
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gazebo/Wood
+ 0.5
+ 0.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scene/grasp-box/models/box.xacro b/scene/grasp-box/models/box.xacro
new file mode 100644
index 0000000..f8acf75
--- /dev/null
+++ b/scene/grasp-box/models/box.xacro
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+ 1e6
+ 100
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+ 1e6
+ 100
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scene/grasp-box/models/fixed_tag.xacro b/scene/grasp-box/models/fixed_tag.xacro
new file mode 100644
index 0000000..5043511
--- /dev/null
+++ b/scene/grasp-box/models/fixed_tag.xacro
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scene/grasp-box/models/table.xacro b/scene/grasp-box/models/table.xacro
new file mode 100644
index 0000000..c9d77ec
--- /dev/null
+++ b/scene/grasp-box/models/table.xacro
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gazebo/Wood
+ 0.5
+ 0.5
+ 1000000.0
+ 100.0
+ 0.001
+ 1.0
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gazebo/Wood
+ 0.5
+ 0.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scene/grasp-box/plugin.py b/scene/grasp-box/plugin.py
new file mode 100644
index 0000000..e69de29
diff --git a/scene/grasp-box/scripts/gen_models.py b/scene/grasp-box/scripts/gen_models.py
new file mode 100644
index 0000000..fd5d923
--- /dev/null
+++ b/scene/grasp-box/scripts/gen_models.py
@@ -0,0 +1,81 @@
+import os
+import subprocess
+
+import rospy
+from gazebo_msgs.srv import SpawnModel
+from geometry_msgs.msg import Point, Pose, Quaternion
+from tf.transformations import quaternion_from_euler
+
+
+class GraspModelGenerator:
+ def __init__(self):
+ rospy.init_node('gazebo_world_manager', anonymous=True)
+ self.spawn_service = rospy.ServiceProxy(
+ '/gazebo/spawn_urdf_model', SpawnModel)
+ ros_package_path = os.environ.get('ROS_PACKAGE_PATH', '')
+ custom_path = '/home/leju/gazebo_world_manager'
+ if custom_path not in ros_package_path.split(':'):
+ os.environ['ROS_PACKAGE_PATH'] = f"{custom_path}:{ros_package_path}" if ros_package_path else custom_path
+
+ def _generate(self, model_name, urdf_content, pose):
+ try:
+ # 生成模型
+ rospy.wait_for_service('/gazebo/spawn_urdf_model')
+ response = self.spawn_service(
+ model_name=model_name,
+ model_xml=urdf_content,
+ robot_namespace='',
+ initial_pose=pose,
+ reference_frame='world'
+ )
+
+ if response.success:
+ rospy.loginfo(f"Successfully spawned {model_name}")
+ else:
+ rospy.logerr(
+ f"Failed to spawn {model_name}: {response.status_message}")
+ except subprocess.CalledProcessError as e:
+ rospy.logerr(f"Failed to convert xacro to urdf: {e}")
+
+ def generate_table(self, name, x, y, height):
+ xacro_file = "/home/leju/gazebo_world_manager/scene/grasp-box/models/table.xacro"
+ urdf_content = subprocess.check_output([
+ 'rosrun', 'xacro', 'xacro', xacro_file,
+ f'x:={x}', f'y:={y}', f'height:={height}'
+ ]).decode('utf-8')
+ pose = Pose(
+ position=Point(x=x, y=y, z=0),
+ orientation=Quaternion(*quaternion_from_euler(0, 0, 0))
+ )
+ self._generate(name, urdf_content, pose)
+
+ def generate_apriltag(self, name, tag_id=0, x=0, y=0, z=0, roll=0, pitch=0, yaw=0):
+ """生成AprilTag标记模型"""
+ xacro_file = "/home/leju/gazebo_world_manager/scene/grasp-box/models/fixed_tag.xacro"
+ urdf_content = subprocess.check_output([
+ 'rosrun', 'xacro', 'xacro', xacro_file, f'tag_id:={tag_id}'
+ ]).decode('utf-8')
+ pose = Pose(
+ position=Point(x=x, y=y, z=z),
+ orientation=Quaternion(
+ *quaternion_from_euler(roll, pitch, yaw))
+ )
+ self._generate(name, urdf_content, pose)
+
+ def generate_box_with_apriltag(self, name, l=0.25, w=0.2, h=0.2, mass=1, tag_id=0, x=0, y=0, z=0, roll=0, pitch=0, yaw=0):
+ """生成带有AprilTag的盒子模型"""
+ xacro_file = "/home/leju/gazebo_world_manager/scene/grasp-box/models/box.xacro"
+ urdf_content = subprocess.check_output([
+ 'rosrun', 'xacro', 'xacro', xacro_file, f'box_length:={l}', f'box_weight:={w}', f'box_height:={h}', f'box_mass:={mass}', f'tag_id:={tag_id}'
+ ]).decode('utf-8')
+ pose = Pose(
+ position=Point(x=x, y=y, z=z),
+ orientation=Quaternion(
+ *quaternion_from_euler(roll, pitch, yaw))
+ )
+ self._generate(name, urdf_content, pose)
+
+
+if __name__ == '__main__':
+ generator = GraspModelGenerator()
+ generator.generate_apriltag("tg2", 0, 2, 0, 1.1, 0, 1.57, 1.57)
diff --git a/scene_plugin.py b/scene_plugin.py
new file mode 100644
index 0000000..d9c5f58
--- /dev/null
+++ b/scene_plugin.py
@@ -0,0 +1,16 @@
+class ScenePlugin:
+ """
+ 场景自定义模型的处理。
+ """
+
+ def __init__(self, scene_name):
+ self.scene_name = scene_name
+
+ def post_scene_model_spawn(self):
+ raise NotImplementedError()
+
+ def post_scene_model_state(self):
+ raise NotImplementedError()
+
+ def get_scene_model_state(self):
+ raise NotImplementedError()