Worked Examples¶
On this page you will find reference implementations for the exercises offered on previous pages and explanations of the key ideas for each one.
The corresponding .mirocode
programs are available to download directly from Blackboard.
Getting Started with MiRoCloud¶
Exercise 1. Clapper control¶
In this exercise, claps are used to control the duration of each of the MiRo's actions in sequence, which should result in MiRo driving into a stack of cans. The key idea is to time the claps just at the right moments. This is an example of a program which has a simple and linear flow, with each block being executed after the next one.
It's useful to note the interplay between the blocks here, as this is something you'll be using a lot in the future. There are both Discrete and Continuous Action blocks in this program (remember the difference? If not, you can look it up here).
The block is a discrete action block. You can think of it as toggling a switch that changes MiRo's state from not moving to moving. However, this block doesn't specify the duration of the action, so another type of block is required for this to actually work. Another way of thinking about it is in terms of blocking/non-blocking calls (yes, blocking blocks... the terminology can be confusing). Discrete action blocks are generally non-blocking; roughly speaking that means they're allowed to run in the background.
Question
Create a simple program that only has two blocks: Program Start, followed by Start Moving Forwards.
What do you see when you run it and why?
On the other hand, the and are both continuous action blocks. Incidentally, both of them are also blocking, which means they prevent execution of the code further down until they complete their own execution.
Combining the effects these two block types provide, it should then be clear how each action in this program is generated. In the snippet below, MiRo starts moving forward and will continue moving forward up until it hears a clap (plus additional 0.3 seconds).
Info
Start Moving is also a good example of a block that permits changing the values inside.
By clicking on the drop-down menu it is possible to change the direction of movement, as well as the speed.
Finally, let's run the whole program. Clapping at the right times should yield the following:
Exercise 2. Watch the Edge (sonar)¶
In this exercise MiRo starts by lowering its head and using the sonar in the nose to measure the distance to the surface of the table. MiRo should then start going forward until it can detect the edge of the table, upon which it should stop.
Info
You will need to disable the built-in cliff reflex to see your code perform its function (see below).
The key idea here is that the distance to the table surface doesn't change, as MiRo moves on the table away from the edges (within measurement error, of course). Upon reaching the edge, however, there will be a sharp increase in the sonar readings, which can be picked up in a conditional statement.
Here you can see how the use of variables, loops and functions can make the program shorter and clearer.
The first thing to note is the assignment of a value to a variable called dist
, which indicates distance to the surface of the table.
The Sonar Range is a conditional block, meaning it plugs into other blocks that receive a value (look for connectors on the side).
Warning
Keep in mind the value types when connecting different blocks together.
Incompatible value types are a common source of error.
A tooltip for this block is displayed on the image below, specifying what sort of output this block produces.
Question
Can you remember how to show the tooltip for a given block?
If you're writing the code from scratch, you have to create the corresponding variable first using the Variables group on the left panel.
Click on , and then on
The next piece of code worth mentioning is the Repeat While
loop.
This type of loop keeps spinning until the criteria no longer returns True, which in this case means that the dist
is more than or equal to half a meter.
The block inside the loop represents a call to a function called sonar_edge
, defined as follows
The gear icon at the top allows to add inputs to the function, something that will be covered later on.
The next symbol — a question mark — allows to add a description to the function.
This text is then displayed as a function tooltip, but otherwise has no bearing on its functionality.
The last bit at the top is the name of the function, which has to be unique.
This type of function doesn't return an output on its own, but there's another type of block for a function which does return output.
Inside the function, you might notice a customised Python print
command being used instead of the regular Print String block. The purpose of this is simply to make the output prettier by printing only two decimal digits in the sonar range value. The second line is where the dist
gets updated with the most current reading obtained from the sonar. Finally, the last line in this function simply blocks execution for 0.1 second, inhibiting the rate of sensor updates and the rate at which messages are printed to the terminal.
Finally, let's run the program and see if MiRo stops at the edge:
Indeed it does! Let's move on to the third exercise.
Exercise 3. Playing with LEDs¶
In this exercise MiRo is acting as if it's an emergency vehicle. MiRo starts turning on the spot and periodically changes the colour of each LED on its body from blue to red in a clockwise manner, five times in a row.
First, let's look in more detail at the first loop in this program, as it contains something that has not yet been covered — lists.
A variable called touch
is created before the loop, and is assigned the output from All Body Touch sensors block.
This block returns the state of the body touch sensors, as a list of 14 Boolean values (True/False).
Each sensor reports True when a touch is being detected and False otherwise.
Inside the Repeat While
loop, this list is scanned to check if any value is True, returning the index of the first True value (which could be an integer from 1 to 14), or 0 in case none were found.
Info
Indices in the MiRoCode interface start with a 1, while in the Python interface they start with a 0.
By default, none of the sensors are touched, and so the condition is evaluated to True. This keeps the loop spinning until one of the sensors detect a body touch.
Similarly to the previous program, the touch
variable is also updated inside the loop every 0.1 second.
Question
The touch
variable has two identical assignments both before and inside the loop, which at a glance might seem redundant.
Would you be able to explain why is it important to have both of them?
Hopefully, everything else in this program should be clear by now.
Below a snapshot of the running program showing the LED panel: