LitchiCheng

  • 2025-04-02
  • 回复了主题帖: MuJoCo 机械臂物体碰撞、接触检测方式一

    蓝雨夜 发表于 2025-4-2 08:37 下次有没有安排从硬件慢慢搭建,选型,到调试的啊  随性做,哈哈哈,不是做课程

  • 回复了主题帖: MuJoCo 机械臂物体碰撞、接触检测方式一

    Jacktang 发表于 2025-4-2 07:42 机械臂抓取物体的场景中,或训练的过程中,还需要示教器吗 现在都是用遥操

  • 回复了主题帖: 《具身智能机器人系统》读后感,第三、四章

    jobszheng5 发表于 2025-4-1 15:15 赞同楼主的说法——端测部署大模型的可能性不大。 我觉得端侧首先是要完成执行器的功能。控制 ... 是的,可以跑小模型

  • 发表了主题帖: MuJoCo 机械臂物体碰撞、接触检测方式一

        视频讲解:MuJoCo 机械臂物体碰撞、接触检测方式一_哔哩哔哩_bilibili   仓库地址:GitHub - LitchiCheng/mujoco-learning 在机械臂抓取物体的场景中,或训练的过程中,较为重要的就是如何判断物体是否被抓住了,或者是否发生了碰撞。 但实际应用场景中,有很多方式可以判断,可以通过视觉识别,通过力传感器进行判断,那在MuJoCo中可以通过什么方式进行判断,今天分享一下其中的一种方式。 在 mjData.contact 数组,存储当前仿真步中所有活跃的接触点信息。每个接触点包含以下字段: geom1 / geom2:接触的两个几何体的ID dist:接触距离(负值表示穿透深度) pos:接触点的三维位置坐标 frame:接触点的局部坐标系(3x3矩阵,法线方向为第一行) friction:摩擦系数 solref / solimp:求解器参数 关键代码: # 遍历所有接触点 for i in range(data.ncon): contact = data.contact[i] # 获取几何体对应的body_id body1_id = model.geom_bodyid[contact.geom1] body2_id = model.geom_bodyid[contact.geom2] # 通过mj_id2name转换body_id为名称 body1_name = mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_BODY, body1_id) body2_name = mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_BODY, body2_id) print(f"接触点 {i}: 几何体 {contact.geom1} 名字 {body1_name} 和 {contact.geom2} 名字 {body2_name} 在位置 {contact.pos} 发生接触") 完整代码如下: import mujoco import numpy as np import glfw import mujoco.viewer from scipy.optimize import minimize import numpy as np import pinocchio from numpy.linalg import norm, solve def inverse_kinematics(current_q, target_dir, target_pos): urdf_filename = '/home/dar/MuJoCoBin/mujoco-learning/franka_panda_description/robots/panda_arm.urdf' # 从 URDF 文件构建机器人模型 model = pinocchio.buildModelFromUrdf(urdf_filename) # 为模型创建数据对象,用于存储计算过程中的中间结果 data = model.createData() # 指定要控制的关节 ID JOINT_ID = 7 # 定义期望的位姿,使用目标姿态的旋转矩阵和目标位置创建 SE3 对象 oMdes = pinocchio.SE3(target_dir, np.array(target_pos)) # 将当前关节角度赋值给变量 q,作为迭代的初始值 q = current_q # 定义收敛阈值,当误差小于该值时认为算法收敛 eps = 1e-4 # 定义最大迭代次数,防止算法陷入无限循环 IT_MAX = 1000 # 定义积分步长,用于更新关节角度 DT = 1e-2 # 定义阻尼因子,用于避免矩阵奇异 damp = 1e-12 # 初始化迭代次数为 0 i = 0 while True: # 进行正运动学计算,得到当前关节角度下机器人各关节的位置和姿态 pinocchio.forwardKinematics(model, data, q) # 计算目标位姿到当前位姿之间的变换 iMd = data.oMi[JOINT_ID].actInv(oMdes) # 通过李群对数映射将变换矩阵转换为 6 维误差向量(包含位置误差和方向误差),用于量化当前位姿与目标位姿的差异 err = pinocchio.log(iMd).vector # 判断误差是否小于收敛阈值,如果是则认为算法收敛 if norm(err) < eps: success = True break # 判断迭代次数是否超过最大迭代次数,如果是则认为算法未收敛 if i >= IT_MAX: success = False break # 计算当前关节角度下的雅可比矩阵,关节速度与末端速度的映射关系 J = pinocchio.computeJointJacobian(model, data, q, JOINT_ID) # 对雅可比矩阵进行变换,转换到李代数空间,以匹配误差向量的坐标系,同时取反以调整误差方向 J = -np.dot(pinocchio.Jlog6(iMd.inverse()), J) # 使用阻尼最小二乘法求解关节速度 v = -J.T.dot(solve(J.dot(J.T) + damp * np.eye(6), err)) # 根据关节速度更新关节角度 q = pinocchio.integrate(model, q, v * DT) # 每迭代 10 次打印一次当前的误差信息 if not i % 10: print(f"{i}: error = {err.T}") # 迭代次数加 1 i += 1 # 根据算法是否收敛输出相应的信息 if success: print("Convergence achieved!") else: print("\n" "Warning: the iterative algorithm has not reached convergence " "to the desired precision") # 打印最终的关节角度和误差向量 print(f"\nresult: {q.flatten().tolist()}") print(f"\nfinal error: {err.T}") # 返回最终的关节角度向量(以列表形式) return q.flatten().tolist() def limit_angle(angle): while angle > np.pi: angle -= 2 * np.pi while angle < -np.pi: angle += 2 * np.pi return angle model = mujoco.MjModel.from_xml_path('/home/dar/MuJoCoBin/mujoco_menagerie/franka_emika_panda/scene.xml') data = mujoco.MjData(model) class CustomViewer: def __init__(self, model, data): self.handle = mujoco.viewer.launch_passive(model, data) self.pos = 0.0001 # 找到末端执行器的 body id self.end_effector_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_BODY, 'left_finger') print(f"End effector ID: {self.end_effector_id}") if self.end_effector_id == -1: print("Warning: Could not find the end effector with the given name.") # 初始关节角度 self.initial_q = data.qpos[:7].copy() print(f"Initial joint positions: {self.initial_q}") theta = np.pi self.R_x = np.array([ [1, 0, 0], [0, np.cos(theta), -np.sin(theta)], [0, np.sin(theta), np.cos(theta)] ]) self.x = 0.3 self.new_q = self.initial_q def is_running(self): return self.handle.is_running() def sync(self): self.handle.sync() @property def cam(self): return self.handle.cam @property def viewport(self): return self.handle.viewport def run_loop(self): status = 0 while self.is_running(): mujoco.mj_forward(model, data) if status == 0: if self.x < 0.5: self.x += 0.01 new_q = inverse_kinematics(self.initial_q, self.R_x, [self.x, 0.0, 0.28]) else: status = 1 elif status == 1: data.ctrl[7] = 10.0 data.qpos[:7] = new_q # 遍历所有接触点 for i in range(data.ncon): contact = data.contact[i] # 获取几何体对应的body_id body1_id = model.geom_bodyid[contact.geom1] body2_id = model.geom_bodyid[contact.geom2] # 通过mj_id2name转换body_id为名称 body1_name = mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_BODY, body1_id) body2_name = mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_BODY, body2_id) print(f"接触点 {i}: 几何体 {contact.geom1} 名字 {body1_name} 和 {contact.geom2} 名字 {body2_name} 在位置 {contact.pos} 发生接触") mujoco.mj_step(model, data) self.sync() viewer = CustomViewer(model, data) viewer.cam.distance = 3 viewer.cam.azimuth = 0 viewer.cam.elevation = -30 viewer.run_loop() 演示代码,关节之间的碰撞,以及关节碰到地上,以及夹爪碰到长方体上     在Viewer中按C键,会显示碰撞的刚体          

  • 发表了日志: MuJoCo 机械臂物体碰撞、接触检测方式一

  • 2025-04-01
  • 发表了主题帖: 《具身智能机器人系统》读后感,第十到十三章

    第 10 章:加速机器人计算 实时性难题:机器人计算要实现实时性不容易,以前主要因为算力需求高(像 SLAM 算法处理图像数据、矩阵计算量超大),加上算法碎片化,不同算法计算模式差异大,很难用单一硬件加速,导致机器人常卡顿。 模块加速方法: 定位模块:物流机器人定位算法碎片化,通过硬件定制加速,比如针对定位中 6 自由度估计设计加速器,提升计算效率。 规划模块:路径规划要找最优路径避障,传统方法耗时。现在用因子图拆分复杂问题,分步骤加速,提升规划效率和实时性。 控制模块:机器人形态复杂(如人形机器人自由度超 44 个),控制难度大。针对任务空间力矩控制模型设计专用加速器,应对高自由度带来的控制挑战。 硬件对比:不同硬件加速效果有差异,像 EDX-CAR 对比 CPU、GPU、DSP 等,展示了不同组合的加速比,为硬件选择提供参考。 第 11 章:算法安全性 深度学习隐患:深度神经网络不安全,训练数据来源不可控(比如经典数据集靠公开网络收集,难保证安全),测试数据分布可能与训练数据不一致,容易被攻击干扰。 大模型安全问题: 幻觉问题:大模型生成内容与事实或用户指令不符,分 “事实性幻觉”(如错误回答登月第一人)和 “忠实性幻觉”(内容与上下文不一致),主要因数据缺陷,过度依赖训练数据模式导致。 具身智能安全:大模型用于机器人时,安全隐患更具体。需从三层面考量:长序列任务安全(拒绝执行有害任务)、子任务安全(避免危险组合)、执行过程安全,需要系统设计者和模型开发者协同限制。 第 12 章:系统可靠性 可靠性定义:可靠性不是安全性,指系统在规定条件和时间内正常运行的能力,关注容错、冗余、恢复能力。机器人可能遇温度异常、碰撞、断电等,设计可靠系统很重要。 机器人本体:运行在不稳定环境时,机械结构、传感器等可能出问题,比如硬件故障、部件磨损。 计算系统:软件错误、算法漏洞等,导致系统失常。已知的可靠设计常伴随冗余,增加面积、功耗负担,需平衡设计。 设计挑战:如何在不引入过多负担的前提下,为机器人计算系统设计可靠性保护,确保面对硬件故障、软件错误时仍能稳定工作,是关键研究方向。 可靠性漏洞:机器人系统可靠性关注系统在规定条件下稳定运行的能力。机器人本体可能遇硬件故障、环境干扰,计算系统也会有软件错误、算法漏洞。以自动驾驶软件 Autoware 为例,算法错误类 Bug 占比最高,涉及代码多、难修复,还列举了 20 种错误类型,像软件崩溃、编译问题最常见,感知、定位、规划模块最容易出问题。 鲁棒性提升难题:为提升可靠性,常用冗余备份(如多硬件模块或多次运行软件对比输出),但会增加计算资源、功耗和芯片面积。比如特斯拉自动驾驶系统为保障鲁棒性,芯片面积大幅增加,负担明显。 自适应冗余设计:发现机器人系统不同节点鲁棒性不同,前端(感知、定位)鲁棒性高,后端(规划、控制)低。于是提出 “定制保护”:高鲁棒性节点用软件保护(如异常值检测,低延迟低功耗),低鲁棒性节点用硬件保护(如硬件冗余备份),既保可靠又减负担,还能按模块细化保护方式。 第 13 章:具身智能的数据挑战 数据价值大:具身智能数据是机器人能力训练的核心,像互联网数据用于广告推荐一样,具身智能数据用于优化机器人。预测其市场价值超互联网三倍,潜力巨大,但目前发展还在初期。 数据瓶颈突出: 质量与多样性难保障:训练具身智能需大量高质量、多样化数据。比如机器人要处理环境数据提升避障规划能力,工业机器人依赖精准数据,家用机器人得适应多样家庭环境数据,采集难度高、成本大。 数据孤岛严重:机器人组织采集数据局限于特定场景,缺乏共享,导致重复劳动和资源浪费,形成 “数据孤岛”,阻碍技术发展。 数据采集优化:设计 AIRSPEED 数据过滤系统,解决数据延迟、带宽不足、质量不稳问题。通过动态调整采集策略,结合数据压缩、关键帧选择等机制,应对不同传感器数据流量,确保在网络带宽有限时也能高效采集数据。

  • 发表了主题帖: 《具身智能机器人系统》读后感,第五到九章

    第 5 章:自主机器人的定位系统 定位作用:自主机器人要在环境里自主导航,得先知道自己的位置和朝向。就像人出门要知道自己在哪儿,机器人也得建立 “坐标系”—— 一个是自身的机器人坐标系,一个是环境的全局坐标系,通过定位系统算清自己在全局坐标系里的位置。 技术实现:现在机器人用多传感器融合定位,比如 GNSS、IMU 直接获取位置运动信息,摄像头、激光雷达测周围物体距离,再反推位置。但传感器数据有噪声,得用卡尔曼滤波这些方法优化,提升定位精度。 计算系统挑战:定位需要高精度、实时性,但传感器数据处理复杂,多传感器融合又考验算力和功耗。比如自动驾驶定位每秒输出多次位置,数据对齐(空间对齐、时间对齐)很关键,稍有误差(像摄像头和 IMU 时间差 40ms,定位误差能到 10 米)就会影响结果。硬件平台选型也难,得在算力、功耗、实时性之间平衡,现在 FPGA 因可重构、低功耗成主流。 第 6 章:自主机器人的规划与控制系统 规划核心:机器人在复杂环境里导航,得规划路径和轨迹。路径规划是找从起点到目标的路线,分 “可行路径”(只要能走)和 “最优路径”(优化时间、平滑度等);轨迹规划更复杂,要考虑时间参数、动态障碍物,甚至机器人运动学约束(比如最大曲率)。 强化学习应用:强化学习让机器人像人类一样从经验中学习,通过和环境互动优化决策。比如在行为决策中,应对复杂交通场景,强化学习能处理 “长尾” 情况(罕见但重要的场景);在规划控制中,设计合适的状态空间、动作空间,让机器人学会动态环境下的路径规划和实时控制,突破传统方法处理不确定性的局限。 第 7 章:具身智能机器人大模型 发展背景:ChatGPT 等大模型火了后,大家想把它用在机器人上。一开始尝试用自然语言让大模型控制机器人,发现有局限,后来就开发多模态大模型,融合视觉、听觉、文本等传感器数据,控制机器人。现在专门针对机器人任务的专用模型出现,精度比通用模型更高。 研究现状:2023 年后,大模型控制机器人成热门,像 ChatGPT for Robotics、Robotic Transformers 这些工作,探索大模型如何提升机器人能力。虽然大模型有潜力,但也有局限性,现在还在研究衡量模型的关键指标,以及未来发展方向,比如怎么更好结合大模型与机器人技术,推动行业变革。 ChatGPT for Robotics:以前机器人靠程序员手动编程,效率低、成本高、迭代慢。比如协作机器人调参数麻烦,任务一变就得重新编程。ChatGPT 出现后,靠强大语言理解和程序生成能力,能零样本学习规划任务,不用针对特定机器人预训练,给提示词就能互动,解决传统编程的迭代慢问题,但它也有局限性,比如实际控制中不够精准。 Robotic Transformers:谷歌提出的多模态大模型 RT,目标是建通用机器人学习系统。RT-1 通过图像和自然语言指令输入,双编码器设计融合信息,用大规模数据集(机器人课堂数据)训练,在复杂任务上成功率超 60%。后续 RT-2 扩大模型参数,编码机器人动作,突破动作函数库限制,让机器人能完成更多操作。 第 8 章:大模型用于机器人计算,颠覆还是进步 算法开发者视角:大模型让机器人在医疗、工业有新应用。医疗领域,多模态大模型辅助手术分析、缩短手术时间,未来手术室可能变成智能空间;工业领域,传统机器人靠编程,任务更新麻烦,具身智能让机器人能自主规划动作,适应新任务,提升工厂自动化效率。 系统开发者视角:机器人系统引入大模型有两种思路。一是 “端到端设计”,像谷歌 PaLM-E 和 RT 系列,让大模型处理多数任务,但实时性难保证,对算力、通信要求高;二是 “改进传统系统”,用大模型取代传统决策模块,保留定位、避障等基础模块,兼顾实时性和实用性,但数据反馈可能割裂大模型能力。现在第二种思路效果较好,但端到端设计潜力更大。 现状指标:具身智能机器人需关注成功率、实时性、安全性等指标。比如大模型参与后,实时性挑战明显,通信和算力跟不上就会影响机器人表现。 第 9 章:构建具身智能基础模型 元学习:让模型快速适应新任务,核心是 “学习如何学习”。通过多个任务训练提取共性知识,遇到新任务用共性快速调整,像机器人通过元学习在不同环境任务中优化行为,不用每次从头学。 模型预训练:选大规模多样化数据集(文本、图像等),用无监督或自监督学习,让模型掌握特征提取和知识储备。比如语言模型预训练预测下一个词,图像模型学分类检测,预训练后模型泛化能力强,后续微调更高效。 模型微调:在预训练基础上,用特定任务数据训练,让模型适应具体场景。比如预训练模型有通用能力,微调时针对机器人抓取任务优化,用小数据集让模型在特定任务表现更优,平衡通用与专用需求。  

  • 发表了主题帖: 《具身智能机器人系统》读后感,第三、四章

    第 3 章:机器人计算系统 机器人基础:1920 年 “机器人” 一词诞生,现在机器人不只是像人的机器,扫地机器人、自动驾驶汽车都算。机器人计算系统超重要,靠软件算法和硬件配合完成任务,比如自动驾驶计算系统,得处理环境感知、决策规划这些。 自主机器人:分自主和非自主。自主机器人能自己感知环境、决策,像自动驾驶汽车;非自主就是固定任务,比如工厂机械臂。自主机器人的计算系统更复杂,得平衡算法精度、实时性。 硬件软件:硬件得满足大算力(跑复杂模型)、低功耗(机器人常用电池)、高实时性(快速反应)。软件架构有端到端和模块化,各有优缺点,现在还结合大模型提升机器人能力。 第 4 章:自主机器人的感知系统 物体检测:机器人用摄像头、激光雷达识别物体,像 HOG+SVM、Faster R-CNN 这些算法,就是让机器人看懂周围有啥东西,还能分类,确保在复杂环境里导航安全。 立体视觉与光流:立体视觉像人眼,用两个相机算深度;光流分析图像像素运动,帮机器人在动态环境里理解物体怎么动,提升感知精度。 鸟瞰视角感知(BEV):把传感器数据转成鸟瞰图,融合多传感器信息,方便后续规划决策。分激光雷达、相机、融合三类 BEV 方法,优势是直观、易融合数据,现在超受关注。   从目前实际看,端测部署大模型的可能性不大,11b\7b之类的模型跑在jetson上还是有可能,比如agx、nx系列,其他更大参数量的模型基本无望。 BEV这个在端到端的智驾方案中用的比较多,多传感器之间的时间同步是我碰到过的问题

  • 2025-03-31
  • 发表了主题帖: 又见PTX,烤机神器Jetson GPU Burn实测

        视频讲解:又见PTX,烤机神器Jetson GPU Burn实测_哔哩哔哩_bilibili   jetson核心板测试gpu的应用程序需要考虑多程序占用gpu时的影响及gpu满负荷时温度的变化,影响着硬件、功耗、散热设计,如下为gpu的一个烤机程序 git clone https://github.com/anseeto/jetson-gpu-burn.git cd jetson-gpu-burn make -j6 ./script.sh     烤机脚本如下,使用stress压测8核,使用gpu_burn 跑满 gpu xterm -e stress --cpu 8 & xterm -e ./gpu_burn 100000 & tegrastats             compare.cu CUDA是NVIDIA提供的高级GPU编程框架,通过扩展C/C++语法实现并行计算。它抽象了硬件细节(如线程调度、内存模型),允许开发者专注于算法逻辑 extern "C" __global__ void compare(float *C, int *faultyElems, size_t iters) { size_t iterStep = blockDim.x*blockDim.y*gridDim.x*gridDim.y; size_t myIndex = (blockIdx.y*blockDim.y + threadIdx.y)* // Y gridDim.x*blockDim.x + // W blockIdx.x*blockDim.x + threadIdx.x; // X int myFaulty = 0; for (size_t i = 1; i < iters; ++i) if (fabsf(C[myIndex] - C[myIndex + i*iterStep]) > EPSILON) myFaulty++; atomicAdd(faultyElems, myFaulty); } compare.ptx PTX(Parallel Thread Execution)是NVIDIA设计的中间指令集,介于CUDA代码与GPU机器码(SASS)之间,类似于虚拟汇编语言。它提供硬件无关性,支持跨代GPU兼容,但需要依赖驱动程序即时编译(JIT)为具体架构的二进制代码,相较于CUDA的抽象层,PTX允许开发者直接操作底层硬件资源。  

  • 2025-03-30
  • 发表了主题帖: MuJoCo 可视化键盘控制球体及位姿实时记录,附代码!

        视频讲解: 今天分享的内容是,在Mujoco场景中添加一个球体,通过方向键控制球体x,y,z移动,至于这个场景可以用来做什么,先留个悬念,下面开始分享: 代码仓库:GitHub - LitchiCheng/mujoco-learning 创建球体场景的xml描述,如下: <mujoco> <visual> <headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0"/> <rgba haze="0.15 0.25 0.35 1"/> <global azimuth="140" elevation="-30"/> </visual> <asset> <texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072"/> <texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300"/> <material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.2"/> </asset> <worldbody> <geom name="floor" size="0 0 0.05" type="plane" material="groundplane"/> <body name="ball" pos="0 0 1"> <freejoint name="free_joint"/> <geom type="sphere" size="0.2" rgba="1 0 0 1" mass="1"/> </body> </worldbody> </mujoco> 键盘的按键获取使用pynput库,如下 from pynput import keyboard key_states = { keyboard.Key.up: False, keyboard.Key.down: False, keyboard.Key.left: False, keyboard.Key.right: False, keyboard.Key.alt_l: False, keyboard.Key.alt_r: False, } def on_press(key): if key in key_states: key_states[key] = True def on_release(key): if key in key_states: key_states[key] = False listener = keyboard.Listener(on_press=on_press, on_release=on_release) listener.start() 上下左右控制x, y方向,Alt L和Alt R控制z方向,完整代码如下: import mujoco import mujoco.viewer import numpy as np from pynput import keyboard key_states = { keyboard.Key.up: False, keyboard.Key.down: False, keyboard.Key.left: False, keyboard.Key.right: False, keyboard.Key.alt_l: False, keyboard.Key.alt_r: False, } def on_press(key): if key in key_states: key_states[key] = True def on_release(key): if key in key_states: key_states[key] = False listener = keyboard.Listener(on_press=on_press, on_release=on_release) listener.start() XML = """ <mujoco> <visual> <headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0"/> <rgba haze="0.15 0.25 0.35 1"/> <global azimuth="140" elevation="-30"/> </visual> <asset> <texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072"/> <texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300"/> <material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.2"/> </asset> <worldbody> <geom name="floor" size="0 0 0.05" type="plane" material="groundplane"/> <body name="ball" pos="0 0 1"> <freejoint name="free_joint"/> <geom type="sphere" size="0.2" rgba="1 0 0 1" mass="1"/> </body> </worldbody> </mujoco> """ model = mujoco.MjModel.from_xml_string(XML) model.opt.gravity = (0, 0, 0) data = mujoco.MjData(model) class CustomViewer: def __init__(self, model, data): self.handle = mujoco.viewer.launch_passive(model, data) self.pos = 0.0001 def is_running(self): return self.handle.is_running() def sync(self): self.handle.sync() @property def cam(self): return self.handle.cam @property def viewport(self): return self.handle.viewport def run_loop(self): while self.is_running(): ball_body_name = "ball" pos = data.body(ball_body_name).xpos quat = data.body(ball_body_name).xquat print(f"Position: {pos}, Orientation: {quat}") if key_states[keyboard.Key.up]: data.qpos[0] += self.pos if key_states[keyboard.Key.down]: data.qpos[0] -= self.pos if key_states[keyboard.Key.left]: data.qpos[1] += self.pos if key_states[keyboard.Key.right]: data.qpos[1] -= self.pos if key_states[keyboard.Key.alt_l]: data.qpos[2] += self.pos if key_states[keyboard.Key.alt_r]: data.qpos[2] -= self.pos mujoco.mj_step(model, data) self.sync() viewer = CustomViewer(model, data) viewer.cam.distance = 3 viewer.cam.azimuth = 0 viewer.cam.elevation = -30 viewer.run_loop()             为什么Alt R无法控制小球z方向运动? 答案是,Mujoco默认开启z轴的重力,小球会自然落到地面 关闭添加如下代码 model.opt.gravity = (0, 0, 0)      

  • 2025-03-29
  • 回复了主题帖: Pinocchio 安装教程|机器人学的必备库

    wangerxian 发表于 2025-3-29 16:06 视频看不到,是不是没添加上? 视频文章里面

  • 发表了主题帖: 【逆解机械臂】Pinocchio+MuJuCo 仿真 CLIK 闭环控制!附代码

        视频讲解: 今天的主题是使用 Pinocchio 结合 MuJuCo 给定机械臂末端位姿,IK出关节角进行控制,pinocchio官方示例,给出了clik的闭环逆运动学的示例 https://github.com/stack-of-tasks/pinocchio/blob/master/examples/inverse-kinematics.py     我们结合Mujoco进行一次仿真测试,给一个变化的末端位姿,进行关节角度控制 其中涉及到雅可比矩阵等,大家可以参考这篇文章《Introduction to Inverse Kinematics with Jacobian Transpose, Pseudoinverse and Damped Least Squares methods》 https://mathweb.ucsd.edu/~sbuss/ResearchWeb/ikmethods/iksurvey.pdf     下面是代码实现,已上传至仓库:https://github.com/LitchiCheng/mujoco-learning import mujoco import numpy as np import glfw from scipy.optimize import minimize import numpy as np import pinocchio from numpy.linalg import norm, solve def inverse_kinematics(current_q, target_dir, target_pos): urdf_filename = '/home/dar/MuJoCoBin/mujoco-learning/franka_panda_description/robots/panda_arm.urdf' # 从 URDF 文件构建机器人模型 model = pinocchio.buildModelFromUrdf(urdf_filename) # 为模型创建数据对象,用于存储计算过程中的中间结果 data = model.createData() # 指定要控制的关节 ID JOINT_ID = 7 # 定义期望的位姿,使用目标姿态的旋转矩阵和目标位置创建 SE3 对象 oMdes = pinocchio.SE3(target_dir, np.array(target_pos)) # 将当前关节角度赋值给变量 q,作为迭代的初始值 q = current_q # 定义收敛阈值,当误差小于该值时认为算法收敛 eps = 1e-4 # 定义最大迭代次数,防止算法陷入无限循环 IT_MAX = 1000 # 定义积分步长,用于更新关节角度 DT = 1e-2 # 定义阻尼因子,用于避免矩阵奇异 damp = 1e-12 # 初始化迭代次数为 0 i = 0 while True: # 进行正运动学计算,得到当前关节角度下机器人各关节的位置和姿态 pinocchio.forwardKinematics(model, data, q) # 计算目标位姿到当前位姿之间的变换 iMd = data.oMi[JOINT_ID].actInv(oMdes) # 通过李群对数映射将变换矩阵转换为 6 维误差向量(包含位置误差和方向误差),用于量化当前位姿与目标位姿的差异 err = pinocchio.log(iMd).vector # 判断误差是否小于收敛阈值,如果是则认为算法收敛 if norm(err) < eps: success = True break # 判断迭代次数是否超过最大迭代次数,如果是则认为算法未收敛 if i >= IT_MAX: success = False break # 计算当前关节角度下的雅可比矩阵,关节速度与末端速度的映射关系 J = pinocchio.computeJointJacobian(model, data, q, JOINT_ID) # 对雅可比矩阵进行变换,转换到李代数空间,以匹配误差向量的坐标系,同时取反以调整误差方向 J = -np.dot(pinocchio.Jlog6(iMd.inverse()), J) # 使用阻尼最小二乘法求解关节速度 v = -J.T.dot(solve(J.dot(J.T) + damp * np.eye(6), err)) # 根据关节速度更新关节角度 q = pinocchio.integrate(model, q, v * DT) # 每迭代 10 次打印一次当前的误差信息 if not i % 10: print(f"{i}: error = {err.T}") # 迭代次数加 1 i += 1 # 根据算法是否收敛输出相应的信息 if success: print("Convergence achieved!") else: print( "\n" "Warning: the iterative algorithm has not reached convergence " "to the desired precision" ) # 打印最终的关节角度和误差向量 print(f"\nresult: {q.flatten().tolist()}") print(f"\nfinal error: {err.T}") # 返回最终的关节角度向量(以列表形式) return q.flatten().tolist() def scroll_callback(window, xoffset, yoffset): global cam # 调整相机的缩放比例 cam.distance *= 1 - 0.1 * yoffset def limit_angle(angle): while angle > np.pi: angle -= 2 * np.pi while angle < -np.pi: angle += 2 * np.pi return angle def main(): global cam # 加载模型 model = mujoco.MjModel.from_xml_path('/home/dar/MuJoCoBin/mujoco_menagerie/franka_emika_panda/scene.xml') data = mujoco.MjData(model) # 打印所有 body 的 ID 和名称 print("All bodies in the model:") for i in range(model.nbody): body_name = mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_BODY, i) print(f"ID: {i}, Name: {body_name}") # 初始化 GLFW if not glfw.init(): return window = glfw.create_window(1200, 900, 'Panda Arm Control', None, None) if not window: glfw.terminate() return glfw.make_context_current(window) # 设置鼠标滚轮回调函数 glfw.set_scroll_callback(window, scroll_callback) # 初始化渲染器 cam = mujoco.MjvCamera() opt = mujoco.MjvOption() mujoco.mjv_defaultCamera(cam) mujoco.mjv_defaultOption(opt) pert = mujoco.MjvPerturb() con = mujoco.MjrContext(model, mujoco.mjtFontScale.mjFONTSCALE_150.value) scene = mujoco.MjvScene(model, maxgeom=10000) # 找到末端执行器的 body id end_effector_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_BODY, 'link7') print(f"End effector ID: {end_effector_id}") if end_effector_id == -1: print("Warning: Could not find the end effector with the given name.") glfw.terminate() return # 初始关节角度 initial_q = data.qpos[:7].copy() print(f"Initial joint positions: {initial_q}") theta = np.pi R_x = np.array([ [1, 0, 0], [0, np.cos(theta), -np.sin(theta)], [0, np.sin(theta), np.cos(theta)] ]) x = 0.3 new_q = initial_q while not glfw.window_should_close(window): # 获取当前末端执行器位置 mujoco.mj_forward(model, data) end_effector_pos = data.body(end_effector_id).xpos print(f"End effector position: {end_effector_pos}") if x < 0.6: x += 0.004 new_q = inverse_kinematics(initial_q, R_x, [x, 0.2, 0.7]) data.qpos[:7] = new_q # 模拟一步 mujoco.mj_step(model, data) # 更新渲染场景 viewport = mujoco.MjrRect(0, 0, 1200, 900) mujoco.mjv_updateScene(model, data, opt, pert, cam, mujoco.mjtCatBit.mjCAT_ALL.value, scene) mujoco.mjr_render(viewport, scene, con) # 交换前后缓冲区 glfw.swap_buffers(window) glfw.poll_events() # 清理资源 glfw.terminate() if __name__ == "__main__": main()          

  • 2025-03-28
  • 回复了主题帖: 机械臂如何稳稳上桌?Mujoco场景修改实操

    秦天qintian0303 发表于 2025-3-28 11:02 愈加的熟练了,主要是这里面的模型如何定义啊   跟据实际场景

  • 发表了主题帖: Pinocchio 安装教程|机器人学的必备库

        视频讲解: https://gepettoweb.laas.fr/doc/stack-of-tasks/pinocchio/master/doxygen-html/index.html     安装pinocchio,不要安装pip3 install pinocchio !最新的库叫pin pip3 install pin git clone https://github.com/Gepetto/example-robot-data.git mkdir models && mv example-robot-data/ models mkdir pinocchio && touch test_pinocchio.py test_pinocchio.py from pathlib import Path from sys import argv import pinocchio # Load the urdf model model = pinocchio.buildModelFromUrdf("/home/dar/MuJoCoBin/mujoco-learning/franka_panda_description/robots/panda_arm.urdf") print("model name: " + model.name) # Create data required by the algorithms data = model.createData() # Sample a random configuration q = pinocchio.randomConfiguration(model) print(f"q: {q.T}") # Perform the forward kinematics over the kinematic tree pinocchio.forwardKinematics(model, data, q) # Print out the placement of each joint of the kinematic tree for name, oMi in zip(model.names, data.oMi): print("{:<24} : {: .2f} {: .2f} {: .2f}".format(name, *oMi.translation.T.flat)) python3 test_pinocchio.py      

  • 回复了主题帖: 被Python版本逼疯?Miniconda环境隔离拯救你

    hellokitty_bean 发表于 2025-3-28 08:51 conda帮你自动解决库依赖问题(尽管有时候也不一定能全部解决) 对喜欢亲力亲为的,原生好 解决依赖的过程本身就是熟悉代码的过程。

  • 回复了主题帖: 被Python版本逼疯?Miniconda环境隔离拯救你

    吾妻思萌 发表于 2025-3-28 08:16 我之前还看一个玩法 自己本地弄一个常用pandas numpy和其他的库,然后本地做库源,新的venv就从本地走,弄 ... 对的,有些公司有自己改过的库,会自己做发布源

  • 回复了主题帖: 被Python版本逼疯?Miniconda环境隔离拯救你

    吾妻思萌 发表于 2025-3-28 08:15 嗯嗯 我意思是conda我以前也有用但是有些公司网conda的服务器似乎有点问题 python 原生就还好,后面就 ... 基础环境我也是原生pthon,依赖大多数都能改好,不过对于很多只做算法的人就很费时间了 docker基本上就是都隔离了

  • 2025-03-27
  • 回复了主题帖: 被Python版本逼疯?Miniconda环境隔离拯救你

    吾妻思萌 发表于 2025-3-27 16:02 不是 楼主 venv不是标配吗 别用啥conda miniconda 原生python 每次项目就放一个文件夹下,每次用自己的p ... 对,venv我视频里说了是python自带的

  • 回复了主题帖: 被Python版本逼疯?Miniconda环境隔离拯救你

    wangerxian 发表于 2025-3-27 15:54 用了这个之后,python环境有十几个 对,这是坏处

  • 发表了主题帖: 机械臂如何稳稳上桌?Mujoco场景修改实操

        视频讲解: 前面《常见机械臂模型不用找!Mujoco这儿都有!》中介绍的mujoco-menagerie中机械臂大多都是base_link放在地上的,这些场景往往和真实的场景对应不上,比如机械臂可能是安装在桌子上,或者安装在底盘上,所以就涉及到修改场景模型文件,今天我们就以so-arm100这个机械臂为例,为其添加一个桌子。 首先我们看下so-arm100原有的场景文件 <mujoco model="so_arm100 scene"> <include file="so_arm100.xml"/> <statistic center="0 -0.2 0.1" extent="0.4"/> <visual> <headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0"/> <rgba haze="0.15 0.25 0.35 1"/> <global azimuth="140" elevation="-30"/> </visual> <asset> <texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072"/> <texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300"/> <material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.2"/> </asset> <worldbody> <light pos="0 0 1.5" dir="0 0 -1" directional="true"/> <geom name="floor" size="0 0 0.05" type="plane" material="groundplane"/> </worldbody> </mujoco> 原有模型只描述了地面、天空等环境     我们可以参考aloha的场景,他是有桌子的,最起码桌子的mesh文件不用自己找了     然后在so-arm100的scene.xml上做修改,大概如下的步骤: a. 首先需要把桌子的模型放进assets文件夹中 b. 然后添加路径说明 c. 添加mesh文件以及texture描述 d. 添加位置关系描述 修改后的文件如下,可以重新命名为scene_with_table.xml <mujoco model="so_arm100 scene"> <compiler meshdir="assets" texturedir="assets"/> <include file="so_arm100.xml"/> <statistic center="0 -0.2 0.1" extent="0.4"/> <visual> <headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0"/> <rgba haze="0.15 0.25 0.35 1"/> <global azimuth="140" elevation="-30"/> </visual> <asset> <mesh file="tablelegs.obj"/> <mesh file="tabletop.obj"/> <texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072"/> <texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300"/> <texture type="2d" file="small_meta_table_diffuse.png"/> <material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.2"/> <material name="table" texture="small_meta_table_diffuse"/> </asset> <worldbody> <light pos="0 0 1.5" dir="0 0 -1" directional="true"/> <geom name="floor" size="0 0 0.05" type="plane" material="groundplane" pos="0 0 -.75"/> <site name="worldref" pos="0 0 -0.75"/> <geom mesh="tabletop" material="table" class="visual" pos="0 0 -0.75" quat="1 0 0 1"/> <geom mesh="tablelegs" material="table" class="visual" pos="0 0 -0.75" quat="1 0 0 1"/> <geom name="table" pos="0 0 -0.1009" size="0.61 0.37 0.1" type="box" class="collision"/> <camera name="overhead_cam" focal="1.93e-3 1.93e-3" resolution="1280 720" sensorsize="3896e-6 2140e-6" pos="0 -0.303794 1.02524" mode="fixed" quat="0.976332 0.216277 0 0"/> <camera name="worms_eye_cam" focal="1.93e-3 1.93e-3" resolution="1280 720" sensorsize="3896e-6 2140e-6" pos="0 -0.377167 0.0316055" mode="fixed" quat="0.672659 0.739953 0 0"/> </worldbody> </mujoco> simulate trs_so_arm100/scene_with_table.xml      

最近访客

< 1/6 >

统计信息

已有455人来访过

  • 芯积分:2796
  • 好友:2
  • 主题:111
  • 回复:350

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言