I'm trying to build a tachometer in C++ for my ESP32. When I uncomment Serial.printf("outside rev: %d \n", rev); outside of the conditional it works, but when I comment it I get values that are orders of magnitude greater than they should be (700 revolutions without, vs 7 revolutions with). My best guess is that the print statement is slowing the loop() down just enough for incrementRevolutions() to toggle the global variable passedMagnet from true to false before the next loop. That would make sense, since a delay in updating passedMagnet would allow newRevCount++; to be triggered multiple times. But this is obviously something I can't debug with either print statements or step-through debugging given the time-sensitive nature of the race condition.
bool passedMagnet = true;
int incrementRevolutions(int runningRevCount, bool passingMagnet)
{
// Serial.printf("passedMagnet: %d , passingMagnet %d , runningRevCount: %d \n", passedMagnet, passingMagnet, runningRevCount);
int newRevCount = runningRevCount;
if (passedMagnet && passingMagnet)
{ //Started a new pass of the magnet
passedMagnet = false;
newRevCount++;
}
else if (!passedMagnet && !passingMagnet)
{ //The new pass of the magnet is complete
passedMagnet = true;
}
return newRevCount;
}
unsigned long elapsedTime = 0;
unsigned long intervalTime = 0;
int rev = 0;
void loop()
{
intervalTime = millis() - elapsedTime;
rev = incrementRevolutions(rev, digitalRead(digitalPin));
// Serial.printf("outside rev: %d \n", rev);
if (intervalTime > 1000)
{
Serial.printf("rev: %d \n", rev);
rev = 0;
elapsedTime = millis();
}
}
Is this a known gotcha with Arduino or C++ programming? What should I do to fix it?
I think the test is to blame. I had to rename and move things a bit to visualize the logic, sorry about that.
bool magStateOld = false; // initialize to digitalRead(digitalPin) in setup()
int incrementRevolutions(int runningRevCount, bool magState)
{
int newRevCount = runningRevCount;
// detect positive edge.
if (magState && !magStateOld) // <- was eq. to if (magState && magStateOld)
// the large counts came from here.
{
newRevCount++;
}
magStateOld = magState; // record last state unconditionally
return newRevCount;
}
You could also write it as...
int incrementRevolutions(int n, bool magState)
{
n += (magState && !magStateOld);
magStateOld = magState;
return n;
}
But the most economical (and fastest) way of doing what you want would be:
bool magStateOld;
inline bool positiveEdge(bool state, bool& oldState)
{
bool result = (state && !oldState);
oldState = state;
return result;
}
void setup()
{
// ...
magStateOld = digitalRead(digitalPin);
}
void loop()
{
// ...
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
// ...
}
It's reusable, and saves both stack space and unnecessary assignments.
If you cannot get clean transitions from your sensor (noise on positive and negative edges, you'll need to debounce the signal a bit, using a timer.
Example:
constexpr byte debounce_delay = 50; // ms, you may want to play with
// this value, smaller is better.
// but must be high enough to
// avoid issues on expected
// RPM range.
// 50 ms is on the high side.
byte debounce_timestamp; // byte is large enough for delays
// up to 255ms.
// ...
void loop()
{
// ...
byte now = (byte)millis();
if (now - debounce_timestamp >= debounce_delay)
{
debounce_timestamp = now;
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
}
// ...
}
Related
Need to update potentiometer values all time not only once, try different ways but nothing works :(
I think that main problem is that this function while(digitalRead(gotoPositionAPin)); blocks
Now it's read value and save speed
workflow of code
press button right save position a
press button left save position b
update pot speed (set speed)
update pot acceleration (set accel)
press button go to position A (its going with previous set of speed and acceleration)
press button go to position B (its going with previous set of speed and acceleration)
#include <AccelStepper.h>
// Define some steppers and the pins the will use
AccelStepper stepper1(1, 12, 11);
#define stepsPerRev 1600
#define stepPin 12
#define dirPin 11
#define ledPin 13
#define rotateLeftPin 7
#define rotateRightPin 6
#define savePositionAPin 5
#define savePositionBPin 4
#define gotoPositionAPin 3
#define gotoPositionBPin 2
#define maxSpeedPin 0
#define accelPin 1
// Set this to zero if you don't want debug messages printed
#define printDebug 0
// These are the constants that define the speed associated with the MaxSpeed pot
#define MAX_STEPS_PER_SECOND 1000 // At 200 s/r and 1/8th microstepping, this will be 333 rev/minute
#define MIN_STEPS_PER_SECOND 27 // At 200 steps/rev and 1/8th microstepping, this will be 1 rev/minute
// Change this value to scale the acceleration pot's scaling factor
#define ACCEL_RATIO 1
int buttonState = 0;
int stepNumber = 0;
int curSpeed = 100;
int dir = 0;
int maxSpeed = 0;
int accel = 0;
long savedPosA = 0;
long savedPosB = 0;
int loopCtr = 0;
float fMaxSpeed = 0.0;
float fStepsPerSecond = 0.0;
void setup()
{
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(ledPin, OUTPUT);
pinMode(rotateLeftPin, INPUT);
pinMode(rotateRightPin, INPUT);
pinMode(savePositionAPin, INPUT);
pinMode(savePositionBPin, INPUT);
pinMode(gotoPositionAPin, INPUT);
pinMode(gotoPositionBPin, INPUT);
if (printDebug)
{
// Initialize the Serial port
Serial.begin(9600);
}
// blink the LED:
blink(2);
stepper1.setMaxSpeed(800.0);
stepper1.setAcceleration(600.0);
// Grab both speed and accel before we start
maxSpeed = analogRead(maxSpeedPin);
// Do the math to scale the 0-1023 value (maxSpeed) to
// a range of MIN_STEPS_PER_SECOND to MAX_STEPS_PER_SECOND
fMaxSpeed = maxSpeed / 1023.0;
fStepsPerSecond = MIN_STEPS_PER_SECOND + (fMaxSpeed * (MAX_STEPS_PER_SECOND - MIN_STEPS_PER_SECOND));
if (fStepsPerSecond > 1000)
{
fStepsPerSecond = 1000;
}
accel = analogRead(accelPin)/ACCEL_RATIO;
}
void loop()
{
// First, we need to see if either rotate button is down. They always take precidence.
if(digitalRead(rotateLeftPin))
{
stepper1.setSpeed(-fStepsPerSecond);
while(digitalRead(rotateLeftPin))
{
CheckPots();
stepper1.runSpeed();
stepper1.setSpeed(-fStepsPerSecond);
}
}
else if (digitalRead(rotateRightPin))
{
stepper1.setSpeed(fStepsPerSecond);
while(digitalRead(rotateRightPin))
{
CheckPots();
stepper1.runSpeed();
stepper1.setSpeed(fStepsPerSecond);
}
}
// Go see if we need to update our analog conversions
CheckPots();
// Check to see if user is trying to save position A or B
if(digitalRead(savePositionAPin))
{
savedPosA = stepper1.currentPosition();
if (printDebug)
{
Serial.print("Saved A at :");
Serial.println(savedPosA);
}
while(digitalRead(savePositionAPin));
}
if(digitalRead(savePositionBPin))
{
savedPosB = stepper1.currentPosition();
if (printDebug)
{
Serial.print("Saved B at :");
Serial.println(savedPosB);
}
while(digitalRead(savePositionBPin));
}
// Check to see if the user wants to go to position A or B
if (digitalRead(gotoPositionAPin))
{
if (printDebug)
{
// Yup, let's go to position A
Serial.print("cur pos = ");
Serial.println(stepper1.currentPosition());
Serial.print("Going to A = ");
Serial.println(savedPosA);
Serial.print("Speed = ");
Serial.println(fStepsPerSecond);
Serial.print("Accel = ");
Serial.println(accel);
}
stepper1.setAcceleration(0);
stepper1.runToNewPosition(stepper1.currentPosition());
stepper1.setMaxSpeed(fStepsPerSecond);
stepper1.setAcceleration(accel);
stepper1.runToNewPosition(savedPosA);
if (printDebug)
{
Serial.print("new pos = ");
Serial.println(stepper1.currentPosition());
}
while(digitalRead(gotoPositionAPin));
}
else if (digitalRead(gotoPositionBPin))
{
// Yup, let's go to position B
if (printDebug)
{
Serial.print("cur pos = ");
Serial.println(stepper1.currentPosition());
Serial.print("Going to B = ");
Serial.println(savedPosB);
Serial.print("Speed = ");
Serial.println(fStepsPerSecond);
Serial.print("Accel = ");
Serial.println(accel);
}
stepper1.setAcceleration(0);
stepper1.runToNewPosition(stepper1.currentPosition());
stepper1.setMaxSpeed(fStepsPerSecond);
stepper1.setAcceleration(accel);
stepper1.runToNewPosition(savedPosB);
if (printDebug)
{
Serial.print("new pos = ");
Serial.println(stepper1.currentPosition());
}
while(digitalRead(gotoPositionBPin));
}
}
// Blink the reset LED:
void blink(int howManyTimes)
{
int i;
for (i=0; i < howManyTimes; i++)
{
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(200);
}
}
void CheckPots(void)
{
loopCtr++;
// Only read these once in a while because they take a LONG time
if (loopCtr == 100)
{
maxSpeed = analogRead(maxSpeedPin);
// Do the math to scale the 0-1023 value (maxSpeed) to
// a range of MIN_STEPS_PER_SECOND to MAX_STEPS_PER_SECOND
fMaxSpeed = maxSpeed / 1023.0;
fStepsPerSecond = MIN_STEPS_PER_SECOND + (fMaxSpeed * (MAX_STEPS_PER_SECOND - MIN_STEPS_PER_SECOND));
if (fStepsPerSecond > 1000)
{
fStepsPerSecond = 1000;
}
}
// Read in the acceleration analog value
// This needs to be scaled too, but to what?
if (loopCtr >= 200)
{
accel = analogRead(accelPin)/ACCEL_RATIO;
loopCtr = 0;
}
}
If you're looking into "continuous operation" but don't want to introduce interrupts into your code (which will have special requirements in and of itself) there are a couple of things you need to get rid of:
Endless loops like: while(digitalRead(savePositionAPin));
System waits like: delay(200); as in your blink()
and instead use state variables. State variables are more or less what the name says: variables that hold the state of something, so you know what value the button, or timer, or counter had last time.
So, instead of a while-loop waiting for a button to be released, just set a global or static boolean that knows what state you were in the last time loop() ran, so you don't trigger the button action again. You need one boolean flag for each button.
And instead of delays, either create a state variable that holds "passed time" which you can get from millis() for example. So don't wait but instead you should just check if a certain amount of time has passed so you can toggle the state of the LED.
Adding a blinking LED to loop() - (untested example):
#define LEDWAIT 300
unsigned long myTime = 0;
bool onoff = false;
loop()
{
if (myTime == 0)
myTime = millis();
if ((millis() - myTime) > LEDWAIT) {
digitalWrite(ledPin, onoff ? HIGH : LOW);
onoff = !onoff;
myTime = millis();
}
// do other things
}
It is not entirely clear to me what your program is supposed to do and what the error is, so please correct me if I am wrong: You want to update a value based on which button is pressed? What is your opinion on using interrupts for triggering the updates?
You may want to edit the formating of your question.
I want make function like void loop or void setup like arduino main function which that function can input another execution code.
unsigned long NOW;
void setup() {
}
void loop() {
void doEvery(2){ //do Every 2 second
//Put Code that Execute every 2 second
}
void doEvery(4){ //do Every 4 second
//Put Code that Execute every 4 second
}
}
How to declare/define function doEvery?
i think that function must contain
if(millis()-NOW>=EVERY){
NOW=millis();
//THE LINE CODE
}
Taking THIS as initial idea:
unsigned long previousMillis2 = 0, previousMillis100 = 0;
void setup() {
}
void loop() {
unsigned long currentMillis = millis();
//doEvery 2
if (currentMillis - previousMillis2 >= 2) {
previousMillis2 = currentMillis; //stores last execution's timestamp
//CODE EVERY 2 millis
}
//doEvery 100
if (currentMillis - previousMillis100 >= 100) {
previousMillis100 = currentMillis; //stores last execution's timestamp
//CODE EVERY 100 millis
}
}
With this, you will use millis() to ask for how many millis passed since initialization of Arduino. Then you store last time you executed your code and compare how many time passed since it.
It's not a dynamic function for defining new intervals but if you only need a pair of it, you can code it easily.
EDIT:
If you need something more dynamic, you should use anonymous functions. SEE THIS or THIS The point here is function as parameter.
I've made an animation library out of this for the WS2812 ledstrip:
https://github.com/laurijssen/ledstripanimator/blob/master/ledanim.c
The timing stuff that jabujavi describes happens in the UpdateFrame function where every animation in the list advances to the next frame after it's configured milliseconds.
class AnimList
{
Animation *first = NULL;
Adafruit_NeoPixel strip;
public:
AnimList(int nleds) : strip(nleds, 9, NEO_GRB + NEO_KHZ800)
{
strip.begin();
}
void UpdateFrame()
{
strip.clear();
Animation **anim = &first;
while (*anim)
{
if (millis() - (*anim)->last >= (*anim)->ms)
{
if (!(*anim)->UpdateFrame(strip))
{
*anim = (*anim)->next;
}
else
{
(*anim)->last = millis();
anim = &(*anim)->next;
}
}
}
}
};
Now you just call AnimList::UpdateFrame as fast as possible inside loop()
void loop() {
list->UpdateFrame();
list->Render();
if (!list->Find(&r1))
{
r1 = Rain (rand() % NUMLEDS, rand() % NUMLEDS, {BRIGHTNESS, 0, 15 }) ;
list->AddFirst(&r1);
}
}
edit
So if you want to execute code every 2 seconds you create a class which inherits from Animation and override Updateframe. Then put ms variable at the time you want to pass between frames.
Of course remove all Adafruit and animation references if you just want a task based lib.
class TaskA : public Task
{
public:
TaskA() { ms = 2000; }
bool UpdateFrame()
{
Serial.println("2 seconds passed");
return true;
}
};
TaskA t;
void setup()
{
list->AddTask(&t);
}
void loop()
{
list->UpdateTasks();
}
So im working on a project making a safety and monitoring system for a bike and im sending the monitored data to Blynk
which is working perfectly.
Im trying to send an SMS when a value is triggered ,I recieve the SMS through Clicksend
but i cant figure out how i can send my values to IFTTT so that it can write those in the Alert SMS
Here is the code:
#include <SoftwareSerial.h>
#include <RH_NRF24.h>
#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <ESP8266HTTPClient.h>
char auth[] = "AUTH_ID";
char ssid[] = "SSID";
char pass[] = "PASS";
const char* iftttURL = "http://maker.ifttt.com/trigger/{event}/with/key/{key}";
BlynkTimer timer;
// Singleton instance of the radio driver
RH_NRF24 nrf24(2, 4); //D4,D2 on esp //nrf24L01
int led = 15; //D8 on esp
int acc;
int touch;
int headtemp;
static const int RXPin = 5, TXPin = 16; //D1,D2 on esp //gps
static const uint32_t GPSBaud = 9600;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
float lati;
float lon;
const int analogInPin = A0; //Pt100 Bike Temp
const int SensorValueLow = 463;
const int SensorValueDiff = 36; // differance between high and low sensor value
const int TempValueDiff = 32; // differance between high and low Temp value
const int TempValueLow = 0;
int sensorValue = 0;
int Temp = 0;
// Calibration: // //RPM
const byte PulsesPerRevolution = 10; // Set how many pulses there are on each revolution. Default: 2.
const unsigned long ZeroTimeout = 100000; // For high response time, a good value would be 100000
// Calibration for smoothing RPM:
const byte numReadings = 2; // Number of samples for smoothing. The higher, the more smoothing, but it's going to
// Variables:
/////////////
unsigned long kmh;
int d=50.8; //diameter of wheel in cm
volatile unsigned long LastTimeWeMeasured; // Stores the last time we measured a pulse so we can calculate the period.
volatile unsigned long PeriodBetweenPulses = ZeroTimeout+1000; // Stores the period between pulses in microseconds.
volatile unsigned long PeriodAverage = ZeroTimeout+1000; // Stores the period between pulses in microseconds in total, if we are taking multiple pulses.
unsigned long FrequencyRaw; // Calculated frequency, based on the period. This has a lot of extra decimals without the decimal point.
unsigned long FrequencyReal; // Frequency without decimals.
unsigned long RPM; // Raw RPM without any processing.
unsigned int PulseCounter = 1; // Counts the amount of pulse readings we took so we can average multiple pulses before calculating the period.
unsigned long PeriodSum; // Stores the summation of all the periods to do the average.
unsigned long LastTimeCycleMeasure = LastTimeWeMeasured; // Stores the last time we measure a pulse in that cycle.
unsigned long CurrentMicros = micros(); // Stores the micros in that cycle.
unsigned int AmountOfReadings = 1;
unsigned int ZeroDebouncingExtra; // Stores the extra value added to the ZeroTimeout to debounce it.
// Variables for smoothing tachometer:
unsigned long readings[numReadings]; // The input.
unsigned long readIndex; // The index of the current reading.
unsigned long total; // The running total.
unsigned long average; // The RPM value after applying the smoothing.
void myTimerEvent()
{
// You can send any value at any time.
// Please don't send more that 10 values per second.
Blynk.virtualWrite(V1, average);
Blynk.virtualWrite(V2, kmh);
Blynk.virtualWrite(V3, Temp);
}
WidgetMap myMap(V5);
void setup()
{
Serial.begin(9600);
Blynk.begin(auth, ssid, pass);
timer.setInterval(1000L, myTimerEvent);
ss.begin(GPSBaud); //GPS
Serial.println(F("DeviceExample.ino"));
Serial.println(F("A simple demonstration of TinyGPS++ with an attached GPS module"));
Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
Serial.println(F("by Mikal Hart"));
Serial.println();
pinMode(led, OUTPUT); //D8 of node mcu //nrf24L01
Serial.begin(9600);
while (!Serial)
; // wait for serial port to connect. Needed for Leonardo only
if (!nrf24.init())
Serial.println("init failed");
// Defaults after init are 2.402 GHz (channel 2), 2Mbps, 0dBm
if (!nrf24.setChannel(1))
Serial.println("setChannel failed");
if (!nrf24.setRF(RH_NRF24::DataRate2Mbps, RH_NRF24::TransmitPower0dBm))
Serial.println("setRF failed");
attachInterrupt(digitalPinToInterrupt(0), Pulse_Event, RISING); //RPM // Enable interruption pin 2 when going from LOW to HIGH.
}
void loop()
{
Blynk.run();
timer.run();
smsonaccident();
while (ss.available() > 0) //GPS
if (gps.encode(ss.read()))
displayInfo(); //GPS function
if (millis() > 5000 && gps.charsProcessed() < 10)
{
Serial.println(F("No GPS detected: check wiring."));
while(true);
}
NRF24L01(); //NRF24L01 Function
BikeTemp(); //Bike Temprature Function
BikeRPM(); //Bike Wheel RPM
}
void NRF24L01()
{
if (nrf24.available()) //nrf24L01
{
// Should be a message for us now
uint8_t buf[RH_NRF24_MAX_MESSAGE_LEN];
uint8_t len = sizeof(buf);
if (nrf24.recv(buf, &len))
{
Serial.println("*****Got Signal*****");
acc = buf[0];
touch = buf[1];
Serial.print("Accelerometer State: ");
Serial.print(buf[0]);
Serial.print(" , Touch State: ");
Serial.print(buf[1]);
if(touch == 1 || acc ==1)
{digitalWrite(led,HIGH);}
else
{digitalWrite(led,LOW);}
}
}
}
void BikeTemp()
{
sensorValue = analogRead(analogInPin); //Pt100 BikeTemp
Temp = sensorValue-SensorValueLow;
Temp = Temp/SensorValueDiff;
Temp = Temp*TempValueDiff;
Temp = Temp+TempValueLow;
Serial.print("Temp= ");
Serial.println(Temp);
}
void BikeRPM()
{
LastTimeCycleMeasure = LastTimeWeMeasured; // RPM+Km/h
CurrentMicros = micros(); // Store the micros() in a variable.
if(CurrentMicros < LastTimeCycleMeasure)
{
LastTimeCycleMeasure = CurrentMicros;
}
// Calculate the frequency:
FrequencyRaw = 10000000000 / PeriodAverage; // Calculate the frequency using the period between pulses.
// Detect if pulses stopped or frequency is too low, so we can show 0 Frequency:
if(PeriodBetweenPulses > ZeroTimeout - ZeroDebouncingExtra || CurrentMicros - LastTimeCycleMeasure > ZeroTimeout - ZeroDebouncingExtra)
{ // If the pulses are too far apart that we reached the timeout for zero:
FrequencyRaw = 0; // Set frequency as 0.
ZeroDebouncingExtra = 2000; // Change the threshold a little so it doesn't bounce.
}
else
{
ZeroDebouncingExtra = 0; // Reset the threshold to the normal value so it doesn't bounce.
}
FrequencyReal = FrequencyRaw / 10000; // Get frequency without decimals.
// Calculate the RPM:
RPM = FrequencyRaw / PulsesPerRevolution * 60; // Frequency divided by amount of pulses per revolution multiply by
RPM = RPM / 10000; // Remove the decimals.
// Smoothing RPM:
total = total - readings[readIndex]; // Advance to the next position in the array.
readings[readIndex] = RPM; // Takes the value that we are going to smooth.
total = total + readings[readIndex]; // Add the reading to the total.
readIndex = readIndex + 1; // Advance to the next position in the array.
if (readIndex >= numReadings) // If we're at the end of the array:
{
readIndex = 0; // Reset array index.
}
// Calculate the average:
average = total / numReadings; // The average value it's the smoothed result.
kmh = d*average*0.001885; // calculate km/h ,where d(in cm) is diameter of wheel
Serial.print("RPM: ");
Serial.print(average);
Serial.print(" , KM/h: ");
Serial.println(kmh);
}
void displayInfo()
{
Serial.print(F("Location: "));
if (gps.location.isValid())
{
// Serial.print(gps.location.lat(), 6);
lati = gps.location.lat() ;
Serial.print(lati, 6);
Serial.print(F(","));
// Serial.print(gps.location.lng(), 6);
lon = gps.location.lng() ;
Serial.print(lon, 6);
}
else
{
Serial.print(F("Invalid"));
}
int index = 5;
myMap.location(index, lati, lon, "Bike location");
Serial.print(F(" Date/Time: "));
if (gps.date.isValid())
{
Serial.print(gps.date.day());
Serial.print(F("/"));
Serial.print(gps.date.month());
Serial.print(F("/"));
Serial.print(gps.date.year());
}
else
{
Serial.print(F("INVALID"));
}
Serial.print(F(" "));
if (gps.time.isValid())
{
if (gps.time.hour() < 10) Serial.print(F("0"));
Serial.print(gps.time.hour());
Serial.print(F(":"));
if (gps.time.minute() < 10) Serial.print(F("0"));
Serial.print(gps.time.minute());
Serial.print(F(":"));
if (gps.time.second() < 10) Serial.print(F("0"));
Serial.print(gps.time.second());
}
else
{
Serial.print(F("INVALID"));
}
Serial.println();
}
ICACHE_RAM_ATTR void Pulse_Event() //RPM Data // The interrupt runs this to calculate the period between pulses:
{
PeriodBetweenPulses = micros() - LastTimeWeMeasured; // Current "micros" minus the old "micros" when the last pulse happens.
LastTimeWeMeasured = micros(); // Stores the current micros so the next time we have a pulse we would have something to compare with.
if(PulseCounter >= AmountOfReadings) // If counter for amount of readings reach the set limit:
{
PeriodAverage = PeriodSum / AmountOfReadings; // Calculate the final period dividing the sum of all readings by the
PulseCounter = 1; // Reset the counter to start over. The reset value is 1 because its the minimum setting allowed (1 reading).
PeriodSum = PeriodBetweenPulses; // Reset PeriodSum to start a new averaging operation.
int RemapedAmountOfReadings = map(PeriodBetweenPulses, 40000, 5000, 1, 10); // Remap the period range to the reading range.
RemapedAmountOfReadings = constrain(RemapedAmountOfReadings, 1, 10); // Constrain the value so it doesn't go below or above the limits.
AmountOfReadings = RemapedAmountOfReadings; // Set amount of readings as the remaped value.
}
else
{
PulseCounter++; // Increase the counter for amount of readings by 1.
PeriodSum = PeriodSum + PeriodBetweenPulses; // Add the periods so later we can average.
}
}
void smsonaccident()
{
if (acc>=1) // You can write any condition to trigger e-mail sending
{
Serial.println("Alert!!! Accident Happens see location. "); // This can be seen in the Serial Monitor
HTTPClient http; // Declare an object of class HTTPClient
http.begin(iftttURL); // Specify request destination
int httpCode = http.GET(); // Send the request
Serial.println("Done");
if (httpCode > 0) {
String payload = http.getString(); // Get the request response payload
Serial.println(payload); // Print the response payload
}
http.end(); // Close connection
acc=0;
delay(10000); // delay for 5 min if accident happens
}
}
Now im trying to find a way so that i can send my GPS values to the "iftttURL" but whatever i try or whatever i know doesnt work
either the value just doesnt get recieved or if it does then the SMS fails to send as it cant validate the values
what do i need to add
or what do i need to change to send my GPS values "lati" and "lon" to my ifttt url where it can recognize it as values that i can put into the alert message
Describtion of the problem:
we need to call a function in extern process as fast as possible. Boost interprocess shared memory is used for communication. The extern process is either mpi master or a single executable. The calculation time of the function lies between 1ms and 1s. The function should be called up to 10^8-10^9 times.
I've tried a lot of possibilities, but I still have some problems with each of them. Here I introduce two of best working implementations
Version 1 ( using intreprocess conditions )
Main-process
bool calculate(double& result, std::vector<double> c){
// data_ptr is a structure in shared memoty
data_ptr_->validCalculation = false;
bool timeout = false;
// write data (cVec_ is a vector in shared memory )
cVec_->clear();
for (int i = 0; i < c.size(); ++i)
{
cVec_->push_back(c[i]);
}
// cond_input_data is boost interprocess condition
data_ptr_->cond_input_data.notify_one();
boost::system_time const waittime = boost::get_system_time() + boost::posix_time::seconds(maxWaitTime_in_sec);
// lock slave process
scoped_lock<interprocess_mutex> lock_output(data_ptr_->mutex_output);
// wait till data calculated
timeout = !(data_ptr_->cond_output_data.timed_wait(lock_output, waittime)); // true if timeout, false if no timeout
if (!timeout)
{
// get result
result = *result_;
return data_ptr_->validCalculation;
}
else
{
return false;
}
};
Extern process runs a while-loop ( till abort condition is fullfilled)
do {
scoped_lock<interprocess_mutex> lock_input(data_ptr_->mutex_input);
boost::system_time const waittime = boost::get_system_time() + boost::posix_time::seconds(maxWaitTime_in_sec);
timeout = !(data_ptr_->cond_input_data.timed_wait(lock_input, waittime)); // true if timeout, false if no timeout
if (!timeout)
{
if (!*abort_flag_) {
c.clear();
for (int i = 0; i < (*cVec_).size(); ++i) //Insert data in the vector
{
c.push_back(cVec_->at(i));
}
// calculate value
if (call_of_function_here(result, c)) { // valid calculation ?
*result_ = result;
data_ptr_->validCalculation = true;
}
}
}
//Notify the other process that the data is avalible or we dont get the input data
data_ptr_->cond_output_data.notify_one();
} while (!*abort_flag_); // while abort flag is not set, check if some values should be calculated
This is best working version, but sometimes it holds up, if the calculation time is short (~1ms). I assume, it happens, if main-process reaches
data_ptr_->cond_input_data.notify_one();
earlier, than extern process is waiting on
timeout = !(data_ptr_->cond_input_data.timed_wait(lock_input, waittime));
waiting condition. So we have probably some kind of synchronisation problem.
Second condition does not help ( i.e. wait only if input data not set, similar to the anonymous condition example with message_in flag). Since, it is still possible, that one process notify the other one, before the second one is waiting for notification.
Version 2 ( using boolean flag and while loop with some delay )
Main-process
bool calculate(double& result, std::vector<double> c){
data_ptr_->validCalculation = false;
bool timeout = false;
// write data
cVec_->clear();
for (int i = 0; i < c.size(); ++i) //Insert data in the vector
{
cVec_->push_back(c[i]);
}
// this is the flag in shared memory used for communication
*calc_flag_ = true;
clock_t test_begin = clock();
clock_t calc_time_begin = clock();
do
{
calc_time_begin = clock();
boost::this_thread::sleep(boost::posix_time::milliseconds(while_loop_delay_m_s));
// wait till data calculated
timeout = (double(calc_time_begin - test_begin) / CLOCKS_PER_SEC > maxWaitTime_in_sec);
} while (*(calc_flag_) && !timeout);
if (!timeout)
{
// get result
result = *result_;
return data_ptr_->validCalculation;
}
else
{
return false;
}
};
and the extern process
do {
// we wait till input data is set
wait_begin = clock();
do
{
wait_end = clock();
timeout = (double(wait_end - wait_begin) / CLOCKS_PER_SEC > maxWaitTime_in_sec);
boost::this_thread::sleep(boost::posix_time::milliseconds(while_loop_delay_m_s));
} while (!(*calc_flag_) && !(*abort_flag_) && !timeout);
if (!timeout)
{
if (!*abort_flag_) {
c.clear();
for (int i = 0; i < (*cVec_).size(); ++i) //Insert data in the vector
{
c.push_back(cVec_->at(i));
}
// calculate value
if (call_of_local_function(result, c)) { // valid calculation ?
*result_ = result;
data_ptr_->validCalculation = true;
}
}
}
//Notify the other process that the data is avalible or we dont get the input data
*calc_flag_ = false;
} while (!*abort_flag_); // while abort flag is not set, check if some values should be calculated
The problem in this version is the delay-time. Since we have calculation times close to 1ms, we have to set the delay at least to this value. For smaller delays the cpu-load is high, for higher delays we lose a lot of performance due to not necessary waiting time
Do you have an idea how to improve one of this versions? or may be there is a better solution?
thx.
I'm trying to use the given code within steptimer.h to set up code that will run every two seconds. However with the code below, timer.GetTotalSeconds() always returns 0.
Unfortunately there isn't much information readily available on StepTimer.h (at least I believe due to a lack of useful search results), so I was hoping someone might be able to shed some light as to why the timer isn't recording the elapsed seconds. Am I using it incorrectly?
Code from Game.h, Game.cpp and StepTimer.h are included below. Any help is greatly appreciated.
From Game.cpp:
double time = timer.GetTotalSeconds();
if (time >= 2) {
laser_power++;
timer.ResetElapsedTime();
}
Initialised in Game.h:
DX::StepTimer timer;
From Common/StepTimer.h:
#pragma once
#include <wrl.h>
namespace DX
{
// Helper class for animation and simulation timing.
class StepTimer
{
public:
StepTimer() :
m_elapsedTicks(0),
m_totalTicks(0),
m_leftOverTicks(0),
m_frameCount(0),
m_framesPerSecond(0),
m_framesThisSecond(0),
m_qpcSecondCounter(0),
m_isFixedTimeStep(false),
m_targetElapsedTicks(TicksPerSecond / 60)
{
if (!QueryPerformanceFrequency(&m_qpcFrequency))
{
throw ref new Platform::FailureException();
}
if (!QueryPerformanceCounter(&m_qpcLastTime))
{
throw ref new Platform::FailureException();
}
// Initialize max delta to 1/10 of a second.
m_qpcMaxDelta = m_qpcFrequency.QuadPart / 10;
}
// Get elapsed time since the previous Update call.
uint64 GetElapsedTicks() const { return m_elapsedTicks; }
double GetElapsedSeconds() const { return TicksToSeconds(m_elapsedTicks); }
// Get total time since the start of the program.
uint64 GetTotalTicks() const { return m_totalTicks; }
double GetTotalSeconds() const { return TicksToSeconds(m_totalTicks); }
// Get total number of updates since start of the program.
uint32 GetFrameCount() const { return m_frameCount; }
// Get the current framerate.
uint32 GetFramesPerSecond() const { return m_framesPerSecond; }
// Set whether to use fixed or variable timestep mode.
void SetFixedTimeStep(bool isFixedTimestep) { m_isFixedTimeStep = isFixedTimestep; }
// Set how often to call Update when in fixed timestep mode.
void SetTargetElapsedTicks(uint64 targetElapsed) { m_targetElapsedTicks = targetElapsed; }
void SetTargetElapsedSeconds(double targetElapsed) { m_targetElapsedTicks = SecondsToTicks(targetElapsed); }
// Integer format represents time using 10,000,000 ticks per second.
static const uint64 TicksPerSecond = 10000000;
static double TicksToSeconds(uint64 ticks) { return static_cast<double>(ticks) / TicksPerSecond; }
static uint64 SecondsToTicks(double seconds) { return static_cast<uint64>(seconds * TicksPerSecond); }
// After an intentional timing discontinuity (for instance a blocking IO operation)
// call this to avoid having the fixed timestep logic attempt a set of catch-up
// Update calls.
void ResetElapsedTime()
{
if (!QueryPerformanceCounter(&m_qpcLastTime))
{
throw ref new Platform::FailureException();
}
m_leftOverTicks = 0;
m_framesPerSecond = 0;
m_framesThisSecond = 0;
m_qpcSecondCounter = 0;
}
// Update timer state, calling the specified Update function the appropriate number of times.
template<typename TUpdate>
void Tick(const TUpdate& update)
{
// Query the current time.
LARGE_INTEGER currentTime;
if (!QueryPerformanceCounter(¤tTime))
{
throw ref new Platform::FailureException();
}
uint64 timeDelta = currentTime.QuadPart - m_qpcLastTime.QuadPart;
m_qpcLastTime = currentTime;
m_qpcSecondCounter += timeDelta;
// Clamp excessively large time deltas (e.g. after paused in the debugger).
if (timeDelta > m_qpcMaxDelta)
{
timeDelta = m_qpcMaxDelta;
}
// Convert QPC units into a canonical tick format. This cannot overflow due to the previous clamp.
timeDelta *= TicksPerSecond;
timeDelta /= m_qpcFrequency.QuadPart;
uint32 lastFrameCount = m_frameCount;
if (m_isFixedTimeStep)
{
// Fixed timestep update logic
// If the app is running very close to the target elapsed time (within 1/4 of a millisecond) just clamp
// the clock to exactly match the target value. This prevents tiny and irrelevant errors
// from accumulating over time. Without this clamping, a game that requested a 60 fps
// fixed update, running with vsync enabled on a 59.94 NTSC display, would eventually
// accumulate enough tiny errors that it would drop a frame. It is better to just round
// small deviations down to zero to leave things running smoothly.
if (abs(static_cast<int64>(timeDelta - m_targetElapsedTicks)) < TicksPerSecond / 4000)
{
timeDelta = m_targetElapsedTicks;
}
m_leftOverTicks += timeDelta;
while (m_leftOverTicks >= m_targetElapsedTicks)
{
m_elapsedTicks = m_targetElapsedTicks;
m_totalTicks += m_targetElapsedTicks;
m_leftOverTicks -= m_targetElapsedTicks;
m_frameCount++;
update();
}
}
else
{
// Variable timestep update logic.
m_elapsedTicks = timeDelta;
m_totalTicks += timeDelta;
m_leftOverTicks = 0;
m_frameCount++;
update();
}
// Track the current framerate.
if (m_frameCount != lastFrameCount)
{
m_framesThisSecond++;
}
if (m_qpcSecondCounter >= static_cast<uint64>(m_qpcFrequency.QuadPart))
{
m_framesPerSecond = m_framesThisSecond;
m_framesThisSecond = 0;
m_qpcSecondCounter %= m_qpcFrequency.QuadPart;
}
}
private:
// Source timing data uses QPC units.
LARGE_INTEGER m_qpcFrequency;
LARGE_INTEGER m_qpcLastTime;
uint64 m_qpcMaxDelta;
// Derived timing data uses a canonical tick format.
uint64 m_elapsedTicks;
uint64 m_totalTicks;
uint64 m_leftOverTicks;
// Members for tracking the framerate.
uint32 m_frameCount;
uint32 m_framesPerSecond;
uint32 m_framesThisSecond;
uint64 m_qpcSecondCounter;
// Members for configuring fixed timestep mode.
bool m_isFixedTimeStep;
uint64 m_targetElapsedTicks;
};
}
Alrighty got what I wanted with the code below. Was missing the .Tick(####) call.
timer.Tick([&]() {
double time = timer.GetTotalSeconds();
if (time >= checkpt) {
laser_power++;
checkpt += 2;
}
});
Just fixed an integer checkpt to increment by 2 each time so that it runs every 2 seconds. There's probably a better way to do it, but it's 3.30am so I'm being lazy for the sake of putting my mind at ease.