Skip to content
Snippets Groups Projects
firmware_modifications_for_version_2020-02.patch 22 KiB
Newer Older
diff --git a/src/modules/interface/attitude_controller.h b/src/modules/interface/attitude_controller.h
index fe25dc0..fd69bdc 100644
--- a/src/modules/interface/attitude_controller.h
+++ b/src/modules/interface/attitude_controller.h
@@ -63,6 +63,11 @@ void attitudeControllerResetRollAttitudePID(void);
  */
 void attitudeControllerResetPitchAttitudePID(void);
 
+/**
+ * Reset controller yaw attitude PID
+ */
+void attitudeControllerResetYawAttitudePID(void);
+
 /**
  * Reset controller roll, pitch and yaw PID's.
  */
diff --git a/src/modules/interface/stabilizer_types.h b/src/modules/interface/stabilizer_types.h
--- a/src/modules/interface/stabilizer_types.h
+++ b/src/modules/interface/stabilizer_types.h
@@ -159,6 +159,10 @@ typedef struct control_s {
   int16_t pitch;
   int16_t yaw;
   float thrust;
+  uint16_t cmd1;
+  uint16_t cmd2;
+  uint16_t cmd3;
+  uint16_t cmd4;
 } control_t;
 
 typedef enum mode_e {
@@ -174,11 +178,17 @@ typedef struct setpoint_s {
   attitude_t attitudeRate;  // deg/s
   quaternion_t attitudeQuaternion;
   float thrust;
+  uint16_t cmd1;
+  uint16_t cmd2;
+  uint16_t cmd3;
+  uint16_t cmd4;
   point_t position;         // m
   velocity_t velocity;      // m/s
   acc_t acceleration;       // m/s^2
   bool velocity_body;       // true if velocity is given in body frame; false if velocity is given in world frame
 
+  bool useDfallAdjustmentsToControllerPID;
+
   struct {
     stab_mode_t x;
     stab_mode_t y;
diff --git a/src/modules/src/attitude_pid_controller.c b/src/modules/src/attitude_pid_controller.c
index b7d707e..bcb02bc 100644
--- a/src/modules/src/attitude_pid_controller.c
+++ b/src/modules/src/attitude_pid_controller.c
@@ -145,6 +145,11 @@ void attitudeControllerResetPitchAttitudePID(void)
     pidReset(&pidPitch);
 }
 
+void attitudeControllerResetYawAttitudePID(void)
+{
+    pidReset(&pidYaw);
+}
+
 void attitudeControllerResetAllPID(void)
 {
   pidReset(&pidRoll);
diff --git a/src/modules/src/controller_pid.c b/src/modules/src/controller_pid.c
--- a/src/modules/src/controller_pid.c
+++ b/src/modules/src/controller_pid.c
@@ -132,6 +132,9 @@ void controllerPid(control_t *control, setpoint_t *setpoint,
     control->thrust = actuatorThrust;
   }
 
+  // The following "if (control->thrust == 0)" block is commented
+  // out because it is replaced with what follows after.
+  /*
   if (control->thrust == 0)
   {
     control->thrust = 0;
@@ -150,6 +153,92 @@ void controllerPid(control_t *control, setpoint_t *setpoint,
     // Reset the calculated YAW angle for rate control
     attitudeDesired.yaw = state->attitude.yaw;
   }
+  */
+
+  // The following "if:then:else" statements is used to
+  // specify the "control->cmd{1,2,3,4}" depending on
+  // the boolean:
+  // >> "setpoint->useDfallAdjustmentsToControllerPID"
+  if (setpoint->useDfallAdjustmentsToControllerPID)
+  {
+    // Set the {roll,pitch,yaw} commands to zero
+    // if indicated by the respective mode
+    if (setpoint->mode.roll == modeDisable)
+    if (setpoint->mode.pitch == modeDisable)
+    {
+      control->pitch = 0;
+      cmd_pitch = 0.0;
+    }
+    if (setpoint->mode.yaw == modeDisable)
+    {
+      control->yaw = 0;
+      cmd_yaw = 0.0;
+    }
+    // Apply the per-motor commands differently
+    // depending on the Z-controller mode
+    if (setpoint->mode.z == modeDisable)
+      // Copy across the per motor commands
+      control->cmd1 = setpoint->cmd1;
+      control->cmd2 = setpoint->cmd2;
+      control->cmd3 = setpoint->cmd3;
+      control->cmd4 = setpoint->cmd4;
+    }
+    else
+    {
+      // Add the setpoints on top of the
+      // "control thrust" computed by the
+      // PID controllers above
+      control->cmd1 = setpoint->cmd1 + control->thrust;
+      control->cmd2 = setpoint->cmd2 + control->thrust;
+      control->cmd3 = setpoint->cmd3 + control->thrust;
+      control->cmd4 = setpoint->cmd4 + control->thrust;
+  // Otherwise, "setpoint->useDfallAdjustmentsToControllerPID == false"
+  else
+  {
+    // Put the thrust value onto each motor
+    control->cmd1 = control->thrust;
+    control->cmd2 = control->thrust;
+    control->cmd3 = control->thrust;
+    control->cmd4 = control->thrust;
+  }
+
+  // If all control commands are zero, i.e., if:
+  // >> "control->cmd{1,2,3,4}==0"
+  // then set all commands to zero and to reset
+  // all PIDs.
+  bool isZeroThrust = ((control->cmd1 == 0 && control->cmd2 == 0 && control->cmd3 == 0 && control->cmd4 == 0));
+  if (isZeroThrust)
+  {
+    // Set all commands to zero
+    control->cmd1 = 0;
+    control->cmd2 = 0;
+    control->cmd3 = 0;
+    control->cmd4 = 0;
+    control->thrust = 0;
+    control->roll = 0;
+    control->pitch = 0;
+    control->yaw = 0;
+
+    // Reset all PIDs
+    attitudeControllerResetAllPID();
+    positionControllerResetAllPID();
+
+    // Reset the calculated YAW angle for rate control
+    attitudeDesired.yaw = state->attitude.yaw;
+
+    // Update also the log variables to reflect this
+    cmd_thrust = 0.0;
+    cmd_roll = 0.0;
+    cmd_pitch = 0.0;
+    cmd_yaw = 0.0;
+  }
 }
 
 
diff --git a/src/modules/src/crtp_commander_generic.c b/src/modules/src/crtp_commander_generic.c
--- a/src/modules/src/crtp_commander_generic.c
+++ b/src/modules/src/crtp_commander_generic.c
   hoverType         = 5,
   fullStateType     = 6,
   positionType      = 7,
 };
 
 /* ---===== 2 - Decoding functions =====--- */
@@ -112,6 +113,9 @@ static void velocityDecoder(setpoint_t *setpoint, uint8_t type, const void *data
   setpoint->mode.yaw = modeVelocity;
 
   setpoint->attitudeRate.yaw = -values->yawrate;
+
+  // Turn off the "dfall mode adjustments"
+  setpoint->useDfallAdjustmentsToControllerPID = false;
 /* zDistanceDecoder
@@ -145,6 +149,9 @@ static void zDistanceDecoder(setpoint_t *setpoint, uint8_t type, const void *dat
 
   setpoint->attitude.roll = values->roll;
   setpoint->attitude.pitch = values->pitch;
+  // Turn off the "dfall mode adjustments"
+  setpoint->useDfallAdjustmentsToControllerPID = false;
 }
 
 /* cppmEmuDecoder
@@ -230,6 +237,9 @@ static void cppmEmuDecoder(setpoint_t *setpoint, uint8_t type, const void *data,
   {
     setpoint->thrust = 0;
   }
+  // Turn off the "dfall mode adjustments"
+  setpoint->useDfallAdjustmentsToControllerPID = false;
 }
 
 /* altHoldDecoder
@@ -263,6 +273,9 @@ static void altHoldDecoder(setpoint_t *setpoint, uint8_t type, const void *data,
 
   setpoint->attitude.roll = values->roll;
   setpoint->attitude.pitch = values->pitch;
+  // Turn off the "dfall mode adjustments"
+  setpoint->useDfallAdjustmentsToControllerPID = false;
 }
 
 /* hoverDecoder
@@ -294,6 +307,9 @@ static void hoverDecoder(setpoint_t *setpoint, uint8_t type, const void *data, s
   setpoint->velocity.y = values->vy;
 
   setpoint->velocity_body = true;
+  // Turn off the "dfall mode adjustments"
+  setpoint->useDfallAdjustmentsToControllerPID = false;
 }
 
 struct fullStatePacket_s {
@@ -338,6 +354,9 @@ static void fullStateDecoder(setpoint_t *setpoint, uint8_t type, const void *dat
   setpoint->mode.roll = modeDisable;
   setpoint->mode.pitch = modeDisable;
   setpoint->mode.yaw = modeDisable;
+
+  // Turn off the "dfall mode adjustments"
+  setpoint->useDfallAdjustmentsToControllerPID = false;
 }
 
 /* positionDecoder
@@ -365,6 +384,313 @@ static void positionDecoder(setpoint_t *setpoint, uint8_t type, const void *data
   setpoint->mode.yaw = modeAbs;
 
   setpoint->attitude.yaw = values->yaw;
+  // Turn off the "dfall mode adjustments"
+  setpoint->useDfallAdjustmentsToControllerPID = false;
+/* dfall mode decoder
+ * set the mode of the onboard {x,y,z,roll,pitch,yaw}
+ * controllers based on the mode specification
+ * contained in the packet. A separate mode is
+ * specified for each of the four independent
+ * coordinates of {x,y,z,yaw}
+#define DFALL_CONTROLLER_MODE_OFF            0
+#define DFALL_CONTROLLER_MODE_ANGULAR_RATE   1
+#define DFALL_CONTROLLER_MODE_ANGLE          2
+#define DFALL_CONTROLLER_MODE_VELOCITY       3
+#define DFALL_CONTROLLER_MODE_POSITION       4
+struct dfallPacket_s {
+    uint16_t controllerModes;
+    uint16_t cmd1;
+    uint16_t cmd2;
+    uint16_t cmd3;
+    uint16_t cmd4;
+    float xControllerSetpoint;
+    float yControllerSetpoint;
+    float zControllerSetpoint;
+    float yawControllerSetpoint;
+static void dfallDecoder(setpoint_t *setpoint, uint8_t type, const void *data, size_t datalen)
+  const struct dfallPacket_s *values = data;
+  ASSERT(datalen == sizeof(struct dfallPacket_s));
+
+  // DECODE THE 16-BIT INTEGER THAT ENCODES
+  // THE REQUESTED {x,y,z,yaw} CONTROLLER MODES
+  // > Each mode is encoded using 3 bits, stacked together as follows:
+  // ---------------------------------------------------------------
+  // |BIT   | 15 14 13 12 | 11 10  9 | 8  7  6 | 5  4  3 | 2  1  0 |
+  // |DESC. | free bits   | yaw_mode | z_mode  | y_mode  | x_mode  |
+  // ---------------------------------------------------------------
+
+  uint16_t mode_selector_bits = 7;
+
+  // EXTRACT THE MODE FOR EACH CONTROLLER
+  uint8_t x_controller_mode   = (values->controllerModes >> 0) & mode_selector_bits;
+  uint8_t y_controller_mode   = (values->controllerModes >> 3) & mode_selector_bits;
+  uint8_t z_controller_mode   = (values->controllerModes >> 6) & mode_selector_bits;
+  uint8_t yaw_controller_mode = (values->controllerModes >> 9) & mode_selector_bits;
+
+  // INITIALISE A BOOLEAN FOR TRACKING IF ANY
+  // OF THE CONTROLLER MODES ARE INVALID
+  bool invalid_controller_mode_requested = false;
+
+  // PROCESS THE X CONTROLLER
+  switch (x_controller_mode)
+  {
+    case DFALL_CONTROLLER_MODE_ANGULAR_RATE:
+      // Set the modes
+      setpoint->mode.x     = modeDisable;
+      setpoint->mode.pitch = modeVelocity;
+      // Set the setpoint
+      setpoint->position.x         = 0.0;
+      setpoint->velocity.x         = 0.0;
+      setpoint->attitude.pitch     = 0.0;
+      setpoint->attitudeRate.pitch = values->xControllerSetpoint;
+      break;
+
+    case DFALL_CONTROLLER_MODE_ANGLE:
+      // Set the modes
+      setpoint->mode.x     = modeDisable;
+      setpoint->mode.pitch = modeAbs;
+      // Set the setpoints
+      setpoint->position.x         = 0.0;
+      setpoint->velocity.x         = 0.0;
+      setpoint->attitude.pitch     = values->xControllerSetpoint;
+      setpoint->attitudeRate.pitch = 0.0;
+      break;
+
+    case DFALL_CONTROLLER_MODE_VELOCITY:
+      // Set the modes
+      setpoint->mode.x     = modeVelocity;
+      setpoint->mode.pitch = modeAbs;
+      // Set the setpoints
+      setpoint->position.x         = 0.0;
+      setpoint->velocity.x         = values->xControllerSetpoint;
+      setpoint->attitude.pitch     = 0.0;
+      setpoint->attitudeRate.pitch = 0.0;
+      break;
+
+    case DFALL_CONTROLLER_MODE_POSITION:
+      // Set the modes
+      setpoint->mode.x     = modeAbs;
+      setpoint->mode.pitch = modeAbs;
+      // Set the setpoints
+      setpoint->position.x         = values->xControllerSetpoint;
+      setpoint->velocity.x         = 0.0;
+      setpoint->attitude.pitch     = 0.0;
+      setpoint->attitudeRate.pitch = 0.0;
+      break;
+
+    case DFALL_CONTROLLER_MODE_OFF:
+      // Set the modes
+      setpoint->mode.x     = modeDisable;
+      setpoint->mode.pitch = modeDisable;
+      // Set the setpoints
+      setpoint->position.x         = 0.0;
+      setpoint->velocity.x         = 0.0;
+      setpoint->attitude.pitch     = 0.0;
+      setpoint->attitudeRate.pitch = 0.0;
+      break;
+
+    default:
+      // Set the flag that an invalid mode
+      // was requested
+      invalid_controller_mode_requested = true;
+      break;
+  }
+
+  // PROCESS THE Y CONTROLLER
+  switch (y_controller_mode)
+  {
+    case DFALL_CONTROLLER_MODE_ANGULAR_RATE:
+      // Set the modes
+      setpoint->mode.y    = modeDisable;
+      setpoint->mode.roll = modeVelocity;
+      // Set the setpoint
+      setpoint->position.y        = 0.0;
+      setpoint->velocity.y        = 0.0;
+      setpoint->attitude.roll     = 0.0;
+      setpoint->attitudeRate.roll = values->yControllerSetpoint;
+      break;
+
+    case DFALL_CONTROLLER_MODE_ANGLE:
+      // Set the modes
+      setpoint->mode.y    = modeDisable;
+      setpoint->mode.roll = modeAbs;
+      // Set the setpoints
+      setpoint->position.y        = 0.0;
+      setpoint->velocity.y        = 0.0;
+      setpoint->attitude.roll     = values->yControllerSetpoint;
+      setpoint->attitudeRate.roll = 0.0;
+      break;
+
+    case DFALL_CONTROLLER_MODE_VELOCITY:
+      // Set the modes
+      setpoint->mode.y    = modeVelocity;
+      setpoint->mode.roll = modeAbs;
+      // Set the setpoints
+      setpoint->position.y        = 0.0;
+      setpoint->velocity.y        = values->yControllerSetpoint;
+      setpoint->attitude.roll     = 0.0;
+      setpoint->attitudeRate.roll = 0.0;
+      break;
+
+    case DFALL_CONTROLLER_MODE_POSITION:
+      // Set the modes
+      setpoint->mode.y    = modeAbs;
+      setpoint->mode.roll = modeAbs;
+      // Set the setpoints
+      setpoint->position.y        = values->yControllerSetpoint;
+      setpoint->velocity.y        = 0.0;
+      setpoint->attitude.roll     = 0.0;
+      setpoint->attitudeRate.roll = 0.0;
+      break;
+
+    case DFALL_CONTROLLER_MODE_OFF:
+      // Set the modes
+      setpoint->mode.y    = modeDisable;
+      setpoint->mode.roll = modeDisable;
+      // Set the setpoints
+      setpoint->position.y        = 0.0;
+      setpoint->velocity.y        = 0.0;
+      setpoint->attitude.roll     = 0.0;
+      setpoint->attitudeRate.roll = 0.0;
+      break;
+
+    default:
+      // Set the flag that an invalid mode
+      // was requested
+      invalid_controller_mode_requested = true;
+      break;
+  }
+
+  // PROCESS THE Z CONTROLLER
+  switch (z_controller_mode)
+  {
+    case DFALL_CONTROLLER_MODE_VELOCITY:
+      // Set the mode
+      setpoint->mode.z = modeVelocity;
+      // Set the setpoints
+      setpoint->position.z = 0.0;
+      setpoint->velocity.z = values->zControllerSetpoint;
+      break;
+
+    case DFALL_CONTROLLER_MODE_POSITION:
+      // Set the mode
+      setpoint->mode.z = modeAbs;
+      // Set the setpoints
+      setpoint->position.z = values->zControllerSetpoint;
+      setpoint->velocity.z = 0.0;
+      break;
+
+    case DFALL_CONTROLLER_MODE_OFF:
+      // Set the mode
+      setpoint->mode.z = modeDisable;
+      // Set the setpoints
+      setpoint->position.z = 0.0;
+      setpoint->velocity.z = 0.0;
+      break;
+
+    case DFALL_CONTROLLER_MODE_ANGULAR_RATE:
+    case DFALL_CONTROLLER_MODE_ANGLE:
+    default:
+      // Set the flag that an invalid mode
+      // was requested
+      invalid_controller_mode_requested = true;
+      break;
+  }
+  // PROCESS THE YAW CONTROLLER
+  switch (yaw_controller_mode)
+  {
+    case DFALL_CONTROLLER_MODE_ANGULAR_RATE:
+      // Set the mode
+      setpoint->mode.yaw = modeVelocity;
+      // Set the setpoint
+      setpoint->attitude.yaw     = 0.0;
+      setpoint->attitudeRate.yaw = values->yawControllerSetpoint;
+      break;
+
+    case DFALL_CONTROLLER_MODE_ANGLE:
+      // Set the modes
+      setpoint->mode.yaw = modeAbs;
+      // Set the setpoints
+      setpoint->attitude.roll     = values->yawControllerSetpoint;
+      setpoint->attitudeRate.roll = 0.0;
+      break;
+
+    case DFALL_CONTROLLER_MODE_OFF:
+      // Set the modes
+      setpoint->mode.yaw = modeDisable;
+      // Set the setpoints
+      setpoint->attitude.yaw     = 0.0;
+      setpoint->attitudeRate.yaw = 0.0;
+      break;
+
+    case DFALL_CONTROLLER_MODE_VELOCITY:
+    case DFALL_CONTROLLER_MODE_POSITION:
+    default:
+      // Set the flag that an invalid mode
+      // was requested
+      invalid_controller_mode_requested = true;
+      break;
+  }
+  setpoint->thrust = 0;
+
+  // Tranfer the per-motor commands from the packet
+  // to the respective setpoints
+  // NOTES:
+  // (1) this is performed regardless of the
+  //     "z_controller_mode" because the per motor
+  //     commands can be used for correcting steady-
+  //     state offsets in {x,y,yaw}.
+  // (2) if the "z_controller_mode" is in "POSITION"
+  //     or "VELOCITY" mode, then onboard controllers
+  //     will compute the main thurst controler, and
+  //     the user is expected to fill in cmd{1,2,3,4}
+  //     with only adjustment values.
+  setpoint->cmd1 = limitUint16(values->cmd1);
+  setpoint->cmd2 = limitUint16(values->cmd2);
+  setpoint->cmd3 = limitUint16(values->cmd3);
+  setpoint->cmd4 = limitUint16(values->cmd4);
+
+  // Set everything to off and zero if an invlaid
+  // controller mode was requested
+  if (invalid_controller_mode_requested)
+  {
+    // Set the modes
+    setpoint->mode.x     = modeDisable;
+    setpoint->mode.pitch = modeDisable;
+    setpoint->mode.y     = modeDisable;
+    setpoint->mode.roll  = modeDisable;
+    setpoint->mode.z     = modeDisable;
+    setpoint->mode.yaw   = modeDisable;
+
+    // Set the setpoints
+    setpoint->position.x         = 0.0;
+    setpoint->velocity.x         = 0.0;
+    setpoint->attitude.pitch     = 0.0;
+    setpoint->attitudeRate.pitch = 0.0;
+    setpoint->position.y         = 0.0;
+    setpoint->velocity.y         = 0.0;
+    setpoint->attitude.roll      = 0.0;
+    setpoint->attitudeRate.roll  = 0.0;
+    setpoint->position.z         = 0.0;
+    setpoint->velocity.z         = 0.0;
+    setpoint->attitude.yaw       = 0.0;
+    setpoint->attitudeRate.yaw   = 0.0;
+  }
+  // Turn on the "dfall mode adjustments"
+  setpoint->useDfallAdjustmentsToControllerPID = true;
 }
 
  /* ---===== 3 - packetDecoders array =====--- */
@@ -377,6 +703,7 @@ const static packetDecoder_t packetDecoders[] = {
   [hoverType]         = hoverDecoder,
   [fullStateType]     = fullStateDecoder,
   [positionType]      = positionDecoder,
 };
 
 /* Decoder switch */
diff --git a/src/modules/src/power_distribution_stock.c b/src/modules/src/power_distribution_stock.c
--- a/src/modules/src/power_distribution_stock.c
+++ b/src/modules/src/power_distribution_stock.c
@@ -80,18 +80,18 @@ void powerDistribution(const control_t *control)
   #ifdef QUAD_FORMATION_X
     int16_t r = control->roll / 2.0f;
     int16_t p = control->pitch / 2.0f;
-    motorPower.m1 = limitThrust(control->thrust - r + p + control->yaw);
-    motorPower.m2 = limitThrust(control->thrust - r - p - control->yaw);
-    motorPower.m3 =  limitThrust(control->thrust + r - p + control->yaw);
-    motorPower.m4 =  limitThrust(control->thrust + r + p - control->yaw);
+    motorPower.m1 = limitThrust(control->cmd1 - r + p + control->yaw);
+    motorPower.m2 = limitThrust(control->cmd2 - r - p - control->yaw);
+    motorPower.m3 = limitThrust(control->cmd3 + r - p + control->yaw);
+    motorPower.m4 = limitThrust(control->cmd4 + r + p - control->yaw);
   #else // QUAD_FORMATION_NORMAL
-    motorPower.m1 = limitThrust(control->thrust + control->pitch +
+    motorPower.m1 = limitThrust(control->cmd1 + control->pitch +
                                control->yaw);
-    motorPower.m2 = limitThrust(control->thrust - control->roll -
+    motorPower.m2 = limitThrust(control->cmd2 - control->roll -
                                control->yaw);
-    motorPower.m3 =  limitThrust(control->thrust - control->pitch +
+    motorPower.m3 = limitThrust(control->cmd3 - control->pitch +
                                control->yaw);
-    motorPower.m4 =  limitThrust(control->thrust + control->roll -
+    motorPower.m4 = limitThrust(control->cmd4 + control->roll -
                                control->yaw);
   #endif
 
@@ -117,11 +117,11 @@ PARAM_ADD(PARAM_UINT16, m1, &motorPowerSet.m1)
 PARAM_ADD(PARAM_UINT16, m2, &motorPowerSet.m2)
 PARAM_ADD(PARAM_UINT16, m3, &motorPowerSet.m3)
 PARAM_ADD(PARAM_UINT16, m4, &motorPowerSet.m4)
-PARAM_GROUP_STOP(ring)
+PARAM_GROUP_STOP(motorPowerSet)
 
 LOG_GROUP_START(motor)
-LOG_ADD(LOG_INT32, m4, &motorPower.m4)
 LOG_ADD(LOG_INT32, m1, &motorPower.m1)
 LOG_ADD(LOG_INT32, m2, &motorPower.m2)
 LOG_ADD(LOG_INT32, m3, &motorPower.m3)
+LOG_ADD(LOG_INT32, m4, &motorPower.m4)
 LOG_GROUP_STOP(motor)
diff --git a/src/modules/src/stabilizer.c b/src/modules/src/stabilizer.c
index 372ec94..cb4f848 100644
--- a/src/modules/src/stabilizer.c
+++ b/src/modules/src/stabilizer.c
@@ -92,6 +92,10 @@ static struct {
   int16_t ax;
   int16_t ay;
   int16_t az;
+  // attitude - milliradians
+  int16_t roll;
+  int16_t pitch;
+  int16_t yaw;
   // compressed quaternion, see quatcompress.h
   int32_t quat;
   // angular velocity - milliradians / sec
@@ -151,6 +155,11 @@ static void compressState()
   stateCompressed.ay = state.acc.y * 9.81f * 1000.0f;
   stateCompressed.az = (state.acc.z + 1) * 9.81f * 1000.0f;
 
+  float const deg2millirad = ((float)M_PI * 1000.0f) / 180.0f;
+  stateCompressed.roll = state.attitude.roll * deg2millirad;
+  stateCompressed.pitch = state.attitude.pitch * deg2millirad;
+  stateCompressed.yaw = state.attitude.yaw * deg2millirad;
+
   float const q[4] = {
     state.attitudeQuaternion.x,
     state.attitudeQuaternion.y,
@@ -158,7 +167,7 @@ static void compressState()
     state.attitudeQuaternion.w};
   stateCompressed.quat = quatcompress(q);
 
-  float const deg2millirad = ((float)M_PI * 1000.0f) / 180.0f;
+  //float const deg2millirad = ((float)M_PI * 1000.0f) / 180.0f;
   stateCompressed.rateRoll = sensorData.gyro.x * deg2millirad;
   stateCompressed.ratePitch = -sensorData.gyro.y * deg2millirad;
   stateCompressed.rateYaw = sensorData.gyro.z * deg2millirad;
@@ -670,6 +679,10 @@ LOG_ADD(LOG_INT16, ax, &stateCompressed.ax)               // acceleration - mm /
 LOG_ADD(LOG_INT16, ay, &stateCompressed.ay)
 LOG_ADD(LOG_INT16, az, &stateCompressed.az)
 
+LOG_ADD(LOG_INT16, roll, &stateCompressed.roll)           // attitude - milliradians
+LOG_ADD(LOG_INT16, pitch, &stateCompressed.pitch)
+LOG_ADD(LOG_INT16, yaw, &stateCompressed.yaw)
+
 LOG_ADD(LOG_UINT32, quat, &stateCompressed.quat)           // compressed quaternion, see quatcompress.h
 
 LOG_ADD(LOG_INT16, rateRoll, &stateCompressed.rateRoll)   // angular velocity - milliradians / sec