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

【代码讲解】北通手柄遥控 + Mujoco 仿真 SO-ARM100 机械臂末端位姿

上期视频展示了使用北通手柄(型号:宙斯精英版T6),获取摇杆以及按键的信息,手柄输出末端控制量x,y,z,夹爪开合控制量,结合早期视频《Pinocchio 结合 CasADi 进行 IK 逆运动学及 Mujoco 仿真》中的IK得到关节控制量,在仿真中可以很流畅的控制SO-ARM100机械的末端运动。

本期中会涉及如下点,需要注意:

1. 在WSL2中手柄需要编译内核增加JOYSTICK选项

2. 北通手柄需要进入XBOX模式,北通模式在WSL2下需要额外增加驱动而且需要插线

3. 增加环境变量显式指定js0设备

【代码讲解】北通手柄遥控 + Mujoco 仿真 SO-ARM100 机械臂末端位姿

视频讲解链接:【代码讲解】北通手柄遥控 + Mujoco 仿真 SO-ARM100 机械臂末端位姿_哔哩哔哩_bilibili

完整代码仓库:https://github.com/LitchiCheng/mujoco-learning

xbox控制类

class XboxController:"""Xbox手柄控制器类,负责处理所有手柄输入"""def __init__(self):# 初始化位置参数self.x = 0.0self.y = -0.3self.z = 0.15# 位置限制self.x_min, self.x_max = -0.3, 0.3self.y_min, self.y_max = -0.4, 0.0self.z_min, self.z_max = 0.05, 0.3# 控制灵敏度self.sensitivity = 0.005# 死区阈值(过滤摇杆中心微小漂移)self.deadzone = 0.1# 存储dof[5]的目标值self.dof5_target = None# 跟踪按钮状态,避免重复触发self.button1_pressed = Falseself.button2_pressed = False# 初始化手柄self.controller = self.init_controller()def init_controller(self):"""初始化Xbox手柄(通过pygame访问js设备)"""# 初始化pygame和游戏杆模块pygame.init()pygame.joystick.init()if pygame.joystick.get_count() == 0:print("未检测到任何游戏杆设备")return None# 对应/dev/input/js0joystick = pygame.joystick.Joystick(0)joystick.init()print(f"检测到手柄: {joystick.get_name()}")print(f"按钮数量: {joystick.get_numbuttons()}")return joystickdef is_connected(self):"""检查手柄是否连接"""return self.controller is not Nonedef handle_input(self, arm):"""处理手柄输入并更新控制参数"""if not self.is_connected():return# 处理pygame事件(必须调用,否则无法更新轴值和按钮状态)pygame.event.pump()# 读取左摇杆X轴(0号轴)x_axis = self.controller.get_axis(1)# 应用死区过滤if abs(x_axis) < self.deadzone:x_axis = 0.0# 读取左摇杆Y轴(1号轴)y_axis = self.controller.get_axis(0)if abs(y_axis) < self.deadzone:y_axis = 0.0# 读取右摇杆Y轴(4号轴)z_axis = -self.controller.get_axis(4)if abs(z_axis) < self.deadzone:z_axis = 0.0# 根据轴值更新位置self.x = np.clip(self.x + x_axis * self.sensitivity, self.x_min, self.x_max)self.y = np.clip(self.y + y_axis * self.sensitivity, self.y_min, self.y_max)self.z = np.clip(self.z + z_axis * self.sensitivity, self.z_min, self.z_max)# 检测按钮1(假设是0号按钮,通常是A键)button1 = self.controller.get_button(0)if button1 and not self.button1_pressed:print("Button1 pressed - 设置dof[5]为满量程")# 设置dof[5]为满量程值self.dof5_target = arm.model.upperPositionLimit[5]self.button1_pressed = Trueelif not button1:self.button1_pressed = False# 检测按钮2(假设是1号按钮,通常是B键)button2 = self.controller.get_button(1)if button2 and not self.button2_pressed:print("Button2 pressed - 设置dof[5]为最小值")# 设置dof[5]为最小值self.dof5_target = arm.model.lowerPositionLimit[5]self.button2_pressed = Trueelif not button2:self.button2_pressed = Falsedef get_position_target(self):return self.x, self.y, self.zdef get_dof5_target(self):return self.dof5_targetdef cleanup(self):pygame.quit()

SO-ARM100 控制类

class RobotController(mujoco_viewer.CustomViewer):    def __init__(self, scene_path, arm_path, controller):super().__init__(scene_path, distance=1.5, azimuth=135, elevation=-30)self.scene_path = scene_pathself.arm_path = arm_pathself.controller = controller# 初始化逆运动学self.arm = casadi_ik.Kinematics("Wrist_Roll")self.arm.buildFromMJCF(arm_path)self.last_dof = Nonedef runBefore(self):passdef runFunc(self):"""主循环中执行的函数"""# 处理控制器输入self.controller.handle_input(self.arm)# 获取目标位置x, y, z = self.controller.get_position_target()print(f"当前位置: x={x:.3f}, y={y:.3f}, z={z:.3f}")# 构建变换矩阵(保持末端执行器姿态不变)tf = self.build_transform_simple(x, y, z, np.pi / 4, 0, 0)# 求解逆运动学self.dof, info = self.arm.ik(tf, current_arm_motor_q=self.last_dof)self.last_dof = self.dofdof5_target = self.controller.get_dof5_target()if dof5_target is not None:self.dof[5] = dof5_targetself.data.qpos[:6] = self.dof[:6]mujoco.mj_step(self.model, self.data)time.sleep(0.01)def build_transform_simple(self, x, y, z, roll, pitch, yaw):cr, sr = np.cos(roll), np.sin(roll)cp, sp = np.cos(pitch), np.sin(pitch)cy, sy = np.cos(yaw), np.sin(yaw)return np.array([[cy*cp, cy*sp*sr - sy*cr, cy*sp*cr + sy*sr, x],[sy*cp, sy*sp*sr + cy*cr, sy*sp*cr - cy*sr, y],[-sp,   cp*sr,            cp*cr,            z],[0,     0,                0,                1]])


文章转载自:

http://uKxoA6ss.kcfnp.cn
http://RMEIu47u.kcfnp.cn
http://RWRDH5a5.kcfnp.cn
http://gLCoXmrz.kcfnp.cn
http://4emjCjuV.kcfnp.cn
http://zXBwI0No.kcfnp.cn
http://YlrmWFE6.kcfnp.cn
http://ZVrEK9KD.kcfnp.cn
http://pkLXnBSt.kcfnp.cn
http://mAojMZgZ.kcfnp.cn
http://QAjw4cNY.kcfnp.cn
http://pV8sA1pP.kcfnp.cn
http://zjL8ZfnJ.kcfnp.cn
http://jDs0efuY.kcfnp.cn
http://a5QFhG2J.kcfnp.cn
http://BOZmLrVU.kcfnp.cn
http://gXxtJpKd.kcfnp.cn
http://uEGRyG6s.kcfnp.cn
http://LWO7m0dV.kcfnp.cn
http://suUsYWuZ.kcfnp.cn
http://M5eNvFQ3.kcfnp.cn
http://MbCsenyy.kcfnp.cn
http://4FboLgEm.kcfnp.cn
http://5QB8WT2i.kcfnp.cn
http://yk9i2erp.kcfnp.cn
http://DamaO7Rk.kcfnp.cn
http://Nxzh1MOb.kcfnp.cn
http://8y3IGwF0.kcfnp.cn
http://WdzsUJ41.kcfnp.cn
http://zliHO5oa.kcfnp.cn
http://www.dtcms.com/a/371362.html

相关文章:

  • ARM 体系结构
  • 云平台面试内容(一)
  • React Hooks 钩子
  • js逆向之JSEncrypt的加密
  • Balabolka:免费高效的文字转语音软件
  • 第3天-Jenkins详解-3
  • Linux内核进程管理子系统有什么第四十三回 —— 进程主结构详解(39)
  • Apache 2.0 开源协议详解:自由、责任与商业化的完美平衡-优雅草卓伊凡
  • 【iOS】多界面传值
  • 【C++】简单介绍lambda表达式
  • uv 包管理器:优势解析与使用指南
  • Android studio的adb和终端的adb互相抢占端口
  • 同类软件对比(四):Jupyter vs PyCharm vs VS Code:Python开发工具终极选择指南
  • 【MySQL】数据库的基本操作
  • PaddlePaddle——飞桨深度学习实现手写数字识别任务
  • Docker Compose 运行 Milvus (Mac) 并与 python 连接测试
  • 03-Redis 安装指南:从版本选择到多系统部署(Windows+macOS+Linux)
  • 路由策略实验配置
  • 【高并发内存池】五、页缓存的设计
  • PHP - OPcache 字节码缓存 - 学习/实践
  • redis学习——七
  • nginx反向代理不转发静态文件的解决办法
  • Webassemly和声明宏的联合使用
  • 选拔考试复现
  • 【Linux】 进程控制
  • C++ 连接 Redis:redis-plus-plus 安装与使用入门指南
  • K8s访问控制(二)
  • PerfTest:轻量高性能压测工具,兼容 HTTP/1/2/3、WebSocket,并带实时监控
  • 【Linux基础】fdisk命令详解:从入门到精通的磁盘分区管理完全指南
  • 【从零开始学习Redis】秒杀优化——阻塞队列、消息队列实现异步秒杀