Pybullet入门教程 | 您所在的位置:网站首页 › panda-learning › Pybullet入门教程 |
Pybullet入门教程
![]() 目前,验证连续控制强化学习算法的仿真环境,最常用的是Mujoco,但是需要license,学生邮箱可申请单机一年的免费使用权。同时,大部分情况下,如果使用Gym和Python,还需要安装Mujoco-py,安装过程都不友好。另外很重要的是,据个人了解,Mujoco原生版,也就是C++版的文档写的水平一般,Mujoco-py本身就没什么文档,只有几个example。 相比之下,PyBullet使用免费的Bullet引擎,安装过程也仅是pip install pybullet这么简单。PyBullet的文档也是良心所在,文档几乎面面俱到,文档地址PyBullet Quickstart Guide,同时,每个API都提供了详细的example,还有PyBullet应用在Gym、强化学习算法、机器人等特殊目的的example。对于想用Bullet引擎做游戏和视频的小伙伴,Bullet的每个C++ API也是提供了详细的example。 总结起来就是,PyBullet上手难度更低,国外有博主说明年(2021年)PyBullet有可能会成为机器人强化学习领域的仿真环境的事实标准。 目前,在用PyBullet做仿真的强化学习项目越来越多,像Deep Mimic
一波推销过后,说回正题,下面将一步步的说明pybulelt的使用。我们将以Panda机器人为例。 PyBulelt使用URDF解析运动学、形状、动力学等特性。同时也支持Gazebo的SDF、Mujoco的MJCF。在pybullet_data文件夹,已经定义了很多机器人的描述文件。 当然如果不用os模块,也可以使用p.setAditionalSearchPath()这个函数来做。 import pybullet as p import pybullet_data as pd p.connect(p.GUI) p.setAdditionalSearchPath(pd.getDataPath()) pandaUid=p.loadURDF("franka_panda/panda.urdf",useFixedBase=True) while True: p.stepSimulation()结果就是有个机器人出现了。 那为什么os模块和setAdditionalSearchPath()都可以实现相同的效果呢?原因很简单。因为他俩做的是同样的工作。有点废话废键盘。 在Pycharm中,我们在import pybullet_data as pd这句的pybullet_data上面按Ctrl+B,将会跳转到pybullet_data的定义上面。可以看到打开的是__init__.py文件。 同样,要注意到一个奇怪的现象,看看pybullet_data的安装位置。为什么没有安装在anaconda的env的site-package里面? 我也不知道,已经提交issue了(2020-8-30)。issue erwin大神已经回了. 链接 我们打开pybullet_data文件夹看一下目录结构。里面全都是描述文件。 其实说到pybullet_data文件夹的位置比较奇怪,那看看pybullet的位置,那简直叫离奇了。在import pybullet as p的pybullet上按Ctrl+B,跳转到了pybullet.py,看位置。 C:\Users\born_\AppData\Local\JetBrains\PyCharm2020.2\python_stubs\-520983747什么玩意??黑人问号走起来。pybullet.py中全是函数的定义,函数体都是pass,说明只是暴漏在外的API,还有封装好的文件。看pybullet.py的前面几行注释,其中有一行 可以看到封装好的文件就是这个。pybullet的函数体就定义在里面。 下面,我们将机器人放在桌子上。在pandaUid下面添加这句。 tableUid=p.loadURDF("table/table.urdf",basePosition=[0.5,0,-0.65])再添加一个盒子 trayUid=p.loadURDF("tray/traybox.urdf",basePosition=[0.65,0,0])最后的代码就是 import pybullet as p import pybullet_data as pd p.connect(p.GUI) p.setAdditionalSearchPath(pd.getDataPath()) pandaUid=p.loadURDF("franka_panda/panda.urdf",useFixedBase=True) tableUid=p.loadURDF("table/table.urdf",basePosition=[0.5,0,-0.65]) trayUid=p.loadURDF("tray/traybox.urdf",basePosition=[0.65,0,0]) while True: p.stepSimulation()
文件夹中全是.urdf或者其他描述文件,没办法一下子看出模型长什么样,除非把他们用loadURDF()添加进来查看。但是呢,有更好的办法,走起,不通过ROS直接查看URDF文件。 我们继续添加模型。 objectUid=p.loadURDF("random_urdfs/000/000.urdf",basePosition=[0.7,0,0.7])咋飘着? 模型飘了? 没加重力而已。 p.setGravity(0,0,-10)在p.connect(p.GUI)下面添加这句就行。 上面的截图肯定和刚运行出来的时候不一样,我是拉近了不知道多少才能看到这样,不然显示的效果离自己很远很小。 咋办?调整视窗白。 p.resetDebugVisualizerCamera(cameraDistance=1.5,cameraYaw=0,\ cameraPitch=-40,cameraTargetPosition=[0.55,-0.35,0.2])当然也可以自己调整一下参数值,看一下效果。比如这样也是可以的 p.resetDebugVisualizerCamera(cameraDistance=1,cameraYaw=0,\ cameraPitch=-40,cameraTargetPosition=[0.5,-0.9,0.5])参数中cameraTargetPosition指摄像机的位置,cameraDistance指相机的焦距的变化,类似变焦。 完整代码 import pybullet as p import pybullet_data as pd # cameraTargetPosition=[0.55,-0.35,0.2] p.connect(p.GUI) p.setGravity(0,0,-10) # p.configureDebugVisualizer(p.COV_ENABLE_SINGLE_STEP_RENDERING) p.setAdditionalSearchPath(pd.getDataPath()) p.resetDebugVisualizerCamera(cameraDistance=1,cameraYaw=0,\ cameraPitch=-40,cameraTargetPosition=[0.5,-0.9,0.5]) pandaUid=p.loadURDF("franka_panda/panda.urdf",useFixedBase=True) tableUid=p.loadURDF("table/table.urdf",basePosition=[0.5,0,-0.65]) trayUid=p.loadURDF("tray/traybox.urdf",basePosition=[0.65,0,0]) objectUid=p.loadURDF("random_urdfs/000/000.urdf",basePosition=[0.7,0,0.7]) object1Uid=p.loadURDF("random_urdfs/001/001.urdf",basePosition=[0.7,0.1,0.7]) object2Uid=p.loadURDF("random_urdfs/002/002.urdf",basePosition=[0.6,-0.2,0.7]) object3Uid=p.loadURDF("random_urdfs/003/003.urdf",basePosition=[0.8,0.1,0.7]) object4Uid=p.loadURDF("random_urdfs/004/004.urdf",basePosition=[0.7,-0.1,0.7]) object5Uid=p.loadURDF("random_urdfs/005/005.urdf",basePosition=[0.6,0.1,0.3]) object6Uid=p.loadURDF("random_urdfs/006/006.urdf",basePosition=[0.8,-0.2,0.4]) object7Uid=p.loadURDF("random_urdfs/007/007.urdf",basePosition=[0.6,0.2,0.4]) object8Uid=p.loadURDF("random_urdfs/008/008.urdf",basePosition=[0.7,-0.1,0.4]) object9Uid=p.loadURDF("random_urdfs/009/009.urdf",basePosition=[0.6,0.1,0.4]) while True: p.stepSimulation()下面,我们来控制机械臂运动。控制电机的API是setJointMotorControl2()。在Panda机器人的URDF定义里,joint 0~6是关节电机,9, 10是夹爪电机。 我们将机械臂的抓取过程分成4个步骤:current_state==0时,将机械臂移动到物体的上面,打开夹爪;current_state==1时,往下移动夹爪;current_state==3时,夹住物体。 每个步骤经过1个单位时间,即比如设置setTimeStep=1./240.时,经过240个stepSimulation()完成当前步骤。 完整代码: import pybullet as p import pybullet_data as pd import math import time # cameraTargetPosition=[0.55,-0.35,0.2] p.connect(p.GUI) p.setGravity(0,0,-10) # p.configureDebugVisualizer(p.COV_ENABLE_SINGLE_STEP_RENDERING) p.setAdditionalSearchPath(pd.getDataPath()) p.resetDebugVisualizerCamera(cameraDistance=1,cameraYaw=0,\ cameraPitch=-40,cameraTargetPosition=[0.5,-0.9,0.5]) pandaUid=p.loadURDF("franka_panda/panda.urdf",useFixedBase=True) tableUid=p.loadURDF("table/table.urdf",basePosition=[0.5,0,-0.65]) trayUid=p.loadURDF("tray/traybox.urdf",basePosition=[0.65,0,0]) objectUid=p.loadURDF("random_urdfs/000/000.urdf",basePosition=[0.7,0,0.1]) # object1Uid=p.loadURDF("random_urdfs/001/001.urdf",basePosition=[0.7,0.1,0.7]) # object2Uid=p.loadURDF("random_urdfs/002/002.urdf",basePosition=[0.6,-0.2,0.7]) # object3Uid=p.loadURDF("random_urdfs/003/003.urdf",basePosition=[0.8,0.1,0.7]) # object4Uid=p.loadURDF("random_urdfs/004/004.urdf",basePosition=[0.7,-0.1,0.7]) # object5Uid=p.loadURDF("random_urdfs/005/005.urdf",basePosition=[0.6,0.1,0.3]) # object6Uid=p.loadURDF("random_urdfs/006/006.urdf",basePosition=[0.8,-0.2,0.4]) # object7Uid=p.loadURDF("random_urdfs/007/007.urdf",basePosition=[0.6,0.2,0.4]) # object8Uid=p.loadURDF("random_urdfs/008/008.urdf",basePosition=[0.7,-0.1,0.4]) # object9Uid=p.loadURDF("random_urdfs/009/009.urdf",basePosition=[0.6,0.1,0.4]) state_durations=[1,1,1,1] control_dt=1./240. p.setTimeStep=control_dt state_t=0. current_state=0 while True: state_t+=control_dt #p.configureDebugVisualizer(p.COV_ENABLE_SINGLE_STEP_RENDERING) if current_state==0: p.setJointMotorControl2(pandaUid,0,p.POSITION_CONTROL,0) p.setJointMotorControl2(pandaUid,1,p.POSITION_CONTROL,math.pi/4.) p.setJointMotorControl2(pandaUid,2,p.POSITION_CONTROL,0) p.setJointMotorControl2(pandaUid,3,p.POSITION_CONTROL,-math.pi/2.) p.setJointMotorControl2(pandaUid,4,p.POSITION_CONTROL,0) p.setJointMotorControl2(pandaUid,5,p.POSITION_CONTROL,3*math.pi/4) p.setJointMotorControl2(pandaUid,6,p.POSITION_CONTROL,-math.pi/4.) p.setJointMotorControl2(pandaUid,9,p.POSITION_CONTROL,0.08) p.setJointMotorControl2(pandaUid,10,p.POSITION_CONTROL,0.08) if current_state==1: p.setJointMotorControl2(pandaUid,1,p.POSITION_CONTROL,math.pi/4.+.15) p.setJointMotorControl2(pandaUid,3,p.POSITION_CONTROL,-math.pi/2.+.15) if current_state==2: p.setJointMotorControl2(pandaUid,9,p.POSITION_CONTROL,force=200) p.setJointMotorControl2(pandaUid,10,p.POSITION_CONTROL,force=200) if current_state==3: p.setJointMotorControl2(pandaUid,1,p.POSITION_CONTROL,math.pi/4.-1) p.setJointMotorControl2(pandaUid,3,p.POSITION_CONTROL,-math.pi/2.-1) if state_t>state_durations[current_state]: current_state+=1 if current_state>=len(state_durations): current_state=0 state_t=0 p.stepSimulation()运行代码你会发现,除了机械臂是在突变位置外,其他一切正常。机械臂咋会突变位置呢? 这就牵扯到一个API: p.configureDebugVisualizer(p.COV_ENABLE_SINGLE_STEP_RENDERING)p.COV_ENABLE_SINGLE_STEP_RENDERING是指允许机械臂慢慢的渲染。 在while True:下面的第二句,把注释取消掉,就可以看到缓慢渲染的过程了。 pybullet原创文章作者:bug404。如若转载,请注明出处:古月居 http://www.guyuehome.com/34388 打赏 0 点赞 4 收藏 5 分享 微信 微博 QQ 图片 上一篇:使用Latex自动画神经网络模型图 下一篇:Python多进程 |
今日新闻 |
推荐新闻 |
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 |