feat: 实现场景修改,特殊物品添加

This commit is contained in:
zpff 2025-08-09 22:00:02 +08:00
parent a51153b044
commit 1843c21972
42 changed files with 1800 additions and 0 deletions

169
gazebo_ctrl.py Normal file
View File

@ -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'])))

73
http_server.py Normal file
View File

@ -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__()

63
main.py Executable file
View File

@ -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()

14
package.xml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<package format="2">
<name>gazebo_world_manager</name>
<version>0.0.0</version>
<description>The gazebo_world_manager package</description>
<maintainer email="user@example.com">user</maintainer>
<license>TODO</license>
<buildtool_depend>catkin</buildtool_depend>
<depend>rospy</depend>
<depend>gazebo_msgs</depend>
<depend>geometry_msgs</depend>
</package>

3
scene/grasp-box/launch.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
# 启动仿真程序

View File

@ -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
}
}
}
}

View File

@ -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
}
}
}
}

View File

@ -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
}
}
}
}

View File

@ -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
}
}
}
}

View File

@ -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
}
}
}
}

View File

@ -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
}
}
}
}

View File

@ -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
}
}
}
}

View File

@ -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
}
}
}
}

View File

@ -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
}
}
}
}

View File

@ -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
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,41 @@
<?xml version="1.0"?>
<robot xmlns:xacro="http://ros.org/wiki/xacro" name="apriltag_marker">
<xacro:macro name="apriltag_marker" params="parent_link *origin id">
<!-- 定义二维码的Link -->
<link name="apriltag_marker_${id}">
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<box size="0.11 0.11 0.001"/>
</geometry>
</visual>
<collision>
<geometry>
<box size="0.11 0.11 0.001"/>
</geometry>
</collision>
</link>
<joint name="apriltag_joint_${id}" type="fixed">
<xacro:insert_block name="origin" />
<parent link="${parent_link}"/>
<child link="apriltag_marker_${id}"/>
</joint>
<gazebo reference="apriltag_marker_${id}">
<visual>
<material>
<script>
<uri>file://$(find gazebo_world_manager)/scene/grasp-box//models/apriltag/materials/apriltag_${id}.material</uri>
<name>AprilTag/Marker${id}</name>
</script>
<shader type="pixel">
<normal_map>__default__</normal_map>
</shader>
<double_sided>false</double_sided>
</material>
</visual>
</gazebo>
</xacro:macro>
</robot>

View File

@ -0,0 +1,51 @@
<?xml version="1.0"?>
<robot xmlns:xacro="http://ros.org/wiki/xacro">
<!-- 引入apriltag -->
<xacro:include filename="$(find gazebo_world_manager)/scene/grasp-box//models/apriltag/urdf/apriltag.xacro"/>
<!-- 左臂AprilTag标记 -->
<xacro:macro name="left_arm_apriltags" params="parent_link">
<xacro:apriltag_marker parent_link="${parent_link}" id="0">
<origin xyz="0.055 0 -0.165" rpy="0 1.5708 0"/>
</xacro:apriltag_marker>
<xacro:apriltag_marker parent_link="${parent_link}" id="1">
<origin xyz="-0.055 0 -0.165" rpy="0 1.5708 3.1415"/>
</xacro:apriltag_marker>
<xacro:apriltag_marker parent_link="${parent_link}" id="2">
<origin xyz="0 0.055 -0.165" rpy="0 1.5708 1.5708"/>
</xacro:apriltag_marker>
<xacro:apriltag_marker parent_link="${parent_link}" id="3">
<origin xyz="0 -0.055 -0.165" rpy="0 1.5708 -1.5708"/>
</xacro:apriltag_marker>
<xacro:apriltag_marker parent_link="${parent_link}" id="4">
<origin xyz="0 0 -0.22" rpy="0 3.1416 0"/>
</xacro:apriltag_marker>
<xacro:apriltag_marker parent_link="${parent_link}" id="111">
<origin xyz="0 0 -0.11" rpy="0 3.1416 0"/>
</xacro:apriltag_marker>
</xacro:macro>
<!-- 右臂AprilTag标记 -->
<xacro:macro name="right_arm_apriltags" params="parent_link">
<xacro:apriltag_marker parent_link="${parent_link}" id="5">
<origin xyz="0.055 0 -0.165" rpy="0 1.5708 0"/>
</xacro:apriltag_marker>
<xacro:apriltag_marker parent_link="${parent_link}" id="6">
<origin xyz="-0.055 0 -0.165" rpy="0 1.5708 3.1415"/>
</xacro:apriltag_marker>
<xacro:apriltag_marker parent_link="${parent_link}" id="7">
<origin xyz="0 0.055 -0.165" rpy="0 1.5708 1.5708"/>
</xacro:apriltag_marker>
<xacro:apriltag_marker parent_link="${parent_link}" id="8">
<origin xyz="0 -0.055 -0.165" rpy="0 1.5708 -1.5708"/>
</xacro:apriltag_marker>
<xacro:apriltag_marker parent_link="${parent_link}" id="9">
<origin xyz="0 0 -0.22" rpy="0 3.1416 0"/>
</xacro:apriltag_marker>
<xacro:apriltag_marker parent_link="${parent_link}" id="999">
<origin xyz="0 0 -0.11" rpy="0 3.1416 0"/>
</xacro:apriltag_marker>
</xacro:macro>
</robot>

View File

@ -0,0 +1,93 @@
<?xml version="1.0"?>
<robot name="block">
<link name="world"/>
<link name="base_link">
<!-- 主体视觉和碰撞 -->
<visual>
<geometry>
<box size="0.2 0.2 0.2"/>
</geometry>
<origin xyz="0 0 0" rpy="0 0 0"/>
<material name="red">
<color rgba="1 0 0 1"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.2 0.2 0.2"/>
</geometry>
<origin xyz="0 0 0" rpy="0 0 0"/>
<surface>
<contact>
<max_contacts>10</max_contacts>
<ode>
<kp>1e6</kp>
<kd>100</kd>
</ode>
</contact>
</surface>
</collision>
<!-- 左耳 -->
<visual>
<geometry>
<box size="0.1 0.15000000000000002 0.025"/>
</geometry>
<origin xyz="-0.125 0.0 0.07500000000000001" rpy="0 0 0"/>
<material name="red"/>
</visual>
<collision>
<geometry>
<box size="0.1 0.15000000000000002 0.025"/>
</geometry>
<origin xyz="-0.125 0.0 0.07500000000000001" rpy="0 0 0"/>
<surface>
<contact>
<max_contacts>10</max_contacts>
<ode>
<kp>1e6</kp>
<kd>100</kd>
</ode>
</contact>
</surface>
</collision>
<!-- 右耳 -->
<visual>
<geometry>
<box size="0.1 0.15000000000000002 0.025"/>
</geometry>
<origin xyz="0.125 0.0 0.07500000000000001" rpy="0 0 0"/>
<material name="red"/>
</visual>
<collision>
<geometry>
<box size="0.1 0.15000000000000002 0.025"/>
</geometry>
<origin xyz="0.125 0.0 0.07500000000000001" rpy="0 0 0"/>
<surface>
<contact>
<max_contacts>10</max_contacts>
<ode>
<kp>1e6</kp>
<kd>100</kd>
</ode>
</contact>
</surface>
</collision>
<!-- 质量惯性(合并计算) -->
<inertial>
<mass value="1.5"/>
<inertia ixx="0.010000000000000002" iyy="0.010000000000000002" izz="0.010000000000000002" ixy="0" iyz="0" ixz="0"/>
</inertial>
</link>
<!-- Floating joint to make the block freely movable -->
<joint name="floating" type="floating">
<parent link="world"/>
<child link="base_link"/>
<origin xyz="0 -1.0 0.9" rpy="0 0 0"/>
</joint>
</robot>

View File

@ -0,0 +1,263 @@
<?xml version="1.0"?>
<robot xmlns:xacro="http://ros.org/wiki/xacro" name="standalone_apriltag_cube">
<!-- 定义参数 -->
<xacro:property name="table_height" value="0.88" /> <!-- 桌子高度参数 -->
<xacro:property name="table2_height" value="0.88" /> <!-- 桌子高度参数 -->
<xacro:property name="table_thickness" value="0.04" /> <!-- 桌面厚度 -->
<xacro:property name="leg_radius" value="0.02" /> <!-- 桌腿半径 -->
<!-- 第一个桌子位置参数 -->
<xacro:property name="table1_x" value="0.0" />
<xacro:property name="table1_y" value="2.0" />
<xacro:property name="table1_z" value="${table_height}" />
<!-- 第二个桌子位置参数 -->
<xacro:property name="table2_x" value="0.0" />
<xacro:property name="table2_y" value="-0.9" />
<xacro:property name="table2_z" value="${table2_height}" />
<!-- 立方体位置参数/参数相对于桌子来说 -->
<xacro:property name="cube_x" value="0.0" />
<xacro:property name="cube_y" value="0.0" />
<xacro:property name="cube_z" value="${table_thickness/2 + 0.05}" />
<!-- 引入apriltag -->
<xacro:include filename="$(find gazebo_world_manager)/scene/grasp-box//models/apriltag/urdf/apriltag.xacro"/>
<!-- 添加一个世界链接作为根链接 -->
<link name="world"/>
<!-- 创建第一个桌子链接 -->
<link name="table1_link">
<visual>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
<material name="wood">
<color rgba="0.8 0.6 0.4 1.0"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
</collision>
<inertial>
<mass value="5.0"/>
<inertia ixx="0.1" ixy="0" ixz="0" iyy="0.1" iyz="0" izz="0.1"/>
</inertial>
</link>
<!-- 添加Gazebo物理属性 -->
<gazebo reference="table1_link">
<material>Gazebo/Wood</material>
<mu1>0.5</mu1>
<mu2>0.5</mu2>
<kp>1000000.0</kp>
<kd>100.0</kd>
<minDepth>0.001</minDepth>
<maxVel>1.0</maxVel>
<maxContacts>20</maxContacts>
</gazebo>
<!-- 将世界链接与第一个桌子连接 -->
<joint name="world_to_table1_joint" type="fixed">
<parent link="world"/>
<child link="table1_link"/>
<origin xyz="${table1_x} ${table1_y} ${table1_z}" rpy="0.0 0.0 1.5707963267948966"/>
</joint>
<!-- 创建第二个桌子链接 -->
<link name="table2_link">
<visual>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
<material name="wood">
<color rgba="0.8 0.6 0.4 1.0"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
</collision>
<inertial>
<mass value="5.0"/>
<inertia ixx="0.1" ixy="0" ixz="0" iyy="0.1" iyz="0" izz="0.1"/>
</inertial>
</link>
<!-- 添加Gazebo物理属性 -->
<gazebo reference="table2_link">
<material>Gazebo/Wood</material>
<mu1>0.5</mu1>
<mu2>0.5</mu2>
<kp>1000000.0</kp>
<kd>100.0</kd>
<minDepth>0.001</minDepth>
<maxVel>1.0</maxVel>
<maxContacts>20</maxContacts>
</gazebo>
<!-- 将世界链接与第二个桌子连接 -->
<joint name="world_to_table2_joint" type="fixed">
<parent link="world"/>
<child link="table2_link"/>
<origin xyz="${table2_x} ${table2_y} ${table2_z}" rpy="0.0 0.0 1.5707963267948966"/>
</joint>
<!-- 创建第一个桌子的四条桌腿 -->
<xacro:macro name="table_leg" params="name x y height">
<link name="${name}">
<visual>
<geometry>
<cylinder radius="${leg_radius}" length="${height}"/>
</geometry>
<material name="wood">
<color rgba="0.7 0.5 0.3 1.0"/>
</material>
</visual>
<collision>
<geometry>
<cylinder radius="${leg_radius}" length="${height}"/>
</geometry>
</collision>
<inertial>
<mass value="0.5"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.001"/>
</inertial>
</link>
<gazebo reference="${name}">
<material>Gazebo/Wood</material>
<mu1>0.5</mu1>
<mu2>0.5</mu2>
</gazebo>
</xacro:macro>
<!-- 创建第一个桌子的桌腿 -->
<xacro:table_leg name="table1_leg1" x="0.15" y="0.15" height="${table_height}"/>
<xacro:table_leg name="table1_leg2" x="-0.15" y="0.15" height="${table_height}"/>
<xacro:table_leg name="table1_leg3" x="0.15" y="-0.15" height="${table_height}"/>
<xacro:table_leg name="table1_leg4" x="-0.15" y="-0.15" height="${table_height}"/>
<!-- 创建第二个桌子的桌腿 -->
<xacro:table_leg name="table2_leg1" x="0.15" y="0.15" height="${table2_height}"/>
<xacro:table_leg name="table2_leg2" x="-0.15" y="0.15" height="${table2_height}"/>
<xacro:table_leg name="table2_leg3" x="0.15" y="-0.15" height="${table2_height}"/>
<xacro:table_leg name="table2_leg4" x="-0.15" y="-0.15" height="${table2_height}"/>
<!-- 连接第一个桌子的桌腿 -->
<joint name="table1_to_leg1_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg1"/>
<origin xyz="0.15 0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table1_to_leg2_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg2"/>
<origin xyz="-0.15 0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table1_to_leg3_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg3"/>
<origin xyz="0.15 -0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table1_to_leg4_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg4"/>
<origin xyz="-0.15 -0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<!-- 连接第二个桌子的桌腿 -->
<joint name="table2_to_leg1_joint" type="fixed">
<parent link="table2_link"/>
<child link="table2_leg1"/>
<origin xyz="0.15 0.15 ${-table2_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table2_to_leg2_joint" type="fixed">
<parent link="table2_link"/>
<child link="table2_leg2"/>
<origin xyz="-0.15 0.15 ${-table2_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table2_to_leg3_joint" type="fixed">
<parent link="table2_link"/>
<child link="table2_leg3"/>
<origin xyz="0.15 -0.15 ${-table2_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table2_to_leg4_joint" type="fixed">
<parent link="table2_link"/>
<child link="table2_leg4"/>
<origin xyz="-0.15 -0.15 ${-table2_height/2}" rpy="0 0 0"/>
</joint>
<!-- 创建三个基础链接作为立方体的中心 -->
<link name="apriltag_box_base">
<visual>
<geometry>
<box size="0.1 0.1 0.1"/>
</geometry>
<material>
<color rgba="0.8 0.8 0.8 0.5"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.1 0.1 0.1"/>
</geometry>
</collision>
<inertial>
<mass value="0.1"/>
<inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0001"/>
</inertial>
</link>
<link name="apriltag_shelf_base">
<visual>
<geometry>
<box size="0.1 0.1 0.1"/>
</geometry>
<material>
<color rgba="0.8 0.8 0.8 0.5"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.1 0.1 0.1"/>
</geometry>
</collision>
<inertial>
<mass value="0.1"/>
<inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0001"/>
</inertial>
</link>
<!-- 将立方体连接到世界坐标系 -->
<joint name="world_to_box_tag_joint" type="fixed">
<parent link="table1_link"/>
<child link="apriltag_box_base"/>
<origin xyz="-0.0005 0 0.02" rpy="0 0 1.5707963"/>
</joint>
<joint name="world_to_table_joint" type="fixed">
<parent link="table2_link"/>
<child link="apriltag_shelf_base"/>
<origin xyz="-0.0005 0 0.02" rpy="0 0 -1.5707963"/> <!-- 绕z轴旋转270度 (4.712389弧度 = 270度) -->
</joint>
<xacro:apriltag_marker parent_link="apriltag_box_base" id="1">
<origin xyz="0 0.1 0.1" rpy="1.5708 1.5708 0"/>
</xacro:apriltag_marker>
<xacro:apriltag_marker parent_link="apriltag_shelf_base" id="0">
<origin xyz="0 0.1 0.8" rpy="1.5708 1.5708 0"/>
</xacro:apriltag_marker>
</robot>

View File

@ -0,0 +1,232 @@
<?xml version="1.0"?>
<robot xmlns:xacro="http://ros.org/wiki/xacro" name="standalone_apriltag_cube">
<!-- 定义参数 -->
<xacro:property name="table_height" value="0.8" /> <!-- 桌子高度参数 -->
<xacro:property name="table_thickness" value="0.04" /> <!-- 桌面厚度 -->
<xacro:property name="leg_radius" value="0.02" /> <!-- 桌腿半径 -->
<!-- 第一个桌子位置参数 -->
<xacro:property name="table1_x" value="0.0" />
<xacro:property name="table1_y" value="-1.0" />
<xacro:property name="table1_z" value="${table_height}" />
<!-- 第二个桌子位置参数 -->
<xacro:property name="table2_x" value="0.0" />
<xacro:property name="table2_y" value="1.0" />
<xacro:property name="table2_z" value="${table_height}" />
<!-- 立方体位置参数/参数相对于桌子来说 -->
<xacro:property name="cube_x" value="0.0" />
<xacro:property name="cube_y" value="0.0" />
<xacro:property name="cube_z" value="${table_thickness/2 + 0.05}" />
<!-- 引入apriltag -->
<xacro:include filename="$(find gazebo_world_manager)/scene/grasp-box//models/apriltag/urdf/apriltag.xacro"/>
<!-- 添加一个世界链接作为根链接 -->
<link name="world"/>
<!-- 创建第一个桌子链接 -->
<link name="table1_link">
<visual>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
<material name="wood">
<color rgba="0.8 0.6 0.4 1.0"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
</collision>
<inertial>
<mass value="5.0"/>
<inertia ixx="0.1" ixy="0" ixz="0" iyy="0.1" iyz="0" izz="0.1"/>
</inertial>
</link>
<!-- 添加Gazebo物理属性 -->
<gazebo reference="table1_link">
<material>Gazebo/Wood</material>
<mu1>0.5</mu1>
<mu2>0.5</mu2>
<kp>1000000.0</kp>
<kd>100.0</kd>
<minDepth>0.001</minDepth>
<maxVel>1.0</maxVel>
<maxContacts>20</maxContacts>
</gazebo>
<!-- 将世界链接与第一个桌子连接 -->
<joint name="world_to_table1_joint" type="fixed">
<parent link="world"/>
<child link="table1_link"/>
<origin xyz="${table1_x} ${table1_y} ${table1_z}" rpy="0 0 0"/>
</joint>
<!-- 创建第二个桌子链接 -->
<link name="table2_link">
<visual>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
<material name="wood">
<color rgba="0.8 0.6 0.4 1.0"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
</collision>
<inertial>
<mass value="5.0"/>
<inertia ixx="0.1" ixy="0" ixz="0" iyy="0.1" iyz="0" izz="0.1"/>
</inertial>
</link>
<!-- 添加Gazebo物理属性 -->
<gazebo reference="table2_link">
<material>Gazebo/Wood</material>
<mu1>0.5</mu1>
<mu2>0.5</mu2>
<kp>1000000.0</kp>
<kd>100.0</kd>
<minDepth>0.001</minDepth>
<maxVel>1.0</maxVel>
<maxContacts>20</maxContacts>
</gazebo>
<!-- 将世界链接与第二个桌子连接 -->
<joint name="world_to_table2_joint" type="fixed">
<parent link="world"/>
<child link="table2_link"/>
<origin xyz="${table2_x} ${table2_y} ${table2_z}" rpy="0 0 0"/>
</joint>
<!-- 创建第一个桌子的四条桌腿 -->
<xacro:macro name="table_leg" params="name x y">
<link name="${name}">
<visual>
<geometry>
<cylinder radius="${leg_radius}" length="${table_height}"/>
</geometry>
<material name="wood">
<color rgba="0.7 0.5 0.3 1.0"/>
</material>
</visual>
<collision>
<geometry>
<cylinder radius="${leg_radius}" length="${table_height}"/>
</geometry>
</collision>
<inertial>
<mass value="0.5"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.001"/>
</inertial>
</link>
<gazebo reference="${name}">
<material>Gazebo/Wood</material>
<mu1>0.5</mu1>
<mu2>0.5</mu2>
</gazebo>
</xacro:macro>
<!-- 创建第一个桌子的桌腿 -->
<xacro:table_leg name="table1_leg1" x="0.15" y="0.15"/>
<xacro:table_leg name="table1_leg2" x="-0.15" y="0.15"/>
<xacro:table_leg name="table1_leg3" x="0.15" y="-0.15"/>
<xacro:table_leg name="table1_leg4" x="-0.15" y="-0.15"/>
<!-- 创建第二个桌子的桌腿 -->
<xacro:table_leg name="table2_leg1" x="0.15" y="0.15"/>
<xacro:table_leg name="table2_leg2" x="-0.15" y="0.15"/>
<xacro:table_leg name="table2_leg3" x="0.15" y="-0.15"/>
<xacro:table_leg name="table2_leg4" x="-0.15" y="-0.15"/>
<!-- 连接第一个桌子的桌腿 -->
<joint name="table1_to_leg1_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg1"/>
<origin xyz="0.15 0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table1_to_leg2_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg2"/>
<origin xyz="-0.15 0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table1_to_leg3_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg3"/>
<origin xyz="0.15 -0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table1_to_leg4_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg4"/>
<origin xyz="-0.15 -0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<!-- 连接第二个桌子的桌腿 -->
<joint name="table2_to_leg1_joint" type="fixed">
<parent link="table2_link"/>
<child link="table2_leg1"/>
<origin xyz="0.15 0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table2_to_leg2_joint" type="fixed">
<parent link="table2_link"/>
<child link="table2_leg2"/>
<origin xyz="-0.15 0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table2_to_leg3_joint" type="fixed">
<parent link="table2_link"/>
<child link="table2_leg3"/>
<origin xyz="0.15 -0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table2_to_leg4_joint" type="fixed">
<parent link="table2_link"/>
<child link="table2_leg4"/>
<origin xyz="-0.15 -0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<!-- 创建一个基础链接作为立方体的中心 -->
<link name="apriltag_cube_base">
<visual>
<geometry>
<box size="0.1 0.1 0.1"/>
</geometry>
<material>
<color rgba="0.8 0.8 0.8 0.5"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.1 0.1 0.1"/>
</geometry>
</collision>
<inertial>
<mass value="0.1"/>
<inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0001"/>
</inertial>
</link>
<!-- 将立方体直接连接到世界坐标系 -->
<joint name="world_to_cube_joint" type="fixed">
<parent link="world"/>
<child link="apriltag_cube_base"/>
<origin xyz="0.0 -1.3 1.2" rpy="0 0 0"/>
</joint>
<xacro:include filename="$(find gazebo_world_manager)/scene/grasp-box//models/apriltag/urdf/apriltag_cube.xacro"/>
<xacro:left_arm_apriltags parent_link="apriltag_cube_base"/>
<!-- 确保您已为这些ID创建了相应的材质文件放在 kuavo_assets/models/apriltag/materials/ 目录下 -->
</robot>

View File

@ -0,0 +1,262 @@
<?xml version="1.0"?>
<robot xmlns:xacro="http://ros.org/wiki/xacro" name="standalone_apriltag_cube">
<!-- 定义参数 -->
<xacro:property name="table_height" value="0.8" /> <!-- 桌子高度参数 -->
<xacro:property name="table_thickness" value="0.04" /> <!-- 桌面厚度 -->
<xacro:property name="leg_radius" value="0.02" /> <!-- 桌腿半径 -->
<!-- 第一个桌子位置参数 -->
<xacro:property name="table1_x" value="0.0" />
<xacro:property name="table1_y" value="-1.8" />
<xacro:property name="table1_z" value="${table_height}" />
<!-- 第二个桌子位置参数 -->
<xacro:property name="table2_x" value="0.0" />
<xacro:property name="table2_y" value="1.8" />
<xacro:property name="table2_z" value="${table_height}" />
<!-- 立方体位置参数/参数相对于桌子来说 -->
<xacro:property name="cube_x" value="0.0" />
<xacro:property name="cube_y" value="0.0" />
<xacro:property name="cube_z" value="${table_thickness/2 + 0.05}" />
<!-- 引入apriltag -->
<xacro:include filename="$(find gazebo_world_manager)/scene/grasp-box//models/apriltag/urdf/apriltag.xacro"/>
<!-- 添加一个世界链接作为根链接 -->
<link name="world"/>
<!-- 创建第一个桌子链接 -->
<link name="table1_link">
<visual>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
<material name="wood">
<color rgba="0.8 0.6 0.4 1.0"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
</collision>
<inertial>
<mass value="5.0"/>
<inertia ixx="0.1" ixy="0" ixz="0" iyy="0.1" iyz="0" izz="0.1"/>
</inertial>
</link>
<!-- 添加Gazebo物理属性 -->
<gazebo reference="table1_link">
<material>Gazebo/Wood</material>
<mu1>0.5</mu1>
<mu2>0.5</mu2>
<kp>1000000.0</kp>
<kd>100.0</kd>
<minDepth>0.001</minDepth>
<maxVel>1.0</maxVel>
<maxContacts>20</maxContacts>
</gazebo>
<!-- 将世界链接与第一个桌子连接 -->
<joint name="world_to_table1_joint" type="fixed">
<parent link="world"/>
<child link="table1_link"/>
<origin xyz="${table1_x} ${table1_y} ${table1_z}" rpy="0 0 0"/>
</joint>
<!-- 创建第二个桌子链接 -->
<link name="table2_link">
<visual>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
<material name="wood">
<color rgba="0.8 0.6 0.4 1.0"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
</collision>
<inertial>
<mass value="5.0"/>
<inertia ixx="0.1" ixy="0" ixz="0" iyy="0.1" iyz="0" izz="0.1"/>
</inertial>
</link>
<!-- 添加Gazebo物理属性 -->
<gazebo reference="table2_link">
<material>Gazebo/Wood</material>
<mu1>0.5</mu1>
<mu2>0.5</mu2>
<kp>1000000.0</kp>
<kd>100.0</kd>
<minDepth>0.001</minDepth>
<maxVel>1.0</maxVel>
<maxContacts>20</maxContacts>
</gazebo>
<!-- 将世界链接与第二个桌子连接 -->
<joint name="world_to_table2_joint" type="fixed">
<parent link="world"/>
<child link="table2_link"/>
<origin xyz="${table2_x} ${table2_y} ${table2_z}" rpy="0 0 0"/>
</joint>
<!-- 创建第一个桌子的四条桌腿 -->
<xacro:macro name="table_leg" params="name x y">
<link name="${name}">
<visual>
<geometry>
<cylinder radius="${leg_radius}" length="${table_height}"/>
</geometry>
<material name="wood">
<color rgba="0.7 0.5 0.3 1.0"/>
</material>
</visual>
<collision>
<geometry>
<cylinder radius="${leg_radius}" length="${table_height}"/>
</geometry>
</collision>
<inertial>
<mass value="0.5"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.001"/>
</inertial>
</link>
<gazebo reference="${name}">
<material>Gazebo/Wood</material>
<mu1>0.5</mu1>
<mu2>0.5</mu2>
</gazebo>
</xacro:macro>
<!-- 创建第一个桌子的桌腿 -->
<xacro:table_leg name="table1_leg1" x="0.15" y="0.15"/>
<xacro:table_leg name="table1_leg2" x="-0.15" y="0.15"/>
<xacro:table_leg name="table1_leg3" x="0.15" y="-0.15"/>
<xacro:table_leg name="table1_leg4" x="-0.15" y="-0.15"/>
<!-- 创建第二个桌子的桌腿 -->
<xacro:table_leg name="table2_leg1" x="0.15" y="0.15"/>
<xacro:table_leg name="table2_leg2" x="-0.15" y="0.15"/>
<xacro:table_leg name="table2_leg3" x="0.15" y="-0.15"/>
<xacro:table_leg name="table2_leg4" x="-0.15" y="-0.15"/>
<!-- 连接第一个桌子的桌腿 -->
<joint name="table1_to_leg1_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg1"/>
<origin xyz="0.15 0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table1_to_leg2_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg2"/>
<origin xyz="-0.15 0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table1_to_leg3_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg3"/>
<origin xyz="0.15 -0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table1_to_leg4_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg4"/>
<origin xyz="-0.15 -0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<!-- 连接第二个桌子的桌腿 -->
<joint name="table2_to_leg1_joint" type="fixed">
<parent link="table2_link"/>
<child link="table2_leg1"/>
<origin xyz="0.15 0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table2_to_leg2_joint" type="fixed">
<parent link="table2_link"/>
<child link="table2_leg2"/>
<origin xyz="-0.15 0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table2_to_leg3_joint" type="fixed">
<parent link="table2_link"/>
<child link="table2_leg3"/>
<origin xyz="0.15 -0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table2_to_leg4_joint" type="fixed">
<parent link="table2_link"/>
<child link="table2_leg4"/>
<origin xyz="-0.15 -0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<!-- 创建三个基础链接作为立方体的中心 -->
<link name="apriltag_box_base">
<visual>
<geometry>
<box size="0.1 0.1 0.1"/>
</geometry>
<material>
<color rgba="0.8 0.8 0.8 0.5"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.1 0.1 0.1"/>
</geometry>
</collision>
<inertial>
<mass value="0.1"/>
<inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0001"/>
</inertial>
</link>
<link name="apriltag_shelf_base">
<visual>
<geometry>
<box size="0.1 0.1 0.1"/>
</geometry>
<material>
<color rgba="0.8 0.8 0.8 0.5"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.1 0.1 0.1"/>
</geometry>
</collision>
<inertial>
<mass value="0.1"/>
<inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0001"/>
</inertial>
</link>
<!-- 将立方体连接到世界坐标系 -->
<joint name="world_to_box_tag_joint" type="fixed">
<parent link="world"/>
<child link="apriltag_box_base"/>
<origin xyz="0.0 1.7 1.1" rpy="0 0 0"/>
</joint>
<joint name="world_to_cube2_joint" type="fixed">
<parent link="world"/>
<child link="apriltag_shelf_base"/>
<origin xyz="0.0 -1.7 1.6" rpy="0 0 4.712389"/> <!-- 绕z轴旋转270度 (4.712389弧度 = 270度) -->
</joint>
<xacro:apriltag_marker parent_link="apriltag_box_base" id="1">
<origin xyz="0 -0.055 -0.165" rpy="1.5708 -1.5708 0"/>
</xacro:apriltag_marker>
<xacro:apriltag_marker parent_link="apriltag_shelf_base" id="0">
<origin xyz="0.055 0 -0.165" rpy="0 1.5708 0"/>
</xacro:apriltag_marker>
</robot>

View File

@ -0,0 +1,105 @@
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="block">
<xacro:include filename="$(find gazebo_world_manager)/scene/grasp-box/models/apriltag/urdf/apriltag.xacro"/>
<!-- ===== 参数定义 ===== -->
<xacro:arg name="box_length" default="0.5"/> <!-- x -->
<xacro:arg name="box_width" default="0.3"/> <!-- y -->
<xacro:arg name="box_height" default="0.2"/> <!-- z -->
<xacro:arg name="box_mass" default="1.0"/>
<xacro:arg name="tag_id" default="0"/>
<!-- ===== 派生参数计算 ===== -->
<!-- 从参数创建属性 -->
<xacro:property name="box_length" value="$(arg box_length)"/>
<xacro:property name="box_width" value="$(arg box_width)"/>
<xacro:property name="box_height" value="$(arg box_height)"/>
<xacro:property name="box_mass" value="$(arg box_mass)"/>
<!-- 耳朵长度:箱子宽度 - 0.05 -->
<xacro:property name="ear_length" value="${box_width - 0.05}"/>
<!-- 耳朵偏移:箱子长度的一半 + 0.025 -->
<xacro:property name="ear_offset" value="${box_length/2 + 0.025}"/>
<xacro:property name="ear_width" value="0.1"/>
<xacro:property name="ear_thickness" value="0.025"/>
<!-- 惯性矩阵计算 -->
<xacro:property name="ixx" value="${(1.0/12.0) * box_mass * (box_height*box_height + box_width*box_width)}"/>
<xacro:property name="iyy" value="${(1.0/12.0) * box_mass * (box_length*box_length + box_height*box_height)}"/>
<xacro:property name="izz" value="${(1.0/12.0) * box_mass * (box_length*box_length + box_width*box_width)}"/>
<!-- ===== 耳朵宏定义 ===== -->
<!-- 参数:
side_offset左右位置正值右耳负值左耳
-->
<xacro:macro name="ear" params="side_offset">
<visual>
<geometry>
<box size="${ear_width} ${ear_length} ${ear_thickness}"/>
</geometry>
<origin xyz="${side_offset} 0.0 ${box_height/2 - ear_thickness}" rpy="0 0 0"/>
<material name="red"/>
</visual>
<collision>
<geometry>
<box size="${ear_width} ${ear_length} ${ear_thickness}"/>
</geometry>
<origin xyz="${side_offset} 0.0 ${box_height/2 - ear_thickness}" rpy="0 0 0"/>
<surface>
<contact>
<max_contacts>10</max_contacts>
<ode>
<kp>1e6</kp>
<kd>100</kd>
</ode>
</contact>
</surface>
</collision>
</xacro:macro>
<!-- 主体 -->
<link name="base_link">
<!-- 主体视觉 -->
<visual>
<geometry>
<box size="${box_length} ${box_width} ${box_height}"/>
</geometry>
<origin xyz="0 0 0" rpy="0 0 0"/>
<material name="red">
<color rgba="1 0 0 1"/>
</material>
</visual>
<!-- 主体碰撞 -->
<collision>
<geometry>
<box size="${box_length} ${box_width} ${box_height}"/>
</geometry>
<origin xyz="0 0 0" rpy="0 0 0"/>
<surface>
<contact>
<max_contacts>10</max_contacts>
<ode>
<kp>1e6</kp>
<kd>100</kd>
</ode>
</contact>
</surface>
</collision>
<!-- 左耳(调用宏) -->
<xacro:ear side_offset="-${ear_offset}"/>
<!-- 右耳(调用宏) -->
<xacro:ear side_offset="${ear_offset}"/>
<!-- 质量惯性(自动计算) -->
<inertial>
<mass value="${box_mass}"/>
<inertia ixx="${ixx}" iyy="${iyy}" izz="${izz}" ixy="0" iyz="0" ixz="0"/>
</inertial>
</link>
<xacro:apriltag_marker parent_link="base_link" id="$(arg tag_id)">
<origin xyz="0 -${box_width/2 + 0.001} 0" rpy="-${pi/2} 0 0"/>
</xacro:apriltag_marker>
</robot>

View File

@ -0,0 +1,26 @@
<?xml version="1.0"?>
<robot xmlns:xacro="http://ros.org/wiki/xacro" name="apriltag_complete">
<xacro:include filename="$(find gazebo_world_manager)/scene/grasp-box/models/apriltag/urdf/apriltag.xacro"/>
<xacro:arg name="tag_id" default="0"/>
<link name="base_link">
<inertial>
<mass value="1e9"/>
<inertia ixx="1e9" ixy="0" ixz="0" iyy="1e9" iyz="0" izz="1e9"/>
</inertial>
</link>
<xacro:apriltag_marker parent_link="base_link" id="$(arg tag_id)">
<origin xyz="0 0 0" rpy="0 0 0"/>
</xacro:apriltag_marker>
<link name="world"/>
<joint name="base_link_fixed_joint" type="fixed">
<parent link="world"/>
<child link="base_link"/>
<origin xyz="0 0 0" rpy="0 0 0"/>
</joint>
</robot>

View File

@ -0,0 +1,128 @@
<?xml version="1.0"?>
<robot xmlns:xacro="http://ros.org/wiki/xacro" name="standalone_no_apriltag_table">
<xacro:arg name="x" default="0"/>
<xacro:arg name="y" default="0"/>
<xacro:arg name="height" default="0"/>
<!-- 定义参数 -->
<xacro:property name="table_height" value="$(arg height)" /> <!-- 桌子高度参数 -->
<xacro:property name="table_thickness" value="0.04" /> <!-- 桌面厚度 -->
<xacro:property name="leg_radius" value="0.02" /> <!-- 桌腿半径 -->
<!-- 第一个桌子位置参数 -->
<xacro:property name="table1_x" value="$(arg x)" />
<xacro:property name="table1_y" value="$(arg y)" />
<xacro:property name="table1_z" value="${table_height}" />
<!-- 立方体位置参数/参数相对于桌子来说 -->
<xacro:property name="cube_x" value="0.0" />
<xacro:property name="cube_y" value="0.0" />
<xacro:property name="cube_z" value="${table_thickness/2 + 0.05}" />
<!-- 引入apriltag -->
<xacro:include filename="$(find gazebo_world_manager)/scene/grasp-box/models/apriltag/urdf/apriltag.xacro"/>
<!-- 添加一个世界链接作为根链接 -->
<link name="world"/>
<!-- 创建第一个桌子链接 -->
<link name="table1_link">
<visual>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
<material name="wood">
<color rgba="0.8 0.6 0.4 1.0"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.4 0.4 ${table_thickness}"/>
</geometry>
</collision>
<inertial>
<mass value="5.0"/>
<inertia ixx="0.1" ixy="0" ixz="0" iyy="0.1" iyz="0" izz="0.1"/>
</inertial>
</link>
<!-- 添加Gazebo物理属性 -->
<gazebo reference="table1_link">
<material>Gazebo/Wood</material>
<mu1>0.5</mu1>
<mu2>0.5</mu2>
<kp>1000000.0</kp>
<kd>100.0</kd>
<minDepth>0.001</minDepth>
<maxVel>1.0</maxVel>
<maxContacts>20</maxContacts>
</gazebo>
<!-- 将世界链接与第一个桌子连接 -->
<joint name="world_to_table1_joint" type="fixed">
<parent link="world"/>
<child link="table1_link"/>
<origin xyz="${table1_x} ${table1_y} ${table1_z}" rpy="0.0 0.0 1.5707963267948966"/>
</joint>
<!-- 创建第一个桌子的四条桌腿 -->
<xacro:macro name="table_leg" params="name x y height">
<link name="${name}">
<visual>
<geometry>
<cylinder radius="${leg_radius}" length="${height}"/>
</geometry>
<material name="wood">
<color rgba="0.7 0.5 0.3 1.0"/>
</material>
</visual>
<collision>
<geometry>
<cylinder radius="${leg_radius}" length="${height}"/>
</geometry>
</collision>
<inertial>
<mass value="0.5"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.001"/>
</inertial>
</link>
<gazebo reference="${name}">
<material>Gazebo/Wood</material>
<mu1>0.5</mu1>
<mu2>0.5</mu2>
</gazebo>
</xacro:macro>
<!-- 创建第一个桌子的桌腿 -->
<xacro:table_leg name="table1_leg1" x="0.15" y="0.15" height="${table_height}"/>
<xacro:table_leg name="table1_leg2" x="-0.15" y="0.15" height="${table_height}"/>
<xacro:table_leg name="table1_leg3" x="0.15" y="-0.15" height="${table_height}"/>
<xacro:table_leg name="table1_leg4" x="-0.15" y="-0.15" height="${table_height}"/>
<!-- 连接第一个桌子的桌腿 -->
<joint name="table1_to_leg1_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg1"/>
<origin xyz="0.15 0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table1_to_leg2_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg2"/>
<origin xyz="-0.15 0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table1_to_leg3_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg3"/>
<origin xyz="0.15 -0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
<joint name="table1_to_leg4_joint" type="fixed">
<parent link="table1_link"/>
<child link="table1_leg4"/>
<origin xyz="-0.15 -0.15 ${-table_height/2}" rpy="0 0 0"/>
</joint>
</robot>

View File

View File

@ -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)

16
scene_plugin.py Normal file
View File

@ -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()