Inputs & Outputs
Invent Logo

Computers can use both input and output devices. An input device sends information to a computer. An example would be a keyboard or a mouse. An output device receives information from a computer. An example is a computer monitor or speakers.

We've already used one output device. The drive module is a good example. The two motors are controlled by a signal from the robot so they are output devices. Let's now use some more outputs. We'll use the in-built LEDs.

Inputs & Outputs
The LEDs

We've already looked at some of the other LEDs that show the status of the robot, but there are two additional LEDs that you can control at the front of the robot; one on the left and one on the right.

The LEDs
Testing them out

Start a new program and drag the 'LED' block into your code. This block allows you to select either the left or right LED and specify the colour you want. You can select any colour for either LED.

Try this out now. Set one of your LEDs to green and the other to red.

Testing them out
Testing them out

Now swap to the 'Files' tab and click on the 'code.bipes.py' file to see the code that the blocks we've just inserted would generate.

You'll see something like this ...

from invent import *

np[0]=(255,0,0)
np.write()
np[1]=(0,255,0)
np.write()
How it works

You already know about the first line - it's needed for all our programmes as it's got essential 'library' code to operate the robot.

In this library it defines a variable called np ('Neopixel' - this is what these the two little lights are called on the front of your robot).

The 'np' variable is actually an 'array', meaning that it an contain more than one value. In our case it contains two (np[0] for the left LED and np[1] for the right LED). So what we're doing here is telling the left LED to light up with the colour (255,0,0) and the right one with (0,255,0). But what do these mean?

from invent import *

np[0]=(255,0,0)
np.write()
np[1]=(0,255,0)
np.write()
RGB colours

The numbers inside the brackets are the values of red, green and blue, respectively for the three mini LEDs that are actually inside each of the left and right LEDs.

By having red green and blue LEDs we can show any colour. Each number is a value between 0 (fully off) and 255 (fully on). So can you see that we've set the left LED to fully red, and the right one to fully green?

The 'np.write()' command tells the LEDs to update to their new colours. We need to have this command in every time we want to make a change. We could actually simplify this code a little ...

from invent import *

np[0]=(255,0,0)
np.write()
np[1]=(0,255,0)
np.write()
Simplified

Here we've taken out the first np.write() command that the automatic 'Blocks-to-Python' conversion inserted.

The reason that we only need one of these is that it will tell all of the LEDs to update their colour based on the colours we've set in the lines above them.

Now experiment with these values.

  • Can you work out how to display a colour like Cyan (a bluey-green)?
  • Can you get one of them to shine purple?
  • How about yellow?
  • Now try making one of them white!
from invent import *

np[0]=(255,0,0)
np[1]=(0,255,0)
np.write()
Morse code

Morse code was invented by Samuel Morse and Alfred Vail in the early 1830s. He wanted a way to send messages using electricity over telegraph wires. They assigned each letter of the alphabet and some symbols a unique combination of dots (short taps) and dashes (long taps). This allowed messages to be transmitted using simple codes, revolutionizing communication over long distances before phones or the internet.

Morse code
SOS

Morse code is like a secret language using sounds and pauses instead of words. Imagine tapping a pencil to talk to a friend far away. A short tap means a dot, a long tap means a dash, and pauses separate letters and words. So, "SOS" would be three short taps, three long taps, then three short taps again. It's a clever way to send messages without needing to talk or write!

"SOS" is a distress signal used to ask for help when someone is in trouble, like when they're lost at sea or in danger. It's like saying "please help me" in a simple and urgent way that people all around the world understand. It stands for 'Save Our Souls!'.

Sending SOS

Can you write a program to send SOS on one of your LEDs? You can send it using any colour you like. To use this, you'll need to use the sleep command which requires the 'time' library. The code shown here won't look like it's doing anything because it will just wait 1 second and then not do anything else.

You'll need to use a combination of LED commands and 'time.sleep' commands to send your SOS (three short blinks, three long blinks, three short blinks again). You'll want delays less than 1 second, so you can change the '1' to a fraction of a second.

Experiment with the delays until you get a recognisable pattern, and then put your code in a big loop so that it flashes 'SOS' twice. You'll want a bigger delay between each 'SOS' than you have between each letter.

Remember, you'll still need the code to import the 'invent' library' to use the LEDs, so you'll have to add this at the top either above or below the 'import time' command.

import time

time.sleep(1)
Making sounds

The speaker is another example of an output as it can be controlled by your robot.

We can use the speaker to play notes.

Different ways of importing

Do you recall that last time we used:

import time

and then when we wanted to sleep we used:

time.sleep(1)

This is because when you import a library just by it's name you need to prefix the function we want to call with the library name and a dot. Instead, now we use:

from time import *

(just like we used when we imported everything from the invent library), and then we just need to use:

sleep(1)

Playing a note

Using the playtone function is a good way to create you own beep sounds from the code, give it a try!

The first parameter is the frequency of the note in Hertz, in this case it is 50Hz.

The second parameter is the number of seconds you want the note played for, in this case it is 2 seconds.

from invent import *

playtone(50, 2)
Beeps

Try getting your robot to beep 3 times using the playtone function from the previous step.

Don't forget to add a delay between beeps! Use the sleep function you learned earlier to wait for half a second before playing the next beep. You will also need to import the time library.

Beep Code

Your code should look something like this.

In this example I chose a frequency of 40, and a beep that lasted for 2 seconds.

Next lets take a look at varying the frequency.

from invent import *
import time

playtone(40,2)
time.sleep(0.5)
playtone(40,2)
time.sleep(0.5)
playtone(40,2)
Frequencies

The average human can hear between 20Hz and 20,000Hz!

Test your own hearing by changing the frequency in the playtone function. Remember that the first parameter represents the frequency.

Beeps extended

Can you improve the beep code to reduce the number of lines of code needed?

Hint: Use a for loop that will run the code 3 times. Call the playtone function and use the sleep command to create a delay before the next iteration of the loop.


Beeps extended code

Here is the loop that will play a 50Hz beep 3 times using a loop.

Can you change this code to increase the pitch of each beep as the code is running?

Hint: If you create a new variable for the frequency, you will be able to add to it every time the loop happens.

from invent import *
import time

for i in range(3):
  playtone(50,2)
  time.sleep(0.5)
Beeps variable loop

Here is the final beep code!

The frequency variable is created outside the loop. At the bottom of the loop it is then increased so the next beep is played at a higher pitch.

from invent import *
import time

frequency = 30
for i in range(3):
  playtone(frequency,2)
  time.sleep(0.5)
  frequency += 10
SOS buzzer

Can you change your 'SOS' program so it plays beeps for the 'dots' and 'dashes' on the speaker? Once you've done this, we want you to repeat your previous 'Save the Astronaut' challenge by playing an 'SOS' message after the astronaut is rescued.

So ... you robot should go forward, rescue the astronaut, turn around and return back to where it started, and then play the 'SOS' message on the speaker!

Playing a tune

Can you play a tune using a combination of notes? There are blocks to play pre-defined tunes but that's too easy! We want you to play a tune by specifying individual notes and durations. You can pick the tune. Feel free to keep it simple. How about 'Twinkle twinkle little star' or 'Happy birthday'?

The button

Let's now look at some input options. There's an inbuilt button on the main board as shown here. Let's find out how we can detect whether it's pressed or not.

The button
Moving when button pressed

Try the following code out. It should move forward 5cm if you press the button.

Can you work out how it works?

The code:

while True:

Is an endless (or 'infinite') loop - it keeps on going forever because the condition ('True') always evaluates as true! The 'button()' function returns 'True' if the button is pressed, and it's inside an 'if' statement, meaning that the indented commands underneath (we've just got a 'move()' function) will only get executed if the button is pressed.

N.B. As we've seen before, we need to indent by another two spaces the code inside this 'if' statement, as we're already inside a 'while' loop.

When you try running your code, the 'play' button will change to a 'stop' button. You'll need to click this to stop it before making any changes, as with an endless loop your code will never stop running unless you tell it to!

from invent import *
from time import *

while True:
  if button():
    move(5,True)
  sleep(0.001)
The sleep

You might wonder why we've put:

sleep(0.001)

inside the while loop?

Try removing it, saving your code, and then running it.

You should see it works fine, but now try changing your code (let's say to move 20cm rather than 5cm). Then save it and run it again. You will probably find that nothing happens!

When you call the sleep() function, it gives the microcontroller a small amount of time to do some 'housekeeping'. This is basically all the other things it needs to do to do things other than your code (including checking from communications from your web browser when you want to send new code to it!)

If you leave this sleep() function out of an endless loop you don't allow it to do it's housekeeping. From now on, just include this command in any long (or endless!) loops.

from invent import *
from time import *

while True:
  if button():
    move(5,True)
  sleep(0.001)
Obstacle sensor

Get the obstacle sensor and attach it by aligning the four pins on each plug with the holes in the sockets underneath.

Be careful here - make sure all 8 pins go into the socket holes.

Obstacle sensor
... attached

When the sensor is fully attached it should look like this. It has two eyes that can detect objects that are with 1 or 2 cm.

... attached
Test code

Now create this programme, and upload it to the robot. It will print to the console what the left channel of the obstacle sensor 'sees'.

  • You've used the console before when you've tried typing commands directly into it for the robot to run straight away, but it's really useful for 'debugging' programs and understanding how they work.
  • We've used a new function here: 'obstacle()', which returns a value from either the left or right obstacle sensor, and another new function ('print()') which will display that number on the console
  • You might also notice that instead of saying 'sleep(0.001'), we've replaced it with 'sleep_ms(1)'. This does the same thing. 1 'ms' (millisecond) is the same as 0.001 seconds as there are 1000 milliseconds in a second.
from invent import *
from time import *

while True:
  print(obstacle("left"))
  sleep_ms(1)
Interpreting the numbers

Now run the program, but this time click on the 'Console' tab. This is where we see what the robot is 'printing'.

Move your finger near the left eye and look at the numbers that are being displayed. You should notice that with your finger away from the sensor, the number is close to zero, and with it very close it goes to about 4000.

Interpreting the numbers
How it works

The sensors we are using work with invisible 'infrared' light. The sensor sends out some light and detects how much light is reflected back from an object.

That's why it only shows a high number when an object is held close to it.

We can use this to know if the robot is close to an object. As with no object the amount of light coming back was close to zero, and with an object really close, the amount of light was around 4000, let's choose half of this amount (2000) as a threshold. If there's more than 2000 returned by the sensor, we'll know an object is there!

Detecting an obstacle

Now let's change our programme to print whether there's an obstacle in from of the robot or not.

We need an 'if' statement that looks at the amount of light returned from the left obstacle sensor, and if it is higher than our '2000' threshold it tells us that an obstacle is present.

Type in the following code and try it out!

from invent import *
from time import *

while True:
  if (obstacle("left")) > 2000:
    print('Obstacle!')
  else:
    print('No Obstacle')
  sleep_ms(1)
The autonomous robot

You're now ready to create your autonomous robot. What you really just need to do is remove the two 'Print' blocks and replace them with the code you want to run if the robot detects an obstacle or not.

Hint: You probably want to go forward when there's no obstacle. When there is an obstacle, we suggest you reverse a little while, and turn around a bit. We also suggest that when you go forward, you should select a small distance - perhaps just 1cm at a time. Remember that your robot will only check if it has hit an obstacle after doing the move!

Experiment with your code. You should now be able to let your robot loose to roam around. When it hits something it should turn around and move away from it.

An improved robot

Rather than just go forward 1cm at a time and check for an obstacle, there's an even better way ...

Where you've used the code:

move(1,True)

Change it to:

move(1,False)

You'll recall that the 'True' tells the move command to wait for the movement to finish before going onto whatever the next command is. If we change this to 'False', if it detects no obstacle, it will START moving 1cm forward, but it won't wait to proceed with the next part of the program until the 1cm movement has finished. This means it will be continually checking if an obstacle has been hit, even when it's moving. Your robot should be more responsive if your code is written like this.

Even more improved

Can you improve your code further so it uses both the left and the right obstacle sensor?

You could use an 'and' block from the 'Logic' group to only move forward if both the left and right sensor DON'T see an object. But an even more clever robot would turn away from the obstruction.

Can you get your robot to turn clockwise if its left sensor is activated, and anticlockwise if its right sensor is activated?

Obstacle course

Your last challenge this lesson is to complete an obstacle course. Your teacher will set one up for you with several obstacles. Written on each obstacle will be an instruction. You might have to detect the obstacle and go around it, play a tune, flash some lights, or do a particular type of movement.

Have fun!