Coder Social home page Coder Social logo

Comments (11)

3dluvr avatar 3dluvr commented on May 26, 2024 1

My latest code is below. I think it needs more cleanup as those .Stop() and .Update() calls could be all bundled into a procedure. I'd also like to add more random effects for the INTERACTION state as well as during RESTING state...

I'm going to be adding ESP-NOW connectivity next, and RTC with DS3231 via I2C. Fingers crossed I can do all that, troubleshoot/test in the next few hours as that's all the time I have left, and still have some electronics tasks to complete, too.

#include <jled.h>

auto LED1_PIN = 2; // Wh-Top
auto LED2_PIN = 4; // Wh-Right
auto LED3_PIN = 15; // Wh-Left
auto LED4_PIN = 17; // R
auto LED5_PIN = 18; // G
auto LED6_PIN = 19; // B

auto MWSENSOR_PIN = 35; // Microwave detector input pin

#define CONTACT_PERIOD 5000 // in ms how long should the continous CONTACT last
                            // or allowing for gap in detection while person is standing still

#define DETECT_PERIOD 8000 // in ms how long is the detection interval
                           // that we consider for switching from 
                           // CONTACT to INTERACTION state

#define SLEEP_PERIOD 180000 // (180sec) in ms how long before we go to sleep

#define COUNT(x)   (sizeof(x) / sizeof(x[0]))

byte state;
byte lastState;
bool detect;

// initial state is RESTING, unless we are SLEEPING due to long inactivity
// once we make CONTACT if it continues after set period, we elevate into INTERACTION
// if our partner has been detected but we haven't been, be AGITATED or JEALOUS
String states[] = { "RESTING", "CONTACT", "AGITATED", "JEALOUS", "INTERACTION", "SLEEPING" };

const byte RESTING = 0;
const byte CONTACT = 1;
const byte AGITATED = 2;
const byte JEALOUS = 3;
const byte INTERACTION = 4;
const byte SLEEPING = 5;

unsigned long currentMillis, detectMillis, contactMillis;

JLed rest1 = JLed(LED1_PIN).Breathe(3000).Forever();
JLed rest2 = JLed(LED2_PIN).DelayBefore(3000).Breathe(3000).Forever();
JLed rest3 = JLed(LED3_PIN).DelayBefore(6000).Breathe(3000).Forever();

JLed contact = JLed(LED4_PIN).Candle(6, 60).Forever();

JLed interaction1 = JLed(LED5_PIN).Blink(750, 250).Forever();
JLed interaction2 = JLed(LED6_PIN).DelayBefore(200).FadeOn(750).DelayAfter(250).Forever();

JLed sleeping = JLed(LED6_PIN).Breathe(5000).Forever();

void checkMWSensor();

//=======================================================================
//                    Power on setup
//=======================================================================
void setup() {
  Serial.begin(115200);
  Serial.println("Initializing console");

  // initialize the states...
  state = RESTING;
  lastState = RESTING;
    
  // set up the pin to read the sensor state
  pinMode(MWSENSOR_PIN, INPUT);

  // initialize the timing counters
  currentMillis = millis();
  detectMillis = millis();
  contactMillis = millis();

  sleeping.Off();
  contact.Off();
  interaction1.Off();
  interaction2.Off();
  
  checkMWSensor();

}
 
//=======================================================================
//                    Main Program Loop
//=======================================================================
void loop() {
  checkMWSensor(); // are we detecting any movement arond us?
  switch(state) {
    case SLEEPING:
      if (state != lastState) {
        rest1.Stop();
        rest2.Stop();
        rest3.Stop();
        contact.Stop();
        interaction1.Stop();
        interaction2.Stop();
        sleeping = JLed(LED6_PIN).Breathe(6000).Forever();
      }
      break;
    case CONTACT:
      if (state != lastState) {
        sleeping.Stop();
        rest1.Stop();
        rest2.Stop();
        rest3.Stop();
        interaction1.Stop();
        interaction2.Stop();
        contact = JLed(LED4_PIN).Candle(6, 60).Forever();
      }
      break;
    case INTERACTION:
      if (state != lastState) {
        sleeping.Stop();
        rest1.Stop();
        rest2.Stop();
        rest3.Stop();
        contact.Stop();
        interaction1 = JLed(LED5_PIN).Blink(750, 250).Forever();
        interaction2 = JLed(LED6_PIN).DelayBefore(200).FadeOn(750).DelayAfter(250).Forever();
      }
      break;
    case RESTING:
      if (state != lastState) {
        sleeping.Stop();
        contact.Stop();
        interaction1.Stop();
        interaction2.Stop();
        rest1 = JLed(LED1_PIN).Breathe(3000).Forever();
        rest2 = JLed(LED2_PIN).DelayBefore(3000).Breathe(3000).Forever();
        rest3 = JLed(LED3_PIN).DelayBefore(6000).Breathe(3000).Forever();
      }
      break;
  } 
  sleeping.Update();
  rest1.Update();
  rest2.Update();
  rest3.Update();
  contact.Update();
  interaction1.Update();
  interaction2.Update();
}

// ********************************************************************* //

void checkMWSensor() {
  detect = digitalRead(MWSENSOR_PIN);
  
  //Serial.println(String(millis()) + " - " + String(detectMillis));
  //Serial.println("Detection: " + String(detect ? "TRUE" : "FALSE") + " (" + states[state] + " - " + states[lastState] + ")");
  
  if (detect)
  {
    if (millis() - detectMillis < DETECT_PERIOD) // are we within the set period since the last detection
    {
      if (state == CONTACT)
      {
        if (millis() - contactMillis > CONTACT_PERIOD) // are we over the set period of initial contact
        {
          lastState = state;
          state = INTERACTION; // bump us to interaction
        } else {
          lastState = state;
        }
        detectMillis = millis();
      } 
      else if (state == INTERACTION) // we are already interacting
      {
        lastState = state; // update the last state and
        detectMillis = millis(); // detection accordingly
      }
    } else {
      // we must be initiating contact after a while (more than our detection periods)
      lastState = state;
      state = CONTACT;
      detectMillis = millis();
      contactMillis = millis();
    }
  } else {
    // nothing detected in a while 
    // are we ready to drop back to RESTING or SLEEP state?
    if (millis() - detectMillis > DETECT_PERIOD)
    {
      if (millis() - detectMillis < SLEEP_PERIOD) // has it been long enough to go to sleep
      {
        if (state != RESTING)
        {
          state = RESTING;
        } else {
          lastState = state;
        }
      } else {
        lastState = state;
        state = SLEEPING;
      }
    }
  }
}

from jled.

jandelgado avatar jandelgado commented on May 26, 2024

Hi, I just did a quick test with my ESP32 WROOM Devkit (https://circuits4you.com/2018/12/31/esp32-devkit-esp32-wroom-gpio-pinout/). The GPIOs 16,17,26 and 27 work fine for me, also all in parallel.

Please note that you must pass the GPIO-Number to the JLed Constructor, not the physical pin number. Example (WROOM 32 Devkit): Physical pin 36 = GPIO23. So you have to construct the JLed instance with JLed(23).

  • Are you sure you did not mix up physical pin numbers and GPIO numbers?
  • Which version of JLed are you using?

from jled.

3dluvr avatar 3dluvr commented on May 26, 2024

Thanks for your quick reply.

I am passing GPIO pins, and I use ESP32 DevKitC board for my project, and I'm using your master branch.

This is the part of the code I use to set the values:

`constexpr auto LED1_PIN = 2; // W-Top
constexpr auto LED2_PIN = 4; // W-Right
constexpr auto LED3_PIN = 18; // W-Left
constexpr auto LED4_PIN = 16; // R
constexpr auto LED5_PIN = 17; // G
constexpr auto LED6_PIN = 26; // B

auto Led1 = JLed(LED1_PIN).Breathe(5000).Repeat(1);
auto Led2 = JLed(LED2_PIN).Breathe(5000).Repeat(1);
auto Led3 = JLed(LED3_PIN).Breathe(5000).Repeat(1);
auto Led4 = JLed(LED4_PIN).Blink(500, 500).Forever;
auto Led5 = JLed(LED5_PIN).Blink(750, 250).Forever();
auto Led6 = JLed(LED6_PIN).Breathe(1000).Forever();

JLed resting1[] = {
Led3, Led6
};
JLed resting2[] = {
Led2, Led6
};
JLed resting3[] = {
Led1, Led6
};

JLedSequence resting1_sequence(JLedSequence::eMode::PARALLEL, resting1);
JLedSequence resting2_sequence(JLedSequence::eMode::PARALLEL, resting2);
JLedSequence resting3_sequence(JLedSequence::eMode::PARALLEL, resting3);`

What happens is that depending on the pin I used above, the LED ends up being either HIGH or LOW but no effect is being applied to it.

This is really a deal breaker for me, especially after spending 2 days thinking I'm doing something wrong. And I'm on a deadline to finish by Friday on top of it all. :(

I still need to tie sequences to some motion detection so that they are triggered by it and run or stop.

from jled.

jandelgado avatar jandelgado commented on May 26, 2024

Hi, could you please post a compilable sketch so I can try to reproduce the problem?

This for example works on the ESP32:

#include <jled.h>

auto led1 = JLed(2).Blink(500,750).Forever();
auto led2 = JLed(16).Breathe(2000).Forever().DelayAfter(500);
auto led3 = JLed(17).Breathe(1000).Forever();
auto led4 = JLed(23).Breathe(500).Forever();

JLed leds[] = {led1, led2, led3, led4};

JLedSequence sequence(JLedSequence::eMode::PARALLEL, leds);

void setup() {
}

void loop() {
    sequence.Update();
}

from jled.

3dluvr avatar 3dluvr commented on May 26, 2024

Thanks !!

Please see below, it's one variant from earlier today, just butchered. :)

#include <jled.h>

constexpr auto LED1_PIN = 2; // W-Top
constexpr auto LED2_PIN = 4; // W-Right
constexpr auto LED3_PIN = 16; // W-Left
constexpr auto LED4_PIN = 17; // R
constexpr auto LED5_PIN = 18; // G
constexpr auto LED6_PIN = 19; // B

constexpr auto MWSENSOR_PIN = 35; // Microwave detector input pin

auto Led1 = JLed(LED1_PIN).Breathe(5000).Repeat(1);
auto Led2 = JLed(LED2_PIN).Breathe(5000).Repeat(1);
auto Led3 = JLed(LED3_PIN).Breathe(5000).Repeat(1);
auto Led4 = JLed(LED4_PIN).Blink(500, 500).Forever();
auto Led5 = JLed(LED5_PIN).Blink(750, 250).Forever();
auto Led6 = JLed(LED6_PIN).Breathe(1000).Forever();

JLed resting1[] = {
    Led3, Led6
};
JLed resting2[] = {
    Led2, Led6
};
JLed resting3[] = {
    Led1, Led6
};

JLedSequence resting1_sequence(JLedSequence::eMode::PARALLEL, resting1);
JLedSequence resting2_sequence(JLedSequence::eMode::PARALLEL, resting2);
JLedSequence resting3_sequence(JLedSequence::eMode::PARALLEL, resting3);

auto running1 = 0;
auto running2 = 0;
auto running3 = 0;

bool state;
bool lastState;

unsigned long currentMillis, previousMillis, stepMillis;

void checkMWSensor() {
    state = digitalRead(MWSENSOR_PIN);
    if (state != lastState)
    {
        // remember this state as the last
        lastState = state;
    }
    //Serial.println("polled - " + String(state ? "ACTIVE" : "IDLE"));
}

void setup() { 
    Serial.begin(115200);
    Serial.println("Initializing console");

    // initialize the states...
    state = false;
    lastState = false;
    
    // set up the pin to read the sensor state
    pinMode(MWSENSOR_PIN, INPUT);

    // initialize the timing counters
    currentMillis, previousMillis, stepMillis = millis();
}

void loop() {
    checkMWSensor();
    if (state) {
        Led4.Off();
        Led4.Reset();
        //resting1_sequence.Reset();
        //running2 = resting2_sequence.Update();
        Led6.Update();
    } else {
      Led6.Off();
      Led6.Reset(); 
      Led4.Update();
    }
    
    //running1 = resting1_sequence.Update();
    Serial.println("polled - " + String(state ? "ACTIVE" : "IDLE"));
}

from jled.

3dluvr avatar 3dluvr commented on May 26, 2024

Hi, could you please post a compilable sketch so I can try to reproduce the problem?

This for example works on the ESP32:

#include <jled.h>

auto led1 = JLed(2).Blink(500,750).Forever();
auto led2 = JLed(16).Breathe(2000).Forever().DelayAfter(500);
auto led3 = JLed(17).Breathe(1000).Forever();
auto led4 = JLed(23).Breathe(500).Forever();

JLed leds[] = {led1, led2, led3, led4};

JLedSequence sequence(JLedSequence::eMode::PARALLEL, leds);

void setup() {
}

void loop() {
    sequence.Update();
}

With your example, only LED on GPIO2 blinks, all the others are not lit up.

from jled.

3dluvr avatar 3dluvr commented on May 26, 2024

Update.

With the code below, GPIO16 does not work, so I had to switch to GPIO15.

Problem is, I need to be able to turn sequences on and off, and it appears that's not doable. What happens is that when states switch, the previous state sequence/LEDs remain on. :-(

#include <jled.h>

auto LED1_PIN = 2; // Wh-Top
auto LED2_PIN = 4; // Wh-Right
auto LED3_PIN = 15; // Wh-Left
auto LED4_PIN = 17; // R
auto LED5_PIN = 18; // G
auto LED6_PIN = 19; // B

auto MWSENSOR_PIN = 35; // Microwave detector input pin

#define CONTACT_PERIOD 4000 // in ms how long should the continous CONTACT last
                            // or allowing for gap in detection while person is standing still

#define DETECT_PERIOD 7000 // in ms how long is the detection interval
                           // that we consider for switching from 
                           // CONTACT to INTERACTION state

#define COUNT(x)   (sizeof(x) / sizeof(x[0]))

byte state;
byte lastState;
int detect;

String states[] = { "RESTING", "CONTACT", "AGITATED", "JEALOUS", "INTERACTION", "SLEEP" };

const byte RESTING = 0;
const byte CONTACT = 1;
const byte AGITATED = 2;
const byte JEALOUS = 3;
const byte INTERACTION = 4;
const byte SLEEP = 5;

unsigned long currentMillis, detectMillis, contactMillis;
/*
JLed Led1 = JLed(LED1_PIN).Breathe(5000).Repeat(1);
JLed Led2 = JLed(LED2_PIN).Breathe(5000).Repeat(1);
JLed Led3 = JLed(LED3_PIN).Breathe(5000).Repeat(1);
JLed Led4 = JLed(LED4_PIN).Blink(500, 500).Forever();
JLed Led5 = JLed(LED5_PIN).Blink(750, 250).Forever();
JLed Led6 = JLed(LED6_PIN).Breathe(1000).Forever();
*/

JLed jledLEDtest = JLed(LED4_PIN).Off();

JLed resting_leds[] = {
    JLed(LED1_PIN).Breathe(3000).Forever(),
    JLed(LED2_PIN).Breathe(3000).Forever(),
    JLed(LED3_PIN).Breathe(3000).Forever(),
};

JLedSequence resting_sequence(JLedSequence::eMode::PARALLEL, resting_leds);
//JLedSequence resting2_sequence(JLedSequence::eMode::PARALLEL, resting2);
//JLedSequence resting3_sequence(JLedSequence::eMode::PARALLEL, resting3);

auto running1 = 0;
auto running2 = 0;
auto running3 = 0;

void checkMWSensor();
void tick();

//=======================================================================
//                    Power on setup
//=======================================================================
void setup() {
  Serial.begin(115200);
  Serial.println("Initializing console");

  // initialize the states...
  state = RESTING;
  lastState = RESTING;
    
  // set up the pin to read the sensor state
  pinMode(MWSENSOR_PIN, INPUT);

  // initialize the timing counters
  currentMillis = millis();
  detectMillis = millis();
  contactMillis = millis();
  
  checkMWSensor();

}
 
//=======================================================================
//                    Main Program Loop
//=======================================================================
void loop() {
  checkMWSensor();
  switch(state) {
    case CONTACT:
      if (state != lastState) {
        resting_sequence.Reset();
        jledLEDtest = JLed(LED4_PIN).Blink(500, 250).Forever();
      }
      jledLEDtest.Update();
      break;
    case INTERACTION:
      if (state != lastState) {
        resting_sequence.Reset();
        jledLEDtest = JLed(LED5_PIN).Breathe(500).Forever();
      }
      jledLEDtest.Update();
      break;
    case RESTING:
      if (state != lastState) {
        jledLEDtest.Off();
        //jledLEDtest = JLed(LED1_PIN).Breathe(4000).Forever();
      }
      resting_sequence.Update();
      break;
  } 
}

// ********************************************************************* //

void checkMWSensor() {
  detect = digitalRead(MWSENSOR_PIN);
  
  //Serial.println(String(millis()) + " - " + String(detectMillis));
  //Serial.println("Detection: " + String(detect ? "TRUE" : "FALSE") + " (" + states[state] + " - " + states[lastState] + ")");
  
  if (detect)
  {
    if (millis() - detectMillis < DETECT_PERIOD) // are we within the set period since the last detection
    {
      if (state == CONTACT)
      {
        if (millis() - contactMillis > CONTACT_PERIOD) // are we over the set period of initial contact
        {
          lastState = state;
          state = INTERACTION; // bump us to interaction
        } else {
          lastState = state;
        }
        detectMillis = millis();
      } 
      else if (state == INTERACTION)
      {
        lastState = state; 
        detectMillis = millis(); 
      }
    } else {
      // we must be initiating contact after a while
      lastState = state;
      state = CONTACT;
      detectMillis = millis();
      contactMillis = millis();
    }
  } else {
    if (millis() - detectMillis > DETECT_PERIOD)
    {
      if (state != RESTING)
      {
        state = RESTING;
      } else {
        lastState = state;
      }
    }
  }
}

from jled.

jandelgado avatar jandelgado commented on May 26, 2024

I'm not sure if I fully understood what you trying to do, but anyhow, some hints:

  • In general, If certain pins do not work as expected, build a simple setup to reproduce and validate this single problem (e.g. by using digitalWrite to turn an LED on and off, then proceeding with JLed)
  • Same goes for your transition function in checkMwSensor(). Test it independently to make sure it works as expected. Also some comments on the state machine states and the transitions would be great ;)
  • In your loop() you rather might call Stop() instead of Reset() since Stop stops the effect and turns the Led off permanently. Further calls to Update will have no effect, unless you restart the effect with a call to Reset.

Hope that helps, good luck.

from jled.

3dluvr avatar 3dluvr commented on May 26, 2024

Thanks for those suggestions, I will update my code. I tried the code on two different ESP32 dev kits just to make sure the one I was using is not damaged in any way, and saw no difference in behaviour. They both experienced the same issue of certain pins not working/stoping to work after too many sequences were assigned.

My understanding of .Stop() from reading the docs was that once you call that, you can't do .Reset() anymore, as the effect is cleared? Is that a correct assumption?

Late last night I ended up re-making the sequences as individual LEDs and that appears to work for the most part.

The problem of pins stopping to work is still there but not as prominent when using individually created JLEDs. It appears that using sequences causes something to happen: pin mapping relocation, memory relocation, I can't really say? But the more sequences I add less pins I have available and I notice I keep getting pushed up the to higher pin numbers, although there's a gap around 25 as well.

Could this be related to ESP32 HAL in jled, and the way LEDs are assigned to channels?

If I just use digitalWrite I have no issues, and I wrote a version of my code yesterday that did that, but it was blocking and not as nice and feature-full as your library.

So, I'm back to using jled and individual LEDs grouped into quazi-sequences, as I'm nearly out of time. Still have to work on creating more effects, fixing the logic and reducing the detection range on the microwave detector.

from jled.

jandelgado avatar jandelgado commented on May 26, 2024

Stop and Reset
From the README:

Reset
A call to Reset() brings the JLed object to its initial state. Use it when you want to start-over an effect.

Immediate Stop
Call Stop() to immediately turn the LED off and stop any running effects. Further calls to Update() will > have no effect unless the Led is reset (using Reset()) or a new effect activated.

Channels usage
The ESP32 has a limitation of at most 16 so called LEDC channels that are used by JLed to mimic the analogWrite behaviour of the Arduino framework. JLed will start to cycle through the LEDC channels if more than 16 different pins are used. This results in at most 16 Led being controllable on an ESP32.

Perhaps this is what you observed, or is any other lib also using LEDC channels?

(see eps32_hal.h and https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/ledc.html)

from jled.

3dluvr avatar 3dluvr commented on May 26, 2024

To be honest now I feel crazy, I must have been tired when I read and thought that .Stop() destroys the effect.

I am only using 6 pins for PWM. The other pins are for I2C/RTC and one digital input for motion detector. No other libs are being used but jled.

from jled.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.