Transcript
Overview This is a tutorial about sensing the environment using a Raspberry Pi and a GrovePi+. You will learn: ●
●
●
digital input and output ❍
measure a digital input (from a button)
❍
output a digital signal (to an LED)
analogue sampling and synthesis ❍
measure an analogue input (the "Rotary Angle Sensor" potentiometer, the light sensor)
❍
control an analogue output
❍
convert an analogue value to a physical value
bus-communicated devices ❍
measure range to an object (ultrasonic ranging)
We will continue with pair programming in these practical sessions. You will need to be in a group of two people (with no more than one group of three people). Each person in the group will alternate between the different roles of driver and navigator.
Connecting your Pi Each pair will need to sit at a workstation which is fitted with a KVM switch (keyboard, video display, and mouse) and: ●
a green box (containing a Raspberry Pi 2 model B with a micro-SD card with Raspbian pre-installed, a GrovePi+ board, and a set of GrovePi+ peripherals)
●
a power supply (mains to 5V adapter with a micro-USB connector)
●
an HDMI cable and HDMI female-female adapter
●
an Ethernet cable and Ethernet female-female adapter
●
a USB extension lead
Make sure the green Raspberry Pi board is connected to the blue GrovePi board (carefully do so if not), and the micro-SD card is in the slot on the underside of the Pi. Connect: 1. HDMI cable (through a HDMI female-female adapter, to the HDMI KVM cable) 2. USB keyboard and mouse connection (through a USB male-A to female-A extension cable, to the USB KVM cable) 3. Ethernet cable (through a Ethernet female-female adapter, to the Ethernet cable on the desk) 4. Plug in the power adaptor and connect the micro-USB cable to the Pi. The Pi will now power up. Press the KVM switch once if you don't see anything.
Setting up your Pi for the GrovePi+ DO NOT do these steps if your Pi has already been set up for the GrovePi+ (e.g. if the login credentials above worked, your Pi should already be set up).
1. If you are asked to log-in, the default credentials are pi and password raspberry. 2. In LXTerminal, run the configuration tool with sudo raspi-config. 3. Choose Change User Password. Type the password ubicomp (nothing will be displayed as you type) then Enter, type the password again and Enter. 4. Choose Advanced Options and Hostname. Delete raspberrypi and type the name on your label. Press Enter to accept. 5. Choose Advanced Options, Device Tree, Yes. 6. Choose Advanced Options, I2C, Yes, Ok, Yes, Ok. 7. Choose Finish, and do not accept the prompt when asked to reboot. 8. Edit the list of kernel modules that the operating system will load when it boots with sudo nano /etc/modules, add two lines, one with i2c-bcm2708 and another with i2c-dev 9. Install i2c-tools: sudo apt-get install i2c-tools 10. Allow the user pi to access the I^2^C bus: sudo usermod -a -G i2c pi 11. Now reboot: sudo reboot 12. Log in (username pi, password ubicomp). 13. Get the Java library for I/O: curl -s get.pi4j.com | sudo bash 14. Get and build the library to access the GrovePi+: cd ~; git clone https://github.com/digitalinteraction/jgrove.git; cd jgrove; sudo apt-get install ant; ant
15. Check the communication with the GrovePi+ board is working by running the input test command (you should see a stream of 1): java -jar /home/pi/jgrove/dist/lib/jgrove.jar
Updating your GrovePi+ library Ensure you have the latest version of the GrovePi+ Java library built: cd ~/jgrove git pull ant
The Geany IDE Your Pi comes pre-installed with Geany, a simple IDE: 1. Run Geany from the application menu. 2. Open /home/pi/practical1/Blink.java (or create a new Java file if that doesn't exist on your Pi). 3. Set the class path in Geany by choosing: Build, Set Build Commands, then under Java Commands /Compile, set it to:javac -cp .:/home/pi/jgrove/dist/lib/jgrove.jar "%f" 4. ...and under Execute, set it to (note the java and %e, not javac or %f): java -cp .:/home/pi/jgrove/dist/lib/jgrove.jar "%e"
You can choose your preferred way of developing: you can continue to use Geany, or the command line.
If you want to run javac and java from the command line, you must first set the CLASSPATH environment variable:
export CLASSPATH=.:/home/pi/jgrove/dist/lib/jgrove.jar
Digital I/O Individual digital signal lines are two levels, binary (high/low voltage) -- such as the input from a switch or the output to turn on a buzzer. Pins can be configured for input (where we are measuring their value), or output (where we control their value). Digital inputs effectively have a threshold for the incoming voltage, and result in an binary value. Digital outputs are usually ground (0V) for low 0 and the reference voltage level for high 1.
Switched digital input We will write some Java code to interface through the GrovePi+. Edit a new file at /home/pi/practical2/Button.java (if you're at the terminal, you can run: mkdir ~/practical2; cd ~/practical2; nano Button.java).
Start with a class Button, which has a public static void main(String[] args) method. We will need to add imports for grovepi.GrovePi, grovepi.Pin, and all sensor classes with grovepi.sensors.*.
In the main() method, we need to obtain an instance of a GrovePi class: GrovePi grovePi = new GrovePi();
...then, from that instance, get its device factory, and use it to create a ButtonSensor instance on pin D4.
ButtonSensor button = grovePi.getDeviceFactory().createButtonSensor(Pin.DIGITAL_PIN_4);
Write a loop to continuously poll the state of the button using button.isPressed(), which returns a boolean, and prints the result with System.out.println().
Now try compiling your code and (if successful) running it. If you are at the terminal, this single line will do (if compilation fails, fix the problem and re-run the last command from your history by pressing Up then Enter). cd ~/practical2 && javac Button.java && java Button
When your code successfully runs, connect a Grove Button to port D4 with a cable. Pressing the
button should change the output. If you are at the terminal, press Ctrl+C to stop. You can get the current system time in milliseconds with long System.currentTimeMillis(). Change your loop to measure and display the length of each button press: record the time the button was pressed down, and display the elapsed time difference when the button is released. Now modify it to compare it to a threshold to distinguish a long from a short press (say, 500 milliseconds), and print each case.
Switched digital output Last time, we made an LED turn on with this code: import grovepi.sensors.Led; // ... Led led = grovePi.getDeviceFactory().createLed(Pin.DIGITAL_PIN_3); led.setState(true);
Connect a Grove LED to port D3 with a cable. If there is no LED installed, put one in: the negative (-ve, cathode) side of an LED typically has a larger plate inside the LED (it sometimes also have a flat edge on the LED dome, and a shorter leg), and the positive (+ve, anode) side of an LED typically has a smaller plate inside the LED (it sometimes has the rounded edge on the LED dome, and a longer leg). Modify your loop so that the LED is turned on when the button is pressed, and off when the button is released. Run the code to check.
Timing Now modify your loop so that a long press toggles the LED state (i.e. alternates between on and off), and a short press is ignored. Run the code to check. Now modify the code in Button.java to distinguish a "single click" from a "double click". Chose a timing threshold, say 500 milliseconds. When the button is pressed down, just record the time. If it is pressed down again within the timing threshold, print "double click", if it is not pressed down again within the timing threshold, display "single click". Make the double clicks toggle the LED.
Analogue I/O Analogue values form a continuous spectrum -- such as a measure of the amount of light, or the brightness of an LED. So a computer can make use of them, analogue inputs and outputs are converted between a voltage level and a fixed digital representation.
Analogue Input: Light sensor Analogue inputs require sampling, a process called analogue to digital conversion (ADC). They are
quantized (turned into a fixed representation, effectively an integer number), in both value (e.g. a number of bits resolution over some physical range), and time (e.g. at a given sample rate). In the GrovePi+, ADC sampling is to a 10-bit value (giving 2^10=1024 states) numbers between 0 and 1023 representing the voltage range 0 to 5V. Start a new file ~/practical2/Light.java (perhaps begin with a copy of the previous file: cp Button.java Light.java, but be sure to rename the class from Button to Light).
From the grovePi instance, you can perform an ADC reading. Attach a light sensor to the first an analogue input ("A0"). Write a loop to print the ADC value from the light sensor. You can poll the state of the light sensor with: int grovePi.analogRead(Pin.ANALOG_PIN_0);
Analogue Output The inverse of ADC is digital to analogue conversion (DAC), turning a digital signal into a varying voltage. The GrovePi+ kit doesn't include a true DAC, but does support Pulse-Width Modulation (PWM) on three of the digital pins (D3, D5 & D6), which is suitable for controlling the brightness of LEDs. PWM works by having a high frequency on/off signal, and adjusting the ratio of the on/off time (the frequency remains the same). You will need to set the pin as an output, e.g. for D3: grovePi.pinMode(Pin.DIGITAL_PIN_3, PinMode.OUTPUT);, you will need to add an import for grovepi.PinMode. Now you can use grovePi.analogWrite(Pin.DIGITAL_PIN_3, int value); to control the proportion of the time on
(8-bit range, values 0-255). Change your program to act like a torch by providing more light when dark, less when light. Now modify your program to act like an automatic LCD backlight, by converting a range of light readings into a corresponding range of brightnesses: the lighter it is, the brighter the screen (but none to be completely switched off).
Converting samples to physical values The GrovePi "Rotary Angle Sensor" is a potentiometer -- a knob that varies resistance as it's turned. This change in resistance can be measured as a corresponding change in voltage, by performing an ADC reading.
Start a new file ~/practical2/Rotary.java (perhaps from a copy of the last program: cp Light.java Rotary.java, changing the class name to Rotary).
This potentiometer is linear, the ADC will give a reading that is proportional to the resistance, and the resistance is proportional to angle.
Write your program to read the raw ADC values from the device. Use it to work out the minimum and maximum values for the rotation, store these as constants in your code. Modify your code to calculate the percentage level of maximum rotation. Given that the angular range is 300 degrees, and the change in values is linear with rotation, we can turn this voltage in to physical value. Modify your program to calculate and display the current rotation angle.
Range sensing Ultrasonic ranging works by transmitting a sound pulse at a frequency beyond human hearing, then timing how long it takes to appear at the receiver. Create a new source file Distance.java. Make sure you import grovepi.GrovePi, import grovepi.Pin and import grovepi.sensors.*. Create a new GrovePi object called grovePi, and a
range sensor object: UltrasonicRangerSensor rangeSensor = grovePi.getDeviceFactory().createUltraSonicSensor(Pin.DIGITAL_PIN_4);
Write a sampling loop to measure and display the distance to the nearest object (int rangeSensor.getDistance()). Connect an ultrasonic range sensor to pin D4 and run your program.
Move your hand to different distances to see the range change. Only if you have time, modify your code to map the distance range to fading LEDs. As the distance decreases to zero, fade up firstly the blue LED (D6) to maximum, then also fade up the green LED ( D5) to maximum, then finally fade up the red LED (D3) to maximum.
Turning off your Pi Once you are finished, you can safely power down your Pi, by running: sudo halt -p