LCOV - code coverage report
Current view: top level - controller - FeedbackController.h Hit Total Coverage
Test: doc-coverage.info Lines: 12 13 92.3 %
Date: 2026-04-20 18:26:22

          Line data    Source code
       1             : #ifndef CONTROLS_CONTROLLER_FEEDBACK_CONTROLLER_H
       2             : #define CONTROLS_CONTROLLER_FEEDBACK_CONTROLLER_H
       3             : 
       4             : #include <controller/BaseControllerInterface.h>
       5             : 
       6             : /**
       7             :  * @brief PID feedback controller with anti-windup integral clamping
       8             :  *
       9             :  * Computes proportional, integral, and derivative forces from the body-frame
      10             :  * pose, integral, and twist errors respectively.  Separate gain sets can be
      11             :  * activated near the water surface.  The integral term is clamped when any
      12             :  * thruster axis is saturated to prevent windup.
      13             :  */
      14           1 : class FeedbackController : public BaseControllerInterface {
      15             :     static constexpr double MAX_DT                = 0.1;
      16             :     static constexpr double EXPLODE_THRESHOLD     = 1e4;
      17             :     static constexpr double INTEGRAL_CLAMP        = 5.0;
      18             :     static constexpr double INTEGRAL_DECAY_FACTOR = 0.5;
      19             : 
      20             : private:
      21             :     double error_saturation_limit = 1;
      22             : 
      23             :     /** @brief Full 18-element state error [pose(6), twist(6), accel(6)] */
      24             :     Vector18d e = Vector18d::Zero();
      25             : 
      26             :     Vector6d body_integral_error = Vector6d::Zero();
      27             :     Vector6d body_pose_error     = Vector6d::Zero();
      28             :     Vector6d body_twist_error    = Vector6d::Zero();
      29             : 
      30             :     /** @brief Running integral of the pose error in the body frame */
      31             :     Vector6d integral = Vector6d::Zero();
      32             : 
      33             :     /**
      34             :      * @brief Snapshot of the integral taken at trajectory start
      35             :      *
      36             :      * Restored when the trajectory finishes so the stationkeep integrator is
      37             :      * not corrupted by in-flight trajectory tracking errors.
      38             :      */
      39             :     Vector6d saved_integral = Vector6d::Zero();
      40             : 
      41             :     Vector6d force_i = Vector6d::Zero();
      42             :     Vector6d force_p = Vector6d::Zero();
      43             :     Vector6d force_d = Vector6d::Zero();
      44             : 
      45             : public:
      46           0 :     using BaseControllerInterface::BaseControllerInterface;
      47             : 
      48             :     /** @brief True when the X, Y, or Yaw thruster axes are saturated */
      49             :     bool saturatedOnYawXYAxis = false;
      50             : 
      51             :     /** @brief True when the Z, Roll, or Pitch thruster axes are saturated */
      52             :     bool saturatedOnDepthRollPitchAxis = false;
      53             : 
      54             :     /**
      55             :      * @brief Resets all internal state including the integral term
      56             :      */
      57           1 :     void reset() override;
      58             : 
      59             :     /**
      60             :      * @brief Resets all internal state except the depth (Z) integral term
      61             :      */
      62           1 :     void resetAllExceptDepthIntegral();
      63             : 
      64             :     /**
      65             :      * @brief Computes the PID feedback force from the goal and current state
      66             :      *
      67             :      * @param goal [in] Desired vehicle state
      68             :      * @param curr [in] Current vehicle state
      69             :      * @param dt   [in] Time step in seconds used for integral accumulation
      70             :      *
      71             :      * @return 6-element PID force/torque vector in N and Nm
      72             :      */
      73           1 :     Vector6d getForce(const State& goal, const State& curr, double dt) override;
      74             : 
      75             :     /**
      76             :      * @brief Saves a snapshot of the current integral term for later restoration
      77             :      *
      78             :      * The snapshot is zeroed if either thruster axis group is saturated.
      79             :      */
      80           1 :     void save_integral();
      81             : 
      82             :     /**
      83             :      * @brief Restores the integral term from the most recent saved snapshot
      84             :      */
      85           1 :     void load_integral();
      86             : 
      87             :     /**
      88             :      * @brief Interpolates the integral term between its current value and the saved snapshot
      89             :      *
      90             :      * @param ratio [in] Blending ratio in [0, 1]; 1.0 fully loads the saved integral
      91             :      */
      92           1 :     void ramp_integral(double ratio);
      93             : 
      94             :     /**
      95             :      * @brief Returns the most recently computed body-frame integral error
      96             :      *
      97             :      * @return 6-element integral error vector
      98             :      */
      99           1 :     Vector6d getIntegralError() const;
     100             : 
     101             :     /**
     102             :      * @brief Returns the most recently computed body-frame pose error
     103             :      *
     104             :      * @return 6-element pose error vector
     105             :      */
     106           1 :     Vector6d getPoseError() const;
     107             : 
     108             :     /**
     109             :      * @brief Returns the most recently computed body-frame twist error
     110             :      *
     111             :      * @return 6-element twist error vector
     112             :      */
     113           1 :     Vector6d getTwistError() const;
     114             : 
     115             :     /**
     116             :      * @brief Returns the most recently computed integral force contribution
     117             :      *
     118             :      * @return 6-element integral force vector
     119             :      */
     120           1 :     Vector6d getIntegralForce() const;
     121             : 
     122             :     /**
     123             :      * @brief Directly sets the integral accumulator
     124             :      *
     125             :      * @param i [in] New integral value
     126             :      */
     127           1 :     void setIntegral(const Vector6d& i);
     128             : };
     129             : 
     130             : #endif  // CONTROLS_CONTROLLER_FEEDBACK_CONTROLLER_H

Generated by: LCOV version 1.14