ThirdRobotInterface.cpp
Go to the documentation of this file.
00001 #include "ThirdRobotInterface/ThirdRobotInterface.h"
00002 
00003 // for std
00004 #include <fstream>
00005 #include <iostream>
00006 #include <stdexcept>
00007 #include <string>
00008 #include <vector>
00009 
00010 // for old c
00011 #include <cstdio>
00012 #include <cstdlib>
00013 #include <cstring>
00014 #include <fcntl.h> // for open()
00015 #include <math.h>
00016 #include <netinet/in.h>
00017 #include <sys/ioctl.h> // for ioctl()
00018 #include <sys/stat.h> // for open()
00019 #include <sys/types.h> // for open()
00020 #include <unistd.h> // for close()
00021 
00023 static constexpr int ROBOT_MAX_ENCODER_COUNTS {65535};
00025 static constexpr double WHEELBASE_LENGTH {0.94};
00027 static constexpr double MAX_LIN_VEL {1.11}; // 1.11[m/s] => 4.0[km/h]
00028 
00029 using namespace std; // FIXME: don't erode grobal scope
00030 
00031 cirkit::ThirdRobotInterface::ThirdRobotInterface(const std::string& new_serial_port_imcs01, int new_baudrate_imcs01)
00032 : imcs01_port_name {new_serial_port_imcs01},
00033   fd_imcs01 {-1},
00034   baudrate_imcs01 {new_baudrate_imcs01},
00035   steer_angle {0.0},
00036   last_rear_encoder_time {0},
00037   stasis_ {ROBOT_STASIS_FORWARD_STOP}
00038 {
00039   for (int i = 0; i < 2; i++)
00040   {
00041     delta_rear_encoder_counts[i] = -1;
00042     last_rear_encoder_counts[i] = 0;
00043   }
00044 
00045   resetOdometry();
00046 }
00047 
00048 cirkit::ThirdRobotInterface::~ThirdRobotInterface()
00049 {
00050   //  cout << "Destructor called\n" << endl;
00051   cmd_ccmd.offset[0] = 65535; // iMCs01 CH101 PIN2 is 5[V]. Forwarding flag.
00052   cmd_ccmd.offset[1] = 32767; // STOP
00053   cmd_ccmd.offset[2] = 32767;
00054   cmd_ccmd.offset[3] = 32767;
00055   ioctl(fd_imcs01, URBTC_COUNTER_SET);
00056   write(fd_imcs01, &cmd_ccmd, sizeof(cmd_ccmd));
00057 
00059   if (fd_imcs01 > 0)
00060   {
00061     tcsetattr(fd_imcs01, TCSANOW, &oldtio_imcs01);
00062     close(fd_imcs01);
00063   }
00064   fd_imcs01 = -1;
00065 }
00066 
00067 
00068 // *****************************************************************************
00069 // Open the serial port
00070 int cirkit::ThirdRobotInterface::openSerialPort()
00071 {
00072   try
00073   {
00074     setSerialPort();
00075   }
00076   catch(exception &e)
00077   {
00078     cerr << e.what() << endl;
00079     return -1; // kill exception
00080   }
00081   return 0;
00082 }
00083 
00084 // *****************************************************************************
00085 // Set the serial port
00086 int cirkit::ThirdRobotInterface::setSerialPort()
00087 {
00088   // Setting iMCs01
00089   if (fd_imcs01 > 0)
00090   {
00091     throw logic_error("imcs01 is already open");
00092   }
00093   fd_imcs01 = open(imcs01_port_name.c_str(), O_RDWR);
00094   if (fd_imcs01 > 0)
00095   {
00096     tcgetattr(fd_imcs01, &oldtio_imcs01);
00097   }
00098   else
00099   {
00100     throw logic_error("Faild to open port: imcs01");
00101   }
00102   if (ioctl(fd_imcs01, URBTC_CONTINUOUS_READ) < 0)
00103   {
00104     throw logic_error("Faild to ioctl: URBTC_CONTINUOUS_READ");
00105   }
00106 
00107   cmd_ccmd.selout     = SET_SELECT | CH0 | CH1 | CH2 | CH3; // All PWM.
00108   cmd_ccmd.selin      = SET_SELECT; // All input using for encoder count.
00109   cmd_ccmd.setoffset  = CH0 | CH1 | CH2 | CH3;
00110   cmd_ccmd.offset[0]  = 58981;
00111   cmd_ccmd.offset[1]  = 58981;
00112   cmd_ccmd.offset[2]  = 58981;
00113   cmd_ccmd.offset[3]  = 58981;  // 1/2
00114   cmd_ccmd.setcounter = CH0 | CH1 | CH2 | CH3;
00115   cmd_ccmd.counter[1] = -3633;  //-67[deg]*(1453/27), initialize.
00116   cmd_ccmd.counter[2] = 0;
00117   cmd_ccmd.posneg     = SET_POSNEG | CH0 | CH1 | CH2 | CH3; //POS PWM out.
00118   cmd_ccmd.breaks     = SET_BREAKS | CH0 | CH1 | CH2 | CH3; //No Brake;
00119   cmd_ccmd.magicno    = 0x00;
00120 
00121   if (ioctl(fd_imcs01, URBTC_COUNTER_SET) < 0)
00122   {
00123     throw logic_error("Faild to ioctl: URBTC_COUNTER_SET");
00124   }
00125   if (write(fd_imcs01, &cmd_ccmd, sizeof(cmd_ccmd)) < 0)
00126   {
00127     throw logic_error("Faild to write");
00128   }
00129 
00130   cmd_ccmd.setcounter = 0;
00131 
00132   cout << "ThirdRobotInterface (iMCs01)Connected to : " << imcs01_port_name << endl;
00133   return 0;
00134 }
00135 
00136 // *****************************************************************************
00137 // Set params
00138 void cirkit::ThirdRobotInterface::setParams(double pulse_rate, double geer_rate, double wheel_diameter_right, double wheel_diameter_left, double tred_width)
00139 {
00141   PulseRate = pulse_rate;
00142   ROS_INFO("PulseRate : %lf", PulseRate);
00144   GeerRate = geer_rate;
00145   ROS_INFO("GeerRate : %lf", GeerRate);
00147   WheelDiameter[0] = wheel_diameter_right; // left
00148   WheelDiameter[1] = wheel_diameter_left;
00149   ROS_INFO("wheelDiameter[right] : %lf", WheelDiameter[0]);
00150   ROS_INFO("wheelDiameter[left]  : %lf", WheelDiameter[1]);
00151 
00153   TredWidth = tred_width;
00154   ROS_INFO("TredWidth : %lf", TredWidth);
00155 }
00156 // *****************************************************************************
00157 // Close the serial port
00158 int cirkit::ThirdRobotInterface::closeSerialPort()
00159 {
00160   drive(0.0, 0.0);
00161   usleep(1000);
00162 
00163   if (fd_imcs01 > 0)
00164   {
00165     tcsetattr(fd_imcs01, TCSANOW, &oldtio_imcs01);
00166     close(fd_imcs01);
00167     fd_imcs01 = -1;
00168   }
00169 
00170   return 0;
00171 }
00172 
00173 // *****************************************************************************
00174 // Set the speeds
00175 //   linear_speed  : target linear speed[m/s]
00176 //   angular_speed : target angular speed[rad/s]
00177 geometry_msgs::Twist cirkit::ThirdRobotInterface::drive(double linear_speed, double angular_speed)
00178 {
00179   // Front angle in deg.
00180   double front_angle_deg = 0;
00181   double rear_speed_m_s = 0;
00182 
00183   if (-0.005 < linear_speed && linear_speed < 0.005 && fabs(angular_speed) > 0.0)
00184   {
00185     rear_speed_m_s = 0.3;
00186     if (angular_speed > 0)
00187     {
00188       front_angle_deg = 60;
00189     }
00190     else
00191     {
00192       front_angle_deg = -60;
00193     }
00194   }
00195   else
00196   {
00197     rear_speed_m_s = linear_speed*1.0;
00198     front_angle_deg = angular_speed*1.2*(180.0/M_PI);
00199     //front_angle_deg = atan((angular_speed*1.1)/linear_speed) * (180.0/M_PI);
00200   }
00201 
00202   return driveDirect(front_angle_deg, rear_speed_m_s);
00203 }
00204 
00205 
00206 
00207 // *****************************************************************************
00208 // Set the motor speeds
00209 //   front_angular : target angle[deg]
00210 //   rear_speed    : target velocity[m/s]
00211 //   stasis_ :
00212 //     ROBOT_STASIS_FORWARD      : Forwarding
00213 //     ROBOT_STASIS_FORWARD_STOP : Stoping but forward mode
00214 //     ROBOT_STASIS_BACK         : Backing
00215 //     ROBOT_STASIS_BACK_STOP    : Stoping but back mode
00216 //     ROBOT_STASIS_OTHERWISE    : Braking but not stop.
00217 
00218 geometry_msgs::Twist cirkit::ThirdRobotInterface::driveDirect(double front_angular, double rear_speed)
00219 {
00220   static int forward_stop_cnt = 0;
00221   static int back_stop_cnt = 0;
00222   static int max_spped_x = 3.0;
00223   static double average_spped_x = 0;
00224   static double u = 32767.0;
00225   static double u1 = 32767.0;
00226   static double u2 = 32767.0;
00227   static double e = 0;
00228   static double e1 = 0;
00229   static double e2 = 0;
00230 
00231   static double gain_p = 10000.0;
00232   static double gain_i = 100000.0;
00233   static double gain_d = 1000.0;
00234 
00235   double duty = 0;
00236 
00237   // Forward
00238   if (rear_speed >= 0.0)
00239   {
00240     double rear_speed_m_s = MIN(rear_speed, MAX_LIN_VEL); // return smaller
00241     if (stasis_ == ROBOT_STASIS_FORWARD || stasis_ == ROBOT_STASIS_FORWARD_STOP)
00242     {
00243       // Now Forwarding
00244       // e = rear_speed_m_s - linear_velocity;
00245       // u = u1 + (gain_p + gain_i * delta_rear_encoder_time
00246       //                  + gain_d/delta_rear_encoder_time) * e
00247       //        - (gain_p + 2.0*gain_d/delta_rear_encoder_time)*e1
00248       //        + (gain_d/delta_rear_encoder_time)*e2;
00249       average_spped_x = (average_spped_x + rear_speed)/2.0;
00250       u = (int)(32767.0 + 32767.0 * average_spped_x *1.0);
00251       // ROS_INFO("a : %f", average_spped_x);
00252       // ROS_INFO("u : %f", u);
00253       if (rear_speed == 0.0)
00254       {
00255         u = 32767;
00256         average_spped_x = 0;
00257       }
00258       duty = MIN(u, 60000);
00259       duty = MAX(duty, 32767);
00260       u2 = u1;
00261       u1 = duty;
00262       e2 = e1;
00263       e1 = e;
00264       cmd_ccmd.offset[0] = 65535; // iMCs01 CH101 PIN2 is 5[V]. Forwarding flag.
00265       cmd_ccmd.offset[1] = (int)(duty);
00266 
00267       writeCmd(cmd_ccmd);
00268 
00269       stasis_ = ROBOT_STASIS_FORWARD;
00270     }
00271     else
00272     {
00273       // Now Backing
00274       // Need to stop once.
00275       cmd_ccmd.offset[0] = 65535; // iMCs01 CH101 PIN2 is 5[V]. Forwarding flag. 32767
00276       cmd_ccmd.offset[1] = 32767; // STOP
00277 
00278       u = 32767;
00279       duty = u;
00280       u2 = u1;
00281       u1 = duty;
00282       e2 = e1;
00283       e1 = e;
00284       average_spped_x = 0;
00285       writeCmd(cmd_ccmd);
00286 
00287       if (forward_stop_cnt >= 20)
00288       {
00289         stasis_ = ROBOT_STASIS_FORWARD_STOP;
00290         forward_stop_cnt = 0;
00291         for (int i = 0; i < 10; ++i)
00292         {
00293           cmd_ccmd.offset[0] = 65535; // iMCs01 CH101 PIN2 is 5[V]. Forwarding flag. 32767
00294           cmd_ccmd.offset[1] = 32767; // STOP
00295           writeCmd(cmd_ccmd);
00296         }
00297       }
00298       else
00299       {
00300         stasis_ = ROBOT_STASIS_OTHERWISE;
00301         forward_stop_cnt++;
00302       }
00303     }
00304   }
00305   else
00306   {
00307     // (rear_speed < 0) -> Back
00308     average_spped_x = 0;
00309     if (stasis_ == ROBOT_STASIS_BACK_STOP || stasis_ == ROBOT_STASIS_BACK)
00310     {
00311       // Now backing
00312       cmd_ccmd.offset[0] = 32767; // iMCs01 CH101 PIN2 is 0[V]. Backing flag.
00313       cmd_ccmd.offset[1] = 60000; // Back is constant speed.
00314 
00315       u = 32767;
00316       duty = MIN(u, 62176);
00317       u2 = u1; u1 = duty; e2 = e1; e1 = e;
00318 
00319       writeCmd(cmd_ccmd);
00320 
00321       stasis_ = ROBOT_STASIS_BACK;
00322       ROS_INFO("ROBOT_STASIS_BACK");
00323     }
00324     else
00325     {
00326       // Now forwarding
00327       if (back_stop_cnt >= 10)
00328       {
00329         stasis_ = ROBOT_STASIS_BACK_STOP;
00330         back_stop_cnt = 0;
00331         cmd_ccmd.offset[0] = 32767; // iMCs01 CH101 PIN2 is 0[V].  Backing flag.
00332         cmd_ccmd.offset[1] = 32767; // STOP
00333         writeCmd(cmd_ccmd);
00334         for (int i = 0; i < 300; ++i) usleep(1000);
00335         ROS_INFO("ROBOT_STASIS_BACK_STOP");
00336       }
00337       else
00338       {
00339         cmd_ccmd.offset[0] = 65535; // iMCs01 CH101 PIN2 is 0[V].  Backing flag.
00340         cmd_ccmd.offset[1] = 32767; // STOP
00341         usleep(50000);
00342         writeCmd(cmd_ccmd);
00343         stasis_ = ROBOT_STASIS_OTHERWISE;
00344         back_stop_cnt++;
00345         ROS_INFO("ROBOT_STASIS_OTHERWISE");
00346       }
00347     }
00348   }
00349 
00350   // Steer ctrl
00351   // front_angular      : target angle[deg];
00352   // steer_angle        : now angle[deg];
00353   double input_angle = 0;
00354   input_angle = MAX(front_angular, -60.0);
00355   input_angle = MIN(input_angle, 60.0);
00356   //ROS_INFO("input angle : %lf\n", input_angle);
00357 
00358   double angdiff = (input_angle - steer_angle);
00359   // cout << "steer_angle: " << steer_angle << endl;
00360   // cout << "input_angle: " << input_angle << endl;
00361   // cout << "angdiff: " << angdiff << endl;
00362   return  fixFrontAngle(angdiff);
00363 }
00364 
00365 // *****************************************************************************
00366 // Read the encoders from iMCs01
00367 int cirkit::ThirdRobotInterface::getEncoderPacket()
00368 {
00369   std::lock_guard<std::mutex> lck {communication_mutex_};
00370   if (read(fd_imcs01, &cmd_uin, sizeof(cmd_uin)) != sizeof(cmd_uin))
00371   {
00372     return -1;
00373   }
00374   else
00375   {
00376     return parseEncoderPackets();
00377   }
00378 }
00379 
00380 // *****************************************************************************
00381 // Parse encoder data
00382 int cirkit::ThirdRobotInterface::parseEncoderPackets()
00383 {
00384   parseFrontEncoderCounts();
00385   parseRearEncoderCounts();
00386   return 0;
00387 }
00388 
00389 int cirkit::ThirdRobotInterface::parseFrontEncoderCounts()
00390 {
00391   const int ave_num = 5;
00392   static int cnt = 0;
00393   static vector<double> move_ave(ave_num);
00394 
00395   int steer_encoder_counts = (int)(cmd_uin.ct[1]);
00396 
00397   double alpha = 0.0;
00398   double beta = 0.0;
00399   double R = 0.0;
00400   const double n = 1.00;
00401 
00402   if (steer_encoder_counts == 0.0)
00403   {
00404     steer_angle = 0.0;
00405   }
00406   else
00407   {
00408     double tmp = steer_encoder_counts*67.0/3633.0;
00409     tmp = tmp * M_PI /180;
00410     R = 0.96/tan(tmp);
00411 
00412     steer_angle = atan(WHEELBASE_LENGTH/R); // [rad]
00413 
00414     steer_angle = steer_angle*(180.0/M_PI); // [rad]->[deg]
00415   }
00416 
00417   move_ave[cnt%5] = steer_angle;
00418   size_t size = move_ave.size();
00419   double sum = 0;
00420   for (unsigned int i = 0; i < size; i++)
00421   {
00422     sum += move_ave[i];
00423   }
00424   steer_angle = sum / (double)size;
00425   cnt++;
00426 
00427   return 0;
00428 }
00429 
00430 int cirkit::ThirdRobotInterface::parseRearEncoderCounts()
00431 {
00433   int rear_encoder_counts[2] {(int)(cmd_uin.ct[2]), -(int)(cmd_uin.ct[3])};
00434 
00435   delta_rear_encoder_time = (double)(cmd_uin.time) - last_rear_encoder_time;
00436   if (delta_rear_encoder_time < 0)
00437   {
00438     delta_rear_encoder_time = 65535 - (last_rear_encoder_time - cmd_uin.time);
00439   }
00440   delta_rear_encoder_time = delta_rear_encoder_time / 1000.0; // [ms] -> [s]
00441   last_rear_encoder_time = (double)(cmd_uin.time);
00442 
00443   for (int i = 0; i < 2; i++)
00444   {
00445     if (delta_rear_encoder_counts[i] == -1
00446         || rear_encoder_counts[i] == last_rear_encoder_counts[i])
00447     { // First time.
00448 
00449       delta_rear_encoder_counts[i] = 0;
00450 
00451     }
00452     else
00453     {
00454       delta_rear_encoder_counts[i] = rear_encoder_counts[i] - last_rear_encoder_counts[i];
00455 
00456       // checking imcs01 counter overflow.
00457       if (delta_rear_encoder_counts[i] > ROBOT_MAX_ENCODER_COUNTS/10)
00458       {
00459         delta_rear_encoder_counts[i] = delta_rear_encoder_counts[i] - ROBOT_MAX_ENCODER_COUNTS;
00460       }
00461       if (delta_rear_encoder_counts[i] < -ROBOT_MAX_ENCODER_COUNTS/10)
00462       {
00463         delta_rear_encoder_counts[i] = delta_rear_encoder_counts[i] + ROBOT_MAX_ENCODER_COUNTS;
00464       }
00465     }
00466     last_rear_encoder_counts[i] = rear_encoder_counts[i];
00467   }
00468 
00469   return 0;
00470 }
00471 
00472 
00473 // *****************************************************************************
00474 // Reset Third Robot odometry
00475 void cirkit::ThirdRobotInterface::resetOdometry()
00476 {
00477   setOdometry(0.0, 0.0, 0.0);
00478 }
00479 
00480 // *****************************************************************************
00481 // Set Third Robot odometry
00482 void cirkit::ThirdRobotInterface::setOdometry(double new_x, double new_y, double new_yaw)
00483 {
00484   odometry_x_   = new_x;
00485   odometry_y_   = new_y;
00486   odometry_yaw_ = new_yaw;
00487 }
00488 
00489 
00490 // *****************************************************************************
00491 // Calculate Third Robot odometry
00492 void cirkit::ThirdRobotInterface::calculateOdometry()
00493 {
00494   // Pulse to distance
00495   for (int i = 0; i < 2; i++)
00496   {
00497     delta_dist[i] = (delta_rear_encoder_counts[i]/PulseRate/GeerRate)*(WheelDiameter[i]*M_PI);
00498   }
00499 
00500   linear_velocity = (delta_dist[0] + delta_dist[1])/2.0;
00501   linear_velocity = linear_velocity / delta_rear_encoder_time;
00502   // double delta_L = (delta_dist[0] + delta_dist[1])/2.0;
00503   // double delta_yaw = (delta_dist[0] - delta_dist[1])/TredWidth;
00504   // double rho = 0;
00505   // double dist = 0;
00506 
00507   odometry_yaw_ += ((last_delta_dist[0] - last_delta_dist[1] + delta_dist[0] - delta_dist[1]) /
00508       0.7 * TredWidth);
00509   odometry_x_ += (((last_delta_dist[0] + last_delta_dist[1]) * cos(last_odometry_yaw) +
00510       (delta_dist[0] + delta_dist[1]) * cos(odometry_yaw_)) / 4.0);
00511   odometry_y_ += (((last_delta_dist[0] + last_delta_dist[1]) * sin(last_odometry_yaw) +
00512       (delta_dist[0] + delta_dist[1]) * sin(odometry_yaw_)) / 4.0);
00513 
00514   for (int i = 0; i < 2; i++)
00515   {
00516     last_delta_dist[i] = delta_dist[i];
00517   }
00518   last_odometry_yaw = odometry_yaw_;
00519 }
00520 
00521 
00522 void cirkit::ThirdRobotInterface::writeCmd(ccmd cmd)
00523 {
00524   if (ioctl(fd_imcs01, URBTC_COUNTER_SET) < 0) // FIXME: setup URBTC_COUNTER_SET on every communicate, realry? It wrong!
00525   {
00526     ROS_WARN("URBTC_COUNTER_SET fail."); // error // FIXME: error? if error, you should not write, right?
00527   }
00528   std::lock_guard<std::mutex> lck {communication_mutex_};
00529   if (write(fd_imcs01, &cmd, sizeof(cmd)) < 0)
00530   {
00531     ROS_WARN("iMCs01 write fail.");
00532   }
00533 }
00534 
00535 geometry_msgs::Twist cirkit::ThirdRobotInterface::fixFrontAngle(double angular_diff)
00536 {
00537   geometry_msgs::Twist ret_steer;
00538   if (angular_diff > 0)
00539   {
00540     ret_steer.angular.z = 1;
00541     ret_steer.angular.x = fabs(angular_diff);
00542     return ret_steer;
00543   }
00544   else if(angular_diff < 0)
00545   {
00546     ret_steer.angular.z = -1;
00547     ret_steer.angular.x = fabs(angular_diff);
00548     return ret_steer;
00549   }
00550   else
00551   {
00552     ret_steer.angular.z = 0;
00553     ret_steer.angular.x = 0;
00554     return ret_steer;
00555   }
00556 }
00557 
00558 int plus_or_minus(double value)
00559 {
00560   if (value > 0)
00561   {
00562     return 1;
00563   }
00564   else if(value < 0)
00565   {
00566     return -1;
00567   }
00568   else
00569   {
00570     return 0;
00571   }
00572 }


cirkit_unit03_driver
Author(s): CIR-KIT
autogenerated on Thu Jun 6 2019 21:08:20