Starting with a simple challenge involving a touch sensor and a motor, this learning sequence shows how to turn a motor on and off with a touch sensor using flow control structures that include:
- the master/slave design pattern.
In addition, it also shows how to a range of programing techniques, including:
- user blocks arguments
- arrays and how to operate with them.
Through this learning sequence, students will gain a deeper understanding of how to:
- use a touch sensor to control a motor
- add more conditions and control the flow of the program using different programing techniques and their implications when using Wait, Switch, or Loop blocks
- synchronize different programming flow sequences, using variables and the master/slave design pattern
- use loops that need to run at different rates and the use of variables and timers to control these loops
- use and operate with arrays
- display messages and control the status light of the brick screen.
Exercise 1: Turn a motor ON with touch sensor
The touch sensor is the simplest sensor in the LEGO Mindstorms platform. It gives a true value if it is pressed and false if it is not. In addition, you can configure the touch sensor to give a true value if it has been bumped, that is if the sensor has been pressed and then released.
How could you program a motor to start when a touch sensor is pressed?
The simplest way is to use a Wait block configured to use a touch sensor as shown in the following image.
What are the limitations of this program?
As intended, the motor will only start after the touch sensor is pressed. It will, however, only run for one rotation.
What if you want to make the motor continue running?
Some students might say that you only need to configure the Motor block to turn the motor “on” instead of “on for rotations”. If you try this, you will see that the motor doesn’t even start. Why? Because the program ends after the Motor block and when a program ends, all motors are turned off.
How do you have to modify the program to make the motor run forever?
One option is to put the Motor block inside a Loop set to “Unlimited”. For example:
Either when you stop it manually or when the brick runs out of battery.
Exercise 2: Turn a motor on and off with a touch sensor
Some students might realise that after waiting for the touch sensor to start the motor, you can wait again to stop it, because the actions are sequential. For example:
After the first time the touch sensor is pressed, the motor will start and the program will wait until the sensor is pressed again to stop it.
But does this program work?
Sometimes it works, but not consistently.
The program runs so fast that while you are still pressing the touch sensor it will move through the second Wait block and therefore stop the motor. As a result, you need to press and release the touch sensor extremely quickly (or be very lucky) to make the code work.
How can we solve this problem?
We need to configure the Wait block to use the “Bumped” setting:
What if you want to restart the motor by pressing the touch sensor again? (without having to restart the program)
The solution is to put the previous code inside an unlimited loop:
At this point it might be interesting to ask the students whether we can get the same or similar results using a Switch block instead of a Wait block. It is a nice opportunity to think about the differences between these programing structures.
What are the main differences between this program and the previous one?
With this version we need to keep the touch sensor pressed in to stop the motor. In addition, the motor will start as soon as the program starts, unless the touch sensor is pressed in. Keeping the sensor pressed to stop the motor (or running it if we invert the branches of the switch) might be a requirement for some specific scenarios, but the previous solution using Wait blocks might be more convenient for simple examples.
Is there any advantage of this solution compared to the one using Wait Blocks?
This solution uses one less block and does not repeat any blocks.
Exercise 3: Turn a motor on and off using a touch switch and a loop
How can we obtain the same function as the Wait Block solution using a Switch Block?
The idea is that every time the touch sensor is bumped (i.e. pressed and released), the motor will alternate between on and off.
In the following same code, the logic variable flag alternates between true and false. Its value is then used by a Switch block to determine whether to turn a motor on or off. We use a logic variable because we only have two states (on and off), but we could use another type of variable if we had more than two states.
Although this solution is more complex than the one using a sequence of two Wait blocks, it is a much more versatile approach.
It still has a significant problem though.
Imagine that you want to build a sorter machine and that you want it to show a message on the EV3 brick’s screen about the sorted item, or run specific code depending on the sorted item.
Not only does the motor need to run but also several actions might need to be executed, thus making the branch of the switch take significantly more time to complete. And if we try to stop the motor by pressing the touch sensor, we will have to wait until the branch is completed.
How can we solve this problem?
One approach is to use a master/slave design pattern architecture. (For more about this programming technique, see To light or not to light.)
In the following example, the master loop uses a logic variable flag to instruct the slave motor loop to turn the motor on or off.
Exercise 4: Turn a motor on and off using a touch sensor, and stop the program using another sensor
Let us build on the idea that the motor you are turning on and off is part of a color sorting machine. As a safety measure, you would like the motor to stop if the color sensor detects no color (i.e. there are no more items to sort). Or possibly you want the program to stop completely.
How can we make our robot wait until EITHER the touch sensor is pressed OR the color sensor doesn’t detect any color?
The answer is to create our own version of a Wait block as shown in the following program. (For more about this approach, see How to wait for one or more sensor conditions.)
This program will work fine because the actions, running or stopping the motor, execute quickly, but if we need to execute longer and more time consuming program sequences, we will need a better approach.
What’s a better solution?
One approach is to modify the master loop of the master/slave design pattern solution as shown below.
To stop the program, you could use Loop Interrupt blocks, making sure that the motor, or any part of the main program in the slave loop, is stopped first.
Another solution is to run different sequences in parallel and use variables to control the flow of the program:
You might need to add specific code in each of the “true” branches of the logic switches connected to the stop variable before exiting the master and slave loops.
Since the master loop contains several parallel sequences to control the different processes that occur at the same time, we should be very careful to avoid a race condition, as we will see in the next exercise. A race condition can occur when different parts of the master loop program try to set the slave loop variable at the same time. (For more about race conditions, see To light or not to light.)
Exercise 5: Turn a motor on and off using a touch sensor and run specific code according to various conditions
As a final exercise, and to really grasp the power of the master/slave design pattern, we will build on the last example from the previous exercise to add the following functions to our color sorting machine.
- Count the sorted items by color (blue, green, yellow, and red).
- Display the count for each color on the EV3 brick screen.
- Pause/unpause the machine if the touch sensor is pressed.
- Stop the machine if EITHER no color is detected in a reasonable amount of time OR one of the sorted colors reaches a maximum number.
Note that counting items is relatively fast, but displaying a message on the brick screen long enough for someone to read it requires more time than the other tasks. In addition, while the message is shown, the sorter machine might encounter more items and reach the maximum number of sorted items.
How can we implement these functions? Do we need to change the whole previous program or just a part of it?
We just need to change the last sequence of the previous program. We will add a new loop to that sequence called “MasterColor”.
Let us address the new functions one by one.
Exercise 5-1: Count the sorted items by color
To count each of the different colors, we need somewhere to store the information. The most efficient solution is to store the count for each color in a numeric array.
In this example, we are going to count blue, green, yellow, and red, so let us call the numeric array SortedBGYR.
We also need a variable, ArrayIndex, to store the index of the array corresponding to the color detected by the Switch block. For example:
- Blue => 0
- Green => 1
- Yellow => 2
- Red => 3
- If no color is detected, ArrayIndex is set to -1. This is also the default case. As a result, any color that is not either blue, green, yellow, or red will set ArrayIndex to -1 as well.
- Before entering the loop, we initialise the two variables, SortedBGYR and ArrayIndex, as well as the timer.
Next, we feed the value of ArrayIndex into a Switch block.
If ArrayIndex is -1, we will check the timer and, if necessary, stop the sorter machine, display the message “EXIT”, and set the brick status light to blink red.
Note the use of a Switch Timer block set to 10 seconds to allow time for the next color to be detected. If no color has been detected with 10 seconds, the program is stopped. The false case is empty.
Also, note that if you store the color directly to the ArrayIndex variable, the previous case number will have to be “0” instead of “-1”. In addition the default case will have to be a number other than “0”.
If ArrayIndex is any number other than “-1” (in our example 0, 1, 2 or 3) the appropriate counter will be incremented.
What will happen if a unexpected color is detected?
As mentioned before, the default case of the Color Sensor Switch (in our case “No Color”) will be called and the sorter machine will treat this case as if no item is detected. If this occurs for more than 10 seconds the program will exit.
A little bit of theory
In our example, the Color Switch has five branches, one for each color we want to count. In the EV3 Software, each color is represented internally by an integer number from 0 (no color) to 7 (black), but the user does not necessarily need to be aware of this representation because every time you need to pick a color, the interface shows a menu with all of them, as shown in the following screen capture.
Because our ArrayIndex variable will store the color number, is there a simpler way to set this variable?
If we want to use all seven possible colors of the Color Switch, there is no need to use a Switch block at all. Instead we could use a Color Sensor block and connect the Color output plug to the ArrayIndex variable directly, as shown below.
Exercise 5-2: Display the count for each color on the EV3 brick screen
The next step is to display the contents of the array on the EV3 brick screen.
One option is to create a My Block that takes the array you want to print as its input and goes through the different indexes to display them on the brick’s screen. Note that only the first Display block clears the screen.
Add the My Block, PrintArrayBGYR, into the end of the loop.
This approach makes the main program much easier to read, and helps with debugging. It also means that this code can be used in different places throughout the main program. For example, we could also use it to initialize the brick screen message.
Exercise 5-3: Pause/unpause the machine when the touch sensor is pressed
Next, we incorporate the flag variable from Exercise 4 to pause/unpause the machine when the touch sensor is pressed.
We will add a Logic Switch block to the start of the loop to set ArrayIndex to -2 if the flag has been set to false.
We also need to add a -2 case to the final Switch block to display the PAUSE message and set the brick status light orange.
Exercise 5-4: Stop the machine
Finally, we need to stop the machine when either no color is detected or one of the sorted colors reaches a maximum number.
The example below shows a simple strategy for stopping the machine when the number of items reaches five or more.
If the maximum number of items has not yet been reached, the “PAUSE” message is erased and the timer is reset.
Why is it important to reset the timer?
Otherwise when no color is detected, the sorter machine will stop immediately.
The following image shows the complete sequence of the MasterColor loop sequence of the program.
The following video shows an example of a color counting machine. To increase the chance of the color sensor reading the color correctly, the slave loop has been modified so that each each item is held under the color sensor for a second.
To find more examples, videos, and an introduction course to Mindstorms EV3 for teachers with translations to Catalan and Spanish, visit the BOGATECH website.