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

  1. My RugWarriorPro+Raspberry Pi robot's name is Pogo, and when being a "poser" Rosie, I call it Posie.

    I figured out my cntrl-c not working issue - had to add my set_cntrl_c_handler to my simulated rrb3 init().

    Posie doesn't have a squid LED so I created a "print only" squid.py. Having a "mood indicator" sounds like a great idea, since one should always know when your robot is in a foul mood.
    (My musing on moody robots: http://alanmcdonley.blogspot.com/2014/09/i-sense-therefore-i-feel-moody-behavior.html)

    Posie does have a speaker so I hear "her" report "Too Close! Too Close!" (My text-to-speech path has a painful broadcast delay...)

    Looking forward to setting Posie loose a bit in the next installment.


    ReplyDelete

Post a Comment

MOST VISITED (APPARENTLY)

LoRa-Wan Kenobi

In the regurgitated words of Michael BublĂ©: It's a new dawn .  It's a new day .  It's a new Star Wars film .  For me .  And I'm (George Lucas, and I'm) feeling good .  Unfortunately for Canadian Mike, the Grammy that year was won by the novelty disco classic with the famous refrain: We love IoT, even in Planet Tatooine * . *Not true. Clearly, the Star Wars producers didn't sincerely mean the last Jedi the previous time around.  Return of the Jedi, released during the decade that spearheaded cultural renaissance 2.0 with the mullet and hair-metal , was less economic with the truth.  Either way, we're going to take inspiration from the impressive longevity of the money-spinning space-opera and reboot our franchise with some Jedi mind tricks.  Except this particular flick doesn't require an ever-growing cast of unrecognisable characters, unless ASCII or UTF counts.  In place of an ensemble gathering of Hollywood stars and starlets, we will b

Battle of BLEtain

The trolling . The doxing . An army of perplexing emojis. And endless links to the same - supposedly funny - viral video of a cat confusing a reflection from a dangling key for a golden hamster, while taking part in the mice bucket challenge. Has social media really been this immense force for good? Has it actually contributed significantly to the continued enlightenment of the human (or feline) race? In order to answer these poignant existential questions about the role of prominent platforms such as Critter, StinkedIn and Binterest, employing exceptional scientific rigour equal to that demonstrated by Theranos , we're going to set up a ground-breaking experiment using the Bluetooth Low Energy feature of MicroPython v1.12, and two ESP32 development boards with inexplicable hatred for one another.  And let them hurl quintessentially British expressions (others call them abuse) at each other like two Wiltshire residents who have had their internet access curbed by the co

Hard grapht

You would all be forgiven for assuming that bar , pie and queue line are favourite pastimes of the British .  Yet, in fact – yes, we did learn this back in GCSE maths – they are also mechanisms through which meaningless, mundane data of suspect origin can be given a Gok Wan -grade makeover, with the prime objective of padding out biblical 187-page PowerPoint presentations and 871-page Word reports (*other Microsoft productivity tools are available).  In other words, documents that nobody has the intention of ever reading.  But it becomes apparent over the years; this is perhaps the one skill which serves you well for a lifetime in certain careers.  In sales.  Consultancy.  Politics.  Or any other profession in which the only known entry requirement is the ability to chat loudly over a whizzy graph of dubious quality and value, preferably while frantically waving your arms around. Nevertheless, we are acutely conscious of the fact that we have spent an inordinate amount