尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

PyBullet双足机器人仿真:从零搭建虚拟实验室与步态控制

PyBullet双足机器人仿真:从零搭建虚拟实验室与步态控制 简介本资源是一份面向机器人学初学者与AI研究者的PyBullet双足机器人仿真学习材料聚焦动态行走建模与控制实践解决刚体建模、关节驱动、地面接触力反馈及步态稳定性等核心问题。压缩包共14个文件含4个Python主程序如walking_simulation_example.py、walkGenerator.py、1个URDF机器人模型文件、3张效果截图PNG、3个备份文件zbak、1个Markdown说明文档及LICENSE协议整体大小4.53MB结构清晰便于按模块理解仿真流程与控制逻辑。已有122人学习下载适合希望掌握物理引擎接口调用、PID控制器实现、关键帧步态设计及多线程性能优化的实践者。资源提供可运行示例代码、参数可调的行走模拟脚本及配套可视化截图支持读者通过修改关节角度、质量分布与控制增益直观观察运动变化快速建立从建模到闭环控制的完整认知链条。1. 项目概述为什么用PyBullet模拟双足机器人如果你对机器人、动画或者游戏开发感兴趣大概率听说过“物理仿真”这个词。简单来说它就是在电脑里创建一个虚拟的物理世界让里面的物体像真实世界一样运动、碰撞。而双足机器人比如我们熟知的波士顿动力Atlas其核心挑战就是如何在复杂的地形上稳定行走和奔跑。直接在实体机器人上调试算法成本极高摔一次可能就是几十万上百万的维修费更别提安全风险了。因此在投入真金白银和实体硬件之前在仿真环境里进行充分的“虚拟测试”就成了必经之路。PyBullet就是这样一个强大的“虚拟机器人实验室”。它本质上是一个物理引擎的Python接口背后是Bullet Physics这个在电影特效和游戏行业久经考验的引擎。为什么选择PyBullet而不是其他首先它对机器人仿真非常友好原生支持URDF统一机器人描述格式模型加载这意味着你可以轻松地把从SolidWorks、Fusion 360或者在线模型库导出的机器人模型直接扔进去。其次它完全免费、开源学术和商业用途都没问题。最重要的是它和主流的机器学习框架如PyTorch、TensorFlow集成得非常好你可以很方便地用强化学习等AI方法来训练机器人的控制策略训练好的策略理论上可以直接迁移到真实机器人上这大大加速了研发进程。这个项目就是带你从零开始在PyBullet里搭建一个双足机器人的仿真环境并实现基础的运动控制。无论你是机器人专业的学生、从事运动控制算法研发的工程师还是对AI机器人感兴趣的爱好者都能通过这个“数字替身”来安全、高效地验证你的想法。2. 仿真环境搭建与机器人模型导入2.1 PyBullet环境初始化与基础设置万事开头难但PyBullet的入门却异常简单。首先确保你的Python环境建议3.7以上版本已经安装了pybullet库通常一行命令pip install pybullet就能搞定。初始化仿真环境是第一步。这里有几个关键参数决定了你“虚拟世界”的样貌和性能。import pybullet as p import time # 连接物理引擎 physicsClient p.connect(p.GUI) # 使用图形界面调试时必备。p.DIRECT是无头模式用于纯计算。 # 设置重力 p.setGravity(0, 0, -9.8) # 设置Z轴负方向的重力模拟地球环境 # 设置仿真步长 timeStep 1.0 / 240.0 # 每秒240步步长约4.16毫秒。步长越小越精确但计算越慢。 p.setTimeStep(timeStep)这里有个实操心得p.GUI和p.DIRECT模式的选择。在算法开发初期强烈建议使用GUI模式你能实时看到机器人的每一个动作直观判断是算法问题还是模型问题。当你进入大规模强化学习训练阶段需要成千上万次迭代时就应该切换到p.DIRECT无头模式这会节省大量的图形渲染开销让训练速度提升一个数量级。你可以写一个简单的参数来切换模式便于不同阶段的开发。另一个关键点是仿真步长。1/240是PyBullet文档推荐的值它能平衡精度和速度。对于双足机器人这种动态系统步长太大会导致数值不稳定机器人容易“抽搐”甚至飞出去步长太小则会严重拖慢仿真速度。除非有特殊需求否则不建议随意改动这个值。2.2 加载地面与双足机器人URDF模型一个光秃秃的世界没什么意思我们首先得给机器人一个立足之地。# 加载地面 planeId p.loadURDF(“plane.urdf”)plane.urdf是PyBullet自带的无限大地面模型。接下来是重头戏——加载你的双足机器人。你需要一个描述机器人所有关节、连杆、外观和物理属性的URDF文件。这个文件可以自己用建模软件导出也可以使用开源模型。# 加载双足机器人模型 robotStartPos [0, 0, 1] # 初始位置 (x, y, z)z1表示悬空1米 robotStartOrientation p.getQuaternionFromEuler([0, 0, 0]) # 初始姿态欧拉角转四元数 robotId p.loadURDF(“path/to/your/biped.urdf”, robotStartPos, robotStartOrientation)注意事项URDF文件的路径问题。建议使用绝对路径或者将模型文件放在你的项目目录下使用相对路径。加载失败最常见的原因就是路径错误或者URDF文件里引用的网格文件.obj, .stl找不到。一个调试技巧是先用PyBullet自带的简单模型测试比如p.loadURDF(“r2d2.urdf”)确保基础环境没问题。加载成功后在GUI窗口里你应该能看到你的机器人站立或跌落在地面上。此时机器人所有的关节都处于“默认状态”可能是松散的。我们需要获取它的关节信息为后续控制做准备。# 获取关节数量和信息 numJoints p.getNumJoints(robotId) jointInfoList [] for i in range(numJoints): jointInfo p.getJointInfo(robotId, i) jointInfoList.append(jointInfo) # 打印关节信息方便调试 print(f”Joint Index: {i}, Name: {jointInfo[1].decode(‘utf-8’)}, Type: {jointInfo[2]}”)getJointInfo返回一个元组包含了关节索引、名称、类型旋转关节、平移关节等、阻尼、摩擦系数等一系列参数。对于双足机器人我们通常关注的是“REVOLUTE”旋转类型的关节它们对应机器人的髋关节、膝关节和踝关节。2.3 仿真循环与基础交互环境搭建好后我们需要启动一个仿真循环让时间流动起来。# 仿真主循环 for _ in range(10000): # 循环10000步大约模拟40多秒 # 在这里添加你的控制逻辑 # 例如设置关节力矩或目标位置 # p.setJointMotorControl2(...) # 执行一步仿真 p.stepSimulation() # 延时方便观察。训练时需去掉此行 time.sleep(timeStep)这个循环是仿真的心脏。p.stepSimulation()每被调用一次物理引擎就根据当前所有物体受到的力、关节的控制命令计算下一个时间步的状态。一个关键的坑在GUI模式下如果你不加time.sleep(timeStep)仿真会以CPU能跑的最快速度运行机器人动作会快得像闪电一样看不清。但在DIRECT模式训练时必须去掉这行否则训练速度会被无谓的等待拖慢。3. 双足机器人运动控制原理与实现3.1 双足机器人运动学与动力学基础要让机器人动起来首先要理解它怎么动。双足机器人的运动可以分为两个层面运动学Kinematics和动力学Dynamics。运动学关心的是“几何关系”。不考虑力和质量只研究末端执行器比如脚掌的位置、姿态与各个关节角度之间的关系。这分为正运动学和逆运动学。正运动学是已知所有关节角度计算脚掌在哪里逆运动学则相反给定脚掌要到达的位置和姿态反算出每个关节应该转多少度。对于行走来说我们通常需要逆运动学来规划脚掌的轨迹。动力学则引入了力和质量研究关节扭矩与机器人运动加速度之间的关系。这是核心难点。双足机器人是一个不稳定的“倒立摆”系统。想象一下你把一根棍子竖在手掌上保持平衡需要不停地移动手掌来补偿棍子的倾倒。双足机器人行走就是两个倒立摆两条腿在不停地切换支撑和摆动同时上半身躯干还要保持平衡。在PyBullet中我们通常采用“基于模型的控制”或“基于学习的控制”。前者需要你根据动力学方程精确计算每个关节所需的扭矩后者则利用强化学习让AI自己在试错中学会发力的策略。我们先从相对简单的基于位置的控制入手。3.2 关节控制模式位置、速度与扭矩控制PyBullet提供了几种关节控制模式对应不同的控制层级位置控制你设定一个目标角度PyBullet内置的PD控制器会计算所需的扭矩驱动关节转到那个角度。这是最简单、最稳定的方式类似于给机器人关节装上了“自动舵”。p.setJointMotorControl2(bodyUniqueIdrobotId, jointIndexhipJointIndex, controlModep.POSITION_CONTROL, targetPositiontargetAngle)你需要调整targetPosition并可以设置maxVelocity和力/位置增益参数来调整响应速度和平滑度。速度控制你设定一个目标角速度电机将努力维持这个转速。扭矩控制你直接设定关节的输出扭矩。这是最底层、最灵活但也是最难的控制方式。你需要自己计算所有动力学效应重力、科氏力等并进行补偿否则机器人很容易失控。这通常用于高级的力控或阻抗控制算法。对于初学者强烈建议从位置控制开始。你可以把机器人的行走想象成给每个关节编排一段角度随时间变化的舞蹈。这就是“轨迹规划”。3.3 实现一个简单的原地站立平衡控制在尝试行走之前先让机器人学会站稳。一个最简单的站立策略是让所有关节保持在一个初始的“中立”角度。但对于双足机器人仅仅这样是不够的因为微小的扰动就会让它倒下。我们可以实现一个简单的“踝关节策略”来维持平衡。思路是通过机器人躯干的倾斜角度俯仰角来调整踝关节的角度像一个站在平衡板上的人用脚踝前后移动来保持平衡。# 假设我们已经获取了躯干连杆的索引通常是-1代表基座 basePos, baseOri p.getBasePositionAndOrientation(robotId) # 将四元数转换为欧拉角获取俯仰角pitch euler p.getEulerFromQuaternion(baseOri) pitch euler[1] # 通常第二个是绕Y轴的旋转即前后倾斜 # 简单的比例控制器躯干前倾(pitch0)则脚踝向后转把身体推回来。 ankleTargetAngle neutralAnkleAngle - Kp * pitch # Kp是一个比例系数需要调试 # 分别设置左右踝关节的目标位置 p.setJointMotorControl2(robotId, leftAnkleIndex, p.POSITION_CONTROL, ankleTargetAngle) p.setJointMotorControl2(robotId, rightAnkleIndex, p.POSITION_CONTROL, ankleTargetAngle)这个例子非常简陋但揭示了平衡控制的基本思想感知 - 计算 - 执行。你需要从仿真环境中读取机器人的状态如倾角经过一个控制器这里是一个简单的P控制器计算然后输出给执行器关节电机。实操心得比例系数Kp的调试是个手艺活。太小了反应迟钝机器人会慢慢倒下太大了反应过激机器人会在平衡点附近剧烈振荡。通常需要从一个小值开始慢慢增加观察机器人的响应。在PyBullet的GUI里你可以实时修改参数反复试验这是仿真相比实体实验的巨大优势。4. 步态规划与行走循环实现4.1 步态周期分解与关键帧规划双足行走是一个周期性的运动称为“步态”。一个完整的步态周期可以分为两个主要相位支撑相和摆动相。当一条腿支撑身体重量时它处于支撑相另一条腿则抬起、向前摆动处于摆动相。两条腿交替进行。我们可以用“关键帧”的思想来规划步态。为每个关节在一个周期内的不同时间点设定目标角度然后让控制器驱动关节平滑地过渡到这些关键位置。首先定义步态周期的时间长度和关键时间点gaitCycleTime 1.0 # 一个完整的步态周期1秒 swingPhaseRatio 0.4 # 摆动相占周期的比例 # 关键时间点0.0周期开始 0.5左右腿相位交换 1.0周期结束然后为髋关节、膝关节、踝关节分别设计在支撑相和摆动相的目标角度。例如在摆动相髋关节需要向前摆动膝关节需要弯曲以抬脚踝关节需要背屈脚尖向上以避免刮地。# 定义关键角度需根据你的机器人模型调整单位弧度 hip_swing 0.3 # 摆动相髋关节前摆角度 hip_stance -0.1 # 支撑相髋关节后伸角度 knee_swing 0.7 # 摆动相膝关节弯曲角度 knee_stance 0.0 # 支撑相膝关节伸直 ankle_swing -0.2 # 摆动相踝关节背屈 ankle_stance 0.1 # 支撑相踝关节跖屈4.2 基于时间的关节轨迹插值有了关键帧我们需要根据仿真时间为每个关节计算出当前时刻的“目标角度”。这里可以使用简单的线性插值或者更平滑的三次样条插值。def getGaitPhase(currentTime): “””根据当前时间返回周期内的相位0到1之间和当前是左腿支撑还是右腿支撑””” phaseInCycle (currentTime % gaitCycleTime) / gaitCycleTime # 假设0-0.5相位是右腿支撑左腿摆动 if phaseInCycle 0.5: supportLeg “right” swingLeg “left” swingPhase phaseInCycle / 0.5 # 归一化到0-1表示摆动相的进度 else: supportLeg “left” swingLeg “right” swingPhase (phaseInCycle - 0.5) / 0.5 return phaseInCycle, supportLeg, swingLeg, swingPhase currentTime p.getPhysicsSimulationTime() # 获取当前仿真时间 phase, supLeg, swLeg, swingPhase getGaitPhase(currentTime) # 为摆动腿的关节计算目标角度线性插值示例 if swLeg “left”: hipTarget hip_stance (hip_swing - hip_stance) * swingPhase kneeTarget knee_stance (knee_swing - knee_stance) * swingPhase ankleTarget ankle_stance (ankle_swing - ankle_stance) * swingPhase # 设置左腿关节 p.setJointMotorControl2(robotId, leftHipIndex, p.POSITION_CONTROL, hipTarget) # … 设置左膝、左踝 else: # 设置右腿关节 …注意事项这里的角度值是示意你必须根据自己机器人的模型结构、关节旋转方向正负以及期望的步幅来仔细调整。一个负的髋关节角度可能意味着向后伸也可能意味着模型坐标系下的向前摆。务必在GUI中单步调试观察每个关节的运动方向是否符合预期。4.3 引入躯干平衡与ZMP预观控制仅仅让腿摆动起来机器人很可能会因为重心不稳而摔倒。我们需要在腿脚运动的同时主动控制躯干上半身的姿态来维持平衡。一个经典的概念是零力矩点。ZMP可以粗略理解为机器人脚底压力分布的中心。当ZMP保持在支撑多边形通常是脚掌轮廓内部时机器人是稳定的一旦ZMP越界机器人就会开始倾倒。在规划脚掌轨迹时有意识地让躯干重心的运动趋势将ZMP“拉”回支撑区域内就是一种ZMP预观控制的思想。在简单的仿真中我们可以用一个更直观的方法调节支撑腿髋关节的侧向角度来控制身体左右平衡调节支撑腿踝关节的俯仰角度来控制身体前后平衡。这相当于用一个倒立摆模型来近似。# 在每一步仿真中读取躯干的倾斜角滚转和俯仰 _, baseOri p.getBasePositionAndOrientation(robotId) roll, pitch, _ p.getEulerFromQuaternion(baseOri) # 简单的PD控制器计算平衡补偿量 balanceHipAdjust Kp_roll * roll Kd_roll * (roll - prevRoll) / timeStep balanceAnkleAdjust Kp_pitch * pitch Kd_pitch * (pitch - prevPitch) / timeStep # 将补偿量叠加到原本规划好的关节目标角度上 leftHipTarget balanceHipAdjust # 如果向左倾(roll0)增加左髋外展角度把身体拉回来 rightHipTarget - balanceHipAdjust # 踝关节补偿类似… prevRoll, prevPitch roll, pitch # 记录上一时刻角度用于微分项这里的Kp和Kd需要分别调试。微分项Kd能提供阻尼防止平衡调节过程产生振荡。这个方法的有效性取决于你的机器人质量分布、脚掌大小以及步态速度。对于慢速行走它可能足够但对于快速奔跑或受到较大扰动就需要更复杂的全身动力学控制了。5. 传感器模拟与状态反馈5.1 关节状态读取与电机模型在真实机器人上我们有编码器读取关节角度和速度有力矩传感器测量输出扭矩。在PyBullet中我们可以完美地模拟这些传感器。# 读取特定关节的状态 jointState p.getJointState(robotId, jointIndex) # jointState 是一个元组包含 # [0] 关节位置弧度 # [1] 关节速度弧度/秒 # [2] 关节所受的广义力列表 # [3] 电机施加的扭矩Nm actualPosition jointState[0] actualVelocity jointState[1] motorTorque jointState[3]这些反馈数据至关重要。实操心得在位置控制模式下你设定的是“目标位置”但电机实际输出的扭矩和关节实际达到的位置/速度会受到负载、摩擦和惯性影响。通过比较targetPosition和actualPosition你可以判断控制器是否“跟得上”。如果误差持续很大可能需要调高位置控制的增益p.setJointMotorControl2中的positionGain参数或者检查是否达到了电机的扭矩上限force参数。5.2 力/力矩传感器与触觉反馈对于双足机器人脚底与地面的接触信息是判断支撑相、检测滑倒的关键。PyBullet允许你获取接触点信息。# 获取机器人所有接触点性能开销较大不宜每步调用 contactPoints p.getContactPoints(bodyArobotId, bodyBplaneId) if contactPoints: for point in contactPoints: # point[3] 是接触点位置世界坐标系 # point[9] 是法向接触力 contactForce point[9] if contactForce 5.0: # 设定一个力阈值判断是否有效支撑 # 机器人脚部接触到了地面更高效的做法是为脚底连杆添加一个“虚拟的”力传感器。这通常需要在URDF文件中定义并在仿真中通过p.getLinkState结合物理引擎内部计算来估算。一个常见的简化方法是在脚底安装一个“射线”ray检测它与地面的距离和穿透深度来近似判断接触状态和地面反作用力方向。5.3 IMU惯性测量单元模拟IMU提供躯干的角速度和线加速度是平衡控制的核心传感器。在PyBullet中我们可以直接从基座连杆的状态推导出这些信息。# 获取基座连杆的速度和角速度 baseVel, baseAngVel p.getBaseVelocity(robotId) # baseVel: 线速度 [vx, vy, vz] (m/s) # baseAngVel: 角速度 [wx, wy, wz] (rad/s) # 获取基座姿态四元数 _, baseOri p.getBasePositionAndOrientation(robotId) # 可以通过微分姿态或转换角速度来得到“测量”的角速度 # 模拟的IMU数据通常会加上一些高斯白噪声使其更贴近真实传感器 import numpy as np imu_gyro_noisy np.array(baseAngVel) np.random.normal(0, 0.01, 3) # 加入标准差0.01 rad/s的噪声在强化学习训练中将这些带噪声的状态信息作为观测Observation输入给神经网络可以让学习出的策略对传感器噪声具有鲁棒性从而提高从仿真迁移到实物的成功率。6. 常见问题排查与性能优化6.1 仿真不稳定与机器人“爆炸”这是新手最常遇到的问题点击运行后机器人抽搐几下然后零件四处飞散仿佛内部装了炸弹。原因1初始姿态不稳定。如果你的机器人初始姿态robotStartOrientation不是直立或者初始关节角度导致重心落在支撑多边形之外物理引擎计算的第一步就会产生一个巨大的恢复力矩导致失稳。解决确保加载机器人时它是笔直站立且双脚平稳着地的。可以在URDF中定义好初始关节角度或者在加载后立即用p.resetJointState将所有关节设置为一个稳定的站立角度。原因2控制频率与仿真步长不匹配。如果你在仿真循环中执行复杂的计算如图像处理、神经网络推理导致控制指令的发送频率远低于仿真步频例如每10个仿真步才发一次控制命令机器人就会在大部分时间里处于“失控”状态极易失稳。解决确保你的控制循环频率至少与仿真步频240Hz保持一致。如果控制算法计算量大可以考虑降低仿真步频如120Hz或者使用p.setRealTimeSimulation(1)让仿真时钟等待你的控制指令。原因3关节极限与扭矩限制未设置。物理引擎中关节可以无限旋转或输出无限扭矩这不符合实际。当你的控制指令给出一个超出物理极限的目标时会导致数值计算发散。解决在URDF中正确定义关节的上下限limit lower”-1.57” upper”1.57”/。在设置电机控制时使用force参数限制最大输出扭矩。6.2 运动抖动与地面穿透机器人行走时脚部抖动或者偶尔“踩”进地面里。原因1接触参数设置不当。地面和机器人脚部的摩擦系数、恢复系数弹性设置不合理。解决在加载URDF时可以通过p.changeDynamics函数调整物理属性。p.changeDynamics(robotId, linkIndex, lateralFriction1.0, spinningFriction0.5, rollingFriction0.01) p.changeDynamics(planeId, -1, lateralFriction1.2) # -1代表基座连杆增加lateralFriction侧向摩擦防滑通常能改善行走稳定性。但过高的摩擦也可能导致不真实的“粘滞”感。原因2碰撞形状过于粗糙。URDF中为视觉渲染的网格.obj文件往往很精细但用于物理计算的碰撞形状通常是简化的长方体、圆柱体或凸包如果太粗糙会导致接触计算不准确。解决在URDF中为关键部件特别是脚掌定义更精确的碰撞形状。可以使用collision标签指定一个与视觉网格接近但面数较少的专用碰撞网格文件。6.3 仿真速度慢与性能瓶颈当机器人关节数量多、环境复杂时仿真速度可能跟不上实时。优化1使用p.DIRECT模式。如前所述训练时务必使用无头模式关闭GUI渲染是最大的性能提升手段。优化2简化碰撞检测。碰撞检测是物理仿真中最耗时的部分之一。对于不会发生碰撞的物体对比如机器人的两只脚在摆动时可以禁用它们之间的碰撞检测。p.setCollisionFilterPair(robotId, robotId, leftFootLinkIndex, rightFootLinkIndex, enableCollision0)优化3降低渲染精度和频率。即使在GUI模式下也可以通过API降低视觉渲染的负担。p.configureDebugVisualizer(p.COV_ENABLE_RENDERING, 0) # 临时关闭渲染 # … 执行一段不需要观看的初始化或计算 p.configureDebugVisualizer(p.COV_ENABLE_RENDERING, 1) # 重新开启渲染 p.configureDebugVisualizer(p.COV_ENABLE_SINGLE_STEP_RENDERING, 1) # 启用单步渲染只在stepSimulation后更新画面优化4并行仿真。PyBullet支持在多个线程或进程中同时运行多个独立的仿真环境这对于强化学习中的并行数据采集非常有用。你可以创建多个p.DIRECT连接每个连接运行一个机器人副本大幅提升样本收集效率。7. 从仿真到现实模型与策略迁移的考量仿真的最终目的是为现实服务。然而“仿真到现实”的鸿沟是众所周知的挑战。PyBullet仿真再精确也与真实物理世界存在差异。差异来源1动力学参数不准。机器人的质量、惯性矩、关节摩擦、阻尼系数在仿真模型中都是估计值。细微差别在长期动力学累积下会导致行为显著不同。应对在仿真中引入参数随机化。训练时让机器人的质量、惯性、摩擦系数在一个合理范围内随机波动。这样训练出的策略会学会适应一系列动力学模型从而对真实世界的不确定性更鲁棒。差异来源2执行器模型。仿真中的理想电机模型瞬间达到目标扭矩或位置与真实的伺服电机有响应延迟、扭矩饱和、带宽限制相差甚远。应对在仿真中为电机模型加入延迟、饱和和噪声。PyBullet允许你设置电机的最大力、速度限制和阻尼可以以此来模拟真实电机的特性。差异来源3传感器噪声与延迟。真实IMU、编码器数据充满噪声且存在通信延迟。应对如前所述在仿真观测值中加入噪声。还可以在策略网络的输入中不仅包含当前观测还包含过去几帧的观测让网络学会处理带有延迟的信息。差异来源4接触与摩擦。地面的摩擦特性、脚垫的形变在仿真中很难完美模拟。应对同样使用随机化。在训练时随机化地面的摩擦系数甚至可以在脚底与地面之间引入一个微小的“滑移”概率模型。一个实用的工作流程是首先在“理想”仿真中快速原型化你的算法和步态然后逐步增加上述的随机化和扰动进行鲁棒性训练最后在真实机器人上进行零样本zero-shot或少量样本的微调。PyBullet的保真度和可定制性使其成为搭建这一流程的绝佳起点。我个人在多次仿真项目中的体会是仿真不仅仅是算法的“试炼场”更是一个强大的“思维实验”工具。它允许你以极低的成本去尝试那些在现实中风险极高或成本巨大的想法。当你看到自己编写的代码让虚拟的机器人从蹒跚学步到稳步前行时那种成就感是无可替代的。而在这个过程中积累的对机器人动力学的直觉和理解远比最终生成的行走轨迹本身更有价值。本文还有配套的精品资源点击获取
返回列表