Intro to Robotics Programming: Part 2
Posted: March 21, 2016
Rob is a member of the mobile robot family. In the two dimensional world we will create, he is free to move in any direction. Rob won't be the only robot we meet on our journey, but he'll be our first. Let's help him get moving.
If you're on Linux, you already have Python and so are just about ready to go. I highly recommend the use of pip and virtualenvwrapper to manage package installation, but choose any work-flow that works for you.
You can install all the required Python packages you'll need by downloading this requirements file and running:
mkvirtualenv robotics_intro_env pip install -r requirements.txt
And that's it, we're ready to get coding!
Let's get Rob up and running. Throughout this series we'll use the pymunk library, a wrapper for Chipmunk for our world and object representation, as well as collision detection and joint modeling. There are several components to most robot models. Chipmunk sums it up nicely:
- Rigid Bodies: A rigid body holds the physical properties of an object. (mass, position, rotation, velocity, etc.) It does not have a shape until you attach one or more collision shapes to it. If you’ve done physics with particles before, rigid bodies differ in that they are able to rotate. Rigid bodies generally tend to have a 1:1 correlation to sprites in a game. You should structure your game so that you use the position and rotation of the rigid body for drawing your sprite.
- Collision Shapes: By attaching shapes to bodies, you can define the a body’s shape. You can attach as many shapes to a single body as you need to in order to define a complex shape. Shapes contain the surface properties of an object such as how much friction or elasticity it has.
- Constraints/Joints: Constraints and joints describe how bodies are attached to each other.
- Spaces: Spaces are containers for simulating objects in Chipmunk. You add bodies, shapes and joints to a space and then update the space as a whole. They control how all the rigid bodies, shapes, and constraints interact together.
-- Chipmunk Documentation
All robot models contain the same basic components: physical properties, shape, and joints (generically called constraints). And we must usually put them into some container. We'll come back to joints later, but Rob doesn't really need one, so let's start with just a body and shape. Take note that although I refer to physical units (meters and kilograms), Chipmunk actually doesn't care what units we use. As long as you are consistent, you will get consistent and correct results that you can treat however you like. This allows us to define a meters-to-pixels conversion, and use it directly in our robot body, again simplifying our display code.
import pymunk # constant for converting physical units to pixels M_TO_PIXELS = 200 # build Rob the robot rob_mass = 1 # 1 kg rob_radius = 0.1 * M_TO_PIXELS # 0.1 meter radius, converted to pixels for later display rob_I = pymunk.moment_for_circle(rob_mass, 0, rob_radius) # moment of inertia for disk rob_body = pymunk.Body(rob_mass, rob_I) rob_body.position = 300, 300 # (x, y) rob_shape = pymunk.Circle(rob_body, rob_radius)
That's it! Not very exciting, since we still can't see him yet. The second library we'll make great use of is
pyglet, a fantastic Python wrapper for OpenGL.
OpenGL is an absolute nightmare to use directly, but
pyglet makes it much easier, and there is even a
pymunk.pyglet_util library as well! However, we still have some setting up to do.
# setup context window = pyglet.window.Window(width=600, height=600, visible=False) # define visualization @window.event def on_draw(): # always clear and redraw for graphics programming window.clear() pymunk.pyglet_util.draw(rob_shape) # this is gold right here
We first create a
window object which creates the OpenGL context for us, but set it to
visible=False so it doesn't
display before we finish defining our application.
Next, we create a
pyglet event handler by using the
event annotation on
window, and the function name
indicates to run this function when, you guessed it, drawing.
As with any graphics programming, we want to clear the display buffer first, and then do all of our drawing at once.
We're going to get a lot of mileage out of
pymunk.pyglet_util.draw(), as it saves us from implementing
polygon drawing routines ourselves.
Two more lines of setup and we're ready to run our robot.
rob_shape.color = 255, 0, 0 # make Rob red, RGB value window.set_visible(True) pyglet.app.run() # start application loop
We make our window visible and start our application loop. If you get stuck, ESC exits the window.
Now, although Rob is a masterpiece of robot design, and should probably be put in a contemporary art museum somewhere, you're probably wondering if you could make him do... something.... Anything really. Let's do just that.
Before running your application, at the top add an import
from pyglet.window import key,
and add the following above
# get access to system keyboard keyboard = key.KeyStateHandler() window.push_handlers(keyboard) # use keyboard to control Rob def process_user_input(dt): speed = 0.6 # m/s distance = speed * dt * M_TO_PIXELS # m/s * s -> pixels # direction if keyboard[key.RIGHT]: rob_body.position += distance, 0 if keyboard[key.LEFT]: rob_body.position -= distance, 0 if keyboard[key.UP]: rob_body.position += 0, distance if keyboard[key.DOWN]: rob_body.position -= 0, distance # process input at regular interval pyglet.clock.schedule_interval(process_user_input, 1.0/60) # 60Hz
This allows us to control Rob with the arrow keys on our keyboard.
Just like we would with any hardware, we read and process its signal at a regular, fixed interval.
pyglet cannot guarantee exact timing because of operating system restrictions,
we take in a Δtime to know exactly how much time has passed since the last update.
And there you have it. Running again gives you a real (simulated) robot (colored blob) that you can control!
The complete code for this article can be found in the https://github.com/clintliddick/robotics_intro repository, and you can run the application with:
cd robotics_intro workon robotics_intro_env python -m roboticsintro.hellorobot.simple
We've met our first robot, and learned a little about its composition in simulation space. In the next article, we'll consider rotation, and introduce the concept of configuration space.
Next article: part 3