Skip to content

pid controller not working in read and write #45

Description

@roboticsai

I have integrated the ros pid controllers in the read and write functions of the hardware interface of my robot like this:

RRBotHWInterface::RRBotHWInterface(ros::NodeHandle &nh, urdf::Model *urdf_model)
  : ros_control_boilerplate::GenericHWInterface(nh, urdf_model)
{
    ROS_INFO_NAMED("rrbot_hw_interface", "RRBotHWInterface Ready.");
    left_wheel_pid_controller.initPid(0.1, 0.01, 0.01, 255, -255);
    right_wheel_pid_controller.initPid(0.1, 0.01, 0.01, 255, -255);
    
    radi = 0.049;
    min_ang = 0.00119361423;
    prev_right_wheel_pos = 0;
    prev_left_wheel_pos = 0;
    max_pwm_to_max_vel_radio = 80.7501211252;    
    time = ros::Time::now();
    duration = ros::Duration(0.001);
    Setup();
}

void RRBotHWInterface::read(ros::Duration &elapsed_time)
{
    const char* enc_data = Read();  
    std::vector<std::string> result;  
    boost::split(result, enc_data, boost::is_any_of(","));
    if(result.size()==2) {
	    int curr_left_wheel_pos = atof(result[0].c_str());
	    int curr_right_wheel_pos = atof(result[1].c_str());
	    int delta_left_wheel_pos =  prev_left_wheel_pos - curr_left_wheel_pos;
	    int delta_right_wheel_pos = prev_right_wheel_pos - curr_right_wheel_pos;
	    joint_position_[0] += delta_left_wheel_pos * min_ang; 
	    joint_velocity_[0] = (delta_left_wheel_pos * min_ang)/elapsed_time.toSec();
	    joint_position_[1] += delta_right_wheel_pos * min_ang; 
	    joint_velocity_[1] = (delta_right_wheel_pos * min_ang)/elapsed_time.toSec();
	    prev_left_wheel_pos = curr_left_wheel_pos;
	    prev_right_wheel_pos = curr_right_wheel_pos;
    }
}

void RRBotHWInterface::write(ros::Duration &elapsed_time)
{
  // Safety
  enforceLimits(elapsed_time);
  //int joint2_out_pow = max_pwm_to_max_vel_radio * joint_velocity_command_[0];  
  //int joint1_out_pow = max_pwm_to_max_vel_radio * joint_velocity_command_[1];
  double pow1_error = joint_velocity_command_[0] - joint_velocity_[0];
  double pow2_erro = joint_velocity_command_[1] - joint_velocity_[1];
  int joint1_out_pow = pid1.computeCommand(pow1_error,elapsed_time);
  int joint2_out_pow = pid1.computeCommand(pow2_error,elapsed_time);
  if(joint1_out_pow>255)
	  joint1_out_pow = 255;
  else if(joint1_out_pow<-255)
	  joint1_out_pow=-255;
  if(joint2_out_pow>255)
	  joint2_out_pow=255;
  else if(joint2_out_pow<-255)
	  joint2_out_pow=-255;
  std::string pwm_datas = std::to_string(joint1_out_pow)+","+std::to_string(joint2_out_pow);
  while(pwm_datas.length()<16) {
    pwm_datas.push_back(',');
  }
  const char *res = pwm_datas.c_str(); 
  if(pwm_datas.length()==16) {
    Write(res);    
    usleep(10000);
  }
}

void RRBotHWInterface::enforceLimits(ros::Duration &period)
{
  // ----------------------------------------------------
  // ----------------------------------------------------
  // ----------------------------------------------------
  //
  // CHOOSE THE TYPE OF JOINT LIMITS INTERFACE YOU WANT TO USE
  // YOU SHOULD ONLY NEED TO USE ONE SATURATION INTERFACE,
  // DEPENDING ON YOUR CONTROL METHOD
  //
  // EXAMPLES:
  //
  // Saturation Limits ---------------------------
  //
  // Enforces position and velocity
  pos_jnt_sat_interface_.enforceLimits(period);
  //
  // Enforces velocity and acceleration limits
  // vel_jnt_sat_interface_.enforceLimits(period);
  //
  // Enforces position, velocity, and effort
  // eff_jnt_sat_interface_.enforceLimits(period);

  // Soft limits ---------------------------------
  //
  // pos_jnt_soft_limits_.enforceLimits(period);
  // vel_jnt_soft_limits_.enforceLimits(period);
  // eff_jnt_soft_limits_.enforceLimits(period);
  //
  // ----------------------------------------------------
  // ----------------------------------------------------
  // ----------------------------------------------------
}

But when i run this hardware interface with diff drive controller and publish the cmd_vel command in twist topic. The output power which is pwm in this case is not properly comming.
I asked this question in ros forum they said its not the way to use the pid controllers.
If no what is the correct method to use the pid controllers in the hardware interface with ros control boiler plate?
Plate-form: ros noetic, ubuntu 20.04.
Here i've used the read and write functions from the serial library i've used. which does the reading and writing tasks from arduino nano connected to the raspberry pi where i'm running this, where encoder data is being read and pwm to dc motors has been sent.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions