Quadcopter: RC Signals to Motor speeds

Hi Everyone!

I’ve hit a snag programming my quadcopter. I’ve finally got my bits together, and I can read in the transmitter signals with no problem. My issue is with translating these signals to control the speeds.

I’ve attached what I have so far. This is by no means the final version. All I’m trying to do with this program is lower the speeds of the motors that will tilt the copter in the direction I want to go. Later I plan to make adjustments for stability, more control, etc… at the moment the thing is tied down to a table :roll_eyes:

Heres whats up: As I more the right stick up, the right motors reduce their speed value, which is supposed to happen, but as I move the stick left, the left motor value resets to the original throttle value and starts to count down again.

What I need is something to interpret two axis and give the appropriate motor the right value. My current thinking is that I could read the values of two axis’ and use the lowest (or greatest) for the motor, but that seems like an inefficient way and might cause me headaches down the road when it comes to tweaking/tuning.

I’m not asking for the code to be done for me. The would go against the point of me building this from scratch :). I’m just looking for some direction or ideas. I’ve attached all my code to this post.

Thanks in advance.

ChannelClass.cpp (1021 Bytes)

ChannelClass.h (462 Bytes)

Draft_3.ino (4.3 KB)

MotorClass.cpp (934 Bytes)

MotorClass.h (432 Bytes)

MotorFunctions.ino (1.33 KB)

PinChangeInt.cpp (10.5 KB)

PinChangeInt.h (11 KB)

    if (channels[2].throttleOut()>=770 && channels[2].throttleOut()<=650)

This can never be true. You probably wanted || in place of &&.

Here is your mistake:

void Motor::control(int variance)
{
  if (variance+_fixedOffset <= _variance+RESOLUTION || variance+_fixedOffset >= _variance+RESOLUTION)
  {
    _ESC.writeMicroseconds(_throttle+variance+_fixedOffset);
    _variance = variance+_fixedOffset;
    _status = _throttle+_variance;  
  }
}

You call speedAdjust() to set throttle and then call control() for each axis. The control() function is written to override any existing variance and act independently on throttle. You should set the _variance to 0 when you run speedAdjust() and have control() MODIFY the existing _variance. That way the controls are cumulative rather than the last one having precedence over the previous ones.

johnwasser:
You call speedAdjust() to set throttle and then call control() for each axis. The control() function is written to override any existing variance and act independently on throttle. You should set the _variance to 0 when you run speedAdjust() and have control() MODIFY the existing _variance. That way the controls are cumulative rather than the last one having precedence over the previous ones.

If I set _variance to 0 everytime speedAdjust() is called then I am erasing any axis information currently stored. My thinking in seperating the throttle and axis functions was so I can do operations on the offset (axis control) and throttle control independantly. I’m not sure how I can modify the _variance when I try to say pitch and yaw at the same time. I came up with this included in the main loop:

//------------------------------------PITCH CONTROL
  if (channels[0].reading() > 0 && -motors[0].variance() < channels[0].reading() && motors[3].variance() < channels[0].reading())
  {
    tempPitch = channels[0].reading();
    motors[0].control(-tempPitch);
    motors[3].control(tempPitch);
  }
  else if (channels[0].reading() < 0 && motors[0].variance() > channels[0].reading() && -motors[3].variance() >> channels[0].reading())
  {
    tempPitch = channels[0].reading();
    motors[0].control(-tempPitch);
    motors[3].control(tempPitch);
  }
//------------------------------------ENDPITCH CONTROL

//------------------------------------YAW CONTROL
  if (channels[1].reading() > 0)
  {
    tempYaw = channels[1].reading();
    if (tempYaw > motors[0].variance()) {motors[0].control(tempYaw);}
    
    if (-tempYaw < motors[1].variance()) {motors[1].control(-tempYaw);}
    
    if (-tempYaw < motors[2].variance()) {motors[2].control(-tempYaw);}
    
    if (tempYaw > motors[3].variance()) {motors[3].control(tempYaw);}
  }
  else if (channels[1].reading() < 0)
  {
    tempYaw = channels[1].reading();
    if (tempYaw < motors[0].variance()) {motors[0].control(tempYaw);}
    
    if (-tempYaw > motors[1].variance()) {motors[1].control(-tempYaw);}
    
    if (-tempYaw > motors[2].variance()) {motors[2].control(-tempYaw);}
    
    if (tempYaw < motors[3].variance()) {motors[3].control(tempYaw);}
  }
//------------------------------------ENDYAW CONTROL

This will slow down the appropriate motors, but when the stick is returned to centre, the values do not follow the returning movement, and it waits for the stick to move in the opposite direction before the values reset.
I get the feeling I need some clever mathematics to interpret each value and spit out a single control value. Unfortunately maths was never something I excelled in :frowning:

I’ll keep googling :smiley:

Oh and nice spot on the &&. Changed it to OR. Thanks!

How about something like:

void loop() {
  int pitch = channels[0].reading();
  int yaw = channels[1].reading();
  int throttle = channels[2].throttleOut();
  int roll = channels[3].reading();
 // int knobLeft = channels[4].reading();
 // int knobRight = channels[5].reading();
  int control[4];

  for (int i=0;i<4;i++) {   
    motors[i].speedAdjust(throttle);
    control[i] = 0;
  }

  // Channel 0: Pitch
  // Front motors faster for pitch up
    control[0] += pitch;
    control[1] += pitch;
  // Rear motors slower for pitch up
    control[2] -= pitch;
    control[3] -= pitch;

   // Channel 1: Yaw
   // CW motors faster for yaw right
    control[0] += yaw;
    control[3] += yaw;
   // CCW motors slower for yaw right
    control[1] -= yaw;
    control[2] -= yaw;

  // Channel 3: Roll
   // Left motors faster for roll right
    control[1] += roll;
    control[3] += roll;
   // Right motors slower for roll right
    control[0] -= roll;
    control[2] -= roll;

  for (int i=0;i<4;i++) {   
    motors[i].control(control[i]);
  }

or even simpler:

  int pitch = channels[0].reading();
  int yaw = channels[1].reading();
  int throttle = channels[2].throttleOut();
  int roll = channels[3].reading();
  //int knobLeft = channels[4].reading();
  //int knobRight = channels[5].reading();

  for (int i=0;i<4;i++) {   
    motors[i].speedAdjust(throttle);
  }

  motor[0].control( pitch +yaw -roll);
  motor[1].control( pitch -yaw +roll);
  motor[2].control(-pitch -yaw -roll);
  motor[3].control(-pitch +yaw +roll);

Dude that's awesome. I knew the answer would be deceptively simple. I'll give that a go now and hopefully I can untie the thing and have a go around my living room before the end of the day :smiley:

Thanks a lot for your help.