This is my fourth tutorial focusing Scratch and Physical Computing. Previously, I have published:
- Physical Computing - Scratch for Raspberry Pi (using Scratch V.1.4)
- Physical Computing - Scratch for Arduino (Using S4A, based on Scratch 1.4)
And now, we will develop new projects and ideas integrating Scratch 2.0 and Arduino, the 2 true "champions" when we are talking about teaching electronics and code creation for children, educators, and beginners.
There are few initiatives available on the web about Scratch 2 for Arduinos, being the most known the ones developed with a focus on kits supported by Scratch website like Lego WeDo, PicoBoard or the alternative mBlock, etc.
As a personal option, I have written this tutorial using " s2aio", an open, free and fantastic Arduino Hardware Extension for Scratch 2.0 offline editor, created by MrYsLab. Thanks, Alan Yorinks for that!
Cool! So, what we will learn here in this tutorial is how to use Scratch 2.0 to program an ARDUINO to interact with our physical world!
In short, we will learn how to:
- Read digital inputs as buttons and motion sensors
- Read analog sensors as LDR (to measure light) and temperature
- Generate digital outputs, turning ON/OFF LEDs
- Actuate on analog devices, controlling, for example, a LED brightness using PWM technics
- Generate musical tones using a buzzer
- Controlling a servo motor
- Mesure distances with an ultrasound sensor
- Construct a "Virtual Electronic Playground" to interact with real devices
- Mix animation with real world devices
- Build a real radar
The above diagram shows all the sensors and actuators connected to our Arduino. But do not worry, we will go step by step on each component.
Here, you can see a video with a real and functional radar that you will learn how to project during this tutorial:
So, let's go!
Have on hand below Bill of Material to be used on our experiences:
- Arduino UNO
- LEDs (Red and Blue)
- 1 Button
- 1 LDR
- 1 LM35 Temperature Sensor
- 1 HC-SR501 - Passive infrared sensor (PIR)
- Resistors: 2x 10Kohm and 1x 220 ohm
- 1 HC-SR04 Ultrasonic Sensor
- 180 Degrees 9G Micro Servo
- Full Breadboard
As we know, Scratch is a great tool to teach beginners how to code, but before starting playing with Arduinos and electronics, I really recommend that you familiarize yourself with the Scratch 2.0 language, going to the Scratch Official Website and following some basic tutorials there. Doing that first, will help you later to better understand how to use an Arduino on Physical Computing.
If you have worked with S4A, based on Scratch version 1.4, you should be familiarized with the basic of the language, but the version 2.0 has great new features to enhance (and simplify) our projects, like:
- Clones (to be used on Sprites)
- Custom Blocks (Very useful to write "functions")
- More Blocks section: Where we will find the special blocks for controlling Arduino Pins.
- Vector editor for Sprites and Backdrops
- Sound editing
- “Set Rotation Style” block.
- “Backdrop name” block.
- “when backdrop switches to” Event block, etc.
To use s2aio, we will need a Scratch 2 offline Editor, go to the link and follow the instructions and install it on your desktop. Also, download the Get Starting Guide for Scratch 2.0, so you can be familiarized with the editor.
s2aio requires Python 3.5 to work. If you do not have it, please go to Python site and follow the instructions for proper installation.
When using s2aio, your Arduino will need be running FirmataPlus, that is a custom enhanced version of StandardFirmata that provides support for:
- HC-SR04 Sonar distance devices
- Rotary Encoder
- Stepper Motor Support
- Piezo tone generation.
You can download it from MrYsLab GitHub. Follow the normal procedure to install this library in your Arduino IDE. Once installed, go on Examples/FirmataPlus/FirmataPlus on your Arduino IDE and open it.
- s2aio installation
Now it's time for the s2aio installation. Follow below instructions carefully. The below command will install s2aio and all of its required libraries. Make sure that you have an internet connection.
For Windows users, open a command window and type:
pip install s2aio
For Linux and Mac users, open a terminal window and type:
sudo pip3 install s2aio
Note that several "Base Scratch files", will be installed under s2aio-master directory:
for English, you must open:
Note that exist one "base" file for each supported language. Once opened, go to "More Blocks" section. You will realize that now there are several new "black blocks", which ones we will use to control the Arduino's pins.
Note that probably you will see a red LED on top of those new blocks. This mean that the Arduino is not connected with Scratch editor and that you must execute s2aio.
- s2aio execution
An executable file will be installed on the execution path for easy startup. So, open your terminal and type:
In my case (a Mac user). I included a "batch file" with an icon in my desktop area, so I do not to open a Terminal any time that I want to execute s2aio.
The below steps are optional:
Enter in a text editor, for example, nano at Terminal. I have s2aio-master installed under /documents/Scratch2_Arduino
#!/bin/bash # call s2aio from desktop cd .. /documents; cd Scratch2_Arduino; cd s2aio-master; s2aio; exit;
Give it a name (eg: s2aio_connect), save the script, set it executable. Example:
chmod +x ~/Desktop/s2aio_connect
If you want to click it to run it, add '.command' to the end of it.
That's it. I also included an s2aio (not official) icon graphics to ease location in my desktop. So, once s2aio is running, you will realize that the LED on "More Blocks" section is now green. In short, for initiating a new Scratch 2 project using s2aio, always follow the sequence:
- Connect the Arduino board to your Computer via USB
- Open the Arduino IDE and upload the FirmataPlus on your board
- Open one of base projects or one that you already previously saved
- Execute s2aio at Terminal or with a batch file
That's it! The above print screen shows everything as running on my Mac desktop. If you open a normal "new" Scratch 2 file, the Arduino extensions will not be there.
Let's start connecting a LED to pin 13 of our Arduino UNO.
Going to "More Blocks" menu, you will find the special blocks designed for Arduino. We will use 2 of them to create our Blink function. The first thing to do is to inform Arduino that a specific digital pin (in our case will be 13) will be [Enable] and should work as [output]. Drag this block to code area.
[Enable] Digital Pin ( ) for [output]
Note that at same block you can select [Enable] or [disable], the digital pins number to be used and if this pin will be an output, input, PWM, Servo, Tone and SONAR. Just clicking on this block, will enable pin 13 as an output. Now drag 2 of the Digital Write blocks:
DigitalWrite Set Pin ( ) to 
Note that at same block you can enter the digital pins number to be used and if this pin will be setting up as a  or . If you click on individual blocks, you can turn on or turn off the LED, try that.
OK. Now, let's create a real blink code using Scratch.
- Start your program when the "Green Flag" is clicked, for that you will need the block:
- When "green flag" clicked (it is the first block of Control menu - Yellow)
- Drag the loop block "Forever"
- Inside the loop Forever, put the blocks that you tested before.
- if you run your code, you will see that nothing happens, or better, the LED will be ON and OFF so quickly that you will not realize it. So, you must some delay, let's say 1 second after each block.
And that's it! Below you can see the complete program:
The above screenshot shows you the final program and how I started the s2aio, this time using the Terminal. At below link, you can download the code used here:
Try some changes, explore the code!
What we will do from now on, will be creating one by one, specific Sprites for each one of the below electronic components:
- LED ==> Digital output: ON/OFF
- pwmLED ==> Analog output: Using PWM, we will variate the LED brightness
- Push-Button ==> Digital input: ON/OFF
- LDR ==> Analog Input: Light measurement
- Temperature ==> Analog Input: Temperature measurement
- PIR ==> Digital input: Motion sensor (ON/OFF)
- Buzzer ==> Analog output: Creating musical tones
- Sonar ==> Input/Output: distance measurement
- Servo ==> 180o Servo Motor movement control
Each Sprite will be responsible for the initial setup of Arduino's pins and to monitor or to act accordingly with its designated task. Also, each one of those tasks will be associated with a variable, so we will not change the Sprite specific blocks anymore, independent of our program.
On next step, we will start with the LED and I hope the idea became more clear.
For starting, we will go to Data menu (orange) and create a new variable: "led", that will work for all Sprites (this is very important). This variable will be set to "0" if we want the LED OFF and will set to "1" when we want the LED ON.
Also, we will create a new Sprite going to the editor that we will name it "LED". At the editor, we will create 2 different "costumes": LED OFF and LED ON.
The LED sprite (and all the other components of our playground) will be programmed having 2 specifics group of blocks, one for setup its initial condition and another one that will run forever (in a loop), where we will monitor/actuate on its specific pin. The 2 groups of blocks (or "functions") are described below:
- We will make a specific block named "setup" for initializing the LED
define (setup) Enable] Digital Pin (13) for [Output] DigitalWrite Set Pin (13) to  switch costume to [LED OFF] set [led] to (0)
- Create our "main" function, that will "call" the "setup" function
when GREEN FLAG clicked setup forever if <led> = (1) then DigitalWrite Set Pin (13) to  switch costume to [LED OFF] else DigitalWrite Set Pin (13) to  switch costume to [LED OFF]
Note that at this moment, when you run the program, clicking on GREEN FLAG, nothing will happen, BUT in fact, from now one you can set the variable led anywhere "1" or "0", that the LED will follow!
Let's create a new Sprite, that will be whom will really do all the action for us. I will be using my little friend, MJRoBot for that. Associated with this Sprite ("MJRoBot"), we will develop our program blink never changing or touching again the Scripts associated with LED.
On the Script area associated with MJRoBot, let's drag the blocks:
set [led] to (0) set [led] to (1)
Clicking on those blocks you will see that the real LED will ON and OFF.
So, we can play with variable "led", creating a blink script as we did on the last step:
when GREEN FLAG clicked forever set [led] to (1) wait (1) secs set [led] to (0) wait (1) secs
The above screenshots show the final program and at below link, you can download the code used here: Arduino_blink_V2.sb2
Again, try some changes, explore the code, associate the LED with animation. Install more LEDs with different names (variables), etc!
Now, let's explore a new component, that will be a LED connected to one of a PWM output, writing a script a little more complex to explore the potential of Arduino.
For starting, we will go to Data menu and create a new variable: "pwmLED", that will work for all Sprites. This variable will be set from "0" to "255", what will make the brightness of the LED to change from minimum to a maximum.
Let's now create a new Sprite going to the editor that we will name it "pwmLED". At the editor, we will create 6 different "costumes", simulating different LED brightness.
Follow the above diagram and add a new LED to our circuit. We must connect the LED cathode (the shorter leg) to GND via a 220 ohm resistor and the anode to our Arduino UNO pin 9.
The Arduino UNO can provide on several of its pins, a PWM signal (Pulse Width modulation). See this link for more details: Tutorial/PWM. In short, you can "emulate" an analog signal using a digital output.
The first thing to do is to inform Arduino that a specific pin (in our case will be 9) will be [Enable] and should work as [PWM]. Drag this block to code area.
[Enable] Digital Pin (9) for [PWM]
Just clicking on this block, will enable pin 9 as a PWM output. Now drag the Digital Write blocks:
AnalogWrite Set Pin (9) to (0)
Change the value 255 for other values. You will see that with zero, the LED will be off and with 255, the LED will be on its maximum brightness. Try intermediate values and see what happen.
As we did with Blink, the pwmLED sprite will be programmed having 2 specifics group of blocks, one for setup and another one that will run forever (in a loop), where we will monitor/actuate on its specific pin.
- "setup" for initializing the pwmLED
define (setup) [Enable] Digital Pin (9) for [PWM] AnalogWrite Set Pin (9) to  switch costume to [pwmLED 0] set [pwmLED] to (0)
- Create our "main" function, that will "call" the "setup" function and activate the pin 9 with a PWM value and define which costume our sprite will have to simulate "brightness" on Stage (animation).
when GREEN FLAG clicked setup forever AnalogWrite Set Pin (9) to (pwmLED) if <(pwmLED) > 50> then switch costume to [pwmLED 64] if <(pwmLED) > 100> then switch costume to [pwmLED 128] if <(pwmLED) > 150> then switch costume to [pwmLED 180] if <(pwmLED) > 200> then switch costume to [pwmLED 210] if <(pwmLED) > 250> then switch costume to [pwmLED 255] if <(pwmLED) < 50> then switch costume to [pwmLED 0]
Associated with "MJRoBot" Sprite, we will develop a program (or "Script") that:
- Change the PWM value from 0 to 255, returning to zero after that.
- When the pwmLED (Blue LED) brightness will be at its maximum, let's turn on the led (Red LED) for 1 second.
when GREEN FLAG clicked forever repeat until <(pwmLED) > (255)> change [pwmLED] by (10) wait (0.1) secs set [led] to (1) wait (1) secs set [led] to (0) set [pwmLED] to (0)
Below the code: Arduino_dimmer_LED.sb2
Analog outputs can be used to control motors or position servos for example. You can try it.
Let's begin with connecting a push-button to Arduino pin 2. Follow the above diagrams and make the proper connections. From now on, we can go faster. You have already "catch" the idea! For digital inputs, we will use the same setup block that we used with the LED, but changing its parameter to "input":
[Enable] Digital Pin (2) to [input]
And to "read" the value on this pin, we will use the block:
Read Digital Pin (2)
This block will return "1" if on the pin D2 we have a logical level "1" and "0" if it is a "0". Drag both blocks to Script area and click first on the Enable block and after on the Read Digital block. Press the push-button and verify if the status changed (a "white balloon" will appear over the block with its value).
So, let's create a new variable "button", that will be set up to "1" or "0" depending on the push-button condition and 2 new costumes for the new Sprite (we will call it Push-Button). Try it yourself and only after confirming with the code at bottom of this step.
Again, we will create 2 groups of Blocks, the "setup" and the "main loop". Only note that here the variable "button" will be "loaded" with the Push-Button status:
set [button] to (read Digital Pin (2))
A great feature with Scratch that helps a lot when you are testing a code, is "to check" a variable (with a "v" mark) on the Data menu. Doing that, the variable value will be shown at Stage, as shown on the above screenshot.
Let's Create a code associated with MJRoBot Sprite that will vary pwmLED from minimum (0) to maximum (255), but only during the time that Push-Button is pressed. Also, if the Push-Button is pressed, the RED LED (associated with led variable) must be ON. Try it yourself before look the final code.
After you have tried, you can download my version of the above problem.
For learning how to use the Arduino analog inputs, we will connect an LDR, that is a Light Dependent Resistor on Analog Pin A0.
But, what is an LDR?
LDR, also known as " Photoresistor", is a device that has its electrical resistance varying with light. As you can see above diagram, higher the light, lower the resistance. So, because we will assemble the LDR as a "voltage divider", we will get at Arduino pin A0 an analog signal inversely proportional to light variation:
- High light ==> Lower internal resistance ==> higher voltage input at A0
- Low light ==> higher internal resistance ==> lower voltage input at A0
This way, the pin A0 of Arduino UNO will receive a signal varying from 0 to 5V. The Analog Pins of UNO are internally connected to a 10bits ADC (Analog Digital Converter), that it is a device that as the name explains, will convert the analog value to a digital value that can be read internally by the processor (10 bits ADC generates values from 0 to 1023).
So, on a limit:
- LOW LIGHT ==> LDR with HIGH RESISTANCE ==> 0V at pin A0 ==> ADC: 0
- HIGH LIGHT ==> LDR with LOW RESISTANCE ==> 5V at Pin A0 ==> ADC: 1023
of course in a practice, the values will be between those extremes. Let's see it working:
The block to be used for setting up an analog pin is:
[Enable] Analog Pin (A) (0) for Input
And to "read" the value on this pin, we will use the block:
Read Analog Pin (A) (0)
This block will return an analog value from 0 to 1023, if it is a "0".
Drag both blocks to Script area and click first on the Enable block and after on the Read Analog block. Cover the LDR with your hand and verify if the value reported by the block changed (a "white balloon" will appear over the block with its value). On my case I got the below values:
- Normal light: More than 900
- Dark (I covered the sensor with my hand): Less than 50
So, let's create a new Sprite (LDR) and a new variable "light", that will a value depending on ambient luminosity.
The problem here is that 800, 900, 50, etc that is the values returning from ADC means nothing for us. What we need is something like:
- Maximum luminosity: 100%
- Completely dark: 0%
So, if we have a luminosity of 30%, for sure is the end of the day and we know what really means.
We need to "MAP" our variable, in a way that:
- If the ADC output is let's say 30 ==> we want 0%
- if the ADC output is let's say 1000 ==> we want 100%
And any value intermediary (from 0 to 1000) will proportional to a value from 0% to 100%:
We can generate here a generic block that will MAP an analog input, independent of the values that we have that will transform from minimum (Low) and maximum (High) inputs to a minimum and maximum outputs.
Let's create names:
- minimum input ==> fromLow
- maximum input ==> fromHigh
- minimum output ==> toLow
- maximum output ==> toHigh
- generic input value ==> value
- generic output result of mapping ==> mapReturn
Using "proportions", we can create an equation:
mapReturn = ((value - fromLow) * (toHigh - toLow)) / ((fromHigh - fromLow) + toLow))
Seems a little complicated, but in fact is simple and useful. The important here is that this "Map Block" that you create will work always. Also, note that we have used the operator "Round" that will as its name says, round the final value. At the end you will only need to use:
map (value at A0) (fromLow) (fromHigh) (toLow) (toHigh)
On our case:
map (Read Analog Pin (A) (0)) (30) (1000) (0) (100)
and we will set our light variable with the return of this new map block. For more details about MAP, see see here.
Let's go to our MJRoBot Sprite and use this new variable light, creating a simple code where if the light is less than 30%, we must turn on the Red LED (associated with variable led), if not leave the LED OFF. Spite of simple, this is exactly what happens with street lights for example, that automatically turn ON at end of day.
Create your code and see my simple solution after.
My code: Arduino_LDR.sb2
Modify your code to automatically turn on an external light in your house (here the red LED) when is dark, but you only want to do this if you are traveling, so you will turn on or off your project, using the push-button. Think about how you must play with variables in a way that when you "press the push-button", we keep its status. If we press it again, the status will be "toggled".
Let's explore another sensor that also generates an analog output, the LM35, a temperature sensor.
The LM35 series are precision integrated-circuit temperature sensors, whose output voltage is linearly proportional to the Celsius (Centigrade) temperature and so, does not need external calibration. Its output is 10mV/oC. So, for a temperature of 19 oC for example, the LM35 will generate 190mV.
As we did before, we will create a new Sprite (LM35) and define a new variable, "tempC" that will receive the analog pin A1 value. The setup is similar to what we have done with LDR, only we will change (A) (0) for (A) (1) on Enable Analog Pin block.
[Enable] Analog Pin (A) (1) for Input
And to "read" the value on this pin, we will use the block:
Read Analog Pin (A) (1)
This block will return an analog value from 0 to 1023.
Ops, but when you click on this block, we realize that the temperature is not really correct (it shows "39", but I know that the temperature here in my lab is in fact 19oC).
Remember that each Analog Input will vary from 0 to 5V (or 5,000mV). So, let's calculate for 19oC what should be the output of internal ADC:
Applying proportion, we have:
- 5,000 [mV] ==> 1024
- 190 [mv] ==> x
x = (190 [mV] x 1023) / 5,000 [mV] = 39
So, this is exactly what we are getting internally from A1. But what should we do have the variable "Temp" showing the correct Celsius temperature?
Taking the reading, find what percentage of the range (1024) it is, multiplying that by the range itself (5000 mV), and dividing by ten (10 mV per degree Celcius, according to the datasheet):
The temperature in Celcius will be so calculated:
tempC = (5V x A1_Value x 100%) / 1024 = tempC = A1_Value (500/1024) tempC = A1_Value / 2.048
So, let's use blocks below to calculate it:
set[tempC] to ((Read Analog Pin (A) (1)) / (2.048))
When you click on it, the correct "19oC" will appear associated with variable "tempC".
Note that we at the final code will use round () to "round" the result of the calculation, taking out the value after the decimal point.
Same as we did with LDR and now that we have the variable tempC constantly updated with the sensor value, let's create a code associated with our MJRoBot Sprite, having the following idea:
if <(tempC) > (30)> then set [pwrLED] to (255) else set [pwmLED] to (0)
Note that we are keeping the previous code, that will turn on the "red LED" if the light is lower than 30% and now we are adding an "alarm" using the "blue LED", related with our variable pwmLED. Both sensors will work independently.
In reality, the Arduino UNO has only one internal ADC that is multiplexing amont its 6 analog pins. So, its good not to have measurements imidiatelly one after the other. Its advise to have at least 300ms between measurements.
Returning to our project, you can imagine it to be used to automatically turn on a fan or conditioner air equipment in your house (here the blue LED) when is hot. Put your finger over the sensor. You should see the temperature going up, firing up the blue LED.
Below the complete code for downloading:
Create a code that will draw a "Bulb Thermometer", where the mercury column will go up and down accordingly with temperature (see the above picture as an example).
PIR sensors allow you to sense motion, usually used in home alarms to detect whether an intruder has moved in or out of the sensors range. They are small, inexpensive, low-power, easy to use and don't wear out. For that reason, they are commonly found in appliances and gadgets used in homes or businesses. They are often referred to as PIR, "Passive Infrared", "Pyroelectric", or "IR motion" sensors.
They are "Digital Sensors", being very easy to use them in your projects:
- If you have a "movement" in front of the sensor, its will generate a 5V in its output and the Arduino will understand it as logical level "1".
- With "no movement" a 0V will be at Arduino's digital pin, what means a logical level "0".
You can "think" that the sensor is a "push-button", what means that what we have learned before will apply to it.
So, let's begin with connecting the PIR sensor to Arduino pin 3. Follow the above diagrams and make the proper connections.
Same as we did with the Push-Button, let's create a Sprite (PIR), this time with 2 costumes showing if we get or not a "movement" and a new variable named "motion". Use an Enable Digital Block to setup the pin:
[Enable] Digital Pin (3) to [input]
And to "read" the value on this pin, we will use the block:
Read Digital Pin (3)
This block will return "1" if on the pin D3 we have a logical level "1" and "0" if it is a "0". Try it.
So, we need now set up the variable "motion", with 1 or 0, depending on the PIR condition:
set [motion] to ((Read Digital Pin (3))
As we did before, the variable, "motion" will take the D3 status. We will include it on the "Forever Loop" that is part of the "main" function. At this loop, we should test if there is movement (motion = 1) and change the Sprite's costume properly.
Now, let's think about something useful to do with this sensor. As mentioned before, the PIR is commonly used on home alarms. If a person enters in your home, the sensor will detect it and will fire an alarm for example. In our case, this alarm is represented by the red LED. The code is similar to the one developed for the last sensors.
Try it for yourself. But anyway, the code is below:
Challenge: Modify your code to automatically turn on an external light in your house (here the red LED) when is dark, but you only want to do this if you are traveling, so you will turn on or off your project, using the push-button. Think about how you must play with variables in a way that when you "press the push-button", we keep its status. If we press it again, the status will be "toggled". Also, now consider to include in the code the movement sensor.
Up to now, the Sprites that we have developed used a "straight forward" approach:
- "Sensing" digital pins (Push-Button and PIR),
- "Sensing" analog pins (LDR and Temperature)
- "Acting" at digital pins (LED)
- "Acting" at analog pins (PWM LED)
From now on we will explore new blocks developed on s2aio, the first ones will be related to "Tone Generation":
Those blocks will generate a square wave of the specified frequency (and 50% duty cycle) on a pin. A duration can be specified in milliseconds, otherwise, the wave continues until we use a noTone block. The pin will be connected to a piezo buzzer to play tones. Follow the above diagram and connect the pin "+" of the buzzer to digital Pin 6.
You must configure the pin for tone operation by using the Digital Pin Configuration Block before using this block.
[Enable] Digital Pin (6) for [Tone]
For sending a specific tone to the Piezzo use the Play Tone Block, for example, for 1KHz and 500ms tone:
Play Tone on Pin (6) HZ: (1000) ms: (500)
Entering a duration of zero will leave the tone activated. Use the no tone command block to deactivate.
Turn Tone Off for Pin (6)
Same on previous components, we should:
- Create a Sprite ("Buzzer") and define its costumes
- Define variables to be used with this component. In this case 2:
- toneHz ==> frequency in Hz
- toneMs ==> duration in milliseconds
- Enable Digital Pin (here will be 6) as [Tone]
- Setup our Buzzer, starting with no sound and its proper costume
- Associate on a "main" function the variables toneHZ and toneMs with the block Play Tone
Great! Remember our last step where we had a motion detector? let's now associate a sound alarm (Buzzer) when an intruder is detected! On my example, I used 2 different frequencies to simulate an alarm. Try other ideas!
Here my simple code for the sound alarm:
A very interesting device that can be used for distance measurements is the "Sonar". Here we will be using the HC-SR04 Ultrasonic Ranging Sensor.
Basically, this device emulates what bats do for distance measurements. They emit an ultrasound pulse and count the time for an echo to be received back. Having the time for the Echo to reach back the sensor and knowing the sound speed (340m/s), we can by dividing it by 2, knowing the distance between sensor and obstacle (see above diagram).
This sensor provides 2cm to 400cm of non-contact measurement functionality with a ranging accuracy that can reach up to 3mm. Each HC-SR04 module includes an ultrasonic transmitter, a receiver and a control circuit. The HC-SR04 has 4 pins:
- VCC (Power),
- Trig (Trigger),
- Echo (Receive), and
- GND (Ground).
On our case, s2aio developed their block taking in the consideration that the trigger and echo pins are wired together and a single wire is connected to an Arduino digital input. Note the above diagram, that both pins are together (jump on the breadboard) and connected to Arduino pin D12.
The pin 12 should be enabled using the Digital Pin Configuration block, selecting Sonar mode.
[Enable] Digital Pin (12) for [Sonar]
Sonar data is monitored using a Read Digital block.
Read Digital Pin (12)
Same with previous components, we should:
- Create a Sprite ("Sonar") and define its costumes
- Define a variable to be used with this component. In this case "distance"
- Enable Digital Pin (here will be 12) as [SONAR]
- Setup our distance variable, starting with "0" distance and its proper costume
- Associate on a "main" function the variable distance with the value measured by the Sonar at pin 12
If you do the above, you will get the sensor working, BUT you will realize that sometimes, errors will happen (big or very low measurements). This is because other sound or echoes reflected on different obstacle can generate "false" responses to the sensor. One way to minimize this, it to create a temporary variable ("temp"), that will receive the reading from Digital Pin. We will only pass this value to our real variable "distance" IF the measurement is in between defined limits (see the above print screen). For example, I have setup an area to measure things that will go from a minimum of 3 cm up to a maximum of 40 cm.
Great! Remember our last step where we developed a sound alarm with our motion detector? Let's now associate the sound alarm (Buzzer) and a visual alarm (LED) when an intruder is detected but ONLY on distances less than 30cm (SONAR)! Try other ideas, like also incorporating the motion sensor (PIR) more LEDs, light, etc.
Here my simple code for the sound distance alarm:
Our last device to be included on the MJRoBot Electronic Playground will be a servo motor, using another special s2aio command block to set its position between 0 and 180 degrees.
But before anything, Let's build a "tower" where we will mount together with the Sonar and the 180 degrees Servo Motor. Doing that, we can point our sonar in different directions, using the servo. Follow the above photos as a suggestion how to build the tower.
Having the tower fixed on a table (I used Scott tape), connect the servo cable on protoboard as shown at the diagram. There are only 3 wires, +VCC, GND and Data (usually orange) that must be connected to Arduino pin D10.
The pin 10 should be enabled using the Digital Pin Configuration block, selecting Servo mode.
[Enable] Digital Pin (10) for [Servo]
The command to position the Servo on specific angles is gotten with Move Servo block. Below an example moving it to 20 degrees:
Move Servo on Pin (10) Deg: (20)
Make some tests, changing angles from 0 to 180 (sometimes you must adjust the final values, the servo motor can have problems at extremes (near 0 and near 180)
Same with previous special blocks, we should:
- Create a Sprite ("Servo") and define its costumes
- Define a variable to be used with this component. In this case "angle"
- Enable Digital Pin (here will be 10) as [Servo]
- Position our Servo for its "zero angle position (in my case will be 20)
- Setup our angle variable, starting with "0" and its proper costume
- Associate on a "main" function the variable angle with the value to be set to position the servo
If you do the above, you will get the servo working, BUT it is important to prevent that variable angle be defined by other Sprites with values out of servo range (in my case 20 - 180). So, we will make a "limitation" or "CONSTRAIN" the data angle, in a way that we will only move the servo if variable angle will be between 20 and 180. If the angle is lower than 20, we will keep it 20, same procedure for values over 180. See the above print screen to understand how I create this "constraint idea".
A good procedure will be create a dedicated and generic block for the "CONSTRAIN function", same we did for MAP. Try it!
Let's create a "SWAP" function, where the servo will move in all directions. Let's include the pushbutton, so the Servo will make the swap only when it is pressed.
Here my simple code for the manual swap function:
Now our MJRoBot Electronic Playground is complete. We have a Sprite for each one of our components. Each component has a variable associated with it. So, now we can define a project and work on its code only changing the Script associated with MJRoBOt or any other.
The idea is not change the component sprites if the HW not changed. So, let's create our first real project using the Playground.
Open The Base Playground Scratch2 file:
You will see that the Script area for our Sprite MJRoBot is empty.
To create a new project, go to Scratch 2 Offline Editor File Menu and using "Save as" option name it: "Arduino_Radar_Basic.sb2". Do not change the Base_Playground.sb2 file.
Using what we have learned so far, we will create a code for a base radar where:
- The tower with Servo/Sonar will sweep an area looking for obstacles on a 40 cm range.
- If an obstacle is found on distance less than 10 cm, an alarm should be fired.
- The alarm should use sound and light.
That's it. The video below shows how the final project should work:
And here the final code:
Let's use our last project, the "Base Radar" and also include on it an animation that will show a "Radar Screen" on our Stage area.
We will introduce 2 new Sprites:
- The Radar Screen
- The Radar Scanner (with 2 costumes: normal scan and target founded)
The Radar Screen will only a "background" and will be static. But the Radar Scanner will be a Line that will sweep the Radar screen from left to right (from 0 to 180 degrees), following the Servo Sweep.
In order to, synchronize the animation and the real servo swap, you must add to MJRoBot's last script, two "event calls".
The first any time that the servo goes to its start position:
another during the normal scan:
and one more, when a target is found and the alarm is fired off:
On Radar Scanner Sprite, those 3 events will trigger specific functions:
- When received [startScan ] go to position zero
- When received [draw] change sprite position, turning 3.5 degrees (same as we used on swap function) and also sound and costume properly
- When received [target] change sound and costume properly
Below a quick movie showing the project:
And the final code:
It is your time, now!
Be creative! Mix the sensors, including new ones! The sky is (not) the limit. After you learn about how to control "things" using an Arduino and Scratch 2, try doing the same using the Arduino IDE.
"Live Long and Prosper".
As always, I hope this project can help others find their way in the exciting world of electronics, robotics, and IoT!
Please visit my GitHub for updated files:
For more projects, please visit my blog: MJRoBot.org
Saludos from the south of the world!
See you at my next tutorial
Scratch 2.0 for Arduino
- 14 projects
- 174 followers
- Developer of s2aio : the arduino hardware extension for snap! and the scratch 2.0 offline editor by Alan Yorinks
Published onAugust 1, 2017
Members who respect this project
you might like