How do I create a motion activated Neopixel Jewel?

Hi all!

My team and I are attempting to create a motion activated light. The light we're using is the Neopixel Jewel, and we're using the PIR Motion Sensor. The board is the Arduino UNO R3 and we're using the sketch coding language. Right now, the code we're using for the project seems to print the 'motion detected' terminal message at random intervals instead of when motion is actually detected.

The goal is to make the light turn on once motion is detected and, once motion is no longer detected, make the light turn off. Are there any tutorials/examples that are best to create what we're looking for?

Here's what the code looks like:

/*
 * PIR sensor tester
 */

 #include <Adafruit_NeoPixel.h>

#define LED_PIN 3
#define LED_COUNT  7

Adafruit_NeoPixel pixels(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

const int MOTION_SENSOR_PIN = 7; 
int pirState = LOW;             // we start, assuming no motion detected
int val = 0;                    // variable for reading the pin status
 
void setup() {
  pinMode(LED_PIN, OUTPUT);      // declare LED as output
  pinMode(MOTION_SENSOR_PIN, INPUT);     // declare sensor as input
 
  Serial.begin(9600);
  pinMode(MOTION_SENSOR_PIN, INPUT); // set arduino pin to input mode
  
  pinMode(LED_PIN, OUTPUT);
}
 
void loop(){
  val = digitalRead(MOTION_SENSOR_PIN);  // read input value
  if (val == HIGH) {            // check if the input is HIGH
    digitalWrite(LED_PIN, HIGH);  // turn LED ON
    if (pirState == LOW) {
      // we have just turned on
      pixels.setPixelColor(1, pixels.Color(0, 150, 0));
      pixels.show();
      Serial.println("Motion detected!");
      // We only want to print on the output change, not state
      pirState = HIGH;
    }
  } else {
    digitalWrite(LED_PIN, LOW); // turn LED OFF
    if (pirState == HIGH){
      // we have just turned of
      pixels.setPixelColor(1, pixels.Color(150, 0, 0));
      Serial.println("Motion ended!");
      // We only want to print on the output change, not state
      pirState = LOW;
    }
  }

I think your logic is fouled-up...

I think you don't need val and priState. You proably only need one variable.

Or you need to update priState every time after you read val. (Every time you read the motion sensor.)

...And if you haven't done this already, run the Digital Read Serial Example (modified to read your motion sensor pin instead of a pushbutton) to make sure the motion sensor is working as-expected. Or maybe just turn-on the LED with the motion sensor... Something simple...

...And the serial monitor can be very handy for printing-out little messages for testing & troubleshooting... You can print-out things like "reading motion detector", or "motion detected", or "activating LED", or you can print the current value of a variable (or high or low), etc. It's one of the few ways of "seeing" what your program is doing when it's not behaving as expected.

Then when everything works, you can remove or "comment out" those messages.

1 Like

Thanks for your response.

When I use the serial monitor to keep track of the motion sensor status, it gives me a "motion detected" message even when there's motion in front of it.

Could this be a result of the pirState and val variables being used incorrectly? When I change the code to only use variable, should I keep val or keep pirState?

I'm not sure it is. I don't see a problem with the sketch.

@18bwhite4 have you tried adjusting the sensitivity pot on the sensor? If set to max, it might be triggered apparently at random. Turn sensitivity pot to min to see if it stops the random triggering. Then increase the sensitivity just enough to detect the movement you want.

Do you have the jumper set to H or L on the sensor?

const byte LED_PIN = 3;
const byte LED_COUNT = 7;
const byte MOTION_SENSOR_PIN = 7;
#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel pixels(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  Serial.begin(9600);
  pinMode(LED_PIN, OUTPUT);      // declare LED as output
}

void loop() {
  static bool pirState = false;
  if (digitalRead(MOTION_SENSOR_PIN) == HIGH) {            // check if the input is HIGH
    digitalWrite(LED_PIN, HIGH);  // turn LED ON
    if (!pirState ) {
      pirState = true;
      pixels.setPixelColor(1, pixels.Color(0, 150, 0));
      pixels.show();
      Serial.println("Motion detected!");
    }
  } else {
    digitalWrite(LED_PIN, LOW); // turn LED OFF
    if (pirState) {
      pixels.setPixelColor(1, pixels.Color(150, 0, 0));
      Serial.println("Motion ended!");
      pirState = false;
    }
  }
}

I'll change the sensitivity pot around and see if that helps! Is that the part named "sensitivity adjust" in this image?

Thanks for the question about the jumper setting—I'm pretty sure the jumper setting made our sensor "non-retriggering" and contributed to our bugs.

1 Like

Our PIR motion sensor seems to be working now, thank you! The Jewel still isn't reacting to the motion sensor status, despite the setPixelColor() function that we're using within the if statements. Any ideas as to why this might be the case? We're still not 100 percent sure that this is the right function to use in our case, even after looking at the documentation on GitHub.

Thanks!

So the led on pin 3 and the serial monitor messages show that the sensor is working correctly now? How did you change the logic in your code to fix that?

Does the "jewel" not light at all? setPixelColor() is the correct function, but you must also use pixels.show() after that, or the "jewel" will not be updated. This is done in the first part of your if statement but not in the else part.

Is this something that is stationary that reacts when approached, or something to detect if it is moving? How directional do you want it to be. A PIR sensor's FOV is effectively 180° or non-directional. A too wide FOV can make a sensor touchy. The PIR reacts to IR so detecting general motion vs animals/fires can be an issue. I mean you can buy a motion sensor LED light for a lot less than the Arduino parts are going to cost. This type of problem doesn't need a computer as a simple hardwire from the PIR to an LED would work directly.

The light is intended to light up once it senses motion, but we got that part of it working. Thank you!

I think the sensor/serial monitor was the reason it was being inconsistent, not code. Our current code has the same logic as before, but now it the sensor reacts/turns on the light at the right time.

The jewel has been lighting up correctly too, and we added pixels.show() to each part where the pixel's light changes.

When using the updated code, the pixel turns green when we try to motion activate it for a second time. The first time the motion gets sensed, it uses the color we coded, but the second time, it turns green.

Additionally, sometimes the PIRstate variable outputs "1" on the serial monitor, regardless of whether motion is detected or not.

Here's the updated code:

const byte LED_PIN = 3;
const byte LED_COUNT = 7;
const byte MOTION_SENSOR_PIN = 7;
#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel pixels(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  Serial.begin(9600);
  pinMode(LED_PIN, OUTPUT);      // declare LED as output
  pixels.begin();
}

void loop() {
  static bool pirState = false;
  if (digitalRead(MOTION_SENSOR_PIN) == HIGH) {            // check if the input is HIGH
    digitalWrite(LED_PIN, HIGH);  // turn LED ON
    if (!pirState ) {
      pirState = true;
      Serial.println(pirState);
      pixels.setPixelColor(0, pixels.Color(150, 0, 150));
      pixels.setPixelColor(1, pixels.Color(150, 0, 150));
      pixels.show();
      Serial.println("Motion detected!");
    }
  } else {
    digitalWrite(LED_PIN, LOW); // turn LED OFF
    if (pirState) {
      Serial.println(pirState);
      pixels.setPixelColor(0, pixels.Color(150, 0, 0));
      pixels.setBrightness(10);
      pixels.show();
      Serial.println("Motion ended!");
      pirState = false;
    }
  }
}

Sometimes? Or always? Could it be that it only gets output to serial monitor when it is a "1"/true?

Could it be that it only gets output to serial monitor when it is a "1"/true?

I think this might be the case, I'll change the code to print regardless of the if statements and see if that fixes it.

It seems like the print statement we used to print pirState may have been in the wrong place, so we moved that and now the serial monitor seems to be working correctly! We're still getting an issue with the light not being the right color though.

Colours are not right or wrong, they are just colours.

Colours are not right or wrong, they are just colours.

This is true!

Update: we got the color working, we had just made a mistake with the .setBrightness function.

I did wonder about that. 10 is a pretty low brightness level and can cause some colours to appear different to how they look at higher brightness levels because of the limitations of 8 bit precision pwm.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.