Non-Blocking Frequency Counter

Hi all,

Recently I've been working on designing an H-bridge motor controller for high-powered DC servomotors. The choice I made for the speed control and logic behind the controller was influenced by my familiarity with the Arduino ecosystem.

Involved in my ideal motor controller is a system to regulate the speed (measured in revolutions per time unit) of a motor, regardless of what magnitude of load is placed upon it. To do this, the obvious choice would be to implement a PID controller, which would allow the regulation to react very quickly and without any appreciable loss of rotational speed.

When you are implementing a PID controller to regulate speed of a motor, clearly you need to know the speed of your motor, moreover somewhat instantaneously in a quick-reacting system. This brought me to look for a frequency counter library for Arduino. The problem I ran into is that all of the ones I could find (most likely to my fault) required the program to pause execution while it was counting pulses, even the ones that used interrupts.

To my astonishment, it was extremely simple to implement a frequency counter which doesn't require the program to stop execution. I'm slightly aware there might be some issues with invalid data (because some readings are taken before the loop is executed) influencing erroneous PWM adjustments.

I found that the use of the Rolling Average library, found here, was helpful in preventing spikes in values and making the data more trust-able (if that makes any sense).

Nevertheless, here's what I came up with:

#include "RunningAverage.h"

// For my frequency range, '50' samples for rolling average works
RunningAverage freqCounting(50);

volatile unsigned long lastPulseTime = 0;

// Attach input to digital pin 2
void isr()
{
	unsigned long now = micros();
	freqCounting.addValue(now-lastPulseTime);
	lastPulseTime = now;
}

// Return the frequency of the input signal in Hertz,
// found using the formula:
// Freq = 1/period
float getFrequency()
{
	return (float)(1/((float)freqCounting.getAverage()/1000000.0f));
}

void setup()
{
	attachInterrupt(0, isr, RISING);

	Serial.begin(57600);
}

void loop()
{
        Serial.print("Frequency: ");
        Serial.println(getFrequency());
}

As always, criticism and improvements/suggestions would be much appreciated.

Thanks for reading! :slight_smile:

You can do position feedback as well with a PID loop.

Typically servo motor control is done with an inner current-control loop, so you'd need current
sensing in your H-bridge to drive that loop (which is fast, think 10kHz or more). Then velocity
or position loops are cascaded around the current-control loop. Remember current is proportional
to torque, so the inner loop is a torque-control loop (which you can use directly for a torque-motor
application).

V. good lectures on motor control: Teaching Old Motors New Tricks - Part 1 - YouTube

MarkT:
You can do position feedback as well with a PID loop.

Typically servo motor control is done with an inner current-control loop, so you'd need current
sensing in your H-bridge to drive that loop (which is fast, think 10kHz or more). Then velocity
or position loops are cascaded around the current-control loop. Remember current is proportional
to torque, so the inner loop is a torque-control loop (which you can use directly for a torque-motor
application).

V. good lectures on motor control: https://www.youtube.com/watch?v=fpTvZlnrsP0

Woah, that's really neat. I didn't know they factored 'torque' sensing into it as well.

Try this for the ultimate in servomotor performance: Ultra High Precision Demo - YouTube