What is the difference between scan Window, Interval and scanTime in the ESP32_BLE_Arduino Library? - c++

I am looking at the basic BLE_Scan.ino sketch from the ESP32_BLE_Arduino library. I've modified it to do 5 scans in a row before anything else. I would like to do a few scans very quickly in order to average them. (See code below)
I cannot figure out the difference between scan interval, scan window and the scanTime paramter.
I understand that the window should be how long to scan, this should happen every interval. I am not sure waht the scanTime paramamter does.
I have adjusted the scan interval and scan window to low numbers. Have also put the scanTime variable as low as it can be (1, since it is an int, and it cannot be 0). None of these fixes seem to allow me to do quick scan. Still seems to have a second or two delay between printing "scan!!" each time.
Any help in clarifying what these 3 parameter do, or can point out what I am doing wrong is appreciated.
(Also, my first post on SO, so let me know if I can fix up how I have asked this question, and I will!)
Thanks!!
/*
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
Ported to Arduino ESP32 by Evandro Copercini
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
int scanTime = 1; //In seconds
BLEScan* pBLEScan;
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
}
};
void setup() {
Serial.begin(115200);
Serial.println("Scanning...");
BLEDevice::init("");
pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
pBLEScan->setInterval(50); //interval (how often there is a scan)
pBLEScan->setWindow(49); // window (how long the scans are) must be <= interval
Serial.begin(115200);
}
void loop() {
// put your main code here, to run repeatedly:
//bluetooth scan
for(int x = 0; x < 5; x ++){
BLEScanResults foundDevices = pBLEScan->start(1, true);
Serial.println("Scan!!");
}
delay(200);
}

The Scan_Window configuration parameter defines the amount of time for the duration of the scan. The Inquiry_Scan_Window can only be less than or equal to the Scan_Interval. [Time Default: 11.25 ms]
The Scan_Interval configuration parameter defines the amount of time between consecutive scans. This is defined as the time interval from when the BR/EDR Controller started its last scan until it begins the next scan. [Default: 2.5 sec]
Scan Timeout: A device may scan for a limited duration of time

Related

Issues creating light sequence with pause button ARDUINO

So I am trying to create a program that runs various light sequences using an Arduino board. I am not very familiar with C++ so I feel that my lack of syntax knowledge is preventing me from accomplishing my goal.
My idea is to have various light sequences that are played depending on what button is pressed on an infrared remote. The amount of time that a light is on or off may or may not be the same as that of another light. Unfortunately, the sequences do not seem to be working which indicates that the issue is likely with the toggleLight function.
I also wanted there to be a button that allows the user to pause the sequence (no matter where along the sequence it is). And once the button is pressed again, then the sequence continues where it left off. I read something about an interrupter and sleep mode using C++ but I am unfamiliar with this so it is not included in my code.
The rest of my goals I have included within my code. I created an object "light" because I was trying to create the sequence without using the delay function as the interrupt does not work well with the delay function (as far as I am aware). Then I am able to call the function toggleLight on the specific light object. However, as I previously stated the sequences are not working.
I am more familiar with OOP languages so perhaps creating an object is not the best for Arduino. If anyone has any ideas for how I can accomplish my goal it would be much appreciated.
unsigned long previousMillis = 0;
unsigned long currentMillis = millis();
//sets up the Infrared receiver for the remote controller
const int RECV_PIN = 1;
IRrecv irrecv(RECV_PIN);
decode_results results;
//Sets up the LED's pin number and light status
class light{
private:
int _pinNumber;
byte _Lstatus;
public:
//function that creates the objects with the parameters
light(int pinNum, byte Lstat){
_pinNumber = pinNum;
_Lstatus = Lstat;}
void toggleLight(long interval){
//ensures that the "interval" amount of time has passed between the last LED blink
if ((currentMillis - previousMillis) >= interval) {
// if the LED is off turn it on and vice-versa:
if (_Lstatus == LOW) {
_Lstatus = HIGH;
} else if (_Lstatus == HIGH) {
_Lstatus = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(_pinNumber, _Lstatus);
// save the last time you blinked the LED
previousMillis = currentMillis;
}
}
};
//creating four light objects with the pins and initial status of off.
light J1(13, LOW);
light J2(11, LOW);
light P1(12, LOW);
light P2(10, LOW);
void setup()
{
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
pinMode(10, OUTPUT);
}
//Sequence 1 is a mock sequence. It will probably be longer and the intervals would not all be 1000
void seq1(){
currentMillis = millis();
J1.toggleLight(1000);
P1.toggleLight(1000);
J1.toggleLight(1000);
P1.toggleLight(1000);
J2.toggleLight(1000);
P2.toggleLight(1000);
}
void seq2(){
currentMillis = millis(); //I found that placing currentMillis = millis() here allows the lights to at least turn on
J1.toggleLight(2000);
J1.toggleLight(10);
P1.toggleLight(1000);
P1.toggleLight(0);
J2.toggleLight(1500);
J2.toggleLight(1);
P2.toggleLight(2000);
P2.toggleLight(1);
}
void loop()
{
/* So once i get the sequences working, my idea is to have different sequences play
depending on what button on the remote is pressed. However, first I want to get the sequences and
interrupter
For now I have just tried running sequence #2 but it does not work.. Neither does Sequence #1. */
seq2();
//I MADE THESE LINES OF CODE COMMENTS FOR NOW. UNTIL I GET THE REST OF THE PROGRAM WORKING
/*if (irrecv.decode(&results))
{
switch (results.value) {
case : 0xf00000 // When button #1 sequence one plays
seq1();
break;
case : 0xf00000 // when button #2 is pressed, sequence two plays
seq2();
break;
*/
}
I can see that you haven't yet got around to understanding the flow of code inside the Arduino. Here's a quick tutorial to get you up and running.
Basically, your code is not being processed sequentially. So when the processor is moving through seq() and gets to the first if statement in 'J1.toggleLight(2000);' and finds that the condition is not met (i.e. the 2000 milliseconds have not yet passed,) it immediately moves on to the second line in seq(). The issue with this is that when it does meet the condition at the second line it will reset the 'previousMillis' value which all the lights depend on.
Thus you should dedicate a clock for each light by moving in 'previousMillis' into the class as a member.
class light{
private:
int _pinNumber;
byte _Lstatus;
unsigned long previousMillis = 0;
This way each light will be able to keep track of its own time without conflicting with the other lights. This will lead to your lights flickering at a frequency of 1/interval which I doubt is what you want.(it wont even do that with each light getting toggled twice in the seq() functions. Try removing the second calls and see hat happens) This brings me to the second issue.
The second issue is with the way you set up your sequences. Since you want to the lights to operate sequentially you'll need to find the accumulated time which crosses out the chance of using a class, unless you're willing to implement a scheduling mechanism that takes account the interval and arrangement of each instance. Seems a bit impractical imo.
I think you should ditch the class and use a simple function that that accepts the eight values that each sequence requires. Then you could utilize if statements to manipulate the states of the lights.
I hope the answer made some sense.
Good luck.

How to make DC motor's RPM come to its maximum value (analog 255) SLOWLY

It is a homework and I have completely NO idea, my teacher says you need just while, analogWrite and a counter. I have a DC motor, a transistor and a 9V battery.
I know my code does NOTHING, but just as example.
int analogPin = 3;
int count = 0;
void setup()
{
pinMode(analogPin, OUTPUT);
}
void loop() {
while(count<30){
analogWrite(analogPin , 255);
delay(20000);
count++;
}
}
You need to use counter value as your analogue output value:
void loop()
{
if( count < 256 )
{
analogWrite( analogPin, count ) ;
delay( 20000 );
count++ ;
}
}
Note that you do not need a while loop; the Arduino framework already calls loop() iteratively (the clue is in the name). However if your teacher thinks you need one and is expecting one, you may need to use one just for the marks. Alternatively discuss it with your teacher, and explain why it is unnecessary
In fact the delay too is arguably bad practice - it is unhelpful in applications where the loop() must do other things while controlling the motor. The following allows other code to run whilst controlling the motor:
unsigned long delay_start = 0 ;
void loop()
{
if( count < 256 &&
millis() - delay_start >= 20000ul )
{
analogWrite( analogPin, count ) ;
count++ ;
delay_start = millis() ;
}
// Do other stuff here
}
Because the loop() now never blocks on the delay() function, you can have code that does other things such as read switch inputs and it can react to them instantly, whereas as in your solution, such inputs could be ignored for up-to 20 seconds!
A typical DC motor will not start moving at very low values - you may want to start count somewhat higher than zero to account for the "dead-band". Analogue signals are also generally a poor way to drive a DC motor and varying speed; a PWM is generally a more efficient method, and will allow the motor to run at lower speeds. With an analogue signal at low levels (lower than for PWM), your motor will not move and will just get warm and drain your battery.
For test purposes, reduce the delay time; you don't want to sit there for an hour and 25 minutes just to find the code does not work! Set it to say 500ms, then start it, time how long it takes before the motor starts to move. If that is say 30 seconds, then yu know the motor starts to move when count is about 60; in which case that is a better starting value that zero. Then you can increase your delay back to 20 seconds if you wish - though a DC power supply might be better than a battery - I'm not sure it will last that long.

C++ buzzer to play piano notes for an Arduino

unsigned long t;
boolean isHigh;
#define BUZZER_PIN 3
void setup() {
// put your setup code here, to run once:
pinMode(BUZZER_PIN, OUTPUT);
isHigh = false;
t = micros();
}
void loop() {
playNote('c');
}
void playNote(char note) {
unsigned long timeToWait;
unsigned long timeToPlayTheNote = millis();
while (timeToPlayTheNote - millis() < 1000) {
if (note == 'c') {
timeToWait = 1911;
}
if (micros() - t > timeToWait) {
if (!isHigh) {
digitalWrite(BUZZER_PIN, HIGH);
isHigh = true;
} else {
digitalWrite(BUZZER_PIN, LOW);
isHigh = false;
}
t = micros();
}
}
}
I don't know why this won't work. I used to play a frequency every 1,000 microseconds but is there any way to make this simpler as well? Also, with this method I have to do (1/f)/2 and then convert that value from seconds to microseconds and use that as the value for timeToWait.
Initialization of ˋtimeToWait` should obviously be outside of the loop.
An array could be used for timing data.
ˋt` should probably be initialized inside ˋplayNoteˋ
Alternatively, you might use an enum for delay associated to a note.
enum class notes
{
C = 1911
};
Well, all suggestion assume that you don't want to compensate for drifting offsets.
Buzzers have a fixed frequency. They don't work like speakers at all. You will get better results with a real speaker. Don't forget to put a capacitor in series with it so the speaker sees an AC signal, you can fry a speaker quite easily if you feed it a DC signal..
For best results, you should use 2 x 47uF to 100uF electrolytic capacitors back to back, with the negative poles joined together, one positive to the 'duino and the other positive pole connected to the speaker. With higher capacitance, you'll get more bass.
Why don't you use a PWM at 50% (128) and change the PWM frequency to generate the sound? You could use the Timer1 or Timer3 library for that. Letting the hardware do the work would be more presise and would free your application for other tasks, such as reading a keyboard.
https://playground.arduino.cc/Code/Timer1
Setting the PWM at 0% with an analogWrite() would cut the sound.

For loop with if statement for ardiuno powered humidity control

Really simple question but I'm not entirely sure how to incorporate a for loop in the if statement I have. Context: I have a humidifier I am trying to automate based on the humidity of the room. I'm using an ardiuno, dht11 humidity sensor and a servo. The humidifier knob has three settings (high low off) and so the servo has three positions. I have the code running so the servo turns appropriately according to the humidity level. The issue is that it fluctuates very easily. To correct that I'm looking to incorporate a for loop so that after let say 60 one second iterations of the humidity being greater than 55 the servo moves. I tried to add a for loop but it doesn't seem to be working.
But this is only my solution based on the little programming I know. If there is a better solution or even an equally viable alternative I'd love to know. I'm currently studying mechanical engineering but I'm finding that to really make something one needs a background in electronics and code. I'm trying to learn both independently through a series of projects and so I'm quite eager to learn. Hopefully this helps explain why I'm asking such a simple questions to begin with.
#include <dht.h>
#include <Servo.h>
Servo myservo;//create servo object to control a servo
dht DHT;
#define DHT11_PIN 7 // pin for humidity sensor ( also measure temp)
void setup() {
myservo.attach(9);//attachs the servo on pin 9 to servo object
myservo.write(0);//statting off position at 0 degrees
delay(1000);//wait for a second
Serial.begin(9600);
}
void loop() {
int chk = DHT.read11(DHT11_PIN); // the follow is just so that I can see the readings come out properly
Serial.print("Temperature = ");
Serial.println(DHT.temperature);
Serial.print("Humidity = ");
Serial.println(DHT.humidity);
delay(500);
if (DHT.humidity > 55) // here is where my code really begins
{
for (int i=0; i>60; i++); // my goal is to execute the follow code after the statement above has been true for 60 one second iterations
{
myservo.write(0);//goes to off position
delay(1000);//wait for a second
}
} else if (DHT.humidity > 40 ) {
for (int i=0; i>60; i++); // same thing here
myservo.write(90);//goes to low position
delay(1000);//wait for a second
}
else
{
for (int i=0; i>60; i++);
myservo.write(180);//goes to high position
delay(1000);
}
} // end of void loop()
Just addressing your question, the following line is incorrect:
for (int i=0; i>60; i++);
Two things:
1) The second statement in the for loop describes the conditions on which it executes. The way it is written, it will only execute when i>60 (not what you want according to the comments).
2) The semicolon after the for statement makes the next block unassociated.
Correct that line to the following:
for (int i=0; i<60; i++)
See the following for more information:
https://www.tutorialspoint.com/cprogramming/c_for_loop.htm
It would probably be helpful to examine your compiler warnings, and/or set a higher warning level, to catch these type of things early (this is, of course, somewhat compiler dependent).
I guess you trying kind of de-bouncing at you need humid level stay in same range for some period.
First, I define conversion function to map humid level to state
#define HUMID_OFF 1
#define HUMID_LOW 2
#define HUMID_HIGH 3
byte state_conv (float humid_level){
if (humid_level > 55) return HUMID_OFF ;
else if (humid_level > 40 ) return HUMID_LOW ;
else return HUMID_HIGH ;
}
Second I will check changing of state and use millis() to count time while current state is steady. if counting time are longer than threshold then change the actual state.
/*Global variable*/
byte actual_state;
byte flag_state;
void setup (){
// Do things that necessary
float humid = dht.readHumidity();
/*Initialize value*/
actual_state = state_conv(humid);
flag_state= state_conv(humid);
}
void loop(){
static unsigned long timer = millis();
float humid = dht.readHumidity();
byte crr_state = state_conv(humid);
if (crr_state != actual_state ){// if state is changing
if (flag_state != crr_state){
/if crr_state change form last iteration then reset timer
flag_state = crr_state;/
timer = millis();
}
else if (millis() - timer > 10000){
//if crr_state not change for 10000 ms (10 second)
actual_state = crr_state; // update actual state to crr_state
}
}
// After this use actual_state to control servo
if (actual_state == HUMID_OFF ){
myservo.write(0);//goes to off position
}
else if (actual_state == HUMID_LOW ){
myservo.write(90);//goes to low position
}
else if (actual_state == HUMID_HIGH ){
myservo.write(180);//goes to high position
}
}
DHT.humidity returns a float, so if you want to compare, then first store this in an int, and then compare.

Calculating moving average in C++

I am trying to calculate the moving average of a signal. The signal value ( a double ) is updated at random times.
I am looking for an efficient way to calculate it's time weighted average over a time window, in real time. I could do it my self, but it is more challenging than I thought.
Most of the resources I've found over the internet are calculating moving average of periodical signal, but mine updates at random time.
Does anyone know good resources for that ?
Thanks
The trick is the following: You get updates at random times via void update(int time, float value). However you also need to also track when an update falls off the time window, so you set an "alarm" which called at time + N which removes the previous update from being ever considered again in the computation.
If this happens in real-time you can request the operating system to make a call to a method void drop_off_oldest_update(int time) to be called at time + N
If this is a simulation, you cannot get help from the operating system and you need to do it manually. In a simulation you would call methods with the time supplied as an argument (which does not correlate with real time). However, a reasonable assumption is that the calls are guaranteed to be such that the time arguments are increasing. In this case you need to maintain a sorted list of alarm time values, and for each update and read call you check if the time argument is greater than the head of the alarm list. While it is greater you do the alarm related processing (drop off the oldest update), remove the head and check again until all alarms prior to the given time are processed. Then do the update call.
I have so far assumed it is obvious what you would do for the actual computation, but I will elaborate just in case. I assume you have a method float read (int time) that you use to read the values. The goal is to make this call as efficient as possible. So you do not compute the moving average every time the read method is called. Instead you precompute the value as of the last update or the last alarm, and "tweak" this value by a couple of floating point operations to account for the passage of time since the last update. (i. e. a constant number of operations except for perhaps processing a list of piled up alarms).
Hopefully this is clear -- this should be a quite simple algorithm and quite efficient.
Further optimization: one of the remaining problems is if a large number of updates happen within the time window, then there is a long time for which there are neither reads nor updates, and then a read or update comes along. In this case, the above algorithm will be inefficient in incrementally updating the value for each of the updates that is falling off. This is not necessary because we only care about the last update beyond the time window so if there is a way to efficiently drop off all older updates, it would help.
To do this, we can modify the algorithm to do a binary search of updates to find the most recent update before the time window. If there are relatively few updates that needs to be "dropped" then one can incrementally update the value for each dropped update. But if there are many updates that need to be dropped then one can recompute the value from scratch after dropping off the old updates.
Appendix on Incremental Computation: I should clarify what I mean by incremental computation above in the sentence "tweak" this value by a couple of floating point operations to account for the passage of time since the last update. Initial non-incremental computation:
start with
sum = 0;
updates_in_window = /* set of all updates within window */;
prior_update' = /* most recent update prior to window with timestamp tweaked to window beginning */;
relevant_updates = /* union of prior_update' and updates_in_window */,
then iterate over relevant_updates in order of increasing time:
for each update EXCEPT last {
sum += update.value * time_to_next_update;
},
and finally
moving_average = (sum + last_update * time_since_last_update) / window_length;.
Now if exactly one update falls off the window but no new updates arrive, adjust sum as:
sum -= prior_update'.value * time_to_next_update + first_update_in_last_window.value * time_from_first_update_to_new_window_beginning;
(note it is prior_update' which has its timestamp modified to start of last window beginning). And if exactly one update enters the window but no new updates fall off, adjust sum as:
sum += previously_most_recent_update.value * corresponding_time_to_next_update.
As should be obvious, this is a rough sketch but hopefully it shows how you can maintain the average such that it is O(1) operations per update on an amortized basis. But note further optimization in previous paragraph. Also note stability issues alluded to in an older answer, which means that floating point errors may accumulate over a large number of such incremental operations such that there is a divergence from the result of the full computation that is significant to the application.
If an approximation is OK and there's a minimum time between samples, you could try super-sampling. Have an array that represents evenly spaced time intervals that are shorter than the minimum, and at each time period store the latest sample that was received. The shorter the interval, the closer the average will be to the true value. The period should be no greater than half the minimum or there is a chance of missing a sample.
#include <map>
#include <iostream>
// Sample - the type of a single sample
// Date - the type of a time notation
// DateDiff - the type of difference of two Dates
template <class Sample, class Date, class DateDiff = Date>
class TWMA {
private:
typedef std::map<Date, Sample> qType;
const DateDiff windowSize; // The time width of the sampling window
qType samples; // A set of sample/date pairs
Sample average; // The answer
public:
// windowSize - The time width of the sampling window
TWMA(const DateDiff& windowSize) : windowSize(windowSize), average(0) {}
// Call this each time you receive a sample
void
Update(const Sample& sample, const Date& now) {
// First throw away all old data
Date then(now - windowSize);
samples.erase(samples.begin(), samples.upper_bound(then));
// Next add new data
samples[now] = sample;
// Compute average: note: this could move to Average(), depending upon
// precise user requirements.
Sample sum = Sample();
for(typename qType::iterator it = samples.begin();
it != samples.end();
++it) {
DateDiff duration(it->first - then);
sum += duration * it->second;
then = it->first;
}
average = sum / windowSize;
}
// Call this when you need the answer.
const Sample& Average() { return average; }
};
int main () {
TWMA<double, int> samples(10);
samples.Update(1, 1);
std::cout << samples.Average() << "\n"; // 1
samples.Update(1, 2);
std::cout << samples.Average() << "\n"; // 1
samples.Update(1, 3);
std::cout << samples.Average() << "\n"; // 1
samples.Update(10, 20);
std::cout << samples.Average() << "\n"; // 10
samples.Update(0, 25);
std::cout << samples.Average() << "\n"; // 5
samples.Update(0, 30);
std::cout << samples.Average() << "\n"; // 0
}
Note: Apparently this is not the way to approach this. Leaving it here for reference on what is wrong with this approach. Check the comments.
UPDATED - based on Oli's comment... not sure about the instability that he is talking about though.
Use a sorted map of "arrival times" against values. Upon arrival of a value add the arrival time to the sorted map along with it's value and update the moving average.
warning this is pseudo-code:
SortedMapType< int, double > timeValueMap;
void onArrival(double value)
{
timeValueMap.insert( (int)time(NULL), value);
}
//for example this runs every 10 seconds and the moving window is 120 seconds long
void recalcRunningAverage()
{
// you know that the oldest thing in the list is
// going to be 129.9999 seconds old
int expireTime = (int)time(NULL) - 120;
int removeFromTotal = 0;
MapIterType i;
for( i = timeValueMap.begin();
(i->first < expireTime || i != end) ; ++i )
{
}
// NOW REMOVE PAIRS TO LEFT OF i
// Below needs to apply your time-weighting to the remaining values
runningTotal = calculateRunningTotal(timeValueMap);
average = runningTotal/timeValueMap.size();
}
There... Not fully fleshed out but you get the idea.
Things to note:
As I said the above is pseudo code. You'll need to choose an appropriate map.
Don't remove the pairs as you iterate through as you will invalidate the iterator and will have to start again.
See Oli's comment below also.