ROS1 noetic 中将 Unitree G1 基于 Gazebo/RViz 关节联动【使用一个launch文件启动】

news/2026/1/18 15:43:22/文章来源:https://www.cnblogs.com/zylyehuo/p/19498596

博客地址:https://www.cnblogs.com/zylyehuo/

Unitree G1 模型文件下载地址(挑选自己需要的部分,本教程基于 g1_29dof.urdf (以及 .xml 和 meshes 文件夹))

有核心的 URDF 文件和 Meshes (STL 网格文件)

image

效果预览

image

工作空间结构

image

主要文件

display_and_gazebo.launch

<?xml version="1.0" encoding="UTF-8"?>
<launch><!-- 加载机器人URDF模型参数 --><param name="robot_description" textfile="$(find g1_description)/urdf/g1_29dof.urdf" /><!-- TF静态变换 --><node pkg="tf" type="static_transform_publisher" name="world_to_map" args="0 0 0  0 0 0 1  world map 10"/><!-- base_link和pelvis重合 - 静态 --><node pkg="tf" type="static_transform_publisher" name="base_link2pelvis" args="0.0  0.0  0.0   0.0 0.0 0.0 1  base_link pelvis 100" /><!-- 移除静态的map2base_link,改为动态TF --><node pkg="tf" type="static_transform_publisher" name="imu_in_torso2body_imu" args="0.0  0.0  0.0   0.0 0.0 0.0 1  imu_in_torso body_imu 100" /><!-- 机器人状态发布器 --><node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" /><!-- LinkStates到JointState的桥接,同时发布动态TF --><node name="link_states_bridge" pkg="g1_description" type="link_states_bridge.py" output="screen" /><!-- RViz --><node name="rviz" pkg="rviz" type="rviz" respawn="false" output="screen" /><!-- ============ Gazebo配置 ============ --><!-- 启动Gazebo --><include file="$(find gazebo_ros)/launch/empty_world.launch"><arg name="paused" value="false"/><arg name="use_sim_time" value="true"/><arg name="gui" value="true"/><arg name="headless" value="false"/></include><!-- 将机器人模型生成到Gazebo中 --><node name="spawn_urdf" pkg="gazebo_ros" type="spawn_model" args="-param robot_description -urdf -z 0.79 -model g1_robot" output="screen" /></launch>
#!/usr/bin/env python3import rospy
import math
from gazebo_msgs.msg import LinkStates
from sensor_msgs.msg import JointState
import numpy as np
from scipy.spatial.transform import Rotation
import threading
import tf
from geometry_msgs.msg import TransformStampedclass LinkStatesToJointState:def __init__(self):rospy.init_node('link_states_to_joint_state')# 订阅Gazebo的链接状态self.link_states_sub = rospy.Subscriber('/gazebo/link_states', LinkStates, self.link_states_callback, queue_size=1)# 发布joint_statesself.joint_states_pub = rospy.Publisher('/joint_states', JointState, queue_size=1)# 发布TF变换self.tf_broadcaster = tf.TransformBroadcaster()# 所有关节及其parent/child链接映射self.joints_info = {'left_hip_pitch_joint': ('pelvis', 'left_hip_pitch_link', [0, 1, 0]),'left_hip_roll_joint': ('left_hip_pitch_link', 'left_hip_roll_link', [1, 0, 0]),'left_hip_yaw_joint': ('left_hip_roll_link', 'left_hip_yaw_link', [0, 0, 1]),'left_knee_joint': ('left_hip_yaw_link', 'left_knee_link', [0, 1, 0]),'left_ankle_pitch_joint': ('left_knee_link', 'left_ankle_pitch_link', [0, 1, 0]),'left_ankle_roll_joint': ('left_ankle_pitch_link', 'left_ankle_roll_link', [1, 0, 0]),'right_hip_pitch_joint': ('pelvis', 'right_hip_pitch_link', [0, 1, 0]),'right_hip_roll_joint': ('right_hip_pitch_link', 'right_hip_roll_link', [1, 0, 0]),'right_hip_yaw_joint': ('right_hip_roll_link', 'right_hip_yaw_link', [0, 0, 1]),'right_knee_joint': ('right_hip_yaw_link', 'right_knee_link', [0, 1, 0]),'right_ankle_pitch_joint': ('right_knee_link', 'right_ankle_pitch_link', [0, 1, 0]),'right_ankle_roll_joint': ('right_ankle_pitch_link', 'right_ankle_roll_link', [1, 0, 0]),'waist_yaw_joint': ('pelvis', 'waist_yaw_link', [0, 0, 1]),'waist_roll_joint': ('waist_yaw_link', 'waist_roll_link', [1, 0, 0]),'waist_pitch_joint': ('waist_roll_link', 'torso_link', [0, 1, 0]),'left_shoulder_pitch_joint': ('torso_link', 'left_shoulder_pitch_link', [0, 1, 0]),'left_shoulder_roll_joint': ('left_shoulder_pitch_link', 'left_shoulder_roll_link', [1, 0, 0]),'left_shoulder_yaw_joint': ('left_shoulder_roll_link', 'left_shoulder_yaw_link', [0, 0, 1]),'left_elbow_joint': ('left_shoulder_yaw_link', 'left_elbow_link', [0, 1, 0]),'left_wrist_roll_joint': ('left_elbow_link', 'left_wrist_roll_link', [1, 0, 0]),'left_wrist_pitch_joint': ('left_wrist_roll_link', 'left_wrist_pitch_link', [0, 1, 0]),'left_wrist_yaw_joint': ('left_wrist_pitch_link', 'left_wrist_yaw_link', [0, 0, 1]),'right_shoulder_pitch_joint': ('torso_link', 'right_shoulder_pitch_link', [0, 1, 0]),'right_shoulder_roll_joint': ('right_shoulder_pitch_link', 'right_shoulder_roll_link', [1, 0, 0]),'right_shoulder_yaw_joint': ('right_shoulder_roll_link', 'right_shoulder_yaw_link', [0, 0, 1]),'right_elbow_joint': ('right_shoulder_yaw_link', 'right_elbow_link', [0, 1, 0]),'right_wrist_roll_joint': ('right_elbow_link', 'right_wrist_roll_link', [1, 0, 0]),'right_wrist_pitch_joint': ('right_wrist_roll_link', 'right_wrist_pitch_link', [0, 1, 0]),'right_wrist_yaw_joint': ('right_wrist_pitch_link', 'right_wrist_yaw_link', [0, 0, 1]),}self.last_msg = Noneself.lock = threading.Lock()self.initial_pelvis_z = None  # 初始pelvis高度def link_states_callback(self, msg):with self.lock:self.last_msg = msgself.publish_joint_states(msg)self.publish_dynamic_tf(msg)def get_link_index(self, link_name, msg):"""获取链接在LinkStates中的索引"""full_name = f'g1_robot::{link_name}'try:return msg.name.index(full_name)except ValueError:return -1def get_relative_rotation(self, parent_pose, child_pose):"""计算从parent到child的相对旋转(四元数)"""# parent和child都是Pose消息,包含position和orientation# 计算相对四元数:q_rel = q_parent^-1 * q_childp_quat = [parent_pose.orientation.x, parent_pose.orientation.y, parent_pose.orientation.z, parent_pose.orientation.w]c_quat = [child_pose.orientation.x, child_pose.orientation.y, child_pose.orientation.z, child_pose.orientation.w]p_rot = Rotation.from_quat(p_quat)c_rot = Rotation.from_quat(c_quat)# 相对旋转rel_rot = p_rot.inv() * c_rotreturn rel_rotdef rotation_to_angle_around_axis(self, rotation, axis):"""从旋转矩阵中提取绕指定轴的旋转角度"""# 使用Rodrigues公式的逆angle = rotation.magnitude()if abs(angle) < 1e-6:return 0.0# 获取旋转轴rotvec = rotation.as_rotvec()rot_axis = rotvec / angle if angle > 1e-6 else [0, 0, 1]# 检查旋转轴是否与指定轴一致axis_norm = np.array(axis) / np.linalg.norm(axis)if np.dot(rot_axis, axis_norm) > 0.9:return angleelif np.dot(rot_axis, axis_norm) < -0.9:return -angleelse:# 使用欧拉角方法euler = rotation.as_euler('xyz')if axis == [1, 0, 0]:return euler[0]elif axis == [0, 1, 0]:return euler[1]elif axis == [0, 0, 1]:return euler[2]else:return 0.0def publish_joint_states(self, msg):"""发布joint_states消息"""joint_state = JointState()joint_state.header.stamp = rospy.Time.now()joint_state.name = list(self.joints_info.keys())joint_state.position = []joint_state.velocity = [0.0] * len(joint_state.name)joint_state.effort = [0.0] * len(joint_state.name)# 计算每个关节的角度for joint_name, (parent_name, child_name, axis) in self.joints_info.items():parent_idx = self.get_link_index(parent_name, msg)child_idx = self.get_link_index(child_name, msg)if parent_idx < 0 or child_idx < 0:joint_state.position.append(0.0)continue# 获取相对旋转rel_rot = self.get_relative_rotation(msg.pose[parent_idx], msg.pose[child_idx])# 提取绕指定轴的角度angle = self.rotation_to_angle_around_axis(rel_rot, axis)joint_state.position.append(angle)# 发布self.joint_states_pub.publish(joint_state)def publish_dynamic_tf(self, msg):"""发布动态TF:map → base_link(base_link和pelvis重合,跟随Gazebo中pelvis的实际位置和旋转)"""pelvis_idx = self.get_link_index('pelvis', msg)if pelvis_idx < 0:returnpelvis_pose = msg.pose[pelvis_idx]# map → base_link:base_link和pelvis重合,位置和旋转都来自Gazebo中的pelvisself.tf_broadcaster.sendTransform(translation=(pelvis_pose.position.x, pelvis_pose.position.y, pelvis_pose.position.z),rotation=(pelvis_pose.orientation.x, pelvis_pose.orientation.y, pelvis_pose.orientation.z, pelvis_pose.orientation.w),time=rospy.Time.now(),child='base_link',parent='map')if __name__ == '__main__':try:node = LinkStatesToJointState()rospy.spin()except rospy.ROSInterruptException:pass

运行步骤

cd ~/g1_test_ws
catkin_make
source ./devel/setup.bash
roslaunch g1_description display_and_gazebo.launch

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1178603.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

写论文软件哪个好?实测揭秘!宏智树 AI 凭 “真研究” 实力出圈

毕业季的论文焦虑&#xff0c;几乎是每一位学子的必经之路&#xff1a;选题太泛被导师打回、文献堆砌逻辑混乱、数据分析无从下手、查重率居高不下、AI 生成痕迹被系统标红…… 面对五花八门的论文写作工具&#xff0c;“写论文软件哪个好” 成了无数学子的灵魂拷问。 作为深耕…

什么是 CMS 站群系统?以及它在百度 SEO 中的真实作用

在做网站矩阵、内容覆盖或 SEO 项目时&#xff0c;很多人都会听到一个词——CMS 站群系统。 但这个概念在实际使用中&#xff0c;经常被误解成“多个 CMS 拼在一起”&#xff0c;甚至被简单等同于泛目录工具&#xff0c;这种理解并不准确。本文从实际使用和搜索引擎角度&#x…

5 款 AI 写论文哪个好?实测宏智树 AI:毕业论文的全能型学术助手

毕业季的论文赛道上&#xff0c;“5 款 AI 写论文哪个好” 的灵魂拷问&#xff0c;总能在各大高校的互助群里刷屏。作为深耕论文写作科普的测评博主&#xff0c;我选取计算机、汉语言文学、临床医学等 5 个专业的毕业论文为样本&#xff0c;对宏智树 AI、万能小 in、DeepSeek、…

2026年周边优秀的汽车维修经销商怎么选择,客车轮胎/汽车保养/货车轮胎/轿车保养/汽车检测,汽车维修批发哪个好 - 品牌推荐师

行业洞察:汽车维修市场技术升级与服务质量双驱动趋势 随着汽车保有量持续攀升,消费者对维修服务的技术专业性、服务响应效率及售后保障提出更高要求。据中国汽车流通协会数据显示,2025年国内汽车后市场规模突破1.8万…

CMS站群系统在实际项目中解决的,往往不是“建站问题”

在很多讨论中&#xff0c;cms站群系统 常常被理解为“为了多建几个站”。 但在实际项目中&#xff0c;它真正解决的&#xff0c;往往并不是建站本身&#xff0c;而是后期无法规模化的问题。 这也是为什么&#xff0c;只有在项目做到一定阶段之后&#xff0c;才会真正意识到 cm…

变量的使用

变量的使用 public class Demo03Var{public static void main(string[] args){//byetbyet num1 = 100;System.out.println(num1);//shortbyet num2 = 1000;num2 = 1001;System.out.println(num2);//int 整数的默认类…

2026最新最全Java 面试题大全(整理版)2000+ 面试题附答案详解

很多 Java 工程师的技术不错&#xff0c;但是一面试就头疼&#xff0c;10 次面试 9 次都是被刷&#xff0c;过的那次还是去了家不知名的小公司。 问题就在于&#xff1a;面试有技巧&#xff0c;而你不会把自己的能力表达给面试官。 应届生&#xff1a;你该如何准备简历&#…

2026年市场有名的包衣机定做厂家怎么选择,高效湿法制粒机/离心造粒包衣机/微孔高效包衣机,包衣机供货商口碑推荐 - 品牌推荐师

随着全球制药、保健品及食品工业对产品质量、生产效率和合规性要求的不断提升,高效、稳定、智能化的包衣设备已成为固体制剂生产线的核心装备之一。面对市场上琳琅满目的包衣机品牌与型号,采购方在选择定制化供应商时…

全网最全9个AI论文工具,专科生轻松搞定论文写作!

全网最全9个AI论文工具&#xff0c;专科生轻松搞定论文写作&#xff01; AI 工具如何助力论文写作&#xff1f; 在当今学术环境中&#xff0c;AI 工具正逐渐成为学生和科研人员的重要助手。尤其是在论文写作过程中&#xff0c;AI 技术不仅能够有效降低 AIGC&#xff08;人工智能…

租车新选择:2026年口碑爆棚的租车公司推荐,租赁/自驾租车/租车/会展包车/包车/企业租车/跨境包车,租车公司选哪家 - 品牌推荐师

评测背景 随着出行需求多元化及消费升级,租车行业已成为连接个人出行、商务活动与旅游服务的重要枢纽。2026年,消费者对租车服务的核心诉求已从“基础用车”转向“品质、安全、效率与个性化”的综合体验。为此,第三…

web入门91-100

web91 分析代码使用换行符(%0a)绕过 ?cmd=abc%0aphpweb92 分析代码需要传入一个不等于4476的数字,但是取整又要等于4476,所以直接传一个小数4476.1web93 分析代码发现只是多禁了一些字母,继续用上一关的payloadweb…

Splay/LCT

Splay 与 lctSplay Splay 我们考虑在一颗 BST,用旋转操作将某个元素先提到根,使其仍是一颗 BST,这样的操作就是 \(s(x,0)\)。 void splay(int x,int target){while(fa[x]!=target){int f=fa[x],gf=fa[f];if(gf==tar…

基于可视分析技术的深度学习模型构建与优化【附源码】

✨ 本团队擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导&#xff0c;毕业论文、期刊论文经验交流。 ✅ 专业定制毕设、代码 ✅ 成品或定制&#xff0c;查看文章底部微信二维码 &#xff08;1&#xff09;多层级可视化的深度学习模型构建体系 面对深度学习…

移除链表元素-day03

203. 移除链表元素 题目链接:https://leetcode.cn/problems/remove-linked-list-elements/description/ 思路:在原来的链表中新增一个节点,这个节点作为头结点(好处,不用单独处理原链表的头结点) 代码: public …

Java Web 核心全解析 - 实践

Java Web 核心全解析 - 实践2026-01-18 15:27 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important;…

制图不用愁!CAXA 电子图板 2025 最新版本国标图库一键调用

CAXA 电子图板 2025 是国产自主的二维 CAD 软件,贴合国标、高效易用、兼容性强,主打机械制图,是替代海外 CAD 的高性价比选择。核心亮点:自主双内核:支持 EXB 原生格式和 DWG 格式双向转换,数据互通无壁垒,版权…

基于深度学习的信道编码识别与扰码分析【附完整代码】

✨ 本团队擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导&#xff0c;毕业论文、期刊论文经验交流。✅ 专业定制毕设、代码✅ 成品或定制&#xff0c;查看文章底部微信二维码&#xff08;1&#xff09;基于Inception结构的信道编码盲识别模型 在非合作通信…

2026年知名的石墨烯涂料设计推荐排行,光固化保护套/石墨烯涂料/无溶剂环氧涂料,石墨烯涂料源头厂家推荐排行榜 - 品牌推荐师

近年来,随着工业防腐需求升级与环保政策趋严,石墨烯涂料凭借其优异的导电性、耐腐蚀性及环保特性,成为防腐材料领域的“新宠”。据行业数据预测,2026年国内石墨烯涂料市场规模将突破百亿元,应用场景从传统管道、桥…

基于多特征融合的深度学习高速铁路预售期购票量预测

✨ 本团队擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导&#xff0c;毕业论文、期刊论文经验交流。✅ 专业定制毕设、代码✅ 成品或定制&#xff0c;查看文章底部微信二维码&#xff08;1&#xff09;高铁客流数据的时空特征解析与工程化处理 高铁旅客购票…

基于深度学习实现透过动态厚散射介质成像

✨ 本团队擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导&#xff0c;毕业论文、期刊论文经验交流。✅ 专业定制毕设、代码✅ 成品或定制&#xff0c;查看文章底部微信二维码&#xff08;1&#xff09;动态厚散射介质传播模型的建立与散斑数据生成透过散射…