arduino multitasking help

Hello everyone,

I am new to arduino programming and I am experimenting with things by following tutorials. I have a project in mind, in which an ultra sonic sensor will have to trigger several actions depending on the distance.
To summarize :
If distance> 200 cm everything is off.
-if distance <30 cm, neopixels flicker, leds will fade effects, and a servo will rotate 0> 180 °
-if distance> 30 the neopixels continue to flicker, the leds go out and the motor returns to position 0

So I discovered multitasking and class for arduino and I test the fading on an led depending on the distance. The led does its job well, the fading is triggered as soon as the distance <30, on the other hand, as soon as the distance is> 30cm, the led remains stuck on its last fading state (I hope that is understandable; - ).

Ps : i use the arduino traduction cause my english is poor:-(

[color=#222222][/color]
int led1 =12;
class Fade{

  int pinLed;
  int brightness;
  int fadeAmount;
  unsigned long previousMillis;
  long intervalLed;

  public:
  Fade (int led, int interval)
  {
   pinMode(pinLed,OUTPUT);
   pinLed = led;
   brightness = 0;
   fadeAmount = 5;
   intervalLed = interval;
   previousMillis = 0;
  
  
  }
  void Update(){
   unsigned long currentMillis = millis();
   analogWrite(pinLed, brightness);
   if(currentMillis-previousMillis>=intervalLed){
    
    brightness = brightness + fadeAmount;
    previousMillis=currentMillis;
    Serial.println(intervalLed);
    Serial.print("luminosité = ");
    Serial.println(brightness);
    Serial.println(currentMillis);
    }
   
    if (brightness <= 0 )
  { // reverse the direction of the fading at the ends of the fade:
    brightness = 0;
    fadeAmount = -fadeAmount;
  }
    if (brightness >=100 )
  { // reverse the direction of the fading at the ends of the fade:
    brightness = 100;
    fadeAmount = -fadeAmount;
  }
  }
};
Fade led(11,20);//broche + intervalle

  

// FADING LED CLASS
#include <Adafruit_NeoPixel.h>


#define PIN_TRIG  3
#define PIN_ECHO  2 
long duration_hc, distance_hc;

void setup() {
  Serial.begin (9600);
  pinMode(led1, OUTPUT);
  pinMode(PIN_TRIG, OUTPUT);
  pinMode(PIN_ECHO, INPUT);




}

void loop() {

  mesureDistance();
  Serial.print(" Distance ");
  Serial.print(distance_hc);
  Serial.println(" Cm ");

  if(distance_hc > 200){
  digitalWrite(led1,LOW);
  
  }
 else if(distance_hc <30){
  
  
  led.Update();
  }

  else if(distance_hc >30){
  
  digitalWrite(led1,LOW);

  }
}

void mesureDistance(){
  digitalWrite(PIN_TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(PIN_TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(PIN_TRIG, LOW);
  duration_hc= pulseIn(PIN_ECHO, HIGH);
  Serial.print(duration_hc);
  distance_hc = duration_hc / 58;
}

Thanks for helping

Note: The default timeout for pulseIn() is one second (a million microseconds). That will cause your action to stop for a second if no echo is received. You should set the timeout (optional 3rd argument to pulseIn()) to something like 12000 (200 cm * 58 uS/cm round-trip plus a bit). That will only delay your code 12 milliseconds if no echo is seen.

Note: pulseIn() returns 0 if no pulse is found (timeout). That will read as a distance of 0. You should probably treat 0 as 200 cm.

I have organised your IF tests in descending order which IMHO makes the logic clearer

   if(distance_hc > 200) {
        digitalWrite(led1,LOW);
    }
    else if(distance_hc >30){
        digitalWrite(led1,LOW);
    }
    else {
        led.Update();
    }

If you want the LED to be updated when the distance is greater than 30 you need to include a call the led.Update() in that IF block - like this'

   else if(distance_hc >30){
        digitalWrite(led1,LOW);
        led.Update();
    }

...R

Thank you very much john and Robin for these solutions. I won't have time to test today, but I'm working on this tomorrow and i'll post the results.
Thanks!

ok, i tested the codes by treating the distance 0 as 200 cm and i tested the conditions (if sequence) but the problem persists. The led do the fading effect when distance is < 30cm, but remains blocked in its last state when the distance is> than 30 cm. So I tested another solution that seems to work.
I add a class (class Off) to light off the led when the distance> 30cm, but I don’t know if this way is the right one?

class Off{
  int pinLed;
 

  public:
  Off (int led1)
  {
    pinMode(pinLed, OUTPUT);
    pinLed=led1;
  
    
    }
  
  void UpdateOff(){
   analogWrite(pinLed, LOW);
      
      
      
      }
    

  
  
  };

Off led1(11);
//
class Fade{

  int pinLed;
  int brightness;
  int fadeAmount;
  unsigned long previousMillis;
  long intervalLed;

  public:
  Fade (int led, int interval)
  {
   pinMode(pinLed,OUTPUT);
   pinLed = led;
   brightness = 0;
   fadeAmount = 5;
   intervalLed = interval;
   previousMillis = 0;
  
  
  }
  void Update(){
   unsigned long currentMillis = millis();
   analogWrite(pinLed, brightness);
   if(currentMillis-previousMillis>=intervalLed){
    
    brightness = brightness + fadeAmount;
    previousMillis=currentMillis;
   
    Serial.print("luminosity = ");
    Serial.println(brightness);
   
    }
   
    if (brightness <= 0 )
  { // reverse the direction of the fading at the ends of the fade:
    brightness = 0;
    fadeAmount = -fadeAmount;
  }
    if (brightness >=100 )
  { // reverse the direction of the fading at the ends of the fade:
    brightness = 100;
    fadeAmount = -fadeAmount;
  }
  }
};
Fade led(11,20);//broche + intervalle

  

// FADING LED CLASS
#include <Adafruit_NeoPixel.h>


#define PIN_TRIG  3
#define PIN_ECHO  2 
long duration_hc, distance_hc;

void setup() {
  Serial.begin (9600);

  pinMode(PIN_TRIG, OUTPUT);
  pinMode(PIN_ECHO, INPUT);




}

void loop() {

  measureDistance();
  Serial.print(" Distance ");
  Serial.print(distance_hc);
  Serial.println(" Cm ");

  if(distance_hc > 200){
  
  led1.UpdateOff();
  }
    else if(distance_hc >30){
  
led1.UpdateOff();

  }
    else{
  
  
led.Update();
  }


}

void measureDistance(){
  digitalWrite(PIN_TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(PIN_TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(PIN_TRIG, LOW);
  duration_hc= pulseIn(PIN_ECHO, HIGH);
  Serial.print(duration_hc);
  distance_hc = duration_hc / 58;
}

daf74:
I add a class (class Off) to light off the led when the distance> 30cm, but I don't know if this way is the right one?

If it works, it works.

It seems a very complicated solution to me. And it seems strange to have two separate classes that apply to the same LED.

I can't help feeling the whole thing could be done in far less code without any classes - but then I'm a programming philistine :slight_smile:

...R

What you should do is make Off() a method of the Fade class.

Thank you for your replys. Indeed the code seems a bit long and complicated to do a simple thing :confused: . Argh, can you explain to me how to call an Off method in the class and avoid having two classes on the same Led?

daf74:
The led do the fading effect when distance is < 30cm, but remains blocked in its last state when the distance is> than 30 cm.

Note that ‘brightness’ and ‘fadeAmount’ are local to the “Fade” object. When you turn the LED of with the “Off” object the fade will not re-start from off but will resume the fade cycle where it was.
If you add an “Off” method to the “Fade” object you can have it re-start the fade from off.

    void Off()
    {
      digiitalWrite(pinLed, LOW);
      brightness = 0;
      if (fadeAmount < 0)
        fadeAmount = -fadeAmount;  // Fade up
      previousMillis = millis()
    }

Then you just replace both of the “led1.UpdateOff();” lines with “led.Off();”.

Super John, it works :slight_smile: and my code is now more readable. Thank you all, I learned a lot from you. I come back with other questions when my project has advanced

First of all, merry christmas :slight_smile: I searched for a long time to find a solution to my new problem, but I did’nt find the key to the secret …

My problem : when I reduce the proximity to the sensor, my servo goes to its final position in an imposed interval (remember that I try to work with the millis). It works very well, on the other hand, when I go out of the proximity my servo returns to its starting position, except that it does not use the imposed interval but is much slower.

If anyone can help me that would be great

#include<Servo.h>

//Servo Sweep

class Sweeper {

    Servo monServo;

    int pos;
    int increment;
    int updateInterval;
    unsigned long lastUpdate;
    int endMotor;//position off the open angle off Servo
    int startMotor;//position off the closed angle

  public:
    Sweeper(int interval)
    {

      startMotor = 1;//start of the motor's angle
      endMotor = 150;//end of the mootr's angle
      updateInterval = interval;//

      increment = 1;

    }
    void Attach(int pin)
    {
      monServo.attach(pin);
    }
    void Detach()
    {
      monServo.detach();
    }


    void offmotor() {


      if ((millis() - lastUpdate) > updateInterval) // time to update
      {
        Serial.println(pos);
        lastUpdate = millis();
        pos -= increment;//return to start position
        monServo.write(pos);

      }
      if (pos <= 0) // end of sweep
      {
        pos = startMotor;

      }
    }

    void Update() {

     
      if ((millis() - lastUpdate > updateInterval)) {

        lastUpdate = millis();
        pos += increment;
        monServo.write(pos);



      }
      if (pos >= endMotor) {

        pos = endMotor;
      }

    }
};

Sweeper sweeper(30);//speed for sweep servo





#define PIN_TRIG  3
#define PIN_ECHO  2
long duration_hc, distance_hc;

void setup() {
  Serial.begin (19200);

  pinMode(PIN_TRIG, OUTPUT);
  pinMode(PIN_ECHO, INPUT);
  sweeper.Attach(5);



}

void loop() {

  measureDistance();
  if (distance_hc > 200) {
    sweeper.offmotor();
  }
  else if (distance_hc > 30) {
    sweeper.offmotor();
  }
  else {

    sweeper.Update();
  }


}

void measureDistance() {
  digitalWrite(PIN_TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(PIN_TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(PIN_TRIG, LOW);
  duration_hc = pulseIn(PIN_ECHO, HIGH);
  //Serial.print(duration_hc);
  distance_hc = duration_hc / 58;
}
#include<Servo.h>


//Servo Sweep
class Sweeper : public Servo  // 'Sweeper' is a kind of 'Servo'
{
    int pos;
    int increment;
    unsigned updateInterval;
    unsigned long lastUpdate;
    int closedPosition;
    int openPosition;


  public:
    Sweeper(unsigned interval)
    {
      closedPosition = 1;//start of the motor's angle
      openPosition = 150;//end of the mootr's angle
      updateInterval = interval; //
      lastUpdate = millis();
      pos = closedPosition;
      write(pos);
      increment = 1;
    }


    void sweepClosed()
    {
      if ((millis() - lastUpdate) > updateInterval) // time to update
      {
        lastUpdate = millis();
        pos -= increment; //return to start position
        if (pos <= closedPosition) // end of sweep
        {
          pos = closedPosition;
        }
        Serial.println(pos);
        write(pos);
      }
    }


    void sweepOpen()
    {
      if ((millis() - lastUpdate > updateInterval))
      {
        lastUpdate = millis();
        pos += increment;
        if (pos >= openPosition)
        {
          pos = openPosition;
        }
        Serial.println(pos);
        write(pos);
      }
    }
};


Sweeper sweeper(30); //speed for sweep servo


#define PIN_TRIG  3
#define PIN_ECHO  2


void setup()
{
  Serial.begin (19200);


  pinMode(PIN_TRIG, OUTPUT);
  pinMode(PIN_ECHO, INPUT);
  sweeper.attach(5);
}


void loop()
{
  unsigned int distance = measureDistance();


  // Remember, if no echo is seen it returns a distance of 0
  if (distance > 30 || distance == 0)
  {
    sweeper.sweepClosed();
  }
  else
  {
    sweeper.sweepOpen();
  }
}




unsigned int measureDistance()
{
  static unsigned long lastPingTime = 0;
  static unsigned long duration_hc = 0;


  // WARNING: If pings are sent too often the echo detected
  // may be a late echo from the previous ping.  Only ping if
  //  it has been at least 30 milliseconds since the last ping.
  if (millis() - lastPingTime >= 30)
  {
    lastPingTime = millis();
    digitalWrite(PIN_TRIG, LOW);
    delayMicroseconds(2);
    digitalWrite(PIN_TRIG, HIGH);
    delayMicroseconds(10);
    digitalWrite(PIN_TRIG, LOW);
    // The default timeout for pulseIn() is 1000000 microseconds (1 second).
    // If an echo is not detected, your sketch will be stuck for a full
    // second unless you set a timeout.  Try 200 to 500 cm (2 to 5 meters)
    duration_hc = pulseIn(PIN_ECHO, HIGH, 200 * 58);
  }


  return duration_hc / 58;
}

Thanks a lot John. it works :slight_smile:
Also thanks for taking the time to write the code, it seems so easy. I thought I was making good progress, but I still have things to learn with the code :wink:

but I don't understand why the servo no longer needs the detach () function (in class)?

I will be able to continue my experiments, and learn new things.

daf74:
but I don't understand why the servo no longer needs the detach () function (in class)?

It doesn't need Attach() and Detach() because it inherits attach() and detach() from its parent or 'base' class: Servo. Since "Sweeper" has a public base class of Servo, any functions that Servo has will work the same on Sweeper.