当前位置: 首页 > news >正文

ROS2下利用遥控手柄控制瑞尔曼RM65-B机器人

一、安装启动joy

sudo apt install ros-humble-joy
ros2 run joy joy_node

二、确定键位

ros2 topic echo /joy --once

默认axis值:
axes:

  • -0.0
  • -0.0
  • -0.0
  • -0.0
  • 1.0
  • 1.0
  • 0.0
  • 0.0

测试得出遥感键位对应值,是浮点数:
左遥感上极限: axes[1]=1.0
左遥感下极限: axes[1]=-1.0
左遥感左极限: axes[0]=1.0
左遥感右极限: axes[0]=-1.0

左侧十字按键上:axes[7]=1.0
左侧十字按键上:axes[7]=-1.0

右遥感上极限: axes[3]=1.0
右遥感下极限: axes[3]=-1.0
右遥感左极限: axes[2]=1.0
右遥感右极限: axes[2]=-1.0

右侧X按钮:buttons[3]=1
右侧B按钮:buttons[1]=1

三、运行瑞尔曼节点

source ./install/setup.sh
export LD_LIBRARY_PATH=/home/zc9527/ros2_joy_rm65_ws/src/ros2_rm_robot/rm_driver/lib/linux_x86_c++_v1.1.1:$LD_LIBRARY_PATHros2 launch rm_driver rm_65_driver.launch.py

查看所有话题:

ros2 topic list

查看话题属性:

ros2 topic info -v /rm_driver/movel_cmd

查看消息定义:

source ./install/setup.sh
ros2 interface show rm_ros_interfaces/msg/Movel

定义如下:
geometry_msgs/Pose pose
Point position
float64 x
float64 y
float64 z
Quaternion orientation
float64 x 0
float64 y 0
float64 z 0
float64 w 1
uint8 speed
uint8 trajectory_connect #0 代表立即规划,1 代表和下一条轨迹一起规划,当为 1 时,轨迹不会立即执行
bool block

一句话测试:

ros2 topic pub /rm_driver/movel_cmd rm_ros_interfaces/msg/Movel "{pose: {position: {x: 0.3, y: 0.0, z: 0.2}, orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}}, speed: 50, trajectory_connect: 0, block: true}" -1

四、新建包

ros2 pkg create --build-type ament_python joystick_movel_control --dependencies rclpy rm_ros_interfaces
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Joy
from rm_ros_interfaces.msg import Movel
from geometry_msgs.msg import Pose
from std_msgs.msg import Empty
from tf_transformations import quaternion_from_eulerclass JoystickMovelControl(Node):def __init__(self):super().__init__('joystick_movel_control')# 订阅手柄self.subscription = self.create_subscription(Joy, '/joy', self.joy_callback, 10)# 发布绝对末端位姿self.publisher = self.create_publisher(Movel, '/rm_driver/movel_cmd', 10)# 订阅末端位姿反馈self.sub_fb = self.create_subscription(Pose, '/rm_driver/udp_arm_position', self.feedback_callback, 10)# 停止命令self.stop_pub = self.create_publisher(Empty, '/rm_driver/move_stop_cmd', 10)# 当前末端位姿self.curr_pose = Noneself.initialized = False# 步长self.step_pos = 10.005  # XY 增量(m)self.step_z = 10.005    # Z 增量(m)self.step_rot = 10.01   # 角度增量(rad)self.step_yaw = 10.02   # Yaw增量(rad)def feedback_callback(self, msg: Pose):self.curr_pose = msgif not self.initialized:self.initialized = Trueself.get_logger().info(f'初始末端位姿: x={msg.position.x:.3f}, y={msg.position.y:.3f}, z={msg.position.z:.3f}, 'f'orientation=({msg.orientation.x:.3f},{msg.orientation.y:.3f},{msg.orientation.z:.3f},{msg.orientation.w:.3f})')def stop_arm(self):stop_msg = Empty()self.stop_pub.publish(stop_msg)self.get_logger().info('摇杆归零,机械臂停止!')@staticmethoddef quaternion_multiply(x1, y1, z1, w1, x2, y2, z2, w2):"""四元数乘法"""w = w1*w2 - x1*x2 - y1*y2 - z1*z2x = w1*x2 + x1*w2 + y1*z2 - z1*y2y = w1*y2 - x1*z2 + y1*w2 + z1*x2z = w1*z2 + x1*y2 - y1*x2 + z1*w2return x, y, z, wdef joy_callback(self, msg: Joy):if not self.initialized or self.curr_pose is None:return# XY摇杆归零且Z按钮归零且右摇杆归零且Yaw按钮未按,立即停止if all(abs(a) < 1e-3 for a in msg.axes[:2]) and msg.axes[7] == 0 \and all(abs(a) < 1e-3 for a in msg.axes[2:4]) \and not (msg.buttons[3] or msg.buttons[1]):self.stop_arm()return# XY 绝对位姿new_x = self.curr_pose.position.x - msg.axes[1] * self.step_posnew_y = self.curr_pose.position.y - msg.axes[0] * self.step_pos# Z 按钮控制new_z = self.curr_pose.position.zif msg.axes[7] == 1:new_z += self.step_zelif msg.axes[7] == -1:new_z -= self.step_z# 姿态增量roll_inc = msg.axes[2] * self.step_rot   # 右摇杆上下控制 Rollpitch_inc = msg.axes[3] * self.step_rot  # 右摇杆左右控制 Pitchyaw_inc = 0.0if msg.buttons[3]:  # 按钮3 顺时针旋转yaw_inc += self.step_yawif msg.buttons[1]:  # 按钮1 逆时针旋转yaw_inc -= self.step_yaw                             # 如果需要Yaw可用其它轴q_inc = quaternion_from_euler(roll_inc, pitch_inc, yaw_inc)# 当前姿态四元数qx, qy, qz, qw = self.curr_pose.orientation.x, self.curr_pose.orientation.y, \self.curr_pose.orientation.z, self.curr_pose.orientation.wqx, qy, qz, qw = self.quaternion_multiply(qx, qy, qz, qw, *q_inc)# 发布 Movel 消息movel = Movel()movel.pose.position.x = new_xmovel.pose.position.y = new_ymovel.pose.position.z = new_zmovel.pose.orientation.x = qxmovel.pose.orientation.y = qymovel.pose.orientation.z = qzmovel.pose.orientation.w = qwmovel.speed = 40movel.trajectory_connect = Falsemovel.block = Falseself.publisher.publish(movel)self.get_logger().info(f'发布 Pose: x={new_x:.3f}, y={new_y:.3f}, z={new_z:.3f}, roll_inc={roll_inc:.3f}, pitch_inc={pitch_inc:.3f}')def main(args=None):rclpy.init(args=args)node = JoystickMovelControl()rclpy.spin(node)node.destroy_node()rclpy.shutdown()if __name__ == "__main__":main()
http://www.dtcms.com/a/426675.html

相关文章:

  • SOC(安全运营中心)
  • 济南网站建设山东聚搜网推荐传媒公司招聘
  • C++ STL 深度解析:容器、迭代器与算法的协同作战
  • SPI主控的CS引发的读不到设备寄存器
  • 数据标注、Label Studio
  • 央链知播受权发布:图说《“可信资产 IPO + 数链金融 RWA” 链改 2.0 六方共识》
  • 【Proteus8.17仿真】 STM32仿真 0.96OLED 屏幕显示ds1302实时时间
  • 佛山做营销型网站建设wordpress修改域名后无法登陆
  • mysql数据库学习之常用函数(五)
  • 避坑实战!京东商品详情接口开发指南:分页优化、多规格解析与数据完整性保障
  • win10(十二)Nuitka打包程序
  • 【Rust GUI开发入门】编写一个本地音乐播放器(11. 支持动态明暗主题切换)
  • 自己做网站帮公司出认证证书违法吗上海定制网站建设公司
  • [论文阅读] AI + 软件工程(Debug)| 告别 “猜 bug”:TreeMind 用 LLM+MCTS 破解 Android 不完整报告复现难题
  • ESP32 + MCP over MQTT:通过大模型控制智能硬件设备
  • 五大关系数据库(sqlserver、mysql、oracle、pgsql、sqlite)的对象名称和转义字符
  • 央企云原生PaaS建设方案及案例集锦
  • 使用Django从零开始构建一个个人博客系统
  • 工业互联网的云原生转型路径
  • 做网站需要哪些素材建筑工程 技术支持 东莞网站建设
  • Spring Boot 缓存技术
  • AI应用生成平台:数据库、缓存与存储
  • J2Cache 多级缓存配置与使用
  • 【JAVA】【BUG】经常出现的典型 bug 及解决办法
  • 做网站怎么存放视频哪个公司的室内设计公司
  • GitHub 热榜项目 - 日榜(2025-09-30)
  • Microsoft Fabric - 尝试一下Workspace中的Deployment pipeline
  • 区块链论文速读 CCF A--WWW 2025(6)
  • Bug——PaddleX人脸识别报错:Process finished with exit code -1073741819 (0xC0000005)
  • SSM基于的宠物领养管理系统ugssn(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。