Program Listing for File PID.cc

Program Listing for File PID.cc#

Return to documentation for file (doxygen_docs/GeneralKModels/PID.cc)

#include "Karana/GeneralKModels/PID.h"
#include "Karana/KCore/Allocator.h"

/**
 * @file
 * @brief PID implementation.
 */

namespace Karana::Models {

    namespace kd = Karana::Dynamics;

    PID::PID(std::string_view name,
             const kc::ks_ptr<kd::ModelManager> &mm,
             const kc::ks_ptr<kd::PhysicalSubhinge> &sh,
             const kc::ks_ptr<ProfileGenerator<km::Vec>> &q_traj,
             const kc::ks_ptr<ProfileGenerator<km::Vec>> &u_traj)
        : KModel<PID, PIDParams>(name, mm)
        , q_traj(q_traj)
        , u_traj(u_traj)
        , _sh(sh) {
        params = std::allocate_shared<PIDParams>(kc::Allocator<PIDParams>{},
                                                 std::format("{}_params", name));

        // Start the internal state at zero so the integral gain can be calculated appropriately
        _e_prev.resize(sh->nQ());
        _e_prev.setZero();

        _integral_contrib.resize(sh->nQ());
        _integral_contrib.setZero();

        _prev_t = km::Ktime{0};
    };

    kc::ks_ptr<PID> PID::create(std::string_view name,
                                const kc::ks_ptr<kd::ModelManager> &mm,
                                const kc::ks_ptr<kd::PhysicalSubhinge> &sh,
                                const kc::ks_ptr<ProfileGenerator<km::Vec>> &q_traj,
                                const kc::ks_ptr<ProfileGenerator<km::Vec>> &u_traj) {
        kc::ks_ptr<PID> pid =
            std::allocate_shared<PID>(kc::Allocator<PID>{}, name, mm, sh, q_traj, u_traj);
        mm->registerModel(pid);
        return pid;
    }

    void PID::preDeriv(const km::Ktime &t, const km::Vec &) {
        km::Vec T = params->kp * (q_traj->getValue(t) - _sh->getQ()) +
                    params->kd * (u_traj->getValue(t) - _sh->getU()) + _integral_contrib;
        _sh->setT(T);

        if (debug_model) [[unlikely]] {
            stdDebugMsg(std::format("output torque {}", km::dumpString(T)));
        }
    }

    void PID::preModelStep(const km::Ktime &t, const km::Vec &) {
        // Calculate the integral contribution for this step
        _integral_contrib += params->ki * (_e_prev * km::ktimeToSeconds(t - _prev_t));

        // Calculate new error for next time
        _e_prev = q_traj->getValue(t) - _sh->getQ();

        // Set _prev_t to t for next time
        _prev_t = t;

        if (debug_model) [[unlikely]] {
            stdDebugMsg(std::format("preModelStep integral error {}", km::dumpString(_e_prev)));
        }
    };

    PIDParams::PIDParams(std::string_view name)
        : KModelParams(name) {
        kp = km::notReadyNaN;
        kd = km::notReadyNaN;
        ki = km::notReadyNaN;
    }

    bool PIDParams::isReady() const {
        bool flag = true;
        if (km::isNotReadyNaN(kp)) {
            kc::warn("Parameter kp is not ready.");
            flag = false;
        }
        if (km::isNotReadyNaN(kd)) {
            kc::warn("Parameter kd is not ready.");
            flag = false;
        }
        if (km::isNotReadyNaN(ki)) {
            kc::warn("Parameter ki is not ready.");
            flag = false;
        }
        return flag;
    }

    // Destructor included for MacOS builds. Must have a key-function out-of-line to avoid dulpicate
    // symbols.
    PID::~PID(){};
} // namespace Karana::Models