Skip to content

Exploring MiRoCode Blocks

In this session, you will: * build upon the basics of programming with blocks that you've learnt last week * look at the various blocks available at your disposal in MiRoCode * hopefully, get a better feel for when to use each one.

Note: If you missed last week's session or need a refresher, be sure to check the previous page first.

Bringing it all together

With these three examples, we have covered all the main building blocks (pun intended) of a MiRoCode program and looked at the core concepts that most programs utilise — variables, functions and lists.

Exercise 1. Watch the Edge (Cliff sensors)

Now that you know how to make MiRo watch for the table edge with sonar, can you make it do the same task using the actual cliff sensors? Try to use everything you've learnt so far — variables, functions and lists — in your program.
Here are the details: * MiRo should start by going forward and use its cliff sensors to detect if there's a table edge ahead.
Furthermore, make it so that when Miro sees an edge, it should back off and turn away, then proceed going in the new direction. * Try differentiating whether the triggered sensor is on the left or on the right (or both!) and use that information to determine where to turn, i.e. turn angle. Add some unique cosmetic movements (tail, ears, etc) for each of these three cases.
Add some output in the terminal for certain milestones, e.g. reached the edge 10 times, 100 times, etc. * After you've done the basic functionality, try tweaking your program so that MiRo keeps on exploring the tables for as long as possible (although it's likely to fall off eventually!) From experience, if your MiRo can manage doing 5 minutes of exploration without falling off — that's a great result! * Remember to switch the built-in cliff reflex off, as you're building your own!

Note: In a few weeks time you'll recognise from the lectures on Agent Architectures that both Watch the Edge programs are examples of a Simple Reflex Agent, one of the simplest ones out there.

Exercise 2. Touch buttons

In this exercise you will use lists to dissect the inner workings of the two touch buttons.
MiRoCloud contains a pre-recorded sequence of sensor readings of a person stroking an actual MiRo. Upon clicking on one of the two touch buttons, the corresponding sequence is played back in the simulator, and this is what’s being registered by the simulated sensors.
Can you write a program, which: * Counts how many times each sensor is triggered in the touch sequence? * How many detections there are overall (combined)? * Measures the overall duration of a touch?

Output the answers in the terminal.

Good luck!

Wrapping up

Don't forget to save your codes at the end of the session.
Once you've done these exercises, you should get a better feel of the interface, when to use which blocks and the peculiarities of MiRo behaviour (e.g. difficulty moving in straight lines).
Same as last time, we will be providing model solutions in the following lab session. See you next time!

Navigating This Wiki:
← Introduction to MiRoCloud | Sensing & Vision →

Worked examples from the previous session

Same as before, an example implementation of the two exercises from the last week are given below.
The corresponding .mirocode files are available to download from the Blackboard in this week's folder.

Exercise 1. Watch the Edge (Cliff sensors)

Here, the task was for MiRo to use its cliff sensors to stay away from the edge as it moves around. When Miro sees a cliff it backs off a bit and turns away, with the direction depending on which cliff sensor was triggered (left, right or both).

Note: Switch off the built-in Cliff Reflex when running this program

watch the edge with cliff sensors

The program starts with an init function (initialisation), where MiRo takes the default pose and all the necessary variables are created.

watch the edge with cliff sensors init function

Immediately you can see the program has a main Periodic Control Loop that runs 50 times per second and checks for updates from cliff sensors. The output is assigned to variables called left and right.
Usually, the cliff sensor blocks return Boolean values (cliff / no cliff), bit in this case a float flag is used to switch to Float values. This allows to have more flexibility when setting the threshold for what can be considered a cliff.
The sensor output varies from 0 (definitely a cliff) to 1 (definitely a surface). The thresh variable for cliff sensors in this case is set to 0.81, which is a high threshold that triggers further away from the edge to allow for more reaction time.

The main bulk of the work happens in the function called reflex_agent:

reflex agent function

Each iteration of the main control loop this function uses the current values of the left and right variables to decide which case to trigger, depending on the threshold.

In the prevalent case when both sensors readings are above the threshold MiRo simply carries on going forward. The main if statement triggers only when one of the readings is below the threshold, and there are three cases depending on whether the cliff is on left, right or directly in front.
Depending on the case, MiRo turns away at a different angle, but always going backwards a bit first for safety.

turn left function

When running the code you can tell which sensor was triggered but looking at the terminal output and MiRo's head and ear movements. When turning left or right, MiRo first looks in the direction it's about to turn.

Finally, each 10th turn, the total number of turns is printed in the terminal using the counter to keep track of the overall progress.

Exercise 2. Touch buttons

In this exercise list operations to dissect the inner workings of the two touch buttons. Inside the MiRo robot there are 14 independent touch sensors both in the head and in the body, for a total of 28 sensors. See the picture below showing the body touch sensors.

body touch sensors

Whenever one of the touch button is pressed in the simulator, a pre-recorded stroke sequence is played back, triggering some of these sensors in some order.

Let's overview the code for this program.

touch buttons overview

At first, some variables and an empty list are initialised. MiRo then enters the Periodic Control Loop that runs 50 times per second, waiting for the user to click on one of the touch buttons.

check for touch

Once a touch on any body part has been detected, is_touched is set to True and MiRo enters analysis mode.

touch buttons main loops

In this mode, at each loop iteration MiRo checks the corresponding sensors on the head or body individually and records which exact sensors were triggered in an array called touch_sensor_array. This is done by checking each position in the list that is produced by the All Head Touch and All Body Touch blocks. The values are fed into a function called touch_counter. If there is a True value at some position, the corresponding element in the touch_sensor_array is increased by one.

Note: The touch_counter is an example of a function that takes an input. The same function is used for both cases of head and body touch, simply by replacing the input array.

Additionally, a timer variable is incremented to keep a rough estimate of the time passed since start of the analysis.

The analysis concludes when two conditions are satisfied: (a) it has been started in the first place; and (b) no touch has been detected in the last second. The latter condition is important because there might be slight delays between different sensor detections as the hand moves across the head or body.

touch buttons stopping

Once analysis is concluded, the results are printed in the terminal, containing: * How many times each sensor has detected a touch * How many detections there were overall * What was the total duration of the touch (one second is removed from the total time because MiRo checks that there has been no detections for at least one second)

touch buttons report

Finally, all the variables are reset and the same procedure can be run again without the need to restart the program.

Basic intro to signal processing

When reading information from the sensors sometimes you might get some odd values, e.g. values that are off by large amount, or even things like Null or inf. This occasionally happens with the simulated MiRo, but is especially relevant when working with the physical MiRos. This is why it is useful to apply some basic signal processing to ensure that the readings you get from the sensors make sense.

Below is an example of program that checks the numerical value of a sensor output and then applies a few different methods of filtering to smoothen the effect of any outlier points.

filtering main loop

A list of fixed length is created to store a number of readings. The length of this is list is something that is called a stride. Each time a sensor receives new information, it gets put in the first slot, while the oldest value in the last slot is discarded. This is an example of a process called First in, first out (or FIFO).
This method of updating is also known as a queue (as opposed to a stack), and that's why the processing function is called queueing.

filtering algorithms

The first three filters are the most basic ones, and take, respectively, the median, average and max value from the list. These are filters without any significant overhead and work well where a value changes slowly and smooth.

The final filter is called Exponentially Weighted Moving Average (EWMA) and is useful when a value is changing rapidly. The filter gives more weight to the most recent readings and less to the older ones. You can read more about it on the Wikipedia page. The EWMA function is defined recursively and therefore its performance is dependant on the stride value.

filtering ewma

Note: Run the code with different sensors to see which filter works best

Exercise 1. Strike!

Remember Clapper Control? Write a program the would drive the MiRo into a stack of green cans, starting in the default position, using the Vision blocks to help navigate MiRo.

Try different approaches with different Vision blocks!

Exercise 2. Hitting the ball

Write a program that would help MiRo locate the blue ball using Vision blocks. Once the ball is in sight, drive towards it to kick it off the table.

Note: It is recommended to filter the output from the Vision blocks, as they are particularly noisy!