-1
tcommand=(pwm_value-480.0)/8.22;
flapmag=(pwm_value-880)/41.0+10;

In this piece of code used in arduino radio control aircraft, I don't understand why PWM value is subtracted and divided like this. This is not my code, it came from here. Any explanation would be of great help. I have read about PWM but all have different explanations.

//Arduino servo flap system
//copyright Steve Morris 10-25-16
#include <Servo.h>
volatile int pwm_value = 0;
volatile int prev_time = 0;
static int servo_comm1 = 0;
static int servo_comm2 = 0;
volatile int flapangle1 = 0;
volatile int flapangle2 = 0;
volatile int millisold = 0;
int millinow = 0;
float dt = 0;
float flapmag = 0;
static float flapdeg = 0;
float tcommand = 0;
float floattime = 0;
float temp = 0;
float glide_deg = -10.0;
static int pwm_value_temp = 0;
float omegadot = 0.0;
float thetadot = 0.0;
static float omega = 0.0;
static float theta = 0.0;
static float k0 = 1.0;
static float k2 = 10.0;
static float servo_zero1 = -4;
static float servo_zero2 = 0;

Servo myservo1, myservo2; // create servo object to control a servo

void setup() {
  //Serial.begin(115200);
  // when pin D2 goes high, call the rising function
  attachInterrupt(0, rising, RISING);
  myservo1.attach(5); // attaches the servo on pin 5 to the servo object
  myservo2.attach(6); // attaches the servo on pin 6 to the servo object
}
void loop() {

  millinow = millis();
  floattime = millinow / 1000.0;
  dt = (millinow - millisold) / 1000.0;
  millisold = millinow;

  tcommand = (pwm_value - 480.0) / 8.22;
  omegadot = k0 * tcommand - k2 * omega;
  thetadot = omega;
  flapdeg = sin(theta);
  theta = theta + omega * dt;
  omega = omega + omegadot * dt;

  flapmag = (pwm_value - 880) / 41.0 + 10;
  flapdeg = flapmag * sin(theta); //variable amplitude+freq


  flapangle1 = (int)((30.0 - flapdeg + servo_zero1) * 2.0 + 25.0);
  flapangle2 = (int)((30.0 + flapdeg + servo_zero2) * 2.0 + 25 .0);

  if (pwm_value > 930) {
    servo_comm1 = flapangle1;
    servo_comm2 = flapangle2;
  }

  //Glide Lock
  if (pwm_value < 910) {

    servo_comm1 = (int)((30.0 - glide_deg + servo_zero1) * 2.0 + 25.0);
    servo_comm2 = (int)((30.0 + glide_deg + servo_zero2) * 2.0 + 25.0);

  }

  myservo1.write(servo_comm1); // tell servo to go to position in variable 'pos'
  myservo2.write(servo_comm2); // tell servo to go to position in variable 'pos'

  //Serial.println(servo_comm1);
  //Serial.println(floattime);
  //Serial.println(dt);
  //Serial.println(flapangle);
  //Serial.println(flapdeg);
  //Serial.println(temp);
  //Serial.println(tcommand);
  //Serial.println(pwm_value);

}

void rising() {
  attachInterrupt(0, falling, FALLING);
  prev_time = micros();
}

void falling() {
  attachInterrupt(0, rising, RISING);
  pwm_value = micros() - prev_time;
}
0

1 Answer 1

5

There is not enough context to be certain, but given the variable names I can assume that this is code from a sketch that receives information from an RC controller and is intended to control parts of some form of flying craft.

So with that in mind, let's take this line:

flapmag=(pwm_value-880)/41.0+10;

I assume that this is to calculate the amount the flaps should be extended or retracted.

RC controllers, or rather the receivers that pick up the signals, usually output a PWM signal (square wave with a variable duty cycle) where the duty cycle is directly related to the position of the joystick.

A joystick is usually zero in the center and goes plus or minus for up and down (or right and left). But you can't have a negative PWM value, since that makes no sense (how can you have a signal that is off for less that 0% of the time?!). So the output is "offset" by a certain amount (that's not quite true - actually the joystick is 0 for fully down, and 100% for fully up, with "0" being somewhere in the middle, so the offset is applied by the joystick, not the receiver, but that really doesn't matter for us right now).

So we have a signal that is at any time somewhere between 0% and 100%, with "zero" being somewhere in the middle. What actual value the "100%" is, or exactly where "zero" is, can vary depending on many many factors, so we'll just use "100" for the maximum, and "50" for the middle "zero" offset.

The first thing you want to do, then, is remove that "zero" offset. And that is as simple as subtracting it. With our example numbers above, if you subtract the "zero" offset of "50" from the incoming signal it now goes between -50 and +50 instead of 0 and 100. That now relates much better to how a joystick appears - 0-50 in an upwards direction (+) and 0-50 in a downwards direction (-).

And that is exactly what is happening with pwm_value-880 in your code. The middle "zero" value of 880 is being subtracted from the incoming joystick position to give you an "up" or "down" value that is positive or negative respectively.

Next comes the division. This scales the incoming value to the right size for the device you are driving. In our example we have a ±50 signal. But what if our flaps require a ±10 signal to give the correct movement range. So simply dividing the value by 5 will change ±50 into ±10. That's exactly what the /41.0 is doing - scaling the result to fit the range of the target device.

Then there's one final +10 in there. This simply adds a small offset to the result. You can think of this as a "trim" value. It sets the actual "zero" point of the target device - in this case when the joystick is centered it means the flaps are set to a +10 position.

As to how the pwm_value itself is created, that is usually done through capturing the rising and falling edges of the incoming waveform from the receiver and timing how long the signal is in the HIGH or LOW state. That may be performed by some unspecified library.

1
  • Actually, this is what I was asking. Thanks for the information. Jan 24, 2020 at 18:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.