Skip to main content

Achoo! Crash-choo! Episode I



When someone is about to sneeze in your face, you try and stop them.  And, when a robot is about to crash into your sleeping cat, Tammy, you encourage stop them.

We built something that roams around exactly how you tell it to.  But did you notice something?  If you asked it to do something stupid (sorry, Tammy), it did it without asking.  That doesn't sound very much like human behaviour to us (or does it?)  We want Rosie to be more careful, and to not listen to us all of the time.  After all, robots should surely be cleverer than us humans, right?  Help us make the right decisions, more often than not.

There are many possible ways to prevent a collision with poor old Tammy (the guinea cat).  If it does what it says on the tin, a 'distance sensor' sounds like a good place to start.  Because if you are getting closer to something - generally speaking - you should slow down, or stop.

So let's find Rosie (and Tammy!) a crash helmet, knee-pads and take out some special robot insurance.  It's time to make her - NOT - crash into things.

Be warned, though, as there is more to this than it first seems.  Like all good superhero movies, this post will have a sequel or two.  It's because what should be simple, never is.  Don't worry: you'll always know when you've encountered a frustrating Python conundrum that you have to just, erm, crash through.

You will need to have these:

  • Raspberry Pi 3, and Raspbian running on SDHC card
  • Computer from which you are connecting to the Raspberry Pi remotely
  • Ultrasonic range (distance) sensor to plug into Pi's GPIO pins
  • 'RGB' LED, also to plug into Pi's GPIO pins

You will need to have done these things:

  1. I’ve got Pi(3) brain
  2. Why-Fi-ght the Wi-Fi?
  3. Hurrah-ndom inventions
  4. Don't reinvent the eel

You will need to do this:

  • Connect the ultrasonic range (distance) sensor to Pi's GPIO pins
  • Connect RGB LED to Pi's GPIO pins
  • Create a Python program, using Control Flow statements

What do you get after all this?

A Distance or Range Sensor uses ultrasound to calculate the distance to an object using echoes that are returned after hitting a surface.  Us humans can't see or hear it happening.  If we want to predict that a collision is likely to happen, warning when an object is near enough to be a threat seems like one of many approaches.

The distance being recorded by the sensor will be an input to our program.  But what do we do with it?  Well, quite frankly, we're feeling ambitious.  Very ambitious.  Let's try and do two things(!!!):
  1. What do you see in action movies when something very bad is about to happen (like when baddies have entered the secret hideout)?  Yes.  A big red light comes on.  It's scary.  It's exciting.  And it tells you all you need to know (that... something bad is about to happen).  So let's start with a blue light, turn it yellow as Rosie approaches an object, and finally, turn it red when Rosie thinks she is way too close.  Then we know that Rosie knows.  She knows that we know.  And we know that she knows that we know.  And she knows that...
  2. Are you still controlling your robot manually using your controls?  Great (it hasn't just become human-grade intelligent overnight then).  Let's try and prevent you - silly human - from doing what humans like to do: ignore warnings... like red lights that obviously mean bad.  Disabling the 'forward' control might be one way to do it, forcing you to only turn left, right or back.
In fact, the possibilities here are infinite.  You could get her to automatically turn around.  Play a really annoying warning siren.  Self-destruct.  All of that, of course, can come later.

For now, we are leaving behind the sample programs included with the motor controller board, and 'borrowing' ideas to create our own.  And because we are now telling the program to make its own decisions based on input, we are about to require Python's useful Control Flow statements.  No ifs.  No buts (note to reader: there is really actually no but statements in Python).

Let's proceed to make robots that do (semi-)intelligent things.

This is simply too much detail:

First things first.  If you want to use your distance sensor with your Pi, you will need to connect it to your GPIO pins somehow.  It's best to refer to the instructions that came with your sensor as the pins it needs may vary.  Our RasPiRobot v3 motor controller happens to have four GPIO pins earmarked for a distance sensor (HC-SR04), so we'll be using them.

It's a similar story for the RGB LED, a magical light that can change colour.  However, we had to find spare GPIO pins outside of the motor controller board to avoid conflict with the pins already used by the motor and distance sensor.  We used GPIO pins 16, 20, and 21.  Pi 3 has, in total, 26 configurable GPIO pins (GPIO2 to GPIO27), so there should be some still spare to accommodate the LED.


All cabled up?  Good.  Let's return our attentions to the Python program that will do something interesting, hopefully.

Everyday, we make decisions based on rules that we have inside our heads.  You hurry out your house in the morning if the time on the clock is greater than 08:02.  Only while you are on the bus, you read a book.  And if you have money and you are thirsty, you buy a drink from the shop.  Machines are no different (except, we're not too sure if they get thirsty and drink).

For no other reason than for our amusement, let's momentarily return to our 'rosie_random.py' application we wrote before.  Let's make a copy of it, and call the new file 'rosie_random_with_if.py'.

cd /home/pi/rosie
...navigate to 'rosie' directory where we store all our goodies

cp rosie_random.py rosie_random_with_if.py
...copy existing 'rosie_random.py' file and rename it to become 'rosie_random_with_if.py'

Suddenly, you're feeling helpful.  You know your little brother is definitely afraid of three-wheeled eels, so let's put an if statement at the end of the program to warn him when it appears in a suggestion.  Aren't we nice?

nano rosie_random_with_if.py
...edit the copied file using our frustrating favourite text editor: nano

We want the code to look like this:

Let's step through the changes.  Firstly, rather than print the results directly on the screen (like we did before), we want to store the random selections in three variables.  This allows us to add further code to do something else with the results.

chosen_object = OBJECTS[randint(0, len(OBJECTS)-1)]
chosen_activity = ACTIVITIES[randint(0, len(ACTIVITIES)-1)]
chosen_gadget = GADGETS[randint(0, len(GADGETS)-1)]

As a result, when we are printing the results on-screen, we are now doing it using the variables.

print("Silly human, invent me a")
print(chosen_object)
print(chosen_activity)
print(chosen_gadget)

The final bit of code we have added begins with an if.  In this example, an if statement simply tests a variable to see if it meets a certain condition, and depending on the result, does or does not execute the code after it.  In this case, we are testing to see if 'chosen_gadget' is a 'three-wheeled eel', and printing a message afterwards if it's a match.

if chosen_gadget == "three-wheeled eel":
    print("Oh no! Not another three-wheeled eel! Run away!")

Now, run the new application a few times and you should eventually see the helpful warning message appear for your little brother.

python rosie_random_with_if.py 
...surely you know how to run Python programs by now?


But where's the fun in this?  Wouldn't it be more hilarious if it was always a three-wheeled eel?

We could fix the final selection in many different ways, but let's do it using a while statement.

cp rosie_random.py rosie_random_with_if_and_while.py
nano rosie_random_with_if_and_while.py
...make another copy of the application, called  'rosie_random_with_if_and_while.py'.  Then edit it using nano to make it look like this.


These two new lines have been added immediately after the gadget has been selected.

while chosen_gadget != "three-wheeled eel":
    chosen_gadget = GADGETS[randint(0, len(GADGETS) - 1)]

This way if the chosen gadget is not equal to (!=) a three-wheeled eel, it will continue to randomise until it is... inside a while loop.  Let's run it to see if it has the desired effect.

python rosie_random_with_if_and_while.py
...surely, surely, surely you know how to run Python programs by now?


MISSION ACCOMPLISHED.  Your little brother is now officially irked.  He doesn't know that the program has been rigged... with a suspect while loop.

...But this is just getting too silly.  Does any of this have anything to do with Rosie?  It's time to move on, by creating our application.  And to test whether it works, we'll just move an object in front of Rosie's distance sensor, and observe the LED change colour.

As instructed here, we need to do a few things first to be able to use the RGB LED (aka 'Squid').  Installing the Squid libraries ensures that we can interact with the RGB LED with a few simple Python functions, without needing to understand what's happening with the GPIOs behind the scenes.

git clone https://github.com/simonmonk/squid.git
cd squid
sudo python setup.py install
...clones the squid libraries from GitHub.  Then install using 'setup.py' file.



Now, we can officially use the squid libraries to easily control the RGB LED.

For the distance sensor, the RasPiRobot v3 libraries we installed for the motor controller already has a function to obtain distance readings from the sensor.  It's as easy as running the function get_distance(), and we don't have to worry about the maths taking place behind the scenes.

Now, let's create our application.

touch rosie_distance.py
nano rosie_distance.py
...creates file called 'rosie_distance.py' and edit using nano


All ready?  Let's go.  Here's (very) basic code that allows us to do what we want.

There's plenty of comments in the code to help explain what's going on, but here are some of the key points.

Unlike previous applications we've written, we want this one to run forever.  That's why we have majority of our code in an infinite while loop.  We'll be using this technique a lot going forwards, as sensors, for example, need to keep taking readings.  Don't worry, we can still exit the program at anytime, using Control+C keys.

while True:
    #...application code here

In order to smooth over one suspect distance reading, we have if statements testing for both the current and last distance readings.  Both need to satisfy the test for an alert to be registered:

if distance < distance_danger and distance_last < distance_danger:

And we only want to know when the alert level changes.  Otherwise, the program will be alerting all the time.

if alert_level != 2:
    alert_level = 2
    rgb.set_color(RED)

Lastly, we use the sleep() function to pause the application for 0.5 seconds inside the loop.  This means we only get a distance sensor reading every half a second, which means we're not stressing the application and Pi, and we can also see what's going on.  In reality, if the robot is moving around quickly, we'd want this value to be much smaller to be more sensitive.

time.sleep(0.5)

And that's it.  Run the program and wave objects in front of the distance sensor.

python rosie_distance.py
...seriously?


Congratulations, we now have the key ingredients in place for a collision avoiding robot.

But how do we do all of this while we also control the motors?  Surely robots should be able to multi-task, and do lots of different things, all at the same time?  Some functions will completely stop you from running any other code until they complete (this is called blocking).  A function that waits for you to enter something might just be one of those.

So in our next post, we investigate how we can make Rosie truly multi-task.

Even more reading:

Python's official documentation on control flows can be found here:
Raspberry Pi's official GPIO documentation can be found here:
The motor controller board and libraries in use are from Monk Makes.

Comments

Popular posts from this blog

Tea minus 30

We're fast approaching Christmas time.  And if robots were to make one simple observation about the human species during the Christmas festivities, it's that they watch a lot of TV.  A LOT.  Often, accompanied by an inappropriate amount of greenhouse gas-producing food.  Stuff you don't normally eat during the remainder of the year - for good reason.

And most so-called shows on TV are boring to robots like Rosie.  After all, why watch a minor subspecies of the human race - celebrities - stumble awkwardly around the dance floor, dressed like a faulty, sparking circuit board?  Such branch of entertainment doesn't require robots to engage any of their proud circuitry.  Their processors remain idle.  Memory under-utilised.

But if robots are to be part of people's homes (and blend in), they need to look at least a little interested in some of this irrational nonsense.  Nobody likes a party pooper.  A killjoy.  And this is where a certain subgenre of TV entertainment co…

Beam me up, Rosie!

How do you get from A to B?

You can't, as As and Bs are just letters in the alphabet. But if A is your house, and B is a meerkat village at your favourite safari park, you'd probably use a device equipped with GPS.  Not to be confused with UPS, who will deliver you your chosen meerkat through the post. And why on Earth would Rosie Patrol need one? Precisely, it's because she is on Earth that she needs one. Because our planet is rather big. Big enough to get lost in. And we don't want to lose our friendly plastic boxes on wheels. And maybe, eventually when she's clever enough, she'll go and defeat baddies on her own. And return home afterwards for a well deserved Earl Grey tea.

Besides, why wouldn't we want to add another three letter acronym to Rosie Patrol's repertoire?
All superheroes need:One Raspberry Pi 3, running Raspbian OSComputer from which you are connecting to the Raspberry Pi Probably the most important bit: a GPS receiver thingmy. …

Hello supervision, goodbye supervision

The time has finally come, to let our precious Rosie go.  Wish her luck (yes, she'll really need it).  Press the big red button.  And watch her destroy / navigate (delete as appropriate) the terrain*.  All on her own.  Without your help.  Well, sort of.

*Somewhat scientific term... for your lounge

You see, cool robots are never meant to be controlled by us clumsy humans.  If they want to be clumsy, they can be clumsy on their own.  That way we can deny all responsibility when they crash into the neighbour's car.  Or, less importantly, take over the world.

And by the way, Autonomous stuff seems to be in fashion these days.  Self-driving cars are just around the corner (maybe quite literally).  Very clever computers also beat humans at chess, apparently.  After all, if robots only do what we tell them to do, they are going to need us.  They're going to be just like us.  Oh no.  We want them to work alongside us, to do things that we simply can't be bothered to do.  Like …