前途科技
  • 科技
  • AI
    • AI 前沿技术
    • Agent生态
    • AI应用场景
    • AI 行业应用
  • 初创
  • 报告
  • 学习中心
    • 编程与工具
    • 数据科学与工程
我的兴趣
前途科技前途科技
Font ResizerAa
站内搜索
Have an existing account? Sign In
Follow US
Copyright © 2024 AccessPath.com, 前途国际科技咨询(北京)有限公司,版权所有。 | 京ICP备17045010号-1 | 京公网安备 11010502033860号
编程与工具

Python机器人入门指南:使用PyBullet轻松构建3D仿真

NEXTECH
Last updated: 2025年10月17日 上午6:44
By NEXTECH
Share
59 Min Read
SHARE

引言

机器人技术是一个专注于机器人设计与建造的科学领域,旨在通过复制或替代人类行为来执行任务并做出决策。它是一个多学科的综合体,融合了以下几个关键领域:

Contents
引言环境设置URDF文件关节分析连杆分析机器人运动结论
  • 电气工程:主要负责传感器和执行器的设计与集成。传感器从环境中收集数据,将物理属性转换为电信号(类似于人类的五感);执行器则将这些信号转化为物理动作或运动(好比人类的肌肉)。
  • 机械工程:关注物理结构的设计和运动实现。
  • 计算机科学:负责人工智能软件和算法的开发。

目前,ROS (机器人操作系统)是机器人领域的主要框架,它以模块化的方式处理机器人所有不同的组成部分(传感器、电机、控制器、摄像头等),并协调它们之间的数据交换。ROS框架专为真实的机器人原型设计,可同时支持Python和C++。鉴于其广泛的流行度,许多库都在ROS之上构建,其中最先进的3D模拟器就是Gazebo。

机器人手臂特写,展示其复杂结构

图片由 Simon Kadula 在Unsplash上发布

由于Gazebo相对复杂,开发者仍然可以在ROS生态系统之外学习机器人技术的基础知识并构建用户友好的模拟。主要的Python库包括:

  • PyBullet(适合初学者):非常适合用来探索URDF(统一机器人描述格式),这是一种用于描述机器人本体、部件和几何形状的XML模式。
  • Webots(适合中级用户):其物理模拟更为精确,能够构建更复杂的仿真。
  • MuJoCo(适合高级用户):作为一款真实世界模拟器,它常用于研究级别的实验。OpenAI的RoboGYM库就是基于MuJoCo构建的。

一个在PyBullet中创建的立方体可视化效果

You Might Also Like

懒惰数据科学家的时间序列预测指南:Python与自动化工具的高效实践
特斯拉股东批准埃隆·马斯克万亿薪酬方案:深层影响与未来挑战
锦秋基金杨洁:AI投资三大方向、创业者机遇与焦虑深度解析
高效Streamlit仪表板:5个实用技巧助你快速上手

本文中的可视化效果使用PyBullet创建。

作为一份面向初学者的教程,本文将展示如何使用PyBullet构建简单的3D仿真。其中将包含一些实用的Python代码,这些代码可以轻松应用于其他类似场景(只需复制、粘贴、运行),并会逐行进行注释讲解,以便读者能够轻松复现示例。

环境设置

PyBullet是一款用户友好的物理模拟器,广泛应用于游戏、视觉特效、机器人技术和强化学习领域。通过以下任一命令,即可轻松安装(如果pip安装失败,conda通常可以解决):

pip install pybullet

conda install -c conda-forge pybullet

PyBullet主要有两种运行模式:

  • p.GUI → 打开一个窗口并实时显示模拟过程。
  • p.DIRECT → 无图形界面模式,主要用于脚本运行。
import pybullet as p

p.connect(p.GUI)  #或 p.connect(p.DIRECT)

PyBullet GUI模式连接代码示例
作为一个物理模拟器,首要任务是设置重力:

p.resetSimulation()

p.setGravity(gravX=0, gravY=0, gravZ=-9.8)

此代码设置了模拟的全局重力向量。“-9.8”在Z轴上表示向下9.8米/秒²的加速度,这与地球上的重力加速度相同。若不设置重力,机器人和地面会像在太空中一样,漂浮在零重力环境中。

URDF文件

如果将机器人比作人体,那么URDF文件就是定义其物理结构的骨架。它以XML格式编写,是机器人的基本蓝图,规定了机器人的外观和运动方式。

接下来将展示如何创建一个简单的立方体,这相当于3D世界中的“Hello World”。

urdf_string = """
<robot name="cube_urdf">

  <link name="cube_link">
    <visual>
      <geometry>
        <box size="0.5 0.5 0.5"/> <!-- 50 cm cube -->
      </geometry>
      <material name="blue">
        <color rgba="0 0 1 1"/>
      </material>
    </visual>

    <collision>
      <geometry>
        <box size="0.5 0.5 0.5"/>
      </geometry>
    </collision>

    <inertial>
      <mass value="1.0"/>
      <inertia ixx="0.0001" iyy="0.0001" izz="0.0001"
               ixy="0.0" ixz="0.0" iyz="0.0"/>
    </inertial>
  </link>
</robot>
"""

这些XML代码可以保存为URDF文件,也可以直接作为字符串使用。

import pybullet as p
import tempfile

## setup
p.connect(p.GUI)
p.resetSimulation()
p.setGravity(gravX=0, gravY=0, gravZ=-9.8)

## create a temporary URDF file in memory
with tempfile.NamedTemporaryFile(suffix=".urdf", mode="w", delete=False) as f:
    f.write(urdf_string)
    urdf_file = f.name

## load URDF
p.loadURDF(fileName=urdf_file, basePosition=[0,0,1])

## render simulation
for _ in range(240): 
    p.stepSimulation()

PyBullet中加载URDF文件并渲染立方体的代码和结果截图
请注意,上述循环运行了240步。为何是240步?这是视频游戏开发中常用的固定时间步长,旨在提供流畅且响应迅速的体验,同时避免CPU过载。当以60 FPS(每秒帧数)渲染时,每1/60秒显示一帧,这意味着1/240秒的物理步长为每个渲染帧提供了4次物理更新。

在之前的代码中,立方体是通过p.stepSimulation()进行渲染的。这意味着模拟并非实时进行,而是由用户控制何时执行下一步物理计算。另一种方法是使用time.sleep将其绑定到实际时间。

import time

## render simulation
for _ in range(240):
    p.stepSimulation() #添加一个物理步长(CPU速度 = 0.1秒)
    time.sleep(1/240)  #减慢到实时速度(240步 × 1/240秒休眠 = 1秒)

PyBullet中立方体落地的实时模拟动图
随着机器人XML代码变得越来越复杂,幸好PyBullet自带了一系列预设的URDF文件。无需手动创建XML,便可以直接加载默认的立方体模型。

import pybullet_data

p.setAdditionalSearchPath(path=pybullet_data.getDataPath())

p.loadURDF(fileName="cube.urdf", basePosition=[0,0,1])

URDF文件的核心在于定义两个主要元素:连杆(links)和关节(joints)。连杆是机器人的刚性部分(如同人体的骨骼),而关节则是连接两个刚性连杆的部位(如同人体的肌肉)。没有关节,机器人将只是一尊雕塑;有了关节,它才能成为一台拥有运动能力和特定功能的机器。

简而言之,每个机器人都是一个由关节连接起来的连杆树。每个关节可以是固定的(不可移动),也可以旋转(“旋转关节”)或滑动(“平移关节”)。因此,了解所使用的机器人结构至关重要。

接下来,以《星球大战》中著名的机器人R2D2为例进行说明。

电影《星球大战》中的R2D2机器人

图片由 Alexandr Popadin 在Unsplash上发布

关节分析

这次,除了机器人,还需要导入一个平面作为机器人的地面。如果没有平面,物体将缺乏碰撞表面,会无限期地向下坠落。

## setup
p.connect(p.GUI)
p.resetSimulation()
p.setGravity(gravX=0, gravY=0, gravZ=-9.8)
p.setAdditionalSearchPath(path=pybullet_data.getDataPath())

## load URDF
plane = p.loadURDF("plane.urdf")
robo = p.loadURDF(fileName="r2d2.urdf", basePosition=[0,0,0.1])

## render simulation
for _ in range(240):
    p.stepSimulation()
    time.sleep(1/240)

p.disconnect()

PyBullet中R2D2机器人和地面平面加载后的初始模拟截图
在使用机器人之前,必须了解其组成部分。PyBullet对信息结构进行了标准化,因此导入的每个机器人都将始终由相同的17个通用属性定义。为了运行脚本,这里选择不带图形界面的物理服务器连接模式(p.DIRECT)。分析关节的主要函数是p.getJointInfo()。

p.connect(p.DIRECT)

dic_info = {
    0:"joint Index",  #从0开始
    1:"joint Name",
    2:"joint Type",  #0=旋转关节 (revolute),1=平移关节 (prismatic),4=固定关节 (fixed)
    3:"state vectorIndex",
    4:"velocity vectorIndex",
    5:"flags",  #忽略,通常为0
    6:"joint Damping",  
    7:"joint Friction",  #摩擦系数
    8:"joint lowerLimit",  #最小角度
    9:"joint upperLimit",  #最大角度
    10:"joint maxForce",  #允许的最大力
    11:"joint maxVelocity",  #最大速度
    12:"link Name",  #连接到此关节的子连杆
    13:"joint Axis",
    14:"parent FramePos",  #位置
    15:"parent FrameOrn",  #方向
    16:"parent Index"  #−1 = 基础连杆 (base)
}
for i in range(p.getNumJoints(bodyUniqueId=robo)):
    print(f"--- JOINT {i} ---")
    joint_info = p.getJointInfo(bodyUniqueId=robo, jointIndex=i)
    print({dic_info[k]:joint_info[k] for k in dic_info.keys()})

R2D2机器人关节信息的控制台输出
无论是轮子、肘部还是夹持器,每个关节都必须具备这些相同的特性。上述代码显示R2D2有15个关节。我们来分析第一个关节,名为“base to right-leg”:

  • 关节类型为4,表示它不可移动。父连杆为-1,意味着它连接到机器人的基础连杆(base),即机器人的根部(如同人类的脊柱)。对于R2D2来说,基础连杆就是那个巨大的蓝白色圆筒形主体。
  • 连杆名称是“right leg”,因此可以理解这个关节连接了机器人的基础连杆和右腿,但它并非电动关节。这一点由关节轴、关节阻尼和关节摩擦力都为零所证实。
  • 父框架位置和方向定义了右腿连接到基础连杆的位置。

连杆分析

另一方面,为了分析连杆(物理身体段),必须遍历关节以提取连杆名称。然后,可以使用两个主要函数:p.getDynamicsInfo() 来了解连杆的物理属性,以及 p.getLinkState() 来获取其空间状态。

p.connect(p.DIRECT)

for i in range(p.getNumJoints(robo)):
    link_name = p.getJointInfo(robo, i)[12].decode('utf-8')  #字段 12="link Name"
    dyn = p.getDynamicsInfo(robo, i)
    pos, orn, *_ = p.getLinkState(robo, i)
    dic_info = {"Mass":dyn[0], "Friction":dyn[1], "Position":pos, "Orientation":orn}
    print(f"--- LINK {i}: {link_name} ---")
    print(dic_info)

R2D2机器人连杆信息的控制台输出
让我们分析第一个连杆,“right-leg”。其质量为10千克,这会影响重力和惯性;而摩擦力则影响其与地面接触时的滑动程度。方向(0.707=sin(45°)/cos(45°))和位置表明右腿连杆是一个实心部件,相对于基础连杆略微向前(5厘米),并倾斜了90度。

机器人运动

现在,我们来看看一个可以实际移动的关节。

例如,关节2是右前轮。它是一个类型为0的旋转关节。这个关节连接着右腿(连杆索引1)和右前轮:即基础连杆 → 右腿 → 右前轮。关节轴为(0,0,1),这表示车轮绕Z轴旋转。其限制(下限=0,上限=-1)表明车轮可以无限旋转,这对于转子来说是正常的。

我们可以轻松地驱动这个关节。控制机器人执行器的主要命令是p.setJointMotorControl2(),它允许控制关节的力、速度和位置。在这种情况下,若要使车轮旋转,需要施加力使其速度从零逐渐达到目标速度,然后通过平衡施加的力与阻力(如摩擦力、阻尼、重力)来维持该速度。

p.setJointMotorControl2(bodyUniqueId=robo, jointIndex=2,
                        controlMode=p.VELOCITY_CONTROL, 
                        targetVelocity=10, force=5)

现在,如果对所有4个轮子施加相同的力,就能让这个小机器人向前移动。根据前面进行的分析,我们知道车轮的关节编号分别是2和3(右侧),以及6和7(左侧)。

R2D2机器人前视图,高亮显示了左右两侧的轮子关节
考虑到这一点,首先可以通过仅旋转一侧的轮子让R2D2转身,然后再对所有轮子同时施加力使其向前移动。

import pybullet as p
import pybullet_data
import time

## setup
p.connect(p.GUI)
p.resetSimulation()
p.setGravity(gravX=0, gravY=0, gravZ=-9.8)
p.setAdditionalSearchPath(path=pybullet_data.getDataPath())

## load URDF
plane = p.loadURDF("plane.urdf")
robo = p.loadURDF(fileName="r2d2.urdf", basePosition=[0,0,0.1])

## settle down
for _ in range(240):
    p.stepSimulation()

right_wheels = [2,3]
left_wheels = [6,7]

### first turn
for _ in range(240):
    for j in right_wheels:
        p.setJointMotorControl2(bodyUniqueId=robo, jointIndex=j,
                                controlMode=p.VELOCITY_CONTROL, 
                                targetVelocity=-100, force=50)
    for j in left_wheels:
        p.setJointMotorControl2(bodyUniqueId=robo, jointIndex=j,
                                controlMode=p.VELOCITY_CONTROL, 
                                targetVelocity=100, force=50)
    p.stepSimulation()
    time.sleep(1/240)

### then move forward
for _ in range(500):   
    for j in right_wheels + left_wheels:
        p.setJointMotorControl2(bodyUniqueId=robo, jointIndex=j,
                                controlMode=p.VELOCITY_CONTROL, 
                                targetVelocity=-100, force=10)
    p.stepSimulation()
    time.sleep(1/240)

p.disconnect()

PyBullet中R2D2机器人进行原地转向和向前移动的模拟动图
请注意,每个机器人具有不同的质量(重量),因此其运动表现可能会因模拟物理特性(例如重力)而异。读者可以尝试不同的力与速度值,直到找到理想的运动效果。

PyBullet中R2D2机器人移动的模拟动图

结论

本文作为一份教程,旨在介绍PyBullet以及如何为机器人技术创建非常基础的3D仿真。读者学习了如何导入URDF对象,并分析关节和连杆。同时,也使用著名的R2D2机器人进行了实践。未来将推出更多关于高级机器人的教程。

本文的完整代码请访问:GitHub

TAGGED:PyBulletPython编程URDF仿真机器人
Share This Article
Email Copy Link Print
Previous Article 历史性一步:纽约州立法禁止AI租金定价软件,打击算法勾结抬价
Next Article Manus 1.5 技术架构图 Manus 1.5 版本深度测评:Agent能力全面提升,高效构建复杂AI应用
Leave a Comment

发表回复 取消回复

您的邮箱地址不会被公开。 必填项已用 * 标注

最新内容
20251202135921634.jpg
英伟达20亿美元投资新思科技,AI芯片设计革命加速
科技
20251202130505639.jpg
乌克兰国家AI模型选定谷歌Gemma,打造主权人工智能
科技
20251202121525971.jpg
中国开源AI新突破:DeepSeek V3.2模型性能比肩GPT-5
科技
20251202112744609.jpg
马斯克预言:AI三年内解决美国债务危机,可信吗?
科技

相关内容

AI

中国警示人形机器人行业泡沫风险,投资过热需警惕

2025年11月28日
Brush Tracker应用截图:洁净度分数与牙齿状态展示
编程与工具

AI编程神器Cursor:3天零Swift基础,速成iOS应用开发与发布实战

2025年11月17日
Figure AI机器人募资成功
AI

人形机器人独角兽Figure:募资10亿美元,估值飙升至390亿的背后逻辑与未来展望

2025年9月17日
编程与工具

Python 代码测试利器:Hypothesis 基于属性测试,先于用户发现潜在缺陷

2025年11月1日
Show More
前途科技

前途科技是一个致力于提供全球最新科技资讯的专业网站。我们以实时更新的方式,为用户呈现来自世界各地的科技新闻和深度分析,涵盖从技术创新到企业发展等多方面内容。专注于为用户提供高质量的科技创业新闻和行业动态。

分类

  • AI
  • 初创
  • 学习中心

快速链接

  • 阅读历史
  • 我的关注
  • 我的收藏

Copyright © 2025 AccessPath.com, 前途国际科技咨询(北京)有限公司,版权所有。 | 京ICP备17045010号-1 | 京公网安备 11010502033860号

前途科技
Username or Email Address
Password

Lost your password?

Not a member? Sign Up