brushless rc limitator

Hello,

I am controlling an brushless rc motor with arduino using the servo library and of course the rc controller for the motor…
I want to able to limit the current as precisely and as fast as possible…

The motor is an outrunner with 14 magnets, so I mounted an hall sensor outside of the rotor and I am able to read each magnet that passes…

In the code I am using interrupt for sensors HIGH state and count the time between two readings…

I then compare the curent motor rpm to the output “angle” to the controller(0-180servo degrees) and with some testing, measuring and mapping I am now able to precisely enough know the current that the motor is pulling… Knowing the current I can affect the output to the controller thus limiting the current…

The problem is that when I use the raw time measured I get some spike in the reading now and then and the spike is transfered to the controller…

I then tried to smooth out the reading, and now I cant feel any spikes, but the limiting is now slower in response…

Here is the part of the code that is doing this…

#include <Servo.h>

Servo ESC;

const int motorRpmSmooth = 20;
volatile unsigned long motorRpmReading[motorRpmSmooth];
volatile int motorRpmIndex = 0;
volatile unsigned long motorRpmTotal = 0;
volatile long rpmTime = 0;
volatile long rpmLast = 0;
volatile long rpmRaw = 0;
int throttleOut = 0;
int motorRpm = 0;

void setup()
{
ESC.attach(7);
  attachInterrupt(0, motorRpmRead, HIGH);
for (int rpRead = 0; rpRead < motorRpmSmooth; rpRead++)
       motorRpmReading[rpRead] = 0;
}

void loop()
{
throttleOut = map(analogRead(2), 0, 1023, 0 , 180);

motorRpm = map(rpmTime, 2330, 704, 31, 180);

ESC.write(min(motorRpm + 20, throttleOut));

}

void motorRpmRead()
{
  motorRpmTotal = motorRpmTotal - motorRpmReading[motorRpmIndex];
  motorRpmReading[motorRpmIndex] = micros() - rpmLast;
  rpmRaw = micros() - rpmLast;
  rpmLast = micros();
  motorRpmTotal = motorRpmTotal + motorRpmReading[motorRpmIndex];
  motorRpmIndex++;
  if (motorRpmIndex >= motorRpmSmooth)
     {motorRpmIndex = 0;}
  rpmTime = motorRpmTotal / motorRpmSmooth;
}

I just want to make sure that i am doing it in the best way… Would it be better-faster that I write to the controller in the interrupt? Or to keep in the interrupt only the raw measuring, and the smoothing and the controller writing do in the main loop?

Here is the part of the code that is doing this..

Here is part of the answer: You need to

PaulS:

Here is the part of the code that is doing this…

Here is part of the answer:
You need to

The only problem that I have in the code is to get good time readings, so I was thinking that this way I can make things more easy to follow and understand than to post the entire 30.000 bytes code of whitch 99% is lcd writing data and changing parameters…

I cutted out all the other things from the 30.000bytes code, and tested it, and it is working the same way… So I now editted the first post, and put there the entire working code…

  motorRpmReading[motorRpmIndex] = micros() - rpmLast;
  rpmRaw = micros() - rpmLast;
  rpmLast = micros();

It would be faster if you reversed the order of these statements. There is no reason to call micros() three times. There is no reason to compute micros() - rpmLast twice.

vwteo: The problem is that when I use the raw time measured I get some spike in the reading now and then and the spike is transfered to the controller....

What's the nature of the spike? Is it just one sample (with normal samples either side) or multiple samples? Can you see any clue about what is causing the spike? For example if the value seems to be double or half the expected value it may be that you're getting missed or spurious input pulses and there may be ways to avoid that happening.

Do you have any idea how frequently your ISR will be triggered? It would be useful to know what sort of performance constraints you're working in. The smoothing algorithm you're using is certainly one way to reduce the effect of outlier values but you may need to tune the number of samples to get the best compromise between latency and smoothness, or you may need to consider different smoothing algorithms. To solve this problem effectively you need to know the input frequency, the nature of the outliers you want to smooth out and the required output latency.

Is the hall sensor a digital output one with some hysteresis? False triggers may be due to uneven leakage of field from the motor's magnet bell, careful adjustment of position of the hall sensor might prevent spurious signals.

In software you can try to detect and fake-up any anomolous readings before they get to the motor speed control code (a PID algorithm?)

When you say you can determine the current by measuring the RPM, that's illogical - I presume your load has a fairly predictable current v. rpm curve... To measure current I would use a current sensor in the ESC's supply...

HI,

I found out that there is no much sense trying to speed up arduino, because the RC controller used is not fast enough to make that quick changes to the motor rpm.. So using the smoothing that Is in the above code is a good solution for any spikes and rough reading.. This is now working just fine for me and is fast enough.. Before this I was measuring current with a hall current sensor but I could not achieve fast enough response to the controller, this now is way faster and precise..

The only problem that I have is that every few times I start or reset the arduino I get a strange bigger reading of the rpmTime of the above code.. In normal condition I get the readinngs from 6000(at 10% throttle) and 600(at 100% throttle), and when abnormal i get from ca 27000 to 21000... which vary... then i reset the arduino and the reading is ok.. sometimes even after resseting a few times the reading is strage every time, and vice versa...

thanks for all the answers... ;)