THE PROGRAM
In this tutorial, we will
1) set up a gesture sensor that can detect to which direction an object is heading and
2) respond with a row of LEDs that will light up in a timed sequence if the object is headed toward it.
This tutorial was developed as a prototype project for smart street lights. I am envisioning these lights can sense when a person is entering a street, then turn the lights on the street one after another — lighting up the way, if you will.
As you can see in the diagram, when the person enters the left street, the sensor will initiate a sequential response for the left-side row of lights, starting from LC (left corner) LED. In three seconds, the L1 (left 1) LED will turn on, then L2 (left 2) LED will turn on three seconds after that. All three lights will stay on for 10 seconds since the LC first turned on, then all lights will turn off. Technically, they will go back to their default setting which is very dim, but not off.
I should make it clear that we are not building a set of smart street lights in this tutorial. There are a few limitations, which will be pointed out throughout the post.
What we will be able to do is to think about the logic of making the directional motion sensor and the real-time light response work together. Then when we have the necessary electrical/technological parts available to actually make the smart street lights, we will have a good place to start. This is also why I may refer to the row of LED lights as “streets” and hand gesture movement as “person entering street” at times throughout this tutorial.
The main takeaways from this tutorial will be:
- How to set up and use a gesture sensor (APDS9960) with Arduino Uno and
- How to use millis() to act as a timer to control the lighting sequence.
WHAT YOU NEED
- Adafruit APDS9960 Proximity, Light, RGB, and Gesture Sensor
- 1 Arduino Uno
- 1 Half-sized Breadboard
- 2 Mini Breadboards
- 2 Red LEDs
- 4 Yellow LEDs
- 12~14 wires of various length
WHY APDS9960 SENSOR?
We very commonly see PIR sensors being used for Arduino projects that require motion detection. A PIR sensor could achieve some of the functionalities I was going for, but to be able to achieve the direction-sensitive responses I envisioned, APDS9960 seemed to be the way to go.
The main tradeoff for this decision was the detection range. APDS9960 is a lot more limited in its sensing range (Adafruit says about 6″ from the sensor) compared to the ~10-meter range a PIR sensor can work with. Depending on the purpose of your project and where you are installing it, you might want to turn to a PIR sensor instead.
* Adafruit’s APDS9960 sensor can work with both 3.3V and 5V microcontroller (thank you built-in level-shifter!). If for some reason you can’t purchase from Adafruit, SparkFun also has its own APDS9960 RGB + Gesture Sensor (with detection range 4-8″). Please note that SparkFun APDS9960 can only work with a 3.3V microcontroller (like this Arduino Pro 328). If you are working with an Uno (5V), like I am, you will need a level shifter like this one. SparkFun has a great setup guide for its APDS9960 if you want to find out how to do that.
** Another caveat: You can only connect one APDS9960 to an Uno. Without going into much detail, SCL and SDA pins on the breakout board are I2C clock and data pins, which technically can support multiple devices on a single line as long as each device has a unique address. Adafruit’s APDS9960 uses a fixed address 0x39, which cannot be changed. But you should be able to use 2+ Unos to use more than one APDS9960 on one program. For instructions on how to make two Arduino Unos talk to each other, check out this post by Nate Klass.
SETTING IT UP
1. Soldering
Your APDS-9960 breakout board will arrive with a small strip of male header pins, so you can solder it onto your breadboard using a soldering iron. There are lots of soldering tutorials on YouTube, but I found this one helpful.
You first prepare the header pins (insert the longer metal legs into the breadboard). It doesn’t matter particularly where on the breadboard you choose to put the breakout board, but do make sure that you will have enough room for wires (i.e. soldering the pins to the bottom row wouldn’t be ideal). If you are using a half-sized or a full-sized breadboard, this shouldn’t be a big issue. Next, place the breakout board onto the sticking out header pins so that each of them can poke through the power and logic pin holes. Now solder all six pins.
When we have the breakout board securely attached to the breadboard, we can move onto the circuitry.
2. Wiring
First, make sure each of the breakout board’s pin is connected to the right pin ports on Arduino.
- Connect Vin to 5V power supply.
- Connect GND to ground.
- Connect SCL to A5. (This is because for Arduino Uno A5 acts as SCL. If you are using a different microcontroller, check here to find out how you can wire correctly for your board)
- Connect SDA to A4. (Same as SCL)
It’s probably a good idea to check if your sensor is working before moving forward. Let’s test it!
Place one LED on the breadboard, then wire as shown below:
Once routing is complete, upload the code below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
/************************************************ This is a testing sketch created to check if APDS9960 is sensing gesture correctly, and responding to the code using the library. Code created by Alana S. Kim, 11/15/2017 Based on the sketch by Dean Miller for Adafruit Industries * expected response when everything is working: * when you gesture * 1) up -> down, the light turns on * 2) down -> up, light turns off * 3) right -> left, light turns on * 4) left -> right, light turns off *************************************************/ #include "Adafruit_APDS9960.h" Adafruit_APDS9960 apds; const int testPin = 3; // the setup function runs once when you press reset or power the board void setup() { Serial.begin(115200); if(!apds.begin()){ Serial.println("failed to initialize device! Please check your wiring."); } else Serial.println("Device initialized!"); //gesture mode will be entered once proximity mode senses something close apds.enableProximity(true); apds.enableGesture(true); } void loop() { //read a gesture from the device uint8_t gesture = apds.readGesture(); if(gesture == APDS9960_DOWN) { Serial.println("v"); digitalWrite(testPin, HIGH); } if(gesture == APDS9960_UP) { Serial.println("^"); digitalWrite(testPin, LOW); } if(gesture == APDS9960_LEFT) { Serial.println("<"); digitalWrite(testPin, HIGH); } if(gesture == APDS9960_RIGHT) { Serial.println(">"); digitalWrite(testPin, LOW); } } |
You should be able to turn the light on and off by your moving your hand to different directions in front of the sensor. If the LED turns on and off as it should (check the “expected response” section at the top of the code), we can start connecting more LEDs.
Note: If the test code didn’t work as it was supposed to, there could be a couple different reasons for that. First, be careful with the wires covering over the sensor. Remember that this breakout board is sensing the movement by using photodiodes to detect reflected IR energy from the LED. This means that if there is a wire hovering over the sensor, this can interfere with the sensor reading your gesture correctly. Same goes with the LED. If you have the LED placed right next to the sensor, the light beaming out of the LED can also interfere with the sensor. Or possibly you didn’t properly initiate the sensor. The library is designed so that the directional gesture reading functionality is activated AFTER it first detects something with its proximity sensor. You have to put your hand close to the sensor for a couple seconds, then it will start reading your gesture.
Because we are using the total of 6 LEDs, each of which needs to be controlled individually, we need to connect them to separate pin ports. Also, we need to play with the LED light output intensity, so we can only use the PWM (pulse width modulation) pins. These are the digital pin ports with tilde(~) next to their pin number. Here are the pin numbers, to which each LED should be connected:
Note that only two center LEDs are red and called corner lights. Remember the diagram at the beginning of this tutorial? Like the diagram, the sensor will be placed between those two red LEDs, and depending on the direction the sensor detects, the yellow LEDs will response in sequence (as the street lights would).
A note on using resistors:
Don’t forget to place resistors for each circuit. A LED each only uses up (called forward voltage) about 1.85V out of 5V that each pin port provides, and that’s way too much when we only want the current of 20mA. The ideal resistor for each circuit with an LED is about 158 Ohm, but I am using 330 Ohm resistors because I do not have smaller value resistors available. Use any resistor you have between 158 and 330 Ohm, but I wouldn’t go much higher than 330.
The completed circuit should look like this:
CODE
There are several things to keep in mind when building a sketch for this. Here are some things we want to achieve in this code:
-
- Gesture sensor to tell us where the object is heading to.
- When the sensor detects a movement to left, we want the LEDs on the left side to turn on one-by-one, light the entire row eventually. Imagine a row of street lights turning on one-by-one, lighting the street ahead of you as you enter the street.
- We want more intense light level on the side of the street where there are more people. This means, with more movements detected going left, the left-side LED lights will become brighter.
- We also want the gesture sensor to be constantly detecting motion, so we don’t miss any movements made in front of the sensor. This means we don’t want to use delay functions. Instead, we will be using millis() to keep a timer going so different tasks can be done at different time intervals. This way we don’t have to put the entire brain power of Arduino on hold (like what delays do). (If you went huh? here is a great post by Bill Earl that talks about choosing between delay and millis() in a detailed, easy-to-understand manner. Do check it out!)
- This also means it could get tricky when we detect a movement to left before the lighting response initiated by the previous movement to the left has fully completed. Think streets again: if there is one person walking down the left-side street, and before the person exits the street, there comes another person entering the street. Now we have two people on the street, so we want the street to be brighter.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 |
/* * Tutorial Program: * Multi-Directional Sequential LED Chaser with Gesture/Directional Sensor * * Hardware Connections: * 1 Arduino Uno, 1 Adafruit APDS9960 Sensor, 4 Yellow LEDs, 2 Red LEDs, 14~16 wires * 1 medium breadboard, 2 mini breadboard (Or one long breadboard can work) * 6 330Ohm resistors (158 Ohm is the most ideal value) * * The Full Tutorial With Step-by-Step Instructions + Pictures + Reference Lists * Available On: http://www.sensingthecity.com/multi-directional-sequential-leds-with-directiongesture-sensor/ * * Ver.1 - Created by Alana S. Kim, 11/15/2017 * Based on the library sketch by Dean Miller for Adafruit Industries. * */ /*/ LIBRARIES /*/ #include "Adafruit_APDS9960.h" // Adafruit has a handy and easy library for this sensor. Adafruit_APDS9960 apds; // Read more from: https://github.com/adafruit/Adafruit_APDS9960 /*/ PIN/PORT/OBJECT SETUP /*/ // Assigning six ports for each LED. const int leftCorner = 9; const int leftLedOne= 10; const int leftLedTwo = 11; const int rightCorner = 6; const int rightLedOne = 5; const int rightLedTwo = 3; /*/ GLOBAL VARIABLES SETUP /*/ /// 1. light level control variables and arrays // analog LED light output value range: 0 - 255 // The default LED light intensity (no motion detected) is 20 //(i.e. the light will not turn off) // Level 0: 0; Level 1: 20; level 2: 150; Level 3: 255 int litLeftCorner[] = {0, 20, 150, 255}; // Left Corner (Red) light levels int litRightCorner[] = {0, 20, 150, 255}; // Right Corner (Red) light levels int litLeft[] = {0, 20, 150, 255}; // Left Sequential (Yellow) light levels int litRight[] = {0, 20, 150, 255}; // Right Sequential (Yellow) light levels // below integers will be used for calling above array values // (e.g. litLeft[lightLevelL1]) // Note: If you are looking to accomodate for more than 2 objects detected by the sensor // back-to-back, you would need to include a measure in the toWhere() function // so that these below variables never exceed 4. // Alternatively, you can adjust the number of variables above in the array // to display more levels of light intensity. int lightLevelLC; // light level of the left corner (red) light int lightLevelL1, lightLevelL2; // light level for the left light sequence // each for sequence1 response and sequence2 response int lightLevelRC; // right corner light int lightLevelR1, lightLevelR2; // light level for the right light sequence /// 2. operational variables to response to parallel movements // e.g. when another object enters the left row before // the sequential response currently in progress is complete. //by toggling these variables, the loop can kick into the right segment boolean LSeq1IP = false; // Left-row Sequence 1 In Progress // >> Yes(true) or No(false) boolean LSeq2IP = false; // Left-row Sequence 2 In Progress boolean RSeq1IP = false; // Right-row Sequence 2 In Progress boolean RSeq2IP = false; // Right-row Sequence 2 In Progress // millis() time recording for when the motion is detected // so the sequential light can be programmed at certain time interval. // 1 and 2 indicates sequence index unsigned long leftEnter1, leftEnter2, rightEnter1, rightEnter2; unsigned long timeStamp; // timeStamp for each time loop starts /*/ MAIN OUTPUT ENVIRONMENT SETUP /*/ // the setup function runs once when you press reset or power the board void setup() { Serial.begin(115200); // Initiate the serial monitor // check to see if everything is connected correctly. // or possibly your sensor is not soldered correctly. if(!apds.begin()){ Serial.println("We can't initialize your sensor! Please check your wiring."); } else Serial.println("Sensor is ready!"); //gesture mode will be entered once proximity mode senses something close apds.enableProximity(true); apds.enableGesture(true); // Let's light up the all the lights (on the "street") to the default light level lightLevelLC = 1; lightLevelRC = 1; analogWrite(leftCorner, litLeft[lightLevelLC]); analogWrite(leftLedOne, litLeft[lightLevelLC]); analogWrite(leftLedTwo, litLeft[lightLevelLC]); analogWrite(rightCorner, litRight[lightLevelRC]); analogWrite(rightLedOne, litRight[lightLevelRC]); analogWrite(rightLedTwo, litRight[lightLevelRC]); } //////////// THE PROJECT LOOP //////////// void loop() { // For every run of the loop, start by: // 1) sensing movement and its direction // 2) when there is a movement, initiate the lighting sequence toWhere(); // run toWhere() function timeStamp = millis(); // let's record the loop starting time. // Check 1: Do you have any motion detected that needs lighting response? // No: Keep the light at the default level if ((LSeq1IP == false) && (LSeq2IP == false)) // no motion to left detected { lightLevelLC = 1; analogWrite(leftCorner, litLeft[lightLevelLC]); analogWrite(leftLedOne, litLeft[lightLevelLC]); analogWrite(leftLedTwo, litLeft[lightLevelLC]); } if ((RSeq1IP == false) && (RSeq2IP == false)) // no motion to right detected { lightLevelRC = 1; analogWrite(rightCorner, litRight[lightLevelRC]); analogWrite(rightLedOne, litRight[lightLevelRC]); analogWrite(rightLedTwo, litRight[lightLevelRC]); } // Check 1: // Yes: Motion Detected ////////////////////////////// // LEFT ROW LIGHT RESPONSE // // Operating LSeq1IP if ((LSeq1IP == true) && (LSeq2IP == false)) { lightLevelL1 = lightLevelLC; // transfer the light level value // In three seconds, // turn on the first light left to the corner light if ((lightLevelL1 >= 1) && (timeStamp - leftEnter1 >= 3000)) { analogWrite(leftLedOne, litLeft[lightLevelL1]); } // In six seconds, // turn on the second light left to the corner light. // We are keeping the leftLedOne on. if ((lightLevelL1 >= 1) && (timeStamp - leftEnter1 >= 6000)) { analogWrite(leftLedTwo, litLeft[lightLevelL1]); } // In ten seconds, // return to the light level before the motion was detected. // (This should turn the LEDs down to Light Level 1: 20) if ((lightLevelL1 >= 1) && (timeStamp - leftEnter1 >= 10000)) { lightLevelLC = lightLevelL1 - 1; analogWrite(leftLedOne, litLeft[lightLevelLC]); analogWrite(leftLedTwo, litLeft[lightLevelLC]); analogWrite(leftCorner, litLeftCorner[lightLevelLC]); LSeq1IP = false; // Turn off LSeq1IP } } // END of ((LSeq1IP == true) && (LSeq2IP == false)) // LEFT ROW LIGHT RESPONSE // // Operating LSeq2IP // Logic follows above "Operating LSeq1IP" segment if ((LSeq1IP == true) && (LSeq2IP == true)) { lightLevelL2 = lightLevelLC; // given that the toWhere() function // have augmented the light level (lightLevelLC) if ((lightLevelL2 >= 1) && (timeStamp - leftEnter2 >= 3000)) { analogWrite(leftLedOne, litLeft[lightLevelL2]); } if ((lightLevelL2 >= 1) && (timeStamp - leftEnter2 >= 6000)) { analogWrite(leftLedTwo, litLeft[lightLevelL2]); } if ((lightLevelL2 >= 1) && (timeStamp - leftEnter2 >= 10000)) { lightLevelLC = lightLevelL2 - 1; analogWrite(leftLedOne, litLeft[lightLevelLC]); analogWrite(leftLedTwo, litLeft[lightLevelLC]); analogWrite(leftCorner, litLeftCorner[lightLevelLC]); LSeq2IP = false; // turn off LSeq2IP variable } } // END of ((LSeq1IP == true) && (LSeq2IP == true)) ////////////////////////////// // RIGHT ROW LIGHT RESPONSE // // Operating RSeq1IP // Logic remains the same. if ((RSeq1IP == true) && (RSeq2IP == false)) { lightLevelR1 = lightLevelRC; if ((lightLevelR1 >= 1) && (timeStamp - rightEnter1 >= 3000)) { analogWrite(rightLedOne, litRight[lightLevelR1]); } if ((lightLevelR1 >= 1) && (timeStamp - rightEnter1 >= 6000)) { analogWrite(rightLedTwo, litRight[lightLevelR1]); } if ((lightLevelR1 >= 1) && (timeStamp - rightEnter1 >= 10000)) { lightLevelRC = lightLevelR1 - 1; analogWrite(rightLedOne, litLeft[lightLevelRC]); analogWrite(rightLedTwo, litLeft[lightLevelRC]); analogWrite(rightCorner, litLeftCorner[lightLevelRC]); RSeq1IP = false; } } // END of ((RSeq1IP == true) && (RSeq2IP == false)) // RIGHT ROW LIGHT RESPONSE // // Operating RSeq1IP // Logic remains the same. if ((RSeq1IP == true) && (RSeq2IP == true)) { lightLevelR2 = lightLevelRC; if ((lightLevelR2 >= 1) && (timeStamp - rightEnter2 >= 3000)) { analogWrite(rightLedOne, litRight[lightLevelR2]); } if ((lightLevelR2 >= 1) && (timeStamp - rightEnter2 >= 6000)) { analogWrite(rightLedTwo, litRight[lightLevelR2]); } if ((lightLevelR2 >= 1) && (timeStamp - rightEnter2 >= 10000)) { lightLevelRC = lightLevelR2 - 1; analogWrite(rightLedOne, litLeft[lightLevelRC]); analogWrite(rightLedTwo, litLeft[lightLevelRC]); analogWrite(rightCorner, litLeftCorner[lightLevelRC]); RSeq2IP = false; } } // END of ((RSeq1IP == true) && (RSeq2IP == true)) } // END of project loop //////////// MAIN FUNCTION //////////// // /* toWhere() * This function will * 1) Use Adafruit_APDS9960 library * to sense direction of the movement/gesture. * 2) If it's either heading south or north, * it will simply print on serial monitor the direction. * 3) If heading left, it * a. determines if it is the first or second "person" heading left, * b. displays on monitor that the person 1 or 2 is entering the area, * c. initiates the sequential light chaser on the left side * d. by assigning an appropriate light intensity value to * the corner (red LED) light. * e. The following sequential (yellow LED) lights will turn on * at the same light intensity. * f. If a second object enters before the first sequence is done, * g. the monitor lets the tester know, and augment the light level * to the next level. * 4) Object moving right will initiate the same set of response, but * to the corner and the row of lights on the right side of the sensor. */ void toWhere() { uint8_t gesture = apds.readGesture(); // assign the detected gesture direction // to the variable gesture. /// Detection Kind 1. // When the object moves to LEFT if(gesture == APDS9960_LEFT) { // Check 1: Is this the first object moving left since the last response // on the left side ended? // YES. There is no sequential response going on right now. if ((LSeq1IP == false) && (LSeq2IP == false)) { LSeq1IP = true; // occupy the LSeq1IP (Left Sequence 1 In Progress) leftEnter1 = millis(); // record the time the motion was detected Serial.println("PERSON 1 is entering the LEFT STREET"); Serial.println("Lighting the Street. Safe walk home!"); Serial.println("\n"); // Since this is the first object since the last sequential response ended, // the current light level on the left row is likely 1. // We want to one-up the level. lightLevelLC = lightLevelLC + 1; // Now using the lightLevelLC (light level of left corner light) // light the leftCorner LED. analogWrite(leftCorner, litLeftCorner[lightLevelLC]); } // From Check 1: // NO. There is a sequential response going on right now. else if ((LSeq1IP == true) && (LSeq2IP == false)) { LSeq2IP = true; // Don't interrupt the first sequence in progress. // We can occupy LSeq2IP operational variable. leftEnter2 = millis(); // Also record the time of object entrance. Serial.println("PERSON 2 is entering the LEFT STREET"); Serial.println("Be nice to each other. Safe walk home! "); Serial.println("\n"); // If there is already a lighting sequence in progress, the light level is // probably 2. Let's one-up it. // We want to achieve: more people, brigther light! // This also means that if the first sequence was about to light the 2nd light // when this light intensity augmentation takes place, // the 2nd light will go ahead and light up at this higher level of light // not the previous light level decided when its response sequence was originally initiated. lightLevelLC = lightLevelLC + 1; // Light the leftCorner // Note: this should only make the LED light brighter because the leftCorner light // should've already been on. analogWrite(leftCorner, litLeftCorner[lightLevelLC]); } } // END of when the sensor detects motion to the left. /// Detection Kind 2. // When the object moves to RIGHT // This pretty much mirrors what was written for Detection Kind 1. Left: if(gesture == APDS9960_RIGHT) { // Check 1: Is this the first object moving right since the last response // on the left side ended? // YES. There is no sequential response going on right now. if ((RSeq1IP == false)&& (RSeq2IP == false)) { RSeq1IP = true; // occupy the RSeq1IP (Right Sequence 1 In Progress) rightEnter1 = millis(); Serial.println("PERSON 1 is entering the RIGHT STREET"); Serial.println("Lighting the Street. Safe walk home!"); Serial.println("\n"); // Current light level likely 1. Let's on-up it. lightLevelRC = lightLevelRC + 1; // Now we have the light level we want. Light the rightCorner LED accordingly. analogWrite(rightCorner, litRightCorner[lightLevelRC]); } // From Check 1: // NO. There is a sequential response going on right now. else if ((RSeq1IP == true) && (RSeq2IP == false)) { RSeq2IP = true; // Don't interrupt RSeq1IP. Occupy RSeq2IP. rightEnter2 = millis(); Serial.println("PERSON 2 is entering the RIGHT STREET"); Serial.println("Be nice to each other. Safe walk home! "); Serial.println("\n"); // Remember: more people, brigther light! // Potential light level adjustment admidst finishing up the first sequence // applies here as well. // Detailed note included above in the comments for Left motion detection. lightLevelRC = lightLevelRC + 1; // Make the rightCorner light brighter. analogWrite(rightCorner, litRightCorner[lightLevelRC]); } } // END of when the sensor detects motion to the right. //// For this program, I am designing any response when the sensor detects /// object moving downward or upward, but you can be creative here too! // 3. DOWNWARD from the sensor if(gesture == APDS9960_DOWN) { Serial.println("Someone is heading South"); // Just letting you know. Serial.println("\n"); } // 4. UPWARD from the sensor if(gesture == APDS9960_UP) { Serial.println("Someone is heading North"); Serial.println("\n"); } } // END of toWhere() function |
We are dealing with two rows of LED sequences (on the left and right), and each row can have up to two response sequences going on at any given time. This can get really messy really fast. It may be helpful to see this image to connect LEDs on breadboard and variables in code.
WHEN YOUR ARDUINO WORKS
If everything went as shown here in this post, your Arduino can now do this!
The video was filmed in a dark room to best display the light intensity changes, but it is still somewhat hard to see light level change for the red LEDs. You can still see, though, that the default level of the LEDs is dim (light level 20 out of 255). If the code works correctly, they should never turn completely off. When the hand moved from right to left again, the left-side LEDs one-by-one augmented their light intensity. Also notice we can initiate the sequence for the right-side LEDs before the left-side sequence is completed, which means that our Arduino now can respond immediately to the sensed motion, without waiting.
For the first part of the video, the serial monitor displayed:
More Links to Check Out
*Mentioned above or otherwise
- Check out the datasheet for Adafruit’s APDS-9960
- You can find the Adafruit Library built to work with APDS-9960 on Github
- oneTesla’s Soldering Tutorial for Beginners on YouTube
- Bill Earl’s Multi-tasking the Arduino, Part 1 for delay vs. millis()
- Nate Klass’s How to make two Unos talk to each other