Intro
that may carry out duties and make selections by replicating or substituting human actions. Robotics is the scientific subject centered on the design and building of robots. It’s a multidisciplinary mixture of:
- Electrical Engineering for sensors and actuators. Sensors collect knowledge from the surroundings, changing bodily properties into electrical indicators (like our 5 senses). Actuators convert these indicators into bodily actions or actions (like our muscle tissue).
- Mechanical Engineering for the design and motion of the bodily construction.
- Laptop Science for the AI software program and algorithms.
Presently, ROS (Robotic Working System) is the principle framework for Robotics that handles all of the completely different components of a robotic (sensors, motors, controllers, cameras…), the place all of the parts alternate knowledge in a modular approach. The ROS framework is supposed for actual robotic prototypes, and it may be used with each Python and C++. Given its reputation, there are a lot of libraries constructed on high of ROS, like Gazebo, essentially the most superior 3D simulator.
Since Gazebo is kind of sophisticated, one can nonetheless be taught the fundamentals of Robotics and construct user-friendly simulations exterior the ROS ecosystem. The principle Python libraries are:
- PyBullet (freshmen) — nice for experimenting with URDF (Unified Robotic Description Format), which is the XML schema for describing robotic our bodies, components, and geometry.
- Webots (intermediate) — the physics is extra correct, so it may well construct extra complicated simulations.
- MuJoCo (superior) — actual world simulator, it’s used for research-grade experiments. OpenAI’s RoboGYM library is constructed on high of MuJoCo.
Since it is a tutorial for freshmen, I’m going to indicate learn how to construct easy 3D simulations with PyBullet. I’ll current some helpful Python code that may be simply utilized in different comparable instances (simply copy, paste, run) and stroll by way of each line of code with feedback to be able to replicate this instance.
Setup
PyBullet is essentially the most user-friendly physics simulator for video games, visible results, Robotics, and Reinforcement Studying. You’ll be able to simply set up it with one of many following instructions (if pip fails, conda ought to positively work):
pip set up pybullet
conda set up -c conda-forge pybullet
You’ll be able to run PyBullet in two primary modes:
p.GUI→ opens a window and exhibits the simulation in actual time.p.DIRECT→ no graphics mode, used for scripts.
import pybullet as p
p.join(p.GUI) #or p.join(p.DIRECT)
Since it is a physics simulator, the very first thing to do is ready up gravity:
p.resetSimulation()
p.setGravity(gravX=0, gravY=0, gravZ=-9.8)
Units the worldwide gravity vector for the simulation. “-9.8” on the z-axis means an acceleration of 9.8 m/s^2 downward, similar to on Earth. With out this, your robotic and aircraft would float in zero-gravity, similar to in house.
URDF file
If the robotic was a human physique, the URDF file can be the skeleton that defines its bodily construction. It’s written in XML, and it’s mainly the blueprint for the machine, defining what your robotic appears like and the way it strikes.
I’m going to indicate learn how to create a easy dice, which is the 3D equal of print(“whats up world”).
urdf_string = """"
"""
You’ll be able to both save the XLM code as a URDF file or use it as a string.
import pybullet as p
import tempfile
## setup
p.join(p.GUI)
p.resetSimulation()
p.setGravity(gravX=0, gravY=0, gravZ=-9.8)
## create a brief URDF file in reminiscence
with tempfile.NamedTemporaryFile(suffix=".urdf", mode="w", delete=False) as f:
f.write(urdf_string)
urdf_file = f.identify
## load URDF
p.loadURDF(fileName=urdf_file, basePosition=[0,0,1])
## render simulation
for _ in vary(240):
p.stepSimulation()
Please notice that the loop did run with 240 steps. Why 240? It’s a set timestep generally utilized in videogame improvement for a clean and responsive expertise with out overtaxing the CPU. 60 FPS (frames per second) with 1 body displayed each 1/60 of a second, which signifies that a physics step of 1/240 seconds gives 4 physics updates for each rendered body.
Within the earlier code, I rendered the dice with p.stepSimulation(). It signifies that the simulation just isn’t in real-time and also you management when the following physics step occurs. Alternatively, you could possibly use time sleep to bind it to the true world clock.
import time
## render simulation
for _ in vary(240):
p.stepSimulation() #add a physics step (CPU pace = 0.1 second)
time.sleep(1/240) #decelerate to real-time (240 steps × 1/240 second sleep = 1 second)
Going ahead, the XML code for robots will get way more sophisticated. Fortunately, PyBullet comes with a group of preset URDF information. You’ll be able to simply load the default dice with out creating the XML for it.
import pybullet_data
p.setAdditionalSearchPath(path=pybullet_data.getDataPath())
p.loadURDF(fileName="dice.urdf", basePosition=[0,0,1])
At its core, a URDF file defines two primary issues: hyperlinks and joints. Hyperlinks are the stable a part of the robots (like our bones), and a joint is the connection between two inflexible hyperlinks (like our muscle tissue). With out joints, your robotic can be only a statue, however with joints it turns into a machine with movement and goal.
In a nutshell, each robotic is a tree of hyperlinks linked by joints. Every joint could be mounted (no motion) or rotate (“revolute joint”) and slide (“prismatic joint”). Due to this fact, you could know the robotic you’re utilizing.
Let’s make an instance with the well-known robotic R2D2 from Star Wars.
Joints
This time, we now have to import a aircraft as nicely to be able to create a floor for the robotic. With no aircraft, objects wouldn’t have a floor to collide with and they’d simply fall indefinitely.
## setup
p.join(p.GUI)
p.resetSimulation()
p.setGravity(gravX=0, gravY=0, gravZ=-9.8)
p.setAdditionalSearchPath(path=pybullet_data.getDataPath())
## load URDF
aircraft = p.loadURDF("aircraft.urdf")
robo = p.loadURDF(fileName="r2d2.urdf", basePosition=[0,0,0.1])
## render simulation
for _ in vary(240):
p.stepSimulation()
time.sleep(1/240)
p.disconnect()
Earlier than utilizing the robotic, we should perceive its parts. PyBullet has standardized the data construction so that each robotic you import shall at all times be outlined by the identical 17 common attributes. Since I simply wish to run a script, I’m going to hook up with the physics server with out the graphic interface (p.DIRECT). The principle perform to research a joint is p.getJointInfo().
p.join(p.DIRECT)
dic_info = {
0:"joint Index", #begins at 0
1:"joint Title",
2:"joint Sort", #0=revolute (rotational), 1=prismatic (sliding), 4=mounted
3:"state vectorIndex",
4:"velocity vectorIndex",
5:"flags", #nvm at all times 0
6:"joint Damping",
7:"joint Friction", #coefficient
8:"joint lowerLimit", #min angle
9:"joint upperLimit", #max angle
10:"joint maxForce", #max drive allowed
11:"joint maxVelocity", #max pace
12:"hyperlink Title", #little one hyperlink linked to this joint
13:"joint Axis",
14:"guardian FramePos", #place
15:"guardian FrameOrn", #orientation
16:"guardian Index" #−1 = base
}
for i in vary(p.getNumJoints(bodyUniqueId=robo)):
print(f"--- JOINT {i} ---")
joint_info = p.getJointInfo(bodyUniqueId=robo, jointIndex=i)
print({dic_info[k]:joint_info[k] for okay in dic_info.keys()})
Each joint, irrespective of if it’s a wheel, elbow, or gripper, has to show those self same options. The code above exhibits that R2D2 has 15 joints. Let’s analyze the primary one, known as “base to right-leg”:
- The joint kind is 4, which implies it doesn’t transfer. The guardian hyperlink is -1, which implies it’s linked to the base, the basis a part of the robotic (like our skeleton backbone). For R2D2, the bottom is the principle cylindrical physique, that large blue and white barrel.
- The hyperlink identify is “proper leg”, so we perceive that this joint connects the robotic’s base with the fitting leg, nevertheless it’s not motorized. That’s confirmed by joint axis, joint dumping, and joint friction being all zeros.
- Guardian body place and orientation outline the place the fitting leg is connected to the bottom.
Hyperlinks
Alternatively, to be able to analyze the hyperlinks (the bodily physique segments), one should loop by way of the joints to extract the hyperlink identify. Then, you should utilize two primary features: p.getDynamicsInfo() to grasp the bodily properties of the hyperlink, and p.getLinkState() to know its spatial state.
p.join(p.DIRECT)
for i in vary(p.getNumJoints(robo)):
link_name = p.getJointInfo(robo, i)[12].decode('utf-8') #subject 12="hyperlink Title"
dyn = p.getDynamicsInfo(robo, i)
pos, orn, *_ = p.getLinkState(robo, i)
dic_info = {"Mass":dyn[0], "Friction":dyn[1], "Place":pos, "Orientation":orn}
print(f"--- LINK {i}: {link_name} ---")
print(dic_info)
Let’s analyze the primary one, the “right-leg”. The mass of 10 kg contributes to gravity and inertia, whereas the friction impacts how a lot it slides when contacting the bottom. The orientation (0.707=sin(45°)/cos(45°)) and place point out that the right-leg hyperlink is a stable piece, barely ahead (5cm), tilted 90° relative to the bottom.
Actions
Let’s take a look at a joint that may truly transfer.
For istance, joint 2 is the fitting entrance wheel. It’s a sort=0 joint, so it rotates. This joint connects the fitting leg (hyperlink index 1) to the fitting entrance wheel: base_link → right_leg → right_front_wheel. The joint axis is (0,0,1), so we all know that the wheel spins across the z-axis. The bounds (decrease=0, higher=-1) point out that the wheel can spin infinitely, which is regular for rotors.
We will simply transfer this joint. The principle command for controlling actuators in your robotic is p.setJointMotorControl2(), it permits to regulate the drive, velocity, and place of a joint. On this case, I wish to make the wheel spin, so I’ll apply drive to steadily carry the speed from zero to a goal velocity, then keep it by balancing utilized drive and resistive forces (i.e. friction, damping, gravity).
p.setJointMotorControl2(bodyUniqueId=robo, jointIndex=2,
controlMode=p.VELOCITY_CONTROL,
targetVelocity=10, drive=5)
Now, if we apply the identical drive to all of the 4 wheels, we are going to make our little robotic transfer ahead. From the evaluation carried out earlier, we all know that the joints for the wheel are quantity 2 and three (proper facet), and quantity 6 and seven (left facet).
Contemplating that, I shall first make R2D2 flip round by spinning just one facet, after which apply drive to each wheel on the similar time to make it transfer ahead.
import pybullet as p
import pybullet_data
import time
## setup
p.join(p.GUI)
p.resetSimulation()
p.setGravity(gravX=0, gravY=0, gravZ=-9.8)
p.setAdditionalSearchPath(path=pybullet_data.getDataPath())
## load URDF
aircraft = p.loadURDF("aircraft.urdf")
robo = p.loadURDF(fileName="r2d2.urdf", basePosition=[0,0,0.1])
## quiet down
for _ in vary(240):
p.stepSimulation()
right_wheels = [2,3]
left_wheels = [6,7]
### first flip
for _ in vary(240):
for j in right_wheels:
p.setJointMotorControl2(bodyUniqueId=robo, jointIndex=j,
controlMode=p.VELOCITY_CONTROL,
targetVelocity=-100, drive=50)
for j in left_wheels:
p.setJointMotorControl2(bodyUniqueId=robo, jointIndex=j,
controlMode=p.VELOCITY_CONTROL,
targetVelocity=100, drive=50)
p.stepSimulation()
time.sleep(1/240)
### then transfer ahead
for _ in vary(500):
for j in right_wheels + left_wheels:
p.setJointMotorControl2(bodyUniqueId=robo, jointIndex=j,
controlMode=p.VELOCITY_CONTROL,
targetVelocity=-100, drive=10)
p.stepSimulation()
time.sleep(1/240)
p.disconnect()
Please notice that each robotic has a special mass (weight) so the actions could be completely different primarily based on the simulation physics (i.e. gravity). You’ll be able to play and take a look at completely different drive and velocity till you discover the specified consequence.
Conclusion
This text has been a tutorial to introduce PyBullet and learn how to create very fundamental 3D simulations for Robotics. We discovered learn how to import URDF objects and learn how to analyze joints and hyperlinks. We additionally performed with the well-known robotic R2D2. New tutorials with extra superior robots will come.
Full code for this text: GitHub
I hope you loved it! Be happy to contact me for questions and suggestions or simply to share your attention-grabbing tasks.
👉 Let’s Join 👈
(All photographs are by the writer until in any other case famous)







