Skip to content

File pd_control.cpp

File List > control > pd_control.cpp

Go to the documentation of this file

#include "pd_control.hpp"
#include "robot_dart/robot.hpp"
#include "robot_dart/utils.hpp"
#include "robot_dart/utils_headers_dart_dynamics.hpp"

namespace robot_dart {
    namespace control {
        PDControl::PDControl() : RobotControl() {}
        PDControl::PDControl(const Eigen::VectorXd& ctrl, bool full_control, bool use_angular_errors) : RobotControl(ctrl, full_control), _use_angular_errors(use_angular_errors) {}
        PDControl::PDControl(const Eigen::VectorXd& ctrl, const std::vector<std::string>& controllable_dofs, bool use_angular_errors) : RobotControl(ctrl, controllable_dofs), _use_angular_errors(use_angular_errors) {}

        void PDControl::configure()
        {
            if (_ctrl.size() == _control_dof)
                _active = true;

            if (_Kp.size() == 0)
                set_pd(10., 0.1);
        }

        Eigen::VectorXd PDControl::calculate(double)
        {
            ROBOT_DART_ASSERT(_control_dof == _ctrl.size(), "PDControl: Controller parameters size is not the same as DOFs of the robot", Eigen::VectorXd::Zero(_control_dof));
            auto robot = _robot.lock();

            Eigen::VectorXd dq = robot->velocities(_controllable_dofs);

            Eigen::VectorXd error;
            if (!_use_angular_errors) {
                Eigen::VectorXd q = robot->positions(_controllable_dofs);
                error = _ctrl - q;
            }
            else {
                error = Eigen::VectorXd::Zero(_control_dof);

                std::unordered_map<size_t, Eigen::VectorXd> joint_vals, joint_desired, errors;

                for (int i = 0; i < _control_dof; ++i) {
                    auto dof = robot->dof(_controllable_dofs[i]);
                    size_t joint_index = dof->getJoint()->getJointIndexInSkeleton();
                    if (joint_vals.find(joint_index) == joint_vals.end()) {
                        joint_vals[joint_index] = dof->getJoint()->getPositions();
                        joint_desired[joint_index] = dof->getJoint()->getPositions();
                    }

                    joint_desired[joint_index][dof->getIndexInJoint()] = _ctrl[i];
                }

                for (int i = 0; i < _control_dof; ++i) {
                    auto dof = robot->dof(_controllable_dofs[i]);
                    size_t joint_index = dof->getJoint()->getJointIndexInSkeleton();
                    size_t dof_index_in_joint = dof->getIndexInJoint();

                    Eigen::VectorXd val;
                    if (errors.find(joint_index) == errors.end()) {
                        val = Eigen::VectorXd(dof->getJoint()->getNumDofs());

                        std::string joint_type = robot->dof(_controllable_dofs[i])->getJoint()->getType();
                        if (joint_type == dart::dynamics::RevoluteJoint::getStaticType()) {
                            val[dof_index_in_joint] = _angle_dist(_ctrl[i], joint_vals[joint_index][dof_index_in_joint]);
                        }
                        else if (joint_type == dart::dynamics::BallJoint::getStaticType()) {
                            Eigen::Matrix3d R_desired = dart::math::expMapRot(joint_desired[joint_index]);
                            Eigen::Matrix3d R_current = dart::math::expMapRot(joint_vals[joint_index]);
                            val = dart::math::logMap(R_desired * R_current.transpose());
                        }
                        else if (joint_type == dart::dynamics::EulerJoint::getStaticType()) {
                            // TO-DO: Check if this is 100% correct
                            for (size_t d = 0; d < dof->getJoint()->getNumDofs(); d++)
                                val[d] = _angle_dist(joint_desired[joint_index][d], joint_vals[joint_index][d]);
                        }
                        else if (joint_type == dart::dynamics::FreeJoint::getStaticType()) {
                            auto free_joint = static_cast<dart::dynamics::FreeJoint*>(dof->getJoint());

                            Eigen::Isometry3d tf_desired = free_joint->convertToTransform(joint_desired[joint_index]);
                            Eigen::Isometry3d tf_current = free_joint->convertToTransform(joint_vals[joint_index]);

                            val.tail(3) = tf_desired.translation() - tf_current.translation();
                            val.head(3) = dart::math::logMap(tf_desired.linear().matrix() * tf_current.linear().matrix().transpose());
                        }
                        else {
                            val[dof_index_in_joint] = _ctrl[i] - joint_vals[joint_index][dof_index_in_joint];
                        }

                        errors[joint_index] = val;
                    }
                    else
                        val = errors[joint_index];
                    error(i) = val[dof_index_in_joint];
                }
            }

            Eigen::VectorXd commands = _Kp.array() * error.array() - _Kd.array() * dq.array();

            return commands;
        }

        void PDControl::set_pd(double Kp, double Kd)
        {
            _Kp = Eigen::VectorXd::Constant(_control_dof, Kp);
            _Kd = Eigen::VectorXd::Constant(_control_dof, Kd);
        }

        void PDControl::set_pd(const Eigen::VectorXd& Kp, const Eigen::VectorXd& Kd)
        {
            ROBOT_DART_ASSERT(Kp.size() == _control_dof, "PDControl: The Kp size is not the same as the DOFs!", );
            ROBOT_DART_ASSERT(Kd.size() == _control_dof, "PDControl: The Kd size is not the same as the DOFs!", );
            _Kp = Kp;
            _Kd = Kd;
        }

        std::pair<Eigen::VectorXd, Eigen::VectorXd> PDControl::pd() const
        {
            return std::make_pair(_Kp, _Kd);
        }

        bool PDControl::using_angular_errors() const { return _use_angular_errors; }

        void PDControl::set_use_angular_errors(bool enable) { _use_angular_errors = enable; }

        std::shared_ptr<RobotControl> PDControl::clone() const
        {
            return std::make_shared<PDControl>(*this);
        }

        double PDControl::_angle_dist(double target, double current)
        {
            double theta = target - current;
            while (theta < -M_PI)
                theta += 2 * M_PI;
            while (theta > M_PI)
                theta -= 2 * M_PI;
            return theta;
        }
    } // namespace control
} // namespace robot_dart