zepeu
zepeu

Reputation: 81

Raspberry pi, C++ chrono function, operations on values?

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 :

enter image description here

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

Answers (2)

Ted Lyngmo
Ted Lyngmo

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;

Demo

Upvotes: 2

Howard Hinnant
Howard Hinnant

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

Related Questions