I've been writing some quad copter software and I am not sure what the best way is to map the throttle and PID inputs to ESC power.

My throttle range is 0-1 and my PID outputs are 0-1. My ESC's have a range of 1060us to 1860us.

I have mapped the motor speeds like this:

_motorPower[0] = map((_rcConstrainedCommands[3] + _ratePIDControllerOutputs[1] + _ratePIDControllerOutputs[2] + _ratePIDControllerOutputs[0]), 0.0, 4.0, 1060, 1860);
_motorPower[1] = map((_rcConstrainedCommands[3] + _ratePIDControllerOutputs[1] - _ratePIDControllerOutputs[2] - _ratePIDControllerOutputs[0]), 0.0, 4.0, 1060, 1860);
_motorPower[2] = map((_rcConstrainedCommands[3] - _ratePIDControllerOutputs[1] - _ratePIDControllerOutputs[2] + _ratePIDControllerOutputs[0]), 0.0, 4.0, 1060, 1860);
_motorPower[3] = map((_rcConstrainedCommands[3] - _ratePIDControllerOutputs[1] + _ratePIDControllerOutputs[2] - _ratePIDControllerOutputs[0]), 0.0, 4.0, 1060, 1860);

This works but if my quad is perfectly level (i.e. the PID outputs are 0) and I apply full throttle (1.0) then map this to ESC power I will only get quarter power (1260us).

How should I be doing this so that if my throttle is on max then I get max power? If my throttle is half (0.5) then I should get half power plus the PID values etc.

Can anyone help me with this?

Thanks Joe

  • Maybe this question means something to somebody, but without context, those function calls are a bit meaningless? – Andrew Apr 16 '14 at 19:04
  • float map(float x, float in_min, float in_max, float out_min, float out_max); // In his example, takes the value of x, and linearly re-maps it from the range [0..4] to the range [1060..1860]. – Rocketmagnet Apr 25 '14 at 15:46
up vote 2 down vote accepted

For each motor the output should be:

  • A value at which the power from the 4 motors roughly keeps the quadcopter airborne, for instance 1500ms.
  • Plus or minus the influence of the throttle. For instance with your throttle is in the 0:1 range you could apply 600 * (throttle - 0.5), which will put the motors output in the 1200:1800ms range.
  • Plus or minus the PIDs output. For instance with your PIDs in the 0:1 range you could add 200 * (PID - 0.5). The individual PID contribution would be in the -100:100 range. For a +4 configuration there are 2 PIDs to add for each motor, so the output would be in the 1000:2000ms range.

Here is my unmodified code for this. My throttle is in the -100:100 range, and my PIDs are already in the appropriate range. I'm sure you can translate to your own specifications easily.

uint16_t motor[4];
float base = MOTOR_IDLE + (THROTTLE_K * throttle);
motor[MOTOR_FRONT] = base + pitchRatePID.getControl() - yawRatePID.getControl();
motor[MOTOR_LEFT] = base + rollRatePID.getControl() + yawRatePID.getControl();
motor[MOTOR_BACK] = base - pitchRatePID.getControl() - yawRatePID.getControl();
motor[MOTOR_RIGHT] = base - rollRatePID.getControl() + yawRatePID.getControl();

The THROTTLE_K constant would be what to modify if I experienced your problem.

As you realise the possible motors output exceeds the ESC range, which is evil. Bounding the output is not an elegant way to do it as it will trip up your PIDs computations. A better way which maintains the speed ratios between the motors is the add or remove a constant to all the motors to get all the outputs back within the bounds. Here is a sample from my own code, I hope it makes sense.

// Fix motor mix range
int16_t motorFix = 0;
uint16_t motorMin = motor[0], motorMax = motor[0];
for(int i=1 ; i<4 ; i++)
{
  if(motor[i] < motorMin) motorMin = motor[i];
  if(motor[i] > motorMax) motorMax = motor[i];
}
if(motorMin < MOTOR_MIN) motorFix = MOTOR_MIN - motorMin;
else if(motorMax > MOTOR_MAX) motorFix = MOTOR_MAX - motorMax;

// Refresh motors
for(int i=0 ; i<4 ; i++) Servo::setChannel(i, motor[i] + motorFix);

I hope this helps, please let me know if you need further clarifications!

  • At the moment I am bounding the motor output. The method you have described makes sense, I will try to implement it. Thanks for your answer. – Joseph Roberts May 16 '14 at 14:43
  • Hi, I'm unsure about the throttle part. My throttle is between -1 and 1 and from what you say I should be trying to achieve the full throttle range of 1100 - 1800. Does this mean my formula to work out the throttle base would be 1450 + (350 * throttle)? I have an X config quad so I have 3 PID's for each motor. They output between -1 and 1. For each of these should the formula be 100 * PIDValue? Does this sound correct? – Joseph Roberts May 21 '14 at 7:58
  • @JosephBaldwinRoberts, 3 PIDs per motor is correct for a X setup. If you bound your PIDs -which I didn't do- you need to make sure you use an appropriate technique (back calculation, etc). The throttle formula I recommend is A + B * throttle indeed. A = 1450 and B = 350 are fine values, but you could use other values of A if the quadcopter ascends/descends when the throttle stick is centered, and other values of B if the quadcopter ascends/descends too fast when moving the throttle stick. – marcv81 May 22 '14 at 11:16

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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