Reputation: 81
I am beginning in C++ and with the "chrono" function, and I'd like to use it to get the speed of a motor.
For that, I have a coding wheel linked to a motor, an optocoupler is used to gather the square signal generated by the coding wheel.
Therefore, my raspberry pi receive a square signal which speed depends on the motor speed.
I used the chrono function to try to calculate the duration of the frequency of the square signal. I achieved to have the duration of each signal (almost) which is 7ms. I'd like to simply extract the frequency through the formula 1/F (therefore, 1/0.007 = 142.85).
I've been eating the documentation of the chrono function for a week, and I still don't get it at all...
Apparently, all the answers are here, but I don't understand that, I'm still a beginner in C++ :( https://en.cppreference.com/w/cpp/chrono
This has been REALLY usefull, but limited : https://www.code57.com/cplusplus-programming-beginners-tutorial-utilities-chrono/
If I understand right, the "value" of 7ms is stored in an "object"... How can I simply get it out of there and put it in a standard variable so I can divide, multiply and do whatever I want with it?
Here is the interresting part of the C++ code :
#include <iostream>
#include <wiringPi.h>
#include <cstdio>
#include <csignal>
#include <ctime>
#include <chrono>
// global flag used to exit from the main loop
bool RUNNING = true;
bool StartTimer = false;
//int timer = 0;
std::chrono::steady_clock::time_point BeginMeasurement; //chrono variable representing the beginning of the measurement of a motor speed
//some more code in here, but nothing exceptionnal, just calling the interruption when needed
//interruption function for counting the motor speed
void RPMCounter(){
using namespace std;
using namespace std::chrono;
if (StartTimer == true){
StartTimer = false;
steady_clock::duration result = steady_clock::now()-BeginMeasurement;
if (duration_cast<milliseconds>(result).count() < 150){
double freq;
//cout.precision(4);
std::cout << "Time = " << duration_cast<milliseconds>(result).count() << " ms" << '\n';
// I would like the next line to work and give me the frequency of the detection...
freq = 1/(duration_cast<milliseconds>(result).count()/1000);
std::cout << "Frequency = " << freq << " Hz" << '\n';
}
}
else{
BeginMeasurement = steady_clock::now();
StartTimer = true;
}
}
Here is the result in my command prompt :
the value of 7ms increases because I stopped the motor, therefore, it was turning slower until stopping ;)
Edit :
Thanks to Howard Hinnant and Ted Lyngmo, My code now looks like this :
void RPMCounter(){
using namespace std;
using namespace std::chrono;
if (StartTimer == true){
StartTimer = false;
duration<double> result = steady_clock::now() - BeginMeasurement;
if (result < milliseconds{150}){
double freq;//= 1s / result;
//cout.precision(4);
std::cout << "Time = " << duration_cast<milliseconds>(result).count() << " ms" << '\n';
freq = (1.0/(duration<double>{result}.count()/1000))/1000;
std::cout << "Frequency = " << freq << " Hz" << '\n';
}
}
else{
BeginMeasurement = steady_clock::now();
StartTimer = true;
}
}
and it seems to give me a correct frequency. As i'm a beginner, I'll surely understand all that better in a while and improve it :) (basically, I'm not exactly sure of what I wrote mean... like the "::" and other ways of :) The rest of my coding should be more basic and allow me to learn all the tweaks of C++
Upvotes: 1
Views: 824
Reputation: 117643
I'd make the result
a double
based duration:
auto BeginMeasurement = std::chrono::steady_clock::now();
// some work
// a double based duration
std::chrono::duration<double> result = std::chrono::steady_clock::now() - BeginMeasurement;
You can then divide the duration
1s
with result
to get the frequency:
using namespace std::chrono_literals;
double freq = 1s / result;
std::cout << freq << " Hz\n";
Howard Hinnant pointed out that from C++14 you can make it even easier for youself by changing the dividend from an integer based duration, 1s
, to a double based duration, 1.0s
, and let result
be deduced using auto
:
auto result = std::chrono::steady_clock::now() - BeginMeasurement;
double freq = 1.0s / result;
Upvotes: 2
Reputation: 219245
if (duration_cast<milliseconds>(result).count() < 150){
You can simplify this with:
if (result < 150ms)
Or if you're in C++11:
if (result < milliseconds{150})
The advantage is that you don't have to truncate result to a courser precision, and the code is just easier to read.
freq = 1/(duration_cast<milliseconds>(result).count()/1000);
Instead:
using dsec = duration<double>; // define a double-based second
auto freq = 1/dsec{result}.count();
This could also be written:
auto freq = 1/duration<double>{result}.count();
In any event, this converts result
straight to double-based seconds, and inverts that value using floating point arithmetic. The original code uses integral division resulting in an integral result that is always rounding down to 0. I.e. 1/10 == 0
, whereas 1/10. == 0.1
.
Upvotes: 4