ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Thomas,

I am not sure what kind of path planning algorithm ROS has. But if your goal is a path following (without time specified), how about checking the guidance algorithm, LOS (Line of Sight)? I have been testing the LOS guidance law on the 2D hovercraft with the backstepping controller: Given a set of way points, make the 2D hovercraft follow the way points. I have tested it over Matlab, it works very well. But I have not got the same level of performance in gazebo simulation due to my knowledge in ROS/gazebo environment.

#include <ros/ros.h>
#include <nav_msgs/Odometry.h>
#include <geometry_msgs/Wrench.h>
#include <algorithm>
#include <eigen3/Eigen/Core>
#include <eigen3/Eigen/LU>
#include <gazebo/Simulator.hh>
#include <gazebo/gazebo.h>

//!Global Variables
nav_msgs::Odometry odom;

void vehicleVelocityCallback(const nav_msgs::Odometry::ConstPtr& data)
{
     odom = *data;
}

int main(int argc,char **argv)
{
    //! Constant Variables
    const double m = 15.67;   // mass [kg]
        const double Izz = 0.952; // mass moment of inertia [kg*m^2]
        const double L = 1;     // length [m]
        const double dv = 4.5;   // translational friction coeff.
        const double dw = 0.41;   // rotational friction coeff
        const double ud = 0.2;   // desired speed [m/s]

    const double Delta = 1*L;  // lookahead length [m/s]
    const double Rwpt = 1*L;   // Radius of circle for waypoints

    //! Variables
    int kk = 0;
    int jj = 0;
    double psi = 0 ;
    double Chi_d  ;
    double Chi_d_old = 0 ;
    double alpha_1_old = 0;
    double alpha_3_old = 0;
        double alpha_1 ;
        double alpha_3 ;
    double alpha_dot_1 ;
    double alpha_dot_3 ;

    double rd  ;
    double Xu  ;
    double Xu_old = 0;
    double Xr  ;
    double Xr_old = 0;
    double Xrd  ;
    double Xrd_old = 0;
    double Chi_d_dot  ;

    //! Local Variables
    double wpt_x[8] = {0.372, -0.628, 0.372, 1.872, 6.872,  8.372, 9.372, 8.372}; 
    double wpt_y[8] = {-0.181+1, 1.32+1,  2.82+1,  3.32+1, -0.681+1, -0.181+1, 1.32+1,  2.82+1};
    double ak[7];
    double wpt_x_dis[7];
    double wpt_y_dis[7];
    double s_leng[7];
        // for low-pass filter
    //  double zeta_u = 0.7;
    double omega_u = 0.1*2*3.14159265;
    //  double zeta_r = 0.5;
    double omega_r = 0.2*2*3.14159265;


    for (jj=0; jj<7; jj++)
            {
        ak[jj] = atan2(wpt_y[jj+1]-wpt_y[jj], wpt_x[jj+1]-wpt_x[jj]);
            wpt_x_dis[jj] = wpt_x[jj+1]-wpt_x[jj];
            wpt_y_dis[jj] = wpt_y[jj+1]-wpt_y[jj];
            s_leng[jj] = std::sqrt( wpt_x_dis[jj]*wpt_x_dis[jj] + wpt_y_dis[jj]*wpt_y_dis[jj] );
            }

        //! System Constants
        const double dt = 0.01;
    double time;

    //! Ros Initialization
    ros::init(argc,argv, "hover_controller");
    ros::NodeHandle nh_;

    //! Ros Publisher
//      ros::Publisher left_fan_force_pub_ = nh_.advertise<geometry_msgs::Wrench>("left_fan_force", 1);
//      ros::Publisher right_fan_force_pub_ = nh_.advertise<geometry_msgs::Wrench>("right_fan_force", 1);
    ros::Publisher box_force_pub_ = nh_.advertise<geometry_msgs::Wrench>("box_force", 1);
//      geometry_msgs::Wrench left_fan_force_;
//      geometry_msgs::Wrench right_fan_force_;
    geometry_msgs::Wrench box_force_;

    //! Ros Subscriber
    ros::Subscriber odom_sub_ = nh_.subscribe<nav_msgs::Odometry>("base_pose_ground_truth", 1, vehicleVelocityCallback);


    /*! ---------------------------------------------------------------------------------------------
    *   CONTROLLER
    *   Local Variables
    */

    ros::Rate r(100); //! 100 Hz
    while(ros::ok())
    {
        r.sleep();
        ros::spinOnce();

        time = odom.header.stamp.toSec();
        //time = ros::Time::now().toSec();

        // Local Variables for LOS bs tuning parameters
        double K1 = 10;  
        double K3 = 5;  
        double cc = 1;  

        // inertial frame velocities
        double vx = odom.twist.twist.linear.x;
        double vy = odom.twist.twist.linear.x;
        double omega = odom.twist.twist.angular.z;
        // Rotation matrix from inertial to body
        Eigen::Vector2d vel(vx, vy);
        Eigen::Matrix2d R; // This R is actaully the transposed R.
        R << cos(psi), sin(psi),
                    -sin(psi), cos(psi); 
        // body frame velocities
        Eigen::Vector2d nu = R*vel;
        double u = nu[0];
        double v = nu[1];



        double delta_psi = omega*dt;
        psi += delta_psi;
        /*
        double q0 = odom.pose.pose.orientation.w;
        double q1 = odom.pose.pose.orientation.x;
        double q2 = odom.pose.pose.orientation.y;
        double q3 = odom.pose.pose.orientation.z;
        psi = atan2(2*(q0*q3+q1*q2),1-2*(q2*q2+q3*q3));
        */

        Eigen::Vector2d P(odom.pose.pose.position.x, odom.pose.pose.position.y);

        //! LOS guidance loop variables
        Eigen::Matrix2d R_ak; // This R is actaully the transposed R_ak.
        R_ak << cos(ak[kk]), sin(ak[kk]),
                       -sin(ak[kk]), cos(ak[kk]); 
        Eigen::Vector2d Pk(wpt_x[kk], wpt_y[kk]);
        Eigen::Vector2d epsilon = R_ak*(P-Pk);
        double s = epsilon[0];
        double e = epsilon[1];

        double Chi_p = ak[kk];
        double Chi_r = atan2(-e, Delta);
        double Chi = Chi_p + Chi_r;

        double critic = s_leng[kk] - s;
        //double critic = std::sqrt( std::pow(wpt_x[kk]-P[0],2) + std::pow(wpt_y[kk]-P[1],2) );

        if (std::abs(critic) <= Rwpt) 
               {
                    kk = kk+1;
           }
        else { kk = kk; } 

        //! BS controller loop


        // low pass filter for Chi
        /*
        Xr = -pow(omega_r,2) * Xr_old + Chi;
        Xr_old = Xr;
        Chi_d = pow(omega_r,2) * Xr;
        */

        Xr = ( 1/omega_r/(1/omega_r+dt) ) * Xr_old + dt/(1/omega_r+dt) * Chi;
        Xr_old = Xr;
        Chi_d = Xr;

        /*
        Xr = std::exp(pow(omega_r,2)*dt) * Xr_old + ( 1 - std::exp(pow(omega_r,2)*dt) ) * Chi;
        Xr_old = Xr;
        Chi_d = Xr;
        */  
        //if (time < 3)
        //std::cout << kk << " " << Chi_p << " " << Chi_r << std::endl;

        double z1 = psi - Chi_d;

        Chi_d_dot = (Chi_d - Chi_d_old) / dt;
        Chi_d_old = Chi_d;

        // low pass filter for rd
        /*
        Xrd = -pow(omega_r,2) * Xrd_old + Chi_d_dot;
        Xrd_old = Xrd;
        rd = pow(omega_r,2) * Xrd;
        */

        Xrd = ( 1/omega_r/(1/omega_r+dt) ) * Xrd_old + dt/(1/omega_r+dt) * Chi_d_dot;
        Xrd_old = Xrd;
        rd = Xrd;
        /*
        Xrd = std::exp(pow(omega_r,2)*dt) * Xrd_old + ( 1 - std::exp(pow(omega_r,2)*dt) ) * Chi_d_dot;
        Xrd_old = Xrd;
        rd = Xrd;
        */
        //if (time < 3)
        //{std::cout << rd << " " << time << std::endl;}

        // low pass filter for ud
        /*
        Xu = -pow(omega_u,2) * Xu_old + ud;
        Xu_old = Xu;
        //alpha_1 = pow(omega_u,2) * Xu;
        alpha_1 = ud;
        */

        Xu = ( 1/omega_u/(1/omega_u+dt) ) * Xu_old + dt/(1/omega_u+dt) * ud;
        Xu_old = Xu;
        alpha_1 = Xu;
        /*
        Xu = std::exp(pow(omega_u,2)*dt) * Xu_old + ( 1 - std::exp(pow(omega_u,2)*dt) ) * ud;
        Xu_old = Xu;
        alpha_1 = Xu;
        */

        alpha_3 = -cc*z1 + rd;

        alpha_dot_1 = (alpha_1 - alpha_1_old) / dt;
        alpha_1_old = alpha_1;
        alpha_dot_3 = (alpha_3 - alpha_3_old) / dt;
        alpha_3_old = alpha_3;

        double u1 = m*alpha_dot_1 + (dv - K1)*u -omega*v + K1*ud; // Force [N]
        double u2 = Izz*alpha_dot_3 + (dw - K3)*omega + K3*alpha_3 - (psi - Chi_d); // Moment [N*m]

        if (u1 > 40.032)
        { 
        u1 = 40.032;
        }
        else if (u1 < 0)
        { 
        u1 = 0;
        }

        if (u2 > 5.0841)
        { 
        u2 = 5.0841;
        }
        else if (u2 < -5.0841)
        { 
        u2 = -5.0841;
        }

        /*
        // Actuator model 
        double f1 = 0.5*(u1 - u2/d);
        double f2 = 0.5*(u1 + u2/d);
        double f_max = 4.5;
        double thrust1 = f1/f_max*100;  // percent
        double thrust2 = f2/f_max*100;  // percent

        double f1_act = f_max/(1+std::exp(-0.1*(thrust1-50)))-0.134;
        double f2_act = f_max/(1+std::exp(-0.1*(thrust2-50)))-0.134;

        double u1_act = f1_act + f2_act;
        double u2_act = d*(-f1_act + f2_act);
        */

        box_force_.force.x = u1;  //u1_act*cos(psi);
        box_force_.force.y = 0;    //u1_act*sin(psi);  
        box_force_.torque.z = u2; 
        //! Publish the message
        box_force_pub_.publish(box_force_);

        // out to screen
        //if (time < 10)
        std::cout << critic << " " << kk << " " << Chi_d << " " << u1 << " " << u2 << " " << time << std::endl;
        //std::cout << alpha_dot_1 << " " << alpha_1 << " " << u1 << " " << Xu << " " << time << std::endl;

    }
    return 0;
}