Language: EN

libreria-arduino-asyncsonar

Arduino AsyncSonar Library

The AsyncSonar library allows for non-blocking control of an ultrasonic sensor such as the HC-SR04, meaning it allows the main loop to perform additional actions while waiting for the Echo to be received.

Additionally, the AsyncSonar library allows for the use of the sensor with a single pin for Trigger and Echo. Measurements can be obtained in both microseconds and millimeters. A Timeout period or distance can also be defined.

Furthermore, it includes functions for correcting the speed of sound with temperature and an extremely fast median filter with a window size of 5 elements.

AsyncSonar objects can be chained, so that multiple ultrasonic sensors are triggered sequentially when the previous ping ends, without requiring user intervention.

Requirements

The AsyncSonar library uses the YetAnotherPcInt library developed by Paulo Costa, available on Github and in the Arduino library manager. This library facilitates the use of Pin Change interrupts.

User Manual

The AsyncSonar object represents an ultrasonic sensor that performs measurements asynchronously. In order to make the library as non-intrusive as possible, timers are not used. Instead, the philosophy of using an Update() method is employed, which updates the state of the object.

To perform actions, AsyncSonar allows for defining a callback function, which will be triggered in Update() when a valid measurement has been obtained. Additionally, a callback function can be used in case of a Timeout.

The sensor is activated with the Start() method, to which an optional waiting value in milliseconds can be passed (e.g., for sketch initialization). The process can be stopped with the Stop() method.

When the sensor is activated, it sends a Ping to the sensor pin. Once the ping is sent, the pin state is changed to receive the Echo. Therefore, only a digital pin is needed to control the sensor.

For waiting for the Echo, AsyncSonar defines an interrupt on the pin using the YetAnotherPcInt library. When the Echo is received, AsyncSonar stores the time between the Ping and the Echo, but does not perform any action.

To update the state of AsyncSonar, it is necessary to call the Update() function, which checks the state of AsyncSonar. If the echo has been received, it performs the appropriate callback functions. The Update() function must be called frequently from the main loop.

The callback functions receive the AsyncSonar object itself as a parameter, so within the function, the functions of the AsyncSonar that invoked the method can be used.

The measurement result is obtained with the GetRawMM(), GetRawUS(), GetMeasureMM(), and GetMeasureUS() functions. The RAW functions provide the value obtained in the measurement, while the Measure functions filter out negative measurements and timeouts.

It also includes a fast median filter of 5 elements. The filtered values with the median are obtained using the GetFilteredMM() and GetFilteredUS() functions. The median filter also ignores negative measurements and timeouts.

The Update() function optionally accepts an AsyncSonar object as a parameter, which can be the same object that invokes it or a different one. After receiving the echo, the passed AsyncSonar will be activated. This facilitates continuous measurements or sequential multi-sensor readings.

For the configuration of AsyncSonar, functions are available to set the timeout and the triggerInterval firing interval. To improve the sensor’s accuracy, a function is available to set the temperature and correct the speed of sound.

Additionally, the config.h file contains additional library options.

Therefore, the median filter can be disabled by uncommenting #define ASYNCSONAR_DISABLE_MEDIAN, which speeds up the library. On the other hand, the callback function can be called within the interrupt service routine (ISR) instead of in the next Update(), at the cost of slowing down the ISR. To do this, uncomment the line #define ASYNCSONAR_USE_SONARISR.

Constructor

The AsyncSonar class is instantiated through its constructor.

AsyncSonar(uint8_t trigger_pin, void(*on_ping)(AsyncSonar&) = nullptr, void(*on_time_out)(AsyncSonar&) = nullptr)

If #define ASYNCSONAR_USE_SONARISR is uncommented in the config.h file, the constructor will be as follows.

AsyncSonar(uint8_t trigger_pin, void (*on_ping)(AsyncSonar&) = nullptr, void (*on_time_out)(AsyncSonar&) = nullptr, void (*isr)(AsyncSonar&) = nullptr)

Using AsyncSonar

The AsyncSonar class has the following methods.

// Start and stop
void Start();
void Start(unsigned long);
void Stop();

// Update the state
void Update();
void Update(AsyncSonar*);

// Get measurement
unsigned int GetRawMM();
unsigned long GetRawUS();
unsigned int GetMeasureMM();
unsigned long GetMeasureUS();

// Configuration
void SetTemperatureCorrection(int8_t tempCelsius);
void SetTimeOutDistance(unsigned int distanceMM);
void SetTimeOut(unsigned int timeOutMillis);
void SetTriggerInterval(unsigned int timeOutMillis);

Additionally, the following methods are available if #define ASYNCSONAR_DISABLE_MEDIAN is commented in the config.h file.

unsigned long GetFilteredUS();
unsigned int GetFilteredMM();

Examples

The AsyncSonar library includes the following examples to illustrate its usage.

  • SyncSimple: Shows the blocking usage
#include "AsyncSonarLib.h"

AsyncSonar sonarA0(A0);

void setup() 
{
  Serial.begin(115200);
  sonarA0.SetTemperatureCorrection(28);  // optional
}

void loop()
{
  sonarA0.Start();  // start now
  delay(50);  //wait ping to complete
  sonarA0.Update();  // update sonar
  
  // show results
  Serial.print("Ping: ");
  Serial.println(sonarA0.GetMeasureMM());
}
  • SyncWithCallback: Shows the blocking usage with a callback function
#include "AsyncSonarLib.h"

// ping complete callback
void PingRecieved(AsyncSonar& sonar)
{
  Serial.print("Ping: ");
  Serial.println(sonar.GetMeasureMM());
}

// timeout callback
void TimeOut(AsyncSonar& sonar)
{
  Serial.println("TimeOut");
}

AsyncSonar sonarA0(A0, PingRecieved, TimeOut);

void setup()
{
  Serial.begin(115200);
  
  sonarA0.SetTemperatureCorrection(28);  // optional
}

void loop()
{
  sonarA0.Start();  // start now
  delay(50);  //wait ping to complete
  sonarA0.Update();  // update sonar
}
  • AsyncSingle: Shows a simple example of asynchronous usage
#include "AsyncSonarLib.h"

// ping complete callback
void PingRecieved(AsyncSonar& sonar)
{
  Serial.print("Ping: ");
  Serial.println(sonar.GetMeasureMM());
}

// timeout callback
void TimeOut(AsyncSonar& sonar)
{
  Serial.println("TimeOut");
}

AsyncSonar sonarA0(A0, PingRecieved, TimeOut);

void setup()
{
  Serial.begin(115200);
  
  sonarA0.SetTemperatureCorrection(28);  // optional
  sonarA0.Start(1500);  // start in 1500ms
}

void loop()
{
  // this is where magic begins
  sonarA0.Update();
}
  • AsyncContinuous: Shows continuous asynchronous usage with reactivation in the callback
#include "AsyncSonarLib.h"

AsyncSonar sonarA0(A0, [](AsyncSonar& sonar) { Serial.println(sonar.GetMeasureMM()); Sonar.Start();});

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

  sonarA0.Start(1500);  // start in 1500ms
}

void loop()
{
  // this is where magic begins
  sonarA0.Update();
}
  • AsyncChain: Shows continuous asynchronous usage using the AsyncSonar itself as a parameter in Update
#include "AsyncSonarLib.h"

// ping complete callback
void PingRecieved(AsyncSonar& sonar)
{
  Serial.print("Ping: ");
  Serial.println(sonar.GetMeasureMM());
}

// timeout callback
void TimeOut(AsyncSonar& sonar)
{
  Serial.println("TimeOut");
}

AsyncSonar sonarA0(A0, PingRecieved, TimeOut);

// ---- In this demo, this code simulates other project tasks
unsigned long interval = 1000;
unsigned long previousMillis;

void debug(char* text)
{
  Serial.print(text);
  Serial.println(millis());
}

// show the asynchronous behavior by printing TIME each 1000ms
void OtherTasks()
{
  if (static_cast<unsigned long>(millis() - previousMillis) >= interval)
  {
    debug("  TIME: ");
    previousMillis = millis();
  }
}
// ---- End other tasks

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

  sonarA0.SetTemperatureCorrection(28);  // optional
  sonarA0.Start(500); // start in 500ms
}

void loop()
{
  // this is where magic begins
  sonarA0.Update(&sonarA0);

  OtherTasks();
}
  • AsyncChainMedian: Shows asynchronous usage using the median filter
#include "AsyncSonarLib.h"

// ping complete callback
void PingRecieved(AsyncSonar& sonar)
{
  Serial.print("Ping: ");
  Serial.println(sonar.GetFilteredMM());
}

AsyncSonar sonarA0(A0, PingRecieved);

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

  sonarA0.SetTemperatureCorrection(28);  // optional
  sonarA0.Start(500); // start in 500ms
}

void loop()
{
  // this is where magic begins
  sonarA0.Update(&sonarA0);
}
  • AsyncChainMultiple: Shows continuous asynchronous measurement with multiple sensors
#include "AsyncSonarLib.h"

void PingRecieved(AsyncSonar&);
void TimeOut0(AsyncSonar&);
void TimeOut1(AsyncSonar&);

AsyncSonar sonarA0(A0, PingRecieved, TimeOut0);
AsyncSonar sonarA1(A1, PingRecieved, TimeOut1);

// ping complete callback
// (this example shows how to access sonar from callback)
void PingRecieved(AsyncSonar& sonar)
{
  Serial.print("Ping");
  Serial.print(&sonar == &sonarA1);  // print '0' if sonar A0, '1' if sonar A1
  Serial.print(": ");
  Serial.println(sonar.GetMeasureMM());
}

// timeout callbacks
// (this example shows how to use different callbacks for each sensor)
void TimeOut0(AsyncSonar& sonar)
{
  Serial.println("TimeOut0");
}

void TimeOut1(AsyncSonar& sonar)
{
  Serial.println("TimeOut1");
}

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

  sonarA0.SetTemperatureCorrection(28);  // optional
  sonarA1.SetTemperatureCorrection(28);  // optional
  sonarA0.Start(500);  // start in 500ms
}

void loop()
{
  // this is where magic begins
  sonarA0.Update(&sonarA1);
  sonarA1.Update(&sonarA0);
}
  • AsyncISR: Shows usage with callback execution in the ISR
// Uncomment ASYNCSONAR_USE_SONAR ISR in config.harderr
#include "AsyncSonarLib.h"

// ping complete callback
void PingRecieved(AsyncSonar& sonar)
{
  Serial.print("Ping: ");
  Serial.println(sonar.GetMeasureMM());
}

// timeout callback
void TimeOut(AsyncSonar& sonar)
{
  Serial.println("TimeOut");
}

// ISR callback
void SonarISR(AsyncSonar& sonar)
{
  Serial.print("ISR: ");
  Serial.println(sonar.GetRawMM());
}

AsyncSonar sonarA0(A0, PingRecieved, TimeOut, SonarISR);

void setup()
{
  Serial.begin(115200);
  
  sonarA0.SetTemperatureCorrection(28);  // optional
  sonarA0.Start(500); // start in 500ms
}

void loop()
{
  // this is where magic begins
  sonarA0.Update();
  
  delay(100);
}

Installation

  • Download the latest version from GitHub
  • Unzip the file
  • Copy to your libraries folder (usually My Documents\Arduino\libraries)
  • Restart the Arduino IDE

github-full