Scheduler for UNO

I have this code that works sortof fine. But when I add it to a scheduler it doesn't work similarily.
I found a scheduler on github:

I need a scheduler, becuse I need to send a sync clock to a modular synth. The sync clock is a +5 voltage pulse of a duration of 11-25 ms. And I need the interval between these pulses to be an average of intervals between detections from a sensor.

I have a HC-SR04 that I have set to detect when ever a stick passes in front of it. I then make this into timer, so it measures the time between stick passings. I then get the average of the last ten passings.
This average is to be the interval between pulses sent to the synth.
To avoid the pulse interval timing not be affected by the pulse length timing and the timing needed by the sensor to stabalize I chose to venture into this scheduler business.

When the timer code runs by it self, it works fine:

#include <NewPing.h>

#define TRIGGER_PIN 12 // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN 11 // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.



int distance = 0;
const int threshDist = 4;
int detection = 0;
unsigned long interval = 0;
const int ledPin = 13;
int pulselength = 25;
unsigned long previousMillis = 0; //last detection

const int numReadings = 10;

int readings[numReadings];      // the readings from the analog input
int readIndex = 0;              // the index of the current reading
int total = 0;                  // the running total
int averageInterval = 0;                // the average


void setup() {
  pinMode(ledPin, OUTPUT);

  
  Serial.begin(9600);

  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
}


void loop() {

   unsigned int uS = sonar.ping(); // Send ping, get ping time in microseconds (uS).
  distance = uS / US_ROUNDTRIP_CM;



  if (distance < threshDist) {
    interval = millis() - previousMillis;
    
    Serial.print("Interval = ");
    Serial.print(interval);
    previousMillis = millis();
    
    total = total - readings[readIndex];
    readings[readIndex] = interval;
    total = total + readings[readIndex];
    readIndex = readIndex +1;
    if (readIndex >= numReadings) {
      readIndex = 0;
    }
    averageInterval = total / numReadings;
    Serial.print(" avg = ");
    Serial.println(averageInterval);



    
    delay(50);
    
  }
}

But when I add the scheduler and the pulse sending, it seems like the sensor doesn't behave right. It sometimes works ok, but not always.

#include "TaskScheduler.h"

#include <NewPing.h>

#define TRIGGER_PIN 12 // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN 11 // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.



int distance = 0;
const int threshDist = 4;
int detection = 0;
unsigned long interval = 0;
const int ledPin = 13;
long pulseLength = 25;
unsigned long previousMillis = 0; //last detection

const int numReadings = 10;

int readings[numReadings];      // the readings from the analog input
int readIndex = 0;              // the index of the current reading
int total = 0;                  // the running total
int averageInterval = 100;                // the average

boolean g_led1State=1;


void setup() {
  pinMode(ledPin, OUTPUT);

  Sch.init();  // Initialize task scheduler

  /*
     * use Sch.addTask(task, start_time, period, priority) to add tasks
     * task - tasks to be scheduled
     * start_time - when the task starts (ms)
     * period - repeat period of the task (ms)
     * priority - 1: mormal priority, 0: high priority
     */
  Sch.addTask(timer,0,50,1);  // add a task
  Sch.addTask(pulse,0,50,1);

  Sch.start();  // Start the task scheduler
  
  Serial.begin(9600);

  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
}


void loop() {
  Sch.dispatchTasks();
}

void timer() {

   unsigned int uS = sonar.ping(); // Send ping, get ping time in microseconds (uS).
  distance = uS / US_ROUNDTRIP_CM;



  if (distance < threshDist) {
    interval = millis() - previousMillis;
    
    Serial.print("Interval = ");
    Serial.print(interval);
    previousMillis = millis();
    
    total = total - readings[readIndex];
    readings[readIndex] = interval;
    total = total + readings[readIndex];
    readIndex = readIndex +1;
    if (readIndex >= numReadings) {
      readIndex = 0;
    }
    averageInterval = total / numReadings;
    Serial.print(" avg = ");
    Serial.println(averageInterval);



  }
}

void pulse()
{
    digitalWrite(ledPin, HIGH);
    delay(pulseLength);
    digitalWrite(ledPin, LOW);
    delay(averageInterval - pulseLength);
}

I'm not very experienced, so I might supply you with not the right or useful information. But hopefully, you get an idea. If not, please let me know how to elaborate, and I'll do my very best.

thx

Disclaimer: I have no experience with the NewPing library. I have just downloaded it and played a bit.

The way you use it still seems to be a blocking implementation. There is another way to use the library that does not block (to my limited understanding of the NewPing library, that is its BIG advantage). Look at the NewPingEventTimer.ino example that comes with the library.

Below is a slightly modified version

#include <NewPing.h>

// HC-SR04 pins
#define ECHOPIN A1
#define TRIGGERPIN A0

// ranges in centimeters
#define MAX_DISTANCE 200  // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

NewPing sonar(TRIGGERPIN, ECHOPIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

unsigned int pingSpeed = 50; // How frequently are we going to send out a ping (in milliseconds). 50ms would be 20 times a second.
unsigned long pingTimer;     // Holds the next ping time.

// global variable to hold the measured distance; -1 indicates 'out of range'
int pingDistance = -1;

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

  pingTimer = millis(); // Start now.
}

unsigned long pingStarttime;

void loop()
{
  if (millis() >= pingTimer)     // pingSpeed milliseconds since last ping, do another ping.
  {
    // set the start time; for debugging purposes
    pingStarttime = millis();
    pingTimer += pingSpeed;      // Set the next ping time.
    // start a ping
    sonar.ping_timer(echoCheck); // Send out the ping, calls "echoCheck" function every 24uS where you can check the ping status.
  }

  Serial.print("Ping: ");
  Serial.print(pingDistance);
  Serial.println("cm");
}

void echoCheck()   // Timer2 interrupt calls this function every 24uS where you can check the ping status.
{
  // Don't do anything here!
  if (sonar.check_timer())   // This is how you check to see if the ping was received.
  {
    // get the end time; this is for dubugging only
    unsigned long pingEndtime = millis();
    // print the duration for debugging purposes
    Serial.print("duration: "); Serial.println(pingEndtime - pingStarttime);

    // store the measured distance
    pingDistance = sonar.ping_result / US_ROUNDTRIP_CM;
    // Here's where you can add code.
    //Serial.print("Ping: ");
    //Serial.print(sonar.ping_result / US_ROUNDTRIP_CM); // Ping returned, uS result in ping_result, convert to cm with US_ROUNDTRIP_CM.
    //Serial.println("cm");
  }
  else
  {
    // indicate no object in sight
    pingDistance = -1;
  }
  // Don't do anything here!
}

You can incorporate this is your sketch and there should not be a need for a scheduler.

Further have a look at Demonstration code for several things at the same time. It uses the non-blocking approach.

It depends on your exact needs if you want to set the pingDistance in echoCheck to -1 or keep the old one if there is no object in sight.

Why would you call a function timer() when is has NOTHING to do with timing anything?

It counts the duration between and object passing by the sensor. So it measurest the time between events. I thought timer was an ok name for that. Of course, I could have called it something else, but hey, I like to live dangerously :slight_smile:

So, I managed without a scheduler.

I used the "blink without delay" for sending the pulse.
I now use a Sharp IR sensor to detect activety.

This is the code now:

#include <SharpIR.h>

#define ir A0 //The readpin of the Sharp IR
#define model 1080 

SharpIR sharp(ir, 40, 93, model);

// ir: the pin where your sensor is attached
// 25: the number of readings the library will make before calculating a mean distance
// 93: the difference between two consecutive measurements to be taken as valid
// model: an int that determines your sensor:  1080 for GP2Y0A21Y
//                                            20150 for GP2Y0A02Y
//                                            (working distance range according to the datasheets)

long dist = 0;                   //the current distance from the Sharp IR
const long threshDist = 10;       //The threshold for detection
long detection = 0;              //Detection (1=on / 2=off)
const long detectionWait = 70;   //The duration to wait until looking for a detection (let the object get out of wiev)
unsigned long interval = 0;      //Duration between detections
unsigned long previousMillis = 0;//last detection

int ledPin = 13;          //Pin to output 5v clock trigger
const long pulseLength = 12;     //Duration of the 5v pulse
long ledMillis = 12;            // calculate when the pulse was sent last time


// the averaging of interval readings
const long numReadings = 5;     // the amount of readings to base the averaging
long readings[numReadings];      // the readings from the analog input
long readIndex = 0;              // the index of the current reading
long total = 0;                  // the running total
long averageInterval = 100;      // the average




void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode (ir, INPUT);

 
  Serial.begin(9600);

  for (long thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
}


void loop() {

 
   
  
   dist = sharp.distance(); // Read the distance from the Sharp IR



  if (dist < threshDist && dist > 0  && (millis() - previousMillis > detectionWait) )
    {
    interval = millis() - previousMillis;
    Serial.print("Dist = ");
    Serial.print(dist);
    Serial.print(" Interval = ");
    Serial.print(interval);
    previousMillis = millis();
    
    total = total - readings[readIndex];
    readings[readIndex] = interval;
    total = total + readings[readIndex];
    readIndex = readIndex +1;
    if (readIndex >= numReadings) {
      readIndex = 0;
    }
    averageInterval = total / numReadings;
    Serial.print(" avg = ");
    Serial.println(averageInterval);

   

  }
  long pulseInterval = averageInterval / 2;
  long duration = millis() - ledMillis; //Duration since last pulse high
  
  if (duration > pulseInterval) {
    digitalWrite(ledPin, HIGH);
    ledMillis = millis();
  }
  if (duration < pulseInterval && duration > pulseLength) {
    digitalWrite(ledPin, LOW);
  }


}

Thx for your help