Page 1 of 1
Forum

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not bring you to the same post, in Dutch, as there is no translation for that post!



LED fill triggered ...
 
Share:
Notifications
Clear all

[Solved] LED fill triggered and retriggered by infrared sensor

14 Posts
2 Users
0 Reactions
2,115 Views
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
Topic starter  

From the original post by German:


Hi Hans !!

I will try to write in English. Apologies in advance !! haha

She was studying all the codes, they are quite complicated.

I am making my own code to do the following:

1. All the 150 led strip lights up green.

2. When an infrared sensor is interrupted, a line of 20 red LEDs will be triggered, running the entire length of the LED strip to the end.

Until here I achieved it with the code that I attach.

3.- What I want to achieve is every time the infrared sensor is interrupted, the 20 LEDs are triggered, even when there are already 20 LEDs running on the strip.

If you could help me, I would value it a lot.

Best regards!!

 

#include <Adafruit_NeoPixel.h> // importa libreria

// Primer parametro = cantidad de pixeles en la tira
// Segundo parametro = pin de conexion a Arduino
// Tercer parametro:
// NEO_KHZ800 800 KHz velocidad de datos (WS2812 y nuevos)
// NEO_KHZ400 400 KHz velocidad de datos (WS2811 y mas antiguos)
// NEO_GRB flujo de datos en orden GRB (WS2812 y nuevos)
// NEO_RGB flujo de datos en orden RGB (versiones mas antiguas)

Adafruit_NeoPixel tira = Adafruit_NeoPixel(150, 6, NEO_GRB + NEO_KHZ800); // creacion de objeto “tira”
// con una cantidad de 150 pixeles, sobre pin 6 de Arduino y configurado para WS2812

int pinsensor1=8;
int estado1;

void setup(){
tira.begin(); // inicializacion de la tira
tira.show(); // muestra datos en pixel
pinMode(pinsensor1,INPUT);
}

void loop(){
tira.setBrightness(10);   
for(int i = 0; i < 150; i++){   
  tira.setPixelColor(i, 0, 255,0);   
  tira.show();    
}
estado1=digitalRead(pinsensor1);
if(estado1==LOW) {
for(int i = 0; i < 150; i++){ // bucle para recorrer posiciones 0 a 7
  tira.setPixelColor(i, 255, 0, 0); 
  tira.show(); // muestra datos en pixel
  delay(25); // breve demora de medio segundo
  tira.setPixelColor(i-20, 0, 255, 0); // apaga el pixel 
  tira.show(); // muestra datos en pixel
}
}

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
Topic starter  

So if I understand correctly, each time the sensor gets triggered, you'd like the strip to be filled with green LEDs.

To do this, you'll need to either use an interrupt, or keep polling the sensor while "drawing" the LEDs.

Interrupt

Since I do not have such a sensor, and I do not know if HIGH or LOW is triggered and how, the first option could be something like this (untested so there may be some undesired side effects). I'm assuming that a LOW is what happens when the sensor gets tripped.

In "setup()":

void setup(){
tira.begin(); // inicializacion de la tira
tira.show(); // muestra datos en pixel
pinMode(pinsensor1,INPUT); // this may need to be INPUT_PULLUP instead of INPUT
attachInterrupt (digitalPinToInterrupt(pinsensor1), handleSensorTrigger, CHANGE); // define interrupt
tira.setBrightness(10); // moved it here - no need to set this over and over again 😉
}

Create a function to draw the LEDs, which we want to call when the sensor is being triggered:

void drawGreenLEDs()
{
for(int i = 0; i < 150; i++){
    tira.setPixelColor(i, 0, 255,0);
    tira.show();
}
}

Of course we need a function to handle the trigger:

void handleSensorTrigger() {
if (digitalRead (BUTTON) == LOW)
  {
// note: you may want to clear the LED strip here - to actually see the effect. Something like:
tira.clear(); // make the strip black
tira.show();
  asm volatile ("  jmp 0");      // reset the Arduino
  }
}

The "loop()" will look like this, depending on what you'd like to be the default thing to happen (over and over again).
Obviously, you can do anything you'd like here.

void loop()
{
drawGreenLEDs();
  while(digitalRead (pinsensor1) == HIGH) { delay(100); }
}

Here (based on your code) I fill the LEDs with green and wait forever. I used reading the sensor - but this is not really needed.

So theoretically (again: untested) when the Arduino starts, the sensor is attached to an interrupt and the LEDs will be filled with green.
Now, when the sensor gets tripped, the LED strip will be set to black, the Arduino gets a reset, and the leds get filled with green again.

Things you may have to play with;

  • if the sensor stays LOW for a longer time, you may have to introduce a delay,
    or some timing mechanism to avoid it retriggers the reset too often.
  • I haven't played with an infrared sensor, so things may work a little different than what I assume right now.

 

Checking in between

This is a little trickier and pretty much the only option of the interrupt option doesn't work.
While drawing, and while waiting, we need to check the sensor over and over again.

setup() will look something like this;

void setup(){
tira.begin(); // inicializacion de la tira
tira.show(); // muestra datos en pixel
pinMode(pinsensor1,INPUT); // this may need to be INPUT_PULLUP instead of INPUT
tira.setBrightness(10); // moved it here - no need to set this over and over again 😉
}

Drawing the LEDs something like this:

void drawGreenLEDs()
{
for(int i = 0; i < 150; i++){
    tira.setPixelColor(i, 0, 255,0);

estado1=digitalRead(pinsensor1);
if(estado1==LOW) {
asm volatile ("  jmp 0");
}

    tira.show();
}
}

and the loop:

void loop()
{
drawGreenLEDs();
  while(digitalRead (pinsensor1) == LOW) { asm volatile ("  jmp 0"); }
}

Here you may run into scenarios where the sensor does not get read when the Arduino is busy with other things, and the sensor may be triggered too long as well (so some sorts of timing may be needed).

Note: I have not tested any of these examples, and I have no experience with IR sensors. So this all may work, or may not work. And ... there may be better solutions out there as well of course.


   
ReplyQuote
(@escalatordude)
Active Member
Joined: 4 years ago
Posts: 5
 

Thank you very much for the time Hans !!

I think I explained wrong.
The effect I want is:
The led strip is always lit green.
Whenever the infrared sensor detects an obstacle, a segment of 20 red LEDs lights up, this segment moves from LEDs 1 to 150.
I have only managed to put a red segmene on the green strip.
What I want is that every time I interrupt the infrared sensor, a segment of 20 red LEDs, and these move from 1 to 150 LEDs, be two, three, four, five or six red segments on the green strip.
I attach a link to a video with the result my code to see if I can explain myself better. I want more red segments on the strip.

Thanks you again!

German


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
Topic starter  

Apologies for misunderstanding your question ... 😉 

Note: I've added your video (converted it with Handbrake to a smaller file and removed the audio) to your post as an attachment (so you can remove it from your Google Drive). I hope you don't mind.

Alrighty, let me go through the code, assuming you're having just one red block moving at a time.

If you want to have multiple red blocks running, things will have to change a litte, and then I'd definitely switch over to FastLED. I'd recommend using FastLED over NeoPixel, since FastLED is more mature and has better support for special stuff. I'll continue assuming you'll keep using NeoPixel though.

 

1.Define NUM_LEDS ...

I'd define the number of LEDs as a constant (to be entirely correct: #define is not really a constant, it's a compiler directive to replace all "NUM_LEDS" with 150 just before compiling). So instead of typing 150 (so called "magic number") each time I'd use something like NUM_LEDS. This will make adjusting the code in the future easier (if you decide to use a longer or shorter strip) and it makes the code easier to read.

#define NUM_LEDS 150
...
Adafruit_NeoPixel tira = Adafruit_NeoPixel(NUM_LEDS, 6, NEO_GRB + NEO_KHZ800); // creacion de objeto “tira”
...

 

2. To get multiple red blocks ...

This can a be a little tricky ... I'd draw 20 red leds when the sensor gets triggered, and after that keep moving the leds to the right, even if they are all green.

So when triggered, first draw a red block, for example with a function like this:

void DrawRedBlock()
{
for(int Counter=0; Counter<20; Counter++)
{
tira.setPixelColor(Counter, 255, 0, 0);
tire.show();
}
}

 

While waiting for input, I'd keep doing this endlessly:

// Move all LEDs one position
for(int Counter=NUM_LEDS-1; Counter>0; Counter--)
{
  tira.showPixelColor( Counter, getPixelColor( Counter-1 ));
  tira.show();
}
// add one green LED at the beginning
tira.setPixelColor(0, 0, 255, 0);
tira.show();

This should move the existing colors one LED up, byt copying the color from the previous LED to the current LED.
I'm counting backwards to avoid overwriting a LED color before reading it's value.
So we the color of LED 148 -> LED 149,  LED 147 -> LED 148,  LED 146 -> LED 146, etc.

Note: I do not use NeoPixel anymore, so I had to dig into the documentation to (hopefully) find the correct function for reading the LED color. FastLED works much easier when it comes to "animation" like this. Moving all the LEDs can be done in one single line.

 

So all together:

1. Fill the strip with green LEDs (you already have code for that)

2. When the sensor gets triggered draw a red block at the beginning, one LED at a time.

3. While waiting for input keep shifting the LEDs one position.

 

Now the remaining piece of the puzzle is reading the sensor in a timely fashion.
In one of my projects I've done this by replacing the tira.show() function with one of my own so it reads the sensor very often.
Something like this:

void showstrip()
{
// Read sensor
  estado1=digitalRead(pinsensor1);
// if sensor is LOW then draw the red block and finish drawing it before proceeding
if(estado1==LOW)
{
    DrawRedBlock();
}

tira.show();
}

And in the loop to move the LEDs, we can do something like this:

// Move all LEDs one position
for(int Counter=NUM_LEDS-1; Counter>0; Counter--)
{
  tira.showPixelColor( Counter, getPixelColor( Counter-1 ));
  showstrip(); // was: tira.show();
}

// add one green LED at the beginning
tira.setPixelColor(0, 0, 255, 0);
showstrip(); // was: tira.show();

Now, each time we "show" the strip, we also test the sensor.

Hope this is helpful - and again: I have not tested the code.


   
ReplyQuote
(@escalatordude)
Active Member
Joined: 4 years ago
Posts: 5
 

Hello my friend!!

There is no problem with attaching the video. Many times it is better explained in this way. It also helps other users to learn from this interaction. I will upload a video with each code that we execute.
I chose Neopixel because it was the first thing I found. This is my first project with led strips, I am learning about them. This is much more difficult than I imagined.

If you believe that it is easier to use FastLed, go ahead !! Let's switch to FastLed !!

 

I was working with what you sent me and I got a problem. When I compile the code,

tira.showPixelColor( Counter, getPixelColor( Counter-1 ));

This error message appears:

Prueba.ino: In function 'void loop()':

 'class Adafruit_NeoPixel' has no member named 'showPixelColor'; did you mean 'setPixelColor'?

tira.showPixelColor( Counter, getPixelColor( Counter-1 ));

^~~~~~~~~~~~~~

setPixelColor

Prueba:25:33: error: 'getPixelColor' was not declared in this scope

tira.showPixelColor( Counter, getPixelColor( Counter-1 ));

^~~~~~~~~~~~~

exit status 1
'class Adafruit_NeoPixel' has no member named 'showPixelColor'; did you mean 'setPixelColor'?

 

I looked for information in the library and I couldn't find the showPixelColor function, I couldn't find anything. As a compiler suggestion change to setPixelColor. I did that, but continue with getPixelColor function error. I don't understand how to make this function work ok.
This was too much for me. LOL!!

I m attch the complete code. Please check if the writing order is correct.

Thanks so much for your help!!!

German

 

#include <Adafruit_NeoPixel.h>
//HANS 08-07-2020
#define NUM_LEDS 150
Adafruit_NeoPixel tira = Adafruit_NeoPixel ( NUM_LEDS , 6, NEO_GRB + NEO_KHZ800);
//GERMAN 05-07-2020
int pinsensor1=8;
int estado1;
//GERMAN 05-07-2020
void setup(){
tira.begin();
tira.show();
pinMode(pinsensor1,INPUT);
}
//GERMAN 05-07-2020
void loop(){
tira.setBrightness(10);
for(int i = 0; i < 150; i++){
tira.setPixelColor(i, 0, 255,0);
tira.show();
}
//HANS 08-07-2020
// Move all LEDs one position
for(int Counter=NUM_LEDS-1; Counter>0; Counter--)
{
tira.showPixelColor( Counter, getPixelColor( Counter-1 ));
showstrip(); // was: tira.show();
}
//HANS 08-07-2020
// add one green LED at the beginning
tira.setPixelColor(0, 0, 255, 0);
showstrip(); // was: tira.show();
}
//HANS 08-07-2020
void DrawRedBlock()
{
for(int Counter=0; Counter<20; Counter++)
{
tira.setPixelColor(Counter, 255, 0, 0);
tira.show();
}
}
//HANS 08-07-2020
void showstrip()
{
// Read sensor
estado1=digitalRead(pinsensor1);
// if sensor is LOW then draw the red block and finish drawing it before proceeding
if(estado1==LOW)
{
DrawRedBlock();
}
tira.show();
}

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
Topic starter  

Haha, well, I'll admit that I started with NeoPixel as well ... it was indeed the first one I found and at the time FastLED wasn't that big yet.

Don't worry: it will get easier ... 😋 

Posted by: @escalatordude

'class Adafruit_NeoPixel' has no member named 'showPixelColor'; did you mean 'setPixelColor'?

Yeah that should probably be "setPixelColor" - my bad (not using neoPixel).

The getPixelColor is described in the NeoPixel documentation but I had not tested this (maybe it requires the latest Library version).

 

I couldn't resist, so my initial conversion to FastLED would look something like this:

#define FASTLED_INTERNAL // doesn't do much, just mutes Pragma messages when compiling FastLED
#include "FastLED.h"

#define NUM_LEDS 150
#define LED_PIN 6 // GPIO pin we used for the strip
#define BRIGHTNESS 255 // Default LED brightness.
#define LED_TYPE WS2812 // Type of LED strip
#define COLOR_ORDER GRB // Color order LED strip

#define SensorPin 8

CRGB leds[NUM_LEDS]; // define LED array to hold the colors

void setup(){
// Initialize LED strip
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>( leds, NUM_LEDS ).setCorrection( TypicalLEDStrip );
FastLED.setBrightness( BRIGHTNESS );
FastLED.clear( true ); // clear all LEDs, and Show (true)

// Initial fill of the strip
for(int i = 0; i < NUM_LEDS; i++)
{
leds[i] = CRGB::Green; // this is the same as CRGB( 0, 255,0 );
FastLED.show();
}

pinMode(SensorPin,INPUT);
}

void loop()
{
// Shift all LED colors 1 position
memmove8( &leds[1], &leds[0], (NUM_LEDS-1) * sizeof(CRGB) );
// destination led 1, source led 0, number of leds

leds[0] = CRGB::Green;

showstrip();
}

void DrawRedBlock()
{
for(int Counter=0; Counter<20; Counter++)
{
leds[Counter] = CRGB::Red;
FastLED.show();
}
}

void showstrip()
{
// Read sensor
int PinState=digitalRead(SensorPin);

// if sensor is LOW then draw the red block and finish drawing it before proceeding
if(PinState==LOW)
{
DrawRedBlock();
}

FastLED.show();
delay(10);
}

You may have to test this, and maybe change a few things from this part:

#define BRIGHTNESS 255 // Default LED brightness.
#define LED_TYPE WS2812 // Type of LED strip
#define COLOR_ORDER GRB // Color order LED strip

Give it a try 😋 


   
ReplyQuote
(@escalatordude)
Active Member
Joined: 4 years ago
Posts: 5
 

Hello Hans!!

You are a genius!!! Your code works!!!

I can not insert video in this web. I attach link video.

<link removed>

Now I am going to work with in this code.
I'm going to learn FastLed first !!! Lol FastLed is much more compact !!!
1.- I am going to add another sensor, it does the same effect but in the opposite direction from led 150 to 1.

2.- I'm going to add another effect.

3.- I'm going to add sound when you interrupt a sensor

Thank you very much for your collaboration!!!

 


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
Topic starter  

Awesome!!! 👍 😊 

I was not able to open your video link though ...

I've worked with NeoPixel and FastLED, and I really do not use NeoPixel anymore.
Some very powerful functions found in FastLED are simply not available in NeoPixel.
After doing some testing in the past I also found FastLED to be faster in general.

Keep in mind that when adding more things, catching the sensor or button press can become more challenging, since the Arduino doesn't know how to multitask.
So you will need to check the buttons frequently, so you would not miss a button being pressed.
There are some advanced tricks for that though, feel free to ask when you get to that point.

Tip: using an ESP8266 or ESP32 could be helpful in this.
They can be used as an Arduino replacement, are much faster, often much smaller, and much cheaper (the ESP8266 costs about $5).
They also come with build in WiFi and it works very good (I'm working on a little project right now using an ESP8266).


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
Topic starter  

p.s. my first ESP8266 project can be found here.


   
ReplyQuote
(@escalatordude)
Active Member
Joined: 4 years ago
Posts: 5
 

Hi @hans!!

Days ago I was reading reviews on the ESP8266 boards. Your post made me decide to buy one. I'm still experimenting with two Digispark ATTINY85, but they only work correctly for very small projects.

Here the video of your code.

Now I am trying to do the mirror effect.I mean that the red segments move from led 150 to led 1. I tried to change the code but I am not getting good results. I'm reading about FastLed, there is a lot of documentation and you still can't find the MEMMOVE8 function.

Can you check the code I wrote? I left the original code after     // WAS......

Thanks in advance!!

Germán

#define FASTLED_INTERNAL
#include "FastLED.h"
#define NUM_LEDS 150
#define LED_PIN 6
#define BRIGHTNESS 100
#define LED_TYPE WS2812
#define COLOR_ORDER GRB
#define SensorPin 8
CRGB leds[NUM_LEDS];

void setup(){
// Initialize LED strip
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>( leds, NUM_LEDS ).setCorrection( TypicalLEDStrip );
FastLED.setBrightness( BRIGHTNESS );
FastLED.clear( true );
// Initial fill of the strip
for(int i = 150; i > NUM_LEDS; i--)// WAS for(int i = 0; i < NUM_LEDS; i++)
{
leds[i] = CRGB::Green;
FastLED.show();
}
pinMode(SensorPin,INPUT);
}

void loop()
{
// Shift all LED colors 1 position
memmove8( &leds[149], &leds[150], (NUM_LEDS+1) * sizeof(CRGB) ); // WAS memmove8( &leds[1], &leds[0], (NUM_LEDS-1) * sizeof(CRGB) );
// destination led 1, source led 0, number of leds
leds[150] = CRGB::Green; //WAS leds[0]=CRGB::Green
showstrip();
}
void DrawRedBlock()
{
for(int Counter=150; Counter>130; Counter--) // WAS for(int Counter=0; Counter<20; Counter++)
{
leds[Counter] = CRGB::Red;
FastLED.show();
}
}
void showstrip()
{
// Read sensor
int PinState=digitalRead(SensorPin);
// if sensor is LOW then draw the red block and finish drawing it before proceeding
if(PinState==LOW)
{
DrawRedBlock();
}
FastLED.show();
delay(20);
}

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
Topic starter  

I see you managed to get the video posted - cool 👍 

There is not much documentation on memmove8 (I found it in this paragraph, at the end of the paragraph).

You can use a for-loop, but memmove is easier and memmove8 is easier and faster;

From the FastLED article:

If you are copying a large number of colors from one (part of an) array to another, the standard library function memmove can be used to perform a bulk transfer; the CRGB object "is trivially copyable".

// Copy ten led colors from leds[src .. src+9] to leds[dest .. dest+9]
memmove( &leds[dest], &leds[src], 10 * sizeof( CRGB) );

Performance-minded programmers using AVR/ATmega MCUs to move large number of colors in this way may wish to use the alternative "memmove8" library function, as it is measurably faster than the standard libc "memmove".

memmove8 looks the same:

memmove8( &leds[dest], &leds[src], 10 * sizeof( CRGB) );

 

Basically you pass these parameters:

  • the beginning address of the destination led (&leds[x] means the address ("&") of leds[x])
  • the beginning address of the source led
  • The Number of LEDs you want to move × the size of a CRGB color type

That last parameter tells it how much memory we want to move: The number of LEDs × the calculated the size of a CRGB type (how much memory it would take).
I hope that makes sense.

 

In your code you wrote:

memmove8( &leds[149], &leds[150], (NUM_LEDS+1) * sizeof(CRGB) );

This says that you want to move 151 LEDs (NUM_LEDS+1), starting at LED 150, and moving it to LED 149, but ... you don't have that many leds.
It would mean that you'd want to copy the LEDs 150 to 301.

Instead you'd need to use something like this

memmove8( &leds[0], &leds[1], (NUM_LEDS-1) * sizeof(CRGB) );

So copying 149 LEDs (NUM_LEDS-1) starting at LED 1, and moving it to LED 0.

Hope this helps 😊  - feel free to ask if my explanation made thing more confusing 😉 


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
Topic starter  

As for the ESP8266 ...

I had a few laying around for quite a while already, just never found the time to play with them until recently.
I'm very impressed with the ESP8266. So much more memory, faster, more compact (they can be found in really small form factors!), and so much faster.
I'm using one for a new LED effects project - boy do I have plenty of space for all the effects and the WiFi makes it so easy to work with. Even a tiny webserver can be used. 

I'm confident you'll like working with the ESP8266. 👍 


   
ReplyQuote
(@escalatordude)
Active Member
Joined: 4 years ago
Posts: 5
 

Hi Hans!!

Thanks you for your time!!

Thanks to your advice and some additions, the desired effect appeared.

I leave copied the modification of the code in case someone is interested.
If you ever need any help I have a lot of experience with infrared sensors, ultrasound, gestures, QR code readers, etc. I can help you, do not hesitate to write.
Thank you very much for your support, friend Hans!
I will continue studying FastLed !!

void loop()
{
// Shift all LED colors 1 position
memmove8( &leds[0], &leds[1], (NUM_LEDS-1) * sizeof(CRGB) );
// destination led 1, source led 0, number of leds
leds[0] = CRGB::Green; //WAS leds[0]=CRGB::Green;
showstrip();
}

void DrawRedBlock()
{
for(int Counter=130; Counter<149; Counter++) // VALORES PARA COMBIAR EL LARGO DEL SEGMENTO ROJO
{
leds[Counter] = CRGB::Red;
FastLED.show();
}
}

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
Topic starter  

Thanks Escalatordude! 
You're most welcome and I'm glad I could help 😊 


   
ReplyQuote
Share: