Writing continous PWM pulses.

Hi all!

I am trying to make my quadcopter able to hover a fixed distance above the ground. A downward pointing ultrasonic rangefinder sits on the quad’s belly, measuring the distance to the ground. An Arduino Duemilanove intersects the throttle signals coming from the radio receiver before they go to the flight controller (KK 2.0). I can easily read the PWM signal that comes from both the receiver and the range finder using PulseIn(). I then modify the throttle value based on the distance to the ground.

My question is, how do I best send the modified PWM signal to the flight controller? There is of course no PulseWrite() function, and I don’t think AnalogWrite will work here (I have not tried; if it does not work as I expect, my quad might simply disappear into the clouds, never to be seen again). I have read the Secrets of Arduino PWM article (http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM), but couldn’t quite make sense of it. I think the PWM signal needs to be more or less continuous, it is not enough to send a pulse every now and then.

Here is my code so far. The PulseOut line is the one that needs to be replaced with some other magic.

const int wait = 20; // Loop delay.

const int thrInPin = 3;
const int thrOutPin = 6;
const int distPin = 9;

float dist, h, out;
float thr;

const float thr_min = 1053; // PWM when the throttle is at min.
const float thr_max = 1880; // PWM when the throttle is at max.
const float thr_fall = 1360; // Throttle value that will make the quad make a slow descent.

const float h_ceil = 200; // Above this height (in cm), the throttle value will be decreased.
const float max_stretch = 100; // Above h_ceil + max_stretch, the quad will fall like a rock.
const float k = (thr_max - thr_min) / max_stretch; // Virtual spring constant.


void setup() {
  pinMode(distPin, INPUT);
  pinMode(thrInPin, INPUT);
  pinMode(thrOutPin, OUTPUT);

  Serial.begin(9600);
}


void loop() {
  dist = pulseIn(distPin, HIGH, 80000); // Read distance from ultrasonic range finder.
  h = dist*2.54/147; // Convert to cm.
  thr = pulseIn(thrInPin, HIGH, 40000); // Read value of throttle. 
  
  if (h <= h_ceil)
  {
    // Pass signal through.
    out = thr;
  }
  else if (h > h_ceil)
  {
    // Reduce throttle value.
    out = thr - k * (h - h_ceil);
  }
  
  if (out < thr_min) // In case something is wrong ... 
  {
    out = thr_fall; // LAND!
  }

  PulseOut(out, HIGH) // This does not work.

  delay(wait);
}

and I don't think AnalogWrite will work here

why not.

I think the PWM signal needs to be more or less continuous

it is.

but couldn't quite make sense of it.

Try this:-
http://www.thebox.myzen.co.uk/Tutorial/PWM.html

I don't have your answer right away.
But you could prevent your quad from escaping by either testing it under a roof, or anchoring it so it cant go too far away during your first tests.
In case of an anchor, take some more steps to prevent your quad to tangle up in it.
:wink:

You use digitalWrite() set the pin high and then low as required using (not the only way) micros()/mills() to control the timing - see blink without delay.

Mark

danhje:
I don’t think AnalogWrite will work here (I have not tried; if it does not work as I expect, my quad might simply disappear into the clouds, never to be seen again).

Yes, well I wouldn’t power up the rotors on my first test of the code. I would nail its feet to the perch (apologies to Monty Python).

Yes, PWM output will give you continuous PWM pulses, that’s what it is there for. Calling analogWrite is one way of doing that.

I have quite a few examples of PWM output here:

http://www.gammon.com.au/forum/?id=11504

danhje:
I can easily read the PWM signal that comes from both the receiver

...

My question is, how do I best send the modified PWM signal to the flight controller?

I think you'll find that the 'pwm' signal you're receiving is actually a conventional RC servo signal consisting of a pulse of 1-2ms duration repeated every 20ms. There is a Servo library which you can use to generate an output signal in the same format.

PeterH:
I think you'll find that the 'pwm' signal you're receiving is actually a conventional RC servo signal consisting of a pulse of 1-2ms duration repeated every 20ms. There is a Servo library which you can use to generate an output signal in the same format.

You were right! The Servo library did the trick.

  out = map(out, thr_min, thr_max, 0, 180);
  thrOut.write(out);

The only problem now is that the quad keeps bouncing up and down instead of staying at one fixed level. No surprise, really, as I have been using spring math to calculate the modified throttle value. But I should be able to figure that out, now that I am able to communicate with the KK board.

Thanks!

danhje:
The only problem now is that the quad keeps bouncing up and down instead of staying at one fixed level. No surprise, really, as I have been using spring math to calculate the modified throttle value. But I should be able to figure that out, now that I am able to communicate with the KK board.

This is common in systems with significant inertia and little inherent damping. You need a better control system than a simple proportional feedback. A PID controller would be one way to implement that, although there's nothing to stop you from just adding your own damping term to the existing feedback loop if you prefer. Conceptually, the damping term would compare current and previous ranges to get an indication of speed and generate an output signal that tended to reduce that speed i.e. more lift if descending, less lift if rising. The final control output would be the proportional control value plus the damping control value.

PeterH:
This is common in systems with significant inertia and little inherent damping. You need a better control system than a simple proportional feedback. A PID controller would be one way to implement that, although there's nothing to stop you from just adding your own damping term to the existing feedback loop if you prefer. Conceptually, the damping term would compare current and previous ranges to get an indication of speed and generate an output signal that tended to reduce that speed i.e. more lift if descending, less lift if rising. The final control output would be the proportional control value plus the damping control value.

Thanks for the suggestion. That was exactly what I was thinking to do. I think, however, that the errors in the range is so great that simply comparing two ranges will give wildly varying speed estimate. So, what do you think is the best way to get more reliable speeds? Keeping a running average of the estimated speed? Comparing two ranges further apart in time? Comparing two averages of several ranges?

My original question have been answered, and I am moving a bit outside the topic of this forum section, so I guess I should start a new thread on this topic?