Beyond Basics, Ex. 12-18
The colour sensor block is in 'measure>colour' mode. The output, a number which corresponds to the detected colour, is passed to a compare block which is in 'equal to' mode. The block compares the numerical input from the colour sensor block with the number 3 which corresponds to the colour green. If the numbers are equal (i.e. if the sensed colour is 'green') then the logical value 'true' is passed through a data wire to the switch block, otherwise the value 'false' is passed.
- In the 'true' case (green detected) the upper branch of the switch block is run, causing the 'move steering' block to drive the robot forward at 50% power for 1 rotation of the wheels.
- In the 'false' case (green not detected) the lower branch of the switch block is run, causing a 'click' sound to be played at 100% volume. The sound block's 'play type' is set to 'Wait for completion' (option 0) so the program will pause for an instant until the sound finishes playing. Then a wait block will make the program pause for a full second.
The presence of the forever loop ensures that the program will keep looking for, and reacting to, the presence or absence of the green colour.
Pay attention! Variables are important! Think of a variable as an invisible named box whose contents can be changed while the program is running. In EV3, the contents can be in the form of:
- a text string
- a logical value (true or false)
- a number
- an array (list) of numbers
- an array (list) of logical values
This program starts (after the start block) with a variable block in 'write>numeric' mode. The number zero is written into a variable called 01. Then a forever loop is entered. A wait block in 'touch sensor>compare>state' mode is set to wait until the touch sensor is 'bumped' (pressed and released). The 'measured value' output of the block is not used. A sound block in 'play tone' mode will then play a tone of frequency 293.67 Hz (the note 'D') for 0.05 seconds at 100% volume. The program is told to wait until the sound has finished playing before continuing. Then the number (initially zero) inside the variable '01' is read and output through a data wire to a math block in 'add' mode. The math block adds one to the number but note that it is a copy of the number in the variable that has been modified and not the variable itself. The incremented number is sent through a data wire to a variable block that writes the incremented number back into the variable. The math block also sends the incremented number to a display block in 'text grid' mode which displays the number in the location (10,6) on the text grid (roughly the center). The number is displayed in black using the 'Large' font. Since all this happens inside a forever block the program repeatedly waits for the touch sensor button to be bumped, adding one to the contents of the variable every time the wait block detects a 'bump'.
While the forever loop is running, however, another wait block in the lower branch is also running. It is set so that after five seconds a loop interrupt block will interrupt loop 01, causing loop 01 to exit. That means that loop 01 will only continue counting the 'bumps' of the touch sensor for a five second period. Once the loop 01 has been interrupted a variable block reads the contents of the variable 01 (which contains a number indicating how many times the sensor was bumped) and then a 'move steering' block makes the robot move forward in a straight line at 50% power for a number of wheel rotations equal to the number obtained from the variable. So, for example, if the sensor was bumped four times during the five second waiting period then the robot will move forward four wheel rotations.
14. Colour sensor - calibrate
Let's look at the bottom line first. This is a forever loop that will continually display on the brick's display the reflected light intensity measured by the colour sensor, giving the measurement as a percentage of the maximal possible brightness. First a colour sensor block in 'measure>reflected light intensity' mode measures the reflected light intensity (duh) and outputs that value to a text block through a data wire. The text block joins the string " %" to the number and outputs the resulting string to a display block in 'text grid' mode. This block displays the string in the middle of the screen at grid position (8,6) in black in the 'Large' font.
Let's assume the colour sensor is designed to return the value 0% when placed over a perfectly black surface (which will reflect no light) and 100% when placed over a perfectly white surface. No real 'black' surface is perfect, however, so when placed over a real 'black' piece of paper the sensor might, for example, return the value 23%. Similarly, no real surface is perfectly white so the sensor might return the value of 73%, for example, when placed over a sheet of 'white' paper. It would be much more convenient, when writing the program, to know that the sensor will return '0' when over the black paper and 100% when over the white paper - we can make this happen by 'calibrating' the sensor using a program like the first part of the above image.
Firstly let's calibrate for the dark surface so that the sensor will give its reflected light intensity the value 0%. A wait block in 'brick button>compare' mode waits for the right brick button to be 'bumped' (pressed and released). This 'bump' will tell the program that the sensor is over the dark surface and that calibration can begin. Then a colour sensor block in 'measure>reflected light intensity' mode measures the reflected light intensity - it could be 23%, for example, and outputs that value. Next a colour sensor block in 'calibrate>reflected light intensity>minimum' mode receives the value and calibrates the sensor so that this amount of reflected light will from now on (until the program ends) cause the sensor to return the value 0% rather than 23% when it is over our 'black' paper. Since the forever loop in the other part of the program is continually displaying the output of the sensor we can expect the displayed value to jump from a value like 23% to the value 0%. Note that the colour sensor block in calibration mode does not itself measure the light intensity - it must be told the light intensity by another block (or by typing a value into the 'value' input). It is a common mistake to assume that the colour sensor block in calibration mode measures the light intensity and uses the measured value for calibration. A sound block then plays the 'click' sound at 100% volume, waiting for the sound to finish playing before continuing. This confirms that the first calibration (for a dark surface) has been done.
Now the sensor can be placed over the light surface that we wish to associate with a sensor value of 100%. Like before, bumping the right brick button tells the program that it can proceed with the calibration. A colour sensor block measures the reflected light intensity (73%, perhaps) and passes that value to a colour sensor block in calibration mode like before. This time the 'maximum' value for the sensor is calibrated, so from now on this level of reflected light will return 100% rather than 73%. So we can expect the displayed value to jump from a value like 73% to the value 100% when this second calibration is done. Another click sound confirms that the 'bright' level of reflected light has been calibrated to be 100%.
Now another wait block in 'brick button>compare' mode waits for the right brick button to be bumped. This tells the program we are ready to reset the sensor to its initial state, which is performed by a colour sensor block in 'reset' mode. Another 'click' sound confirms that the sensor has been reset. Now the sensor will report our bright surface as having a brightness of 73%, like before.
This program (or rather, this pair of programs) allows two bricks to communicate with one another using Bluetooth (short range wireless radio communication). The program(s) will allow you to control the rotational speed of the receiving robot, which will be spinning on the spot, by turning the right wheel (motor C) of the sender robot. That's right - we will be controlling the receiving robot by 'remote control'.
I won't explain here how to set up the Bluetooth connection between the two bricks - please refer to the Lego software for that. I'll assume the connection has been established and that the sender brick is called EV3-1 while the receiving brick is called EV3-2. You can rename a brick that is connected to the EV3 software using the 'Brick information' panel in the bottom-right corner of the EV3 software interface.
Here, above, is the program that is to be downloaded to the sending brick, EV3-1.
The first yellow block resets the angle measure of motor C so that it reads zero degrees. Note that motors can act as sensors as well as motors, but that when used as sensors (as in this program) the motor must still be plugged into a motor port rather than a sensor port.
Inside the loop a yellow motor rotation sensor block measures the angle of motor C (the right-hand wheel of the sender robot) and passes that angle value through a data wire which is connected to the 'message' input of the blue Messaging block. This block is in send>numeric mode and its receiving brick name parameter is set to 'EV3-2' since this is the name of the brick which will receive our message. Thus this program reads the angle of the motor and then sends this to the other brick as a Bluetooth message. This is repeated continuously because of the loop.
The second program, above, is to be installed on the receiving brick called EV3-2. The blue messaging block is in receive>numeric mode. It will receive the messages being sent from the sender robot (EV3-1) and pass the values in the messages through the data wire to the 'power' input of the green 'large motor' block. Thus the angle of motor C on the sender robot will control the power (speed) of motor C on the receiver robot. Since only the right wheel of the receiver robot is turning, the receiver robot will simply spin in a circle.
Inside the loop block is a 'move steering' block set to get the robot moving continuously in a straight line at 50% power. Then the ultrasonic sensor block in 'measure>distance centimetres' mode measures the distance between the sensor and the reflecting object and passes the result through the yellow (numeric) data line to a range block. The range block is in 'inside' mode. The block tests whether the measured distance is inside the range 6-25 cm and outputs the result of the test ('true or 'false'). Next is a colour sensor block in 'compare>colour' mode. It tests whether the measured colour is equal to 'black' (colour 1) and passes the result of the test ('true' or 'false') to a logic block. The logic block also receives the output of the range block which indicates whether the reflecting object is between 6 and 25 cm from the sensor. The logic block is in 'and' mode which means its output will be turned on, or 'true', if both the first input AND the second input are true. In this case, that would mean that the reflecting object is within the defined range AND the sensor is detecting black.
So the overall effect of the loop is to make the robot move forward in a straight line UNTIL the logic block tells the loop control input that the reflecting object is within the defined range AND the sensor is detecting black. When this double condition is met the loop will exit and a 'move steering' block in 'reset' mode will reset (stop) the motors.
In the video that accompanies this exercise the robot is initially far from the reflecting object and over a white mat. The conditions are met for the robot to move forward. It passes over a black line but does not stop because the robot is not yet within the defined range. It continues moving forward until it reaches a second black line and there it stops because it detects black AND the robot is within the defined range.
17. Maths - Advanced
This program shows how the program can calculate the length of the hypotenuse of a 45° triangle. The robot is assumed to have just moved along the two perpendicular arms of a triangle, each with length 25 cm, and to have turned around 180° so it is now in the right location to begin drawing the hypotenuse but it is not pointing in the right direction. Let's try to work out the length of the hypotenuse. In a right triangle, the cosine of either of the acute angles is the length of the adjacent side divided by the length of the hypotenuse which we will call x. In this case cos(45°) = 25cm / x
Rearranging gives x = 25cm / cos(45°) which we will calculate within a math block.
First a 'move tank' block makes the robot begin turning continuously hard right at 10% power. This continues until the wait block in mode 'gyro sensor>compare>angle' detects that the robot has turned at least 45° to the right. When the wait block detects that the condition has been met this does NOT in itself cause the motors to stop - it is necessary to include a 'move tank' block in 'off' mode to make that happen. Note that the wait block also passes the measured angle of turn to the math block - it may not be exactly 45°. The math block is in 'advanced' mode which allows rather complex mathematical calculations to be performed by typing them into the header. Up to 4 variables can be included and they correspond to the four inputs on this block. As previously explained, the correct calculation to find the hypotenuse is 25 / cos(45) which we will modify to 25/ cos (a) to use the real angle, which may not be exactly 45°.
The calculated length of the hypotenuse is output through a data wire to a math block in 'division' mode which will convert the length into a number of wheel rotations by dividing the length by the circumference of the wheels. Once the necessary number of rotations has been calculated it is output through a data wire to a 'move tank' block in 'rotations' mode. The block will make the robot move straight forward at 30% power for the required number of rotations and thus the required distance to complete the triangle.
An 'array' is a variable that can hold multiple values. In the EV3 you can have an array of numbers or an array of logical values but not an array of text strings. The order of the elements in an array is important, so the elements in an array are like a list. Each element in the list has an index number, and the first element has index number zero. Here is an example of a numeric array: [5; 2.7; 3.1] . This array has three elements - we say the array has a 'length' of three. The elements have index numbers 0, 1 and 2, so the third element has index number 2 not 3.
The above program starts with a loop that is set to run 4 times. A sound block plays the 'click' sound at 100% volume and waits for the sound to finish playing before allowing the program to continue. Then a wait block in 'touch sensor>compare>state' mode waits for the sensor button to be bumped (i.e. waits for the sensor state to be equal to the 'bumped' state).
Next a wait block in mode 'colour sensor>compare>colour' waits until it sees blue, green or yellow. When one of these colours is detected its corresponding number is output through a data wire.
Next there is a 'variable' block in mode 'read>numeric array'. It is reading an array called 01 which was created (added) when the block was set up. The array is initially empty - it contains no elements at all.
Note that when you read an array what you are really doing is making a copy of the array. You can modify the copy but that does not modify the original array. To apply your modifications you must write (copy) the modified copy back into the original array - the modified array will replace the original. It's like when you open a Word document - you can make changes to the document on the screen but the original document is not changed unless you 'save' the document (i.e. copy what is on the screen back into the file).
The next block is an 'Array Operations' block in 'write at index>numeric' mode. The block's 'index' input is connected by a data wire to the 'loop index' counter of the loop. Important: the loop index counts the number of times the loop has completed. So the first time the loop is running the loop index is zero - it does not become one until the loop has completed. When a loop is set to exit after a count of 4, it means it will exit when the loop counter reaches 4. The loop will run four times with loop index values 0, 1, 2, 3 but never 4 because after completing the loop four times the loop index becomes 4 which causes the loop to exit immediately.
Since the 'Array Operations' block's 'index' input is connected by a data wire to the 'loop index' counter of the loop the loop index will determine which element of the array is written to. The first time the loop runs the loop index value is zero so array element zero will be written to with the number corresponding to the colour the sensor was shown, and so on. Note that if the block writes to an element that does not exist then it simply creates it. This implies that if the block tries to write into element 4 of an empty array (which will never happen in this program) then it will have to create five elements (elements 0 to 4). As previously explained, the entire modified array must now be copied back into the 'real' array with a 'variable' block in mode 'write>numeric array>'.
By the time our loop has completed four times four numbers will have been written into the array and those numbers will have index numbers 0, 1, 2 and 3. The loop then exits and the sound block plays the sound 'Horn 2' at 100% volume, waiting for the sound to finish playing before continuing.
Now we enter another loop that is set to run its contents four times. Within the loop we have first a 'variable' block in mode 'read>numeric array'. It reads the whole array 01 and passes the array to an 'Array Operations' block in mode ' 'read at index>numeric'. Each time the contents of the loop are run the 'loop index' number is passed to this block and the corresponding element of the array is read. For example, the first time the contents of the loop are run the loop index is zero because the contents of the loop have never been completely run so it is element zero (the first element) of the array that is read. The numeric value of that element (which could be a '3', for example, if a green object had been presented to the sensor) is passed to a switch which will make the robot do a movement of some kind.
- If the switch receives the value 2 (blue) then a 'move tank' block in mode 'degrees' will make the robot turn half left for a 345° rotation of the right wheel (0.96 rotations). This angle is intended to make the robot itself turn about 90° left (again, don't confuse the rotation of the motors with the rotation of the robot itself).
- If the switch receives the value 3 (green) then a 'move tank' block in mode 'rotations' will make the robot go straight forward for one wheel rotation.
- If the switch receives the value 4 (yellow) then a 'move tank' block in mode 'degrees' will make the robot turn half right for a 345° rotation of the left wheel. This angle is intended to make the robot itself turn about 90° right.
In the video that accompanies this exercise the sensor is shown colours in this sequence: green, yellow, green, blue, therefore the robot responds by doing this sequence of movements: move forward, turn 90° right, move forward, turn 90° left.