sr_robot_lib.cpp
Go to the documentation of this file.
00001 
00027 #include "sr_robot_lib/sr_hand_lib.hpp"
00028 #include <string>
00029 #include <boost/foreach.hpp>
00030 
00031 #include <sys/time.h>
00032 
00033 #include <ros/ros.h>
00034 
00035 #include "sr_robot_lib/shadow_PSTs.hpp"
00036 #include "sr_robot_lib/biotac.hpp"
00037 #include <pr2_mechanism_msgs/ListControllers.h>
00038 
00039 namespace shadow_robot
00040 {
00041 #ifdef DEBUG_PUBLISHER
00042 //max of 20 publishers for debug
00043   const int SrRobotLib::nb_debug_publishers_const = 20;
00044   const int SrRobotLib::debug_mutex_lock_wait_time = 100;
00045 #endif
00046 
00047   SrRobotLib::SrRobotLib(pr2_hardware_interface::HardwareInterface *hw)
00048     : main_pic_idle_time(0), main_pic_idle_time_min(1000), nullify_demand_(false), motor_current_state(
00049       operation_mode::device_update_state::INITIALIZATION), tactile_current_state(operation_mode::device_update_state::INITIALIZATION),
00050       config_index(MOTOR_CONFIG_FIRST_VALUE),
00051       control_type_changed_flag_(false),
00052       nh_tilde("~")
00053   {
00054     lock_command_sending_ = boost::shared_ptr<boost::mutex>(new boost::mutex());
00055 
00056     //advertise the service to nullify the demand sent to the motor
00057     // this makes it possible to easily stop the controllers.
00058     nullify_demand_server_ = nh_tilde.advertiseService("nullify_demand", &SrRobotLib::nullify_demand_callback, this);
00059 
00060     //reading the parameters to check for a specified default control type
00061     // using FORCE control if no parameters are set
00062     control_type_.control_type = sr_robot_msgs::ControlType::FORCE;
00063     std::string default_control_mode;
00064     nh_tilde.param<std::string>("default_control_mode", default_control_mode, "FORCE");
00065     if( default_control_mode.compare("PWM") == 0 )
00066     {
00067       ROS_INFO("Using PWM control.");
00068       control_type_.control_type = sr_robot_msgs::ControlType::PWM;
00069     }
00070     else
00071     {
00072       ROS_INFO("Using TORQUE control.");
00073     }
00074 
00075     //initialising the change control type service
00076     change_control_type_ = nh_tilde.advertiseService( "change_control_type", &SrRobotLib::change_control_type_callback_, this);
00077 
00079     motor_system_control_server_ = nh_tilde.advertiseService( "change_motor_system_controls", &SrRobotLib::motor_system_controls_callback_, this);
00080 
00081 #ifdef DEBUG_PUBLISHER
00082     debug_motor_indexes_and_data.resize(nb_debug_publishers_const);
00083     for( int i = 0; i < nb_debug_publishers_const; ++i )
00084     {
00085       std::stringstream ss;
00086       ss << "srh/debug_" << i;
00087       debug_publishers.push_back(node_handle.advertise<std_msgs::Int16>(ss.str().c_str(),100));
00088     }
00089 #endif
00090 
00091   }
00092 
00093   void SrRobotLib::update(ETHERCAT_DATA_STRUCTURE_0200_PALM_EDC_STATUS* status_data)
00094   {
00095     this->status_data = status_data;
00096 
00097     //read the PIC idle time
00098     main_pic_idle_time = status_data->idle_time_us;
00099     if (status_data->idle_time_us < main_pic_idle_time_min)
00100       main_pic_idle_time_min = status_data->idle_time_us;
00101 
00102     //get the current timestamp
00103     struct timeval tv;
00104     double timestamp = 0.0;
00105     if (gettimeofday(&tv, NULL))
00106     {
00107       ROS_WARN("SrRobotLib: Failed to get system time, timestamp in state will be zero");
00108     }
00109     else
00110     {
00111       timestamp = double(tv.tv_sec) + double(tv.tv_usec) / 1.0e+6;
00112     }
00113 
00114     //First we read the joints informations
00115     boost::ptr_vector<shadow_joints::Joint>::iterator joint_tmp = joints_vector.begin();
00116     for (; joint_tmp != joints_vector.end(); ++joint_tmp)
00117     {
00118       actuator = (joint_tmp->motor->actuator);
00119 
00120       motor_index_full = joint_tmp->motor->motor_id;
00121       actuator->state_.is_enabled_ = 1;
00122       actuator->state_.device_id_ = motor_index_full;
00123       actuator->state_.halted_ = false;
00124 
00125       //Fill in the tactiles.
00126       if( tactiles != NULL )
00127         actuator->state_.tactiles_ = tactiles->get_tactile_data();
00128 
00129       //calibrate the joint and update the position.
00130       calibrate_joint(joint_tmp);
00131 
00132       //add the last position to the queue
00133       joint_tmp->motor->actuator->state_.timestamp_ = timestamp;
00134 
00135       //filter the position and velocity
00136       std::pair<double, double> pos_and_velocity = joint_tmp->pos_filter.compute(
00137         joint_tmp->motor->actuator->state_.position_unfiltered_, timestamp);
00138       //reset the position to the filtered value
00139       joint_tmp->motor->actuator->state_.position_ = pos_and_velocity.first;
00140       //set the velocity to the filtered velocity
00141       joint_tmp->motor->actuator->state_.velocity_ = pos_and_velocity.second;
00142 
00143       //filter the effort
00144       std::pair<double, double> effort_and_effort_d = joint_tmp->effort_filter.compute(
00145         joint_tmp->motor->actuator->state_.force_unfiltered_, timestamp);
00146       joint_tmp->motor->actuator->state_.last_measured_effort_ = effort_and_effort_d.first;
00147 
00148       //if no motor is associated to this joint, then continue
00149       if ((motor_index_full == -1))
00150         continue;
00151 
00152       //get the remaining information.
00153       bool read_motor_info = false;
00154 
00155       if (status_data->which_motors == 0)
00156       {
00157         //We sampled the even motor numbers
00158         if (motor_index_full % 2 == 0)
00159           read_motor_info = true;
00160       }
00161       else
00162       {
00163         //we sampled the odd motor numbers
00164         if (motor_index_full % 2 == 1)
00165           read_motor_info = true;
00166       }
00167 
00168       //the position of the motor in the message
00169       // is different from the motor index:
00170       // the motor indexes range from 0 to 19
00171       // while the message contains information
00172       // for only 10 motors.
00173       index_motor_in_msg = motor_index_full / 2;
00174 
00175       //setting the position of the motor in the message,
00176       // we'll print that in the diagnostics.
00177       joint_tmp->motor->msg_motor_id = index_motor_in_msg;
00178 
00179       //ok now we read the info and add it to the actuator state
00180       if (read_motor_info)
00181         read_additional_data(joint_tmp);
00182     } //end for joint
00183 
00184     //then we read the tactile sensors information
00185     if (tactile_current_state == operation_mode::device_update_state::INITIALIZATION)
00186     {
00187       if( tactiles_init != NULL )
00188         tactiles_init->update(status_data);
00189     }
00190     else
00191     {
00192       if( tactiles != NULL )
00193         tactiles->update(status_data);
00194     }
00195   } //end update()
00196 
00197   void SrRobotLib::build_motor_command(ETHERCAT_DATA_STRUCTURE_0200_PALM_EDC_COMMAND* command)
00198   {
00199     //Mutual exclusion with the change_control_type service. We have to wait until the control_type_ variable has been set.
00200     boost::mutex::scoped_lock l(*lock_command_sending_);
00201 
00202     if(control_type_changed_flag_)
00203     {
00204       if(!change_control_parameters(control_type_.control_type))
00205       {
00206         ROS_FATAL("Changing control parameters failed. Stopping real time loop to protect the robot.");
00207         exit(EXIT_FAILURE);
00208       }
00209 
00210       control_type_changed_flag_ = false;
00211     }
00212 
00213     if (motor_current_state == operation_mode::device_update_state::INITIALIZATION)
00214     {
00215       motor_current_state = motor_updater_->build_init_command(command);
00216     }
00217     else
00218     {
00219       //build the motor command
00220       motor_current_state = motor_updater_->build_command(command);
00221     }
00222 
00223     if (tactile_current_state == operation_mode::device_update_state::INITIALIZATION)
00224     {
00225       if (tactiles_init->sensor_updater->build_init_command(command)
00226           != operation_mode::device_update_state::INITIALIZATION)
00227       {
00228         tactile_current_state = operation_mode::device_update_state::OPERATION;
00229 
00230         switch (tactiles_init->tactiles_vector->at(0).which_sensor)
00231         {
00232         case TACTILE_SENSOR_PROTOCOL_TYPE_PST3:
00233           tactiles = boost::shared_ptr<tactiles::ShadowPSTs>(
00234             new tactiles::ShadowPSTs(pst3_sensor_update_rate_configs_vector,
00235                                      operation_mode::device_update_state::OPERATION,
00236                                      tactiles_init->tactiles_vector));
00237 
00238           ROS_INFO("PST3 tactiles initialized");
00239           break;
00240 
00241         case TACTILE_SENSOR_PROTOCOL_TYPE_BIOTAC_2_3:
00242           tactiles = boost::shared_ptr<tactiles::Biotac>(
00243             new tactiles::Biotac(biotac_sensor_update_rate_configs_vector, operation_mode::device_update_state::OPERATION,
00244                                  tactiles_init->tactiles_vector));
00245 
00246           ROS_INFO("Biotac tactiles initialized");
00247           break;
00248 
00249         case TACTILE_SENSOR_PROTOCOL_TYPE_INVALID:
00250           ROS_WARN_STREAM("TACTILE_SENSOR_PROTOCOL_TYPE_INVALID!!");
00251           break;
00252         case TACTILE_SENSOR_PROTOCOL_TYPE_CONFLICTING:
00253           ROS_WARN_STREAM("TACTILE_SENSOR_PROTOCOL_TYPE_CONFLICTING!!");
00254           break;
00255         }
00256       }
00257     }
00258     else
00259       tactile_current_state = tactiles->sensor_updater->build_command(command);
00260 
00262     // Now we chose the command to send to the motor
00263     // by default we send a torque demand (we're running
00264     // the force control on the motors), but if we have a waiting
00265     // configuration, a reset command, or a motor system control
00266     // request then we send the configuration
00267     // or the reset.
00268     if ( reconfig_queue.empty() && reset_motors_queue.empty()
00269          && motor_system_control_flags_.empty() )
00270     {
00271       //no config to send
00272       switch( control_type_.control_type )
00273       {
00274       case sr_robot_msgs::ControlType::FORCE:
00275         command->to_motor_data_type = MOTOR_DEMAND_TORQUE;
00276         break;
00277       case sr_robot_msgs::ControlType::PWM:
00278         command->to_motor_data_type = MOTOR_DEMAND_PWM;
00279         break;
00280 
00281       default:
00282         command->to_motor_data_type = MOTOR_DEMAND_TORQUE;
00283         break;
00284       }
00285 
00286       //loop on all the joints and update their motor: we're sending commands to all the motors.
00287       boost::ptr_vector<shadow_joints::Joint>::iterator joint_tmp = joints_vector.begin();
00288       for (; joint_tmp != joints_vector.end(); ++joint_tmp)
00289       {
00290         if (joint_tmp->has_motor)
00291         {
00292           if( !nullify_demand_ )
00293           {
00294             //We send the computed demand
00295             command->motor_data[joint_tmp->motor->motor_id] = joint_tmp->motor->actuator->command_.effort_;
00296           }
00297           else
00298           {
00299             //We want to send a demand of 0
00300             command->motor_data[joint_tmp->motor->motor_id] = 0;
00301           }
00302 
00303 #ifdef DEBUG_PUBLISHER
00304           //publish the debug values for the given motors.
00305           // NB: debug_motor_indexes_and_data is smaller
00306           //     than debug_publishers.
00307           int publisher_index = 0;
00308           boost::shared_ptr<std::pair<int,int> > debug_pair;
00309           if( debug_mutex.try_lock() )
00310           {
00311             BOOST_FOREACH(debug_pair, debug_motor_indexes_and_data)
00312             {
00313               if( debug_pair != NULL )
00314               {
00315                 //check if we want to publish some data for the current motor
00316                 if( debug_pair->first == joint_tmp->motor->motor_id )
00317                 {
00318                   //check if it's the correct data
00319                   if( debug_pair->second == -1 )
00320                   {
00321                     msg_debug.data = joint_tmp->motor->actuator->command_.effort_;
00322                     debug_publishers[publisher_index].publish(msg_debug);
00323                   }
00324                 }
00325               }
00326               publisher_index ++;
00327             }
00328 
00329             debug_mutex.unlock();
00330           } //end try_lock
00331 #endif
00332 
00333           joint_tmp->motor->actuator->state_.last_commanded_effort_ = joint_tmp->motor->actuator->command_.effort_;
00334         } //end if has_motor
00335       } // end for each joint
00336     } //endif reconfig_queue.empty()
00337     else
00338     {
00339       if ( !motor_system_control_flags_.empty() )
00340       {
00341         //treat the first waiting system control and remove it from the queue
00342         std::vector<sr_robot_msgs::MotorSystemControls> system_controls_to_send;
00343         system_controls_to_send = motor_system_control_flags_.front();
00344         motor_system_control_flags_.pop();
00345 
00346         //set the correct type of command to send to the hand.
00347         command->to_motor_data_type = MOTOR_SYSTEM_CONTROLS;
00348 
00349         std::vector<sr_robot_msgs::MotorSystemControls>::iterator it;
00350         for( it = system_controls_to_send.begin(); it != system_controls_to_send.end(); ++it)
00351         {
00352           short combined_flags = 0;
00353           if( it->enable_backlash_compensation )
00354             combined_flags |= MOTOR_SYSTEM_CONTROL_BACKLASH_COMPENSATION_ENABLE;
00355           else
00356             combined_flags |= MOTOR_SYSTEM_CONTROL_BACKLASH_COMPENSATION_DISABLE;
00357 
00358           if( it->increase_sgl_tracking )
00359             combined_flags |= MOTOR_SYSTEM_CONTROL_SGL_TRACKING_INC;
00360           if( it->decrease_sgl_tracking )
00361             combined_flags |= MOTOR_SYSTEM_CONTROL_SGL_TRACKING_DEC;
00362 
00363           if( it->increase_sgr_tracking )
00364             combined_flags |= MOTOR_SYSTEM_CONTROL_SGR_TRACKING_INC;
00365           if( it->decrease_sgr_tracking )
00366             combined_flags |= MOTOR_SYSTEM_CONTROL_SGR_TRACKING_DEC;
00367 
00368           if( it->initiate_jiggling )
00369             combined_flags |= MOTOR_SYSTEM_CONTROL_INITIATE_JIGGLING;
00370 
00371           if( it->write_config_to_eeprom )
00372             combined_flags |= MOTOR_SYSTEM_CONTROL_EEPROM_WRITE;
00373 
00374           command->motor_data[ it->motor_id ] = combined_flags;
00375         }
00376       } //end if motor_system_control_flags_.empty
00377       else
00378       {
00379         if (!reset_motors_queue.empty())
00380         {
00381           //reset the CAN messages counters for the motor we're going to reset.
00382           short motor_id = reset_motors_queue.front();
00383           boost::ptr_vector<shadow_joints::Joint>::iterator joint_tmp = joints_vector.begin();
00384           for (; joint_tmp != joints_vector.end(); ++joint_tmp)
00385           {
00386             if( joint_tmp->motor->motor_id == motor_id )
00387             {
00388               joint_tmp->motor->actuator->state_.can_msgs_transmitted_ = 0;
00389               joint_tmp->motor->actuator->state_.can_msgs_received_ = 0;
00390             }
00391           }
00392 
00393           //we have some reset command waiting.
00394           // We'll send all of them
00395           command->to_motor_data_type = MOTOR_SYSTEM_RESET;
00396 
00397           while (!reset_motors_queue.empty())
00398           {
00399             motor_id = reset_motors_queue.front();
00400             reset_motors_queue.pop();
00401 
00402             // we send the MOTOR_RESET_SYSTEM_KEY
00403             // and the motor id (on the bus)
00404             crc_unions::union16 to_send;
00405             to_send.byte[1] = MOTOR_SYSTEM_RESET_KEY >> 8;
00406             if (motor_id > 9)
00407               to_send.byte[0] = motor_id - 10;
00408             else
00409               to_send.byte[0] = motor_id;
00410 
00411             command->motor_data[motor_id] = to_send.word;
00412           }
00413         } // end if reset queue not empty
00414         else
00415         {
00416           if (!reconfig_queue.empty())
00417           {
00418             //we have a waiting config:
00419             // we need to send all the config, finishing by the
00420             // CRC. We'll remove the config from the queue only
00421             // when the whole config has been sent
00422 
00423             // the motor data type correspond to the index
00424             // in the config array.
00425             command->to_motor_data_type = static_cast<TO_MOTOR_DATA_TYPE>(config_index);
00426 
00427             //convert the motor index to the index of the motor in the message
00428             int motor_index = reconfig_queue.front().first;
00429 
00430             //set the data we want to send to the given motor
00431             command->motor_data[motor_index] = reconfig_queue.front().second[config_index].word;
00432 
00433             //We're now sending the CRC. We need to send the correct CRC to
00434             // the motor we updated, and CRC=0 to all the other motors in its
00435             // group (odd/even) to tell them to ignore the new
00436             // configuration.
00437             // Once the config has been transmitted, pop the element
00438             // and reset the config_index to the beginning of the
00439             // config values
00440             if (config_index == static_cast<int>(MOTOR_CONFIG_CRC))
00441             {
00442               //loop on all the motors and send a CRC of 0
00443               // except for the motor we're reconfiguring
00444               for (int i = 0; i < NUM_MOTORS; ++i)
00445               {
00446                 if (i != motor_index)
00447                   command->motor_data[i] = 0;
00448               }
00449 
00450               //reset the config_index and remove the configuration
00451               // we just sent from the configurations queue
00452               reconfig_queue.pop();
00453               config_index = MOTOR_CONFIG_FIRST_VALUE;
00454             }
00455             else
00456               ++config_index;
00457           } //end if reconfig queue not empty
00458         } // end else reset_queue.empty
00459       } // end else motor_system_control_flags_.empty
00460     } //endelse reconfig_queue.empty() && reset_queue.empty()
00461   }
00462 
00463   void SrRobotLib::add_diagnostics(std::vector<diagnostic_msgs::DiagnosticStatus> &vec,
00464                                    diagnostic_updater::DiagnosticStatusWrapper &d)
00465   {
00466     boost::ptr_vector<shadow_joints::Joint>::iterator joint = joints_vector.begin();
00467     for (; joint != joints_vector.end(); ++joint)
00468     {
00469       std::stringstream name;
00470       name.str("");
00471       name << "SRDMotor " << joint->joint_name;
00472       d.name = name.str();
00473 
00474       if (joint->has_motor)
00475       {
00476         const sr_actuator::SrActuatorState *state(&(joint->motor->actuator)->state_);
00477 
00478         if (joint->motor->motor_ok)
00479         {
00480           if (joint->motor->bad_data)
00481           {
00482             d.summary(d.WARN, "WARNING, bad CAN data received");
00483 
00484             d.clear();
00485             d.addf("Motor ID", "%d", joint->motor->motor_id);
00486           }
00487           else //the data is good
00488           {
00489             d.summary(d.OK, "OK");
00490 
00491             d.clear();
00492             d.addf("Motor ID", "%d", joint->motor->motor_id);
00493             d.addf("Motor ID in message", "%d", joint->motor->msg_motor_id);
00494             d.addf("Serial Number", "%d", state->serial_number );
00495             d.addf("Assembly date", "%d / %d / %d", state->assembly_data_day, state->assembly_data_month, state->assembly_data_year );
00496 
00497             d.addf("Strain Gauge Left", "%d", state->strain_gauge_left_);
00498             d.addf("Strain Gauge Right", "%d", state->strain_gauge_right_);
00499 
00500             //if some flags are set
00501             std::stringstream ss;
00502             if (state->flags_.size() > 0)
00503             {
00504               int flags_seriousness = d.OK;
00505               std::pair<std::string, bool> flag;
00506               BOOST_FOREACH(flag, state->flags_)
00507               {
00508                 //Serious error flag
00509                 if (flag.second)
00510                   flags_seriousness = d.ERROR;
00511 
00512                 if (flags_seriousness != d.ERROR)
00513                   flags_seriousness = d.WARN;
00514                 ss << flag.first << " | ";
00515               }
00516               d.summary(flags_seriousness, ss.str().c_str());
00517             }
00518             else
00519               ss << " None";
00520             d.addf("Motor Flags", "%s", ss.str().c_str());
00521 
00522             d.addf("Measured PWM", "%d", state->pwm_);
00523             d.addf("Measured Current", "%f", state->last_measured_current_);
00524             d.addf("Measured Voltage", "%f", state->motor_voltage_);
00525             d.addf("Measured Effort", "%f", state->last_measured_effort_);
00526             d.addf("Temperature", "%f", state->temperature_);
00527 
00528             d.addf("Unfiltered position", "%f", state->position_unfiltered_);
00529             d.addf("Unfiltered force", "%f", state->force_unfiltered_);
00530 
00531             d.addf("Gear Ratio", "%d", state->motor_gear_ratio);
00532 
00533             d.addf("Number of CAN messages received", "%lld", state->can_msgs_received_);
00534             d.addf("Number of CAN messages transmitted", "%lld", state->can_msgs_transmitted_);
00535 
00536             d.addf("Force control Pterm", "%d", state->force_control_pterm);
00537             d.addf("Force control Iterm", "%d", state->force_control_iterm);
00538             d.addf("Force control Dterm", "%d", state->force_control_dterm);
00539 
00540             d.addf("Force control F", "%d", state->force_control_f_);
00541             d.addf("Force control P", "%d", state->force_control_p_);
00542             d.addf("Force control I", "%d", state->force_control_i_);
00543             d.addf("Force control D", "%d", state->force_control_d_);
00544             d.addf("Force control Imax", "%d", state->force_control_imax_);
00545             d.addf("Force control Deadband", "%d", state->force_control_deadband_);
00546             d.addf("Force control Frequency", "%d", state->force_control_frequency_);
00547 
00548             if (state->force_control_sign_ == 0)
00549               d.addf("Force control Sign", "+");
00550             else
00551               d.addf("Force control Sign", "-");
00552 
00553             d.addf("Last Commanded Effort", "%f", state->last_commanded_effort_);
00554 
00555             d.addf("Encoder Position", "%f", state->position_);
00556 
00557             if (state->firmware_modified_)
00558               d.addf("Firmware svn revision (server / pic / modified)", "%d / %d / True",
00559                      state->server_firmware_svn_revision_, state->pic_firmware_svn_revision_);
00560             else
00561               d.addf("Firmware svn revision (server / pic / modified)", "%d / %d / False",
00562                      state->server_firmware_svn_revision_, state->pic_firmware_svn_revision_);
00563           }
00564         }
00565         else
00566         {
00567           d.summary(d.ERROR, "Motor error");
00568           d.clear();
00569           d.addf("Motor ID", "%d", joint->motor->motor_id);
00570         }
00571       }
00572       else
00573       {
00574         d.summary(d.OK, "No motor associated to this joint");
00575         d.clear();
00576       }
00577       vec.push_back(d);
00578 
00579     } //end for each joints
00580 
00581   }
00582 
00583   void SrRobotLib::calibrate_joint(boost::ptr_vector<shadow_joints::Joint>::iterator joint_tmp)
00584   {
00585     actuator->state_.raw_sensor_values_.clear();
00586     actuator->state_.calibrated_sensor_values_.clear();
00587 
00588     if (joint_tmp->joint_to_sensor.calibrate_after_combining_sensors)
00589     {
00590       //first we combine the different sensors and then we
00591       // calibrate the value we obtained. This is used for
00592       // some compound sensors ( THJ5 = cal(THJ5A + THJ5B))
00593       double raw_position = 0.0;
00594       //when combining the values, we use the coefficient imported
00595       // from the sensor_to_joint.yaml file (in sr_edc_launch/config)
00596       BOOST_FOREACH(shadow_joints::PartialJointToSensor joint_to_sensor, joint_tmp->joint_to_sensor.joint_to_sensor_vector)
00597       {
00598         int tmp_raw = status_data->sensors[joint_to_sensor.sensor_id];
00599         actuator->state_.raw_sensor_values_.push_back(tmp_raw);
00600         raw_position += static_cast<double>(tmp_raw) * joint_to_sensor.coeff;
00601       }
00602 
00603       //and now we calibrate
00604       calibration_tmp = calibration_map.find(joint_tmp->joint_name);
00605       actuator->state_.position_unfiltered_ = calibration_tmp->compute(static_cast<double>(raw_position));
00606     }
00607     else
00608     {
00609       //we calibrate the different sensors first and we combine the calibrated
00610       //values. This is used in the joint 0s for example ( J0 = cal(J1)+cal(J2) )
00611       double calibrated_position = 0.0;
00612       shadow_joints::PartialJointToSensor joint_to_sensor;
00613       std::string sensor_name;
00614 
00615       ROS_DEBUG_STREAM("Combining actuator " << joint_tmp->joint_name);
00616 
00617       for (unsigned int index_joint_to_sensor = 0;
00618            index_joint_to_sensor < joint_tmp->joint_to_sensor.joint_to_sensor_vector.size(); ++index_joint_to_sensor)
00619       {
00620         joint_to_sensor = joint_tmp->joint_to_sensor.joint_to_sensor_vector[index_joint_to_sensor];
00621         sensor_name = joint_tmp->joint_to_sensor.sensor_names[index_joint_to_sensor];
00622 
00623         //get the raw position
00624         int raw_pos = status_data->sensors[joint_to_sensor.sensor_id];
00625         //push the new raw values
00626         actuator->state_.raw_sensor_values_.push_back(raw_pos);
00627 
00628         //calibrate and then combine
00629         calibration_tmp = calibration_map.find(sensor_name);
00630         double tmp_cal_value = calibration_tmp->compute(static_cast<double>(raw_pos));
00631 
00632         //push the new calibrated values.
00633         actuator->state_.calibrated_sensor_values_.push_back(tmp_cal_value);
00634 
00635         calibrated_position += tmp_cal_value * joint_to_sensor.coeff;
00636 
00637         ROS_DEBUG_STREAM("      -> "<< sensor_name<< " raw = " << raw_pos << " calibrated = " << calibrated_position);
00638       }
00639       actuator->state_.position_unfiltered_ = calibrated_position;
00640       ROS_DEBUG_STREAM("          => "<< actuator->state_.position_unfiltered_);
00641     }
00642   } //end calibrate_joint()
00643 
00644   void SrRobotLib::read_additional_data(boost::ptr_vector<shadow_joints::Joint>::iterator joint_tmp)
00645   {
00646     //check the masks to see if the CAN messages arrived to the motors
00647     //the flag should be set to 1 for each motor
00648     joint_tmp->motor->motor_ok = sr_math_utils::is_bit_mask_index_true(status_data->which_motor_data_arrived,
00649                                                                        motor_index_full);
00650 
00651     //check the masks to see if a bad CAN message arrived
00652     //the flag should be 0
00653     joint_tmp->motor->bad_data = sr_math_utils::is_bit_mask_index_true(status_data->which_motor_data_had_errors,
00654                                                                        index_motor_in_msg);
00655 
00656     crc_unions::union16 tmp_value;
00657 
00658     if (joint_tmp->motor->motor_ok && !(joint_tmp->motor->bad_data))
00659     {
00660 #ifdef DEBUG_PUBLISHER
00661       int publisher_index = 0;
00662       //publish the debug values for the given motors.
00663       // NB: debug_motor_indexes_and_data is smaller
00664       //     than debug_publishers.
00665       boost::shared_ptr<std::pair<int,int> > debug_pair;
00666 
00667       if( debug_mutex.try_lock() )
00668       {
00669         BOOST_FOREACH(debug_pair, debug_motor_indexes_and_data)
00670         {
00671           if( debug_pair != NULL )
00672           {
00673             //check if we want to publish some data for the current motor
00674             if( debug_pair->first == joint_tmp->motor->motor_id )
00675             {
00676               //if < 0, then we're not asking for a FROM_MOTOR_DATA_TYPE
00677               if( debug_pair->second > 0 )
00678               {
00679                 //check if it's the correct data
00680                 if( debug_pair->second == status_data->motor_data_type )
00681                 {
00682                   msg_debug.data = status_data->motor_data_packet[index_motor_in_msg].misc;
00683                   debug_publishers[publisher_index].publish(msg_debug);
00684                 }
00685               }
00686             }
00687           }
00688           publisher_index ++;
00689         }
00690 
00691         debug_mutex.unlock();
00692       } //end try_lock
00693 #endif
00694 
00695       //we received the data and it was correct
00696       bool read_torque = true;
00697       switch (status_data->motor_data_type)
00698       {
00699       case MOTOR_DATA_SGL:
00700         actuator->state_.strain_gauge_left_ =
00701           static_cast<int16s>(status_data->motor_data_packet[index_motor_in_msg].misc);
00702 
00703 #ifdef DEBUG_PUBLISHER
00704         if( joint_tmp->motor->motor_id == 8 )
00705         {
00706           //ROS_ERROR_STREAM("SGL " <<actuator->state_.strain_gauge_left_);
00707           msg_debug.data = actuator->state_.strain_gauge_left_;
00708           debug_publishers[0].publish(msg_debug);
00709         }
00710 #endif
00711         break;
00712       case MOTOR_DATA_SGR:
00713         actuator->state_.strain_gauge_right_ =
00714           static_cast<int16s>(status_data->motor_data_packet[index_motor_in_msg].misc);
00715 
00716 #ifdef DEBUG_PUBLISHER
00717         if( joint_tmp->motor->motor_id == 8 )
00718         {
00719           //ROS_ERROR_STREAM("SGR " <<actuator->state_.strain_gauge_right_);
00720           msg_debug.data = actuator->state_.strain_gauge_right_;
00721           debug_publishers[1].publish(msg_debug);
00722         }
00723 #endif
00724         break;
00725       case MOTOR_DATA_PWM:
00726         actuator->state_.pwm_ =
00727           static_cast<int>(static_cast<int16s>(status_data->motor_data_packet[index_motor_in_msg].misc));
00728         break;
00729       case MOTOR_DATA_FLAGS:
00730         actuator->state_.flags_ = humanize_flags(status_data->motor_data_packet[index_motor_in_msg].misc);
00731         break;
00732       case MOTOR_DATA_CURRENT:
00733         //we're receiving the current in milli amps
00734         actuator->state_.last_measured_current_ =
00735           static_cast<double>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc))
00736           / 1000.0;
00737 
00738 #ifdef DEBUG_PUBLISHER
00739         if( joint_tmp->motor->motor_id == 8 )
00740         {
00741           //ROS_ERROR_STREAM("Current " <<actuator->state_.last_measured_current_);
00742           msg_debug.data = static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc);
00743           debug_publishers[2].publish(msg_debug);
00744         }
00745 #endif
00746         break;
00747       case MOTOR_DATA_VOLTAGE:
00748         actuator->state_.motor_voltage_ =
00749           static_cast<double>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc)) / 256.0;
00750 
00751 #ifdef DEBUG_PUBLISHER
00752         if( joint_tmp->motor->motor_id == 8 )
00753         {
00754           //ROS_ERROR_STREAM("Voltage " <<actuator->state_.motor_voltage_);
00755           msg_debug.data = static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc);
00756           debug_publishers[3].publish(msg_debug);
00757         }
00758 #endif
00759         break;
00760       case MOTOR_DATA_TEMPERATURE:
00761         actuator->state_.temperature_ =
00762           static_cast<double>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc)) / 256.0;
00763         break;
00764       case MOTOR_DATA_CAN_NUM_RECEIVED:
00765         // those are 16 bits values and will overflow -> we compute the real value.
00766         // This needs to be updated faster than the overflowing period (which should be roughly every 30s)
00767         actuator->state_.can_msgs_received_ = sr_math_utils::counter_with_overflow(
00768           actuator->state_.can_msgs_received_,
00769           static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc));
00770         break;
00771       case MOTOR_DATA_CAN_NUM_TRANSMITTED:
00772         // those are 16 bits values and will overflow -> we compute the real value.
00773         // This needs to be updated faster than the overflowing period (which should be roughly every 30s)
00774         actuator->state_.can_msgs_transmitted_ = sr_math_utils::counter_with_overflow(
00775           actuator->state_.can_msgs_received_,
00776           static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc));
00777         break;
00778 
00779       case MOTOR_DATA_SLOW_MISC:
00780         //We received a slow data:
00781         // the slow data type is contained in .torque, while
00782         // the actual data is in .misc.
00783         // so we won't read torque information from .torque
00784         read_torque = false;
00785 
00786         switch (static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].torque))
00787         {
00788         case MOTOR_SLOW_DATA_SVN_REVISION:
00789           actuator->state_.pic_firmware_svn_revision_ =
00790             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc));
00791           break;
00792         case MOTOR_SLOW_DATA_SVN_SERVER_REVISION:
00793           actuator->state_.server_firmware_svn_revision_ =
00794             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc));
00795           break;
00796         case MOTOR_SLOW_DATA_SVN_MODIFIED:
00797           actuator->state_.firmware_modified_ =
00798             static_cast<bool>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc));
00799           break;
00800         case MOTOR_SLOW_DATA_SERIAL_NUMBER_LOW:
00801           actuator->state_.set_serial_number_low (
00802             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc)) );
00803           break;
00804         case MOTOR_SLOW_DATA_SERIAL_NUMBER_HIGH:
00805           actuator->state_.set_serial_number_high (
00806             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc)) );
00807           break;
00808         case MOTOR_SLOW_DATA_GEAR_RATIO:
00809           actuator->state_.motor_gear_ratio =
00810             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc));
00811           break;
00812         case MOTOR_SLOW_DATA_ASSEMBLY_DATE_YYYY:
00813           actuator->state_.assembly_data_year =
00814             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc));
00815           break;
00816         case MOTOR_SLOW_DATA_ASSEMBLY_DATE_MMDD:
00817           actuator->state_.assembly_data_month =
00818             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc)
00819                                       >> 8);
00820           actuator->state_.assembly_data_day =
00821             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc)
00822                                       && 0x00FF);
00823           break;
00824         case MOTOR_SLOW_DATA_CONTROLLER_F:
00825           actuator->state_.force_control_f_ =
00826             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc));
00827           break;
00828         case MOTOR_SLOW_DATA_CONTROLLER_P:
00829           actuator->state_.force_control_p_ =
00830             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc));
00831           break;
00832         case MOTOR_SLOW_DATA_CONTROLLER_I:
00833           actuator->state_.force_control_i_ =
00834             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc));
00835           break;
00836         case MOTOR_SLOW_DATA_CONTROLLER_D:
00837           actuator->state_.force_control_d_ =
00838             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc));
00839           break;
00840         case MOTOR_SLOW_DATA_CONTROLLER_IMAX:
00841           actuator->state_.force_control_imax_ =
00842             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc));
00843           break;
00844         case MOTOR_SLOW_DATA_CONTROLLER_DEADSIGN:
00845           tmp_value.word = status_data->motor_data_packet[index_motor_in_msg].misc;
00846           actuator->state_.force_control_deadband_ = static_cast<int>(tmp_value.byte[0]);
00847           actuator->state_.force_control_sign_ = static_cast<int>(tmp_value.byte[1]);
00848           break;
00849         case MOTOR_SLOW_DATA_CONTROLLER_FREQUENCY:
00850           actuator->state_.force_control_frequency_ =
00851             static_cast<unsigned int>(static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc));
00852           break;
00853 
00854         default:
00855           break;
00856         }
00857         break;
00858 
00859       case MOTOR_DATA_CAN_ERROR_COUNTERS:
00860         actuator->state_.can_error_counters =
00861           static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc);
00862         break;
00863       case MOTOR_DATA_PTERM:
00864         actuator->state_.force_control_pterm =
00865           static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc);
00866         break;
00867       case MOTOR_DATA_ITERM:
00868         actuator->state_.force_control_iterm =
00869           static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc);
00870         break;
00871       case MOTOR_DATA_DTERM:
00872         actuator->state_.force_control_dterm =
00873           static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].misc);
00874         break;
00875 
00876       default:
00877         break;
00878       }
00879 
00880       if (read_torque)
00881       {
00882         actuator->state_.force_unfiltered_ =
00883           static_cast<double>(static_cast<int16s>(status_data->motor_data_packet[index_motor_in_msg].torque));
00884 
00885 #ifdef DEBUG_PUBLISHER
00886         if( joint_tmp->motor->motor_id == 8 )
00887         {
00888           msg_debug.data = static_cast<int16s>(status_data->motor_data_packet[index_motor_in_msg].torque);
00889           debug_publishers[4].publish(msg_debug);
00890         }
00891 #endif
00892       }
00893 
00894       //Check the message to see if everything has already been received
00895       if (motor_current_state == operation_mode::device_update_state::INITIALIZATION)
00896       {
00897         if (motor_data_checker->check_message(
00898               joint_tmp, status_data->motor_data_type,
00899               static_cast<int16u>(status_data->motor_data_packet[index_motor_in_msg].torque)))
00900         {
00901           motor_updater_->update_state = operation_mode::device_update_state::OPERATION;
00902           motor_current_state = operation_mode::device_update_state::OPERATION;
00903 
00904           ROS_INFO("All motors were initialized.");
00905         }
00906       }
00907     }
00908   }
00909 
00910   std::vector<std::pair<std::string, bool> > SrRobotLib::humanize_flags(int flag)
00911   {
00912     std::vector<std::pair<std::string, bool> > flags;
00913 
00914     //16 is the number of flags
00915     for (unsigned int i = 0; i < 16; ++i)
00916     {
00917       std::pair<std::string, bool> new_flag;
00918       //if the flag is set add the name
00919       if (sr_math_utils::is_bit_mask_index_true(flag, i))
00920       {
00921         if (sr_math_utils::is_bit_mask_index_true(SERIOUS_ERROR_FLAGS, i))
00922           new_flag.second = true;
00923         else
00924           new_flag.second = false;
00925 
00926         new_flag.first = error_flag_names[i];
00927         flags.push_back(new_flag);
00928       }
00929     }
00930     return flags;
00931   }
00932 
00933   void SrRobotLib::generate_force_control_config(int motor_index, int max_pwm, int sg_left, int sg_right, int f, int p,
00934                                                  int i, int d, int imax, int deadband, int sign)
00935   {
00936     ROS_INFO_STREAM(
00937       "Setting new pid values for motor" << motor_index << ": max_pwm="<< max_pwm <<" sgleftref=" << sg_left << " sgrightref=" << sg_right << " f=" << f << " p=" << p << " i=" << i << " d="<< d << " imax=" << imax << " deadband="<< deadband << " sign=" << sign);
00938 
00939     //the vector is of the size of the TO_MOTOR_DATA_TYPE enum.
00940     //the value of the element at a given index is the value
00941     //for the given MOTOR_CONFIG.
00942     std::vector<crc_unions::union16> full_config(MOTOR_CONFIG_CRC + 1);
00943     crc_unions::union16 value;
00944 
00945     value.word = max_pwm;
00946     full_config.at(MOTOR_CONFIG_MAX_PWM) = value;
00947 
00948     value.byte[0] = sg_left;
00949     value.byte[1] = sg_right;
00950     full_config.at(MOTOR_CONFIG_SG_REFS) = value;
00951 
00952     value.word = f;
00953     full_config.at(MOTOR_CONFIG_F) = value;
00954 
00955     value.word = p;
00956     full_config.at(MOTOR_CONFIG_P) = value;
00957 
00958     value.word = i;
00959     full_config.at(MOTOR_CONFIG_I) = value;
00960 
00961     value.word = d;
00962     full_config.at(MOTOR_CONFIG_D) = value;
00963 
00964     value.word = imax;
00965     full_config.at(MOTOR_CONFIG_IMAX) = value;
00966 
00967     value.byte[0] = deadband;
00968     value.byte[1] = sign;
00969     full_config.at(MOTOR_CONFIG_DEADBAND_SIGN) = value;
00970     ROS_DEBUG_STREAM(
00971       "deadband: " << static_cast<int>(static_cast<int8u>(value.byte[0]) ) << " value: " << static_cast<int16u>(value.word));
00972 
00973     //compute crc
00974     crc_result = 0;
00975     for (unsigned int i = MOTOR_CONFIG_FIRST_VALUE; i <= MOTOR_CONFIG_LAST_VALUE; ++i)
00976     {
00977       crc_byte = full_config.at(i).byte[0];
00978       INSERT_CRC_CALCULATION_HERE;
00979 
00980       crc_byte = full_config.at(i).byte[1];
00981       INSERT_CRC_CALCULATION_HERE;
00982     }
00983 
00984     //never send a CRC of 0, send 1 if the
00985     // computed CRC is 0 (0 is a code for
00986     // ignoring the config)
00987     if (crc_result == 0)
00988       crc_result = 1;
00989     value.word = crc_result;
00990     full_config.at(MOTOR_CONFIG_CRC) = value;
00991 
00992     ForceConfig config;
00993     config.first = motor_index;
00994     config.second = full_config;
00995     //push the new config to the configuration queue
00996     reconfig_queue.push(config);
00997   }
00998 
00999   void SrRobotLib::reinitialize_motors()
01000   {
01001     //Create a new MotorUpdater object
01002     motor_updater_ = boost::shared_ptr<generic_updater::MotorUpdater>(new generic_updater::MotorUpdater(motor_update_rate_configs_vector, operation_mode::device_update_state::INITIALIZATION));
01003     motor_current_state = operation_mode::device_update_state::INITIALIZATION;
01004     //Initialize the motor data checker
01005     motor_data_checker = boost::shared_ptr<generic_updater::MotorDataChecker>(new generic_updater::MotorDataChecker(joints_vector, motor_updater_->initialization_configs_vector));
01006   }
01007 
01008   void SrRobotLib::reinitialize_sensors()
01009   {
01010     //Create a new GenericTactiles object
01011     tactiles_init = boost::shared_ptr<tactiles::GenericTactiles>( new tactiles::GenericTactiles(generic_sensor_update_rate_configs_vector, operation_mode::device_update_state::INITIALIZATION) );
01012     tactile_current_state = operation_mode::device_update_state::INITIALIZATION;
01013   }
01014 
01015   bool SrRobotLib::nullify_demand_callback( sr_robot_msgs::NullifyDemand::Request& request,
01016                                             sr_robot_msgs::NullifyDemand::Response& response )
01017   {
01018     if( request.nullify_demand )
01019       ROS_INFO_STREAM("Nullifying the demand sent to the motor. Will ignore the values computed by the controllers and send 0.");
01020     else
01021       ROS_INFO_STREAM("Using the value computed by the controllers to send the demands to the motors.");
01022 
01023     nullify_demand_ = request.nullify_demand;
01024     return true;
01025   }
01026 
01027   bool SrRobotLib::change_control_type_callback_( sr_robot_msgs::ChangeControlType::Request& request,
01028                                                   sr_robot_msgs::ChangeControlType::Response& response )
01029   {
01030     if( (request.control_type.control_type != sr_robot_msgs::ControlType::PWM) &&
01031         (request.control_type.control_type != sr_robot_msgs::ControlType::FORCE) )
01032     {
01033       std::string ctrl_type_text = "";
01034       if(control_type_.control_type == sr_robot_msgs::ControlType::FORCE)
01035         ctrl_type_text = "FORCE";
01036       else
01037         ctrl_type_text = "PWM";
01038 
01039       ROS_ERROR_STREAM(" The value you specified for the control type (" << request.control_type
01040                        << ") is incorrect. Using " << ctrl_type_text << " control.");
01041 
01042       response.result = control_type_;
01043       return false;
01044     }
01045 
01046     if(control_type_.control_type != request.control_type.control_type)
01047     {
01048       //Mutual exclusion with the build_motor_command() function. We have to wait until the current motor command has been built.
01049       boost::mutex::scoped_lock l(*lock_command_sending_);
01050 
01051       ROS_WARN("Changing control type");
01052 
01053       control_type_ = request.control_type;
01054       //Flag to signal that there has been a change in the value of control_type_ and certain actions are required.
01055       //The flag is set in the callback function of the change_control_type_ service.
01056       //The flag is checked in build_motor_command() and the necessary actions are taken there.
01057       //These actions involve calling services in the controller manager and all the active controllers. This is the
01058       //reason why we don't do it directly in the callback function. As we use a single thread to serve the callbacks,
01059       //doing so would cause a deadlock, thus we do it in the realtime loop thread instead.
01060       control_type_changed_flag_ = true;
01061     }
01062 
01063     response.result = control_type_;
01064     return true;
01065   }
01066 
01067   bool SrRobotLib::change_control_parameters(int16_t control_type)
01068   {
01069     bool success = true;
01070     std::string env_variable;
01071     std::string param_value;
01072 
01073     if( control_type == sr_robot_msgs::ControlType::PWM)
01074     {
01075       env_variable = "PWM_CONTROL=1";
01076       param_value = "PWM";
01077     }
01078     else
01079     {
01080       env_variable = "PWM_CONTROL=0";
01081       param_value = "FORCE";
01082     }
01083 
01084     int result = system((env_variable + " roslaunch sr_ethercat_hand_config sr_edc_default_controllers.launch").c_str());
01085 
01086     if(result == 0)
01087     {
01088       ROS_WARN("New parameters loaded successfully on Parameter Server");
01089 
01090       nh_tilde.setParam("default_control_mode", param_value);
01091 
01092       ros::ServiceClient list_ctrl_client = nh_tilde.serviceClient<pr2_mechanism_msgs::ListControllers>("/pr2_controller_manager/list_controllers");
01093       pr2_mechanism_msgs::ListControllers controllers_list;
01094 
01095       if (list_ctrl_client.call(controllers_list))
01096       {
01097         for(unsigned int i=0; i < controllers_list.response.controllers.size(); ++i)
01098         {
01099           ros::ServiceClient reset_gains_client = nh_tilde.serviceClient<std_srvs::Empty>("/" + controllers_list.response.controllers.at(i) + "/reset_gains");
01100           std_srvs::Empty empty_message;
01101           if (!reset_gains_client.call(empty_message))
01102           {
01103             ROS_ERROR_STREAM("Failed to reset gains for controller: " << controllers_list.response.controllers.at(i));
01104             return false;
01105           }
01106         }
01107       }
01108       else
01109       {
01110         return false;
01111       }
01112     }
01113     else
01114     {
01115       return false;
01116     }
01117 
01118     return success;
01119   }
01120 
01121   bool SrRobotLib::motor_system_controls_callback_( sr_robot_msgs::ChangeMotorSystemControls::Request& request,
01122                                                     sr_robot_msgs::ChangeMotorSystemControls::Response& response )
01123   {
01124     std::vector<sr_robot_msgs::MotorSystemControls> tmp_motor_controls;
01125 
01126     response.result = sr_robot_msgs::ChangeMotorSystemControls::Response::SUCCESS;
01127     bool no_motor_id_out_of_range = true;
01128 
01129     for( unsigned int i=0; i < request.motor_system_controls.size(); ++i)
01130     {
01131       if( request.motor_system_controls[i].motor_id >= NUM_MOTORS ||
01132           request.motor_system_controls[i].motor_id < 0)
01133       {
01134         response.result = sr_robot_msgs::ChangeMotorSystemControls::Response::MOTOR_ID_OUT_OF_RANGE;
01135         no_motor_id_out_of_range = false;
01136       }
01137       else
01138       {
01139         //only pushes the demands with a correct motor_id
01140         tmp_motor_controls.push_back( request.motor_system_controls[i] );
01141       }
01142     }
01143 
01144     //add the request to the queue if it's not empty
01145     if( tmp_motor_controls.size() > 0 )
01146       motor_system_control_flags_.push( tmp_motor_controls );
01147 
01148     return no_motor_id_out_of_range;
01149   }
01150 
01151 } //end namespace
01152 
01153 /* For the emacs weenies in the crowd.
01154  Local Variables:
01155  c-basic-offset: 2
01156  End:
01157  */


sr_robot_lib
Author(s): Ugo Cupcic / ugo@shadowrobot.com , software@shadowrobot.com
autogenerated on Thu Jan 2 2014 12:02:17