00001
00027 #include "sr_robot_lib/sr_robot_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 "sr_robot_lib/UBI0.hpp"
00038 #include <pr2_mechanism_msgs/ListControllers.h>
00039
00040 #define SERIOUS_ERROR_FLAGS PALM_0200_EDC_SERIOUS_ERROR_FLAGS
00041 #define error_flag_names palm_0200_edc_error_flag_names
00042
00043 namespace shadow_robot
00044 {
00045 #ifdef DEBUG_PUBLISHER
00046
00047 template <class StatusType, class CommandType>
00048 const int SrRobotLib<StatusType, CommandType>::nb_debug_publishers_const = 20;
00049
00050
00051 #endif
00052
00053 template <class StatusType, class CommandType>
00054 const int SrRobotLib<StatusType, CommandType>::nb_sensor_data = 32;
00055
00056 template <class StatusType, class CommandType>
00057 const char* SrRobotLib<StatusType, CommandType>::human_readable_sensor_data_types[nb_sensor_data] = {"TACTILE_SENSOR_TYPE_SAMPLE_FREQUENCY_HZ",
00058 "TACTILE_SENSOR_TYPE_MANUFACTURER",
00059 "TACTILE_SENSOR_TYPE_SERIAL_NUMBER",
00060 "TACTILE_SENSOR_TYPE_SOFTWARE_VERSION",
00061 "TACTILE_SENSOR_TYPE_PCB_VERSION",
00062 "TACTILE_SENSOR_TYPE_WHICH_SENSORS",
00063 "TACTILE_SENSOR_TYPE_PST3_PRESSURE_TEMPERATURE",
00064 "TACTILE_SENSOR_TYPE_PST3_PRESSURE_RAW_ZERO_TRACKING",
00065 "TACTILE_SENSOR_TYPE_PST3_DAC_VALUE",
00066 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_1",
00067 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_2",
00068 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_3",
00069 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_4",
00070 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_5",
00071 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_6",
00072 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_7",
00073 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_8",
00074 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_9",
00075 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_10",
00076 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_11",
00077 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_12",
00078 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_13",
00079 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_14",
00080 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_15",
00081 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_16",
00082 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_17",
00083 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_18",
00084 "TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_19",
00085 "TACTILE_SENSOR_TYPE_BIOTAC_PDC",
00086 "TACTILE_SENSOR_TYPE_BIOTAC_TAC",
00087 "TACTILE_SENSOR_TYPE_BIOTAC_TDC",
00088 "TACTILE_SENSOR_TYPE_UBI0_TACTILE"
00089 };
00090
00091 template <class StatusType, class CommandType>
00092 const int32u SrRobotLib<StatusType, CommandType>::sensor_data_types[nb_sensor_data] = {TACTILE_SENSOR_TYPE_SAMPLE_FREQUENCY_HZ,
00093 TACTILE_SENSOR_TYPE_MANUFACTURER,
00094 TACTILE_SENSOR_TYPE_SERIAL_NUMBER,
00095 TACTILE_SENSOR_TYPE_SOFTWARE_VERSION,
00096 TACTILE_SENSOR_TYPE_PCB_VERSION,
00097 TACTILE_SENSOR_TYPE_WHICH_SENSORS,
00098 TACTILE_SENSOR_TYPE_PST3_PRESSURE_TEMPERATURE,
00099 TACTILE_SENSOR_TYPE_PST3_PRESSURE_RAW_ZERO_TRACKING,
00100 TACTILE_SENSOR_TYPE_PST3_DAC_VALUE,
00101 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_1,
00102 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_2,
00103 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_3,
00104 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_4,
00105 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_5,
00106 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_6,
00107 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_7,
00108 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_8,
00109 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_9,
00110 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_10,
00111 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_11,
00112 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_12,
00113 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_13,
00114 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_14,
00115 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_15,
00116 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_16,
00117 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_17,
00118 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_18,
00119 TACTILE_SENSOR_TYPE_BIOTAC_ELECTRODE_19,
00120 TACTILE_SENSOR_TYPE_BIOTAC_PDC,
00121 TACTILE_SENSOR_TYPE_BIOTAC_TAC,
00122 TACTILE_SENSOR_TYPE_BIOTAC_TDC,
00123 TACTILE_SENSOR_TYPE_UBI0_TACTILE
00124 };
00125
00126 template <class StatusType, class CommandType>
00127 SrRobotLib<StatusType, CommandType>::SrRobotLib(pr2_hardware_interface::HardwareInterface *hw)
00128 : main_pic_idle_time(0), main_pic_idle_time_min(1000), nullify_demand_(false),
00129 tactile_current_state(operation_mode::device_update_state::INITIALIZATION),
00130 nh_tilde("~")
00131 {
00132
00133 this->generic_sensor_update_rate_configs_vector = this->read_update_rate_configs("generic_sensor_data_update_rate/", nb_sensor_data, human_readable_sensor_data_types, sensor_data_types);
00134 this->tactiles_init = boost::shared_ptr<tactiles::GenericTactiles<StatusType, CommandType> >( new tactiles::GenericTactiles<StatusType, CommandType>(this->generic_sensor_update_rate_configs_vector, operation_mode::device_update_state::INITIALIZATION) );
00135
00136
00137 this->pst3_sensor_update_rate_configs_vector = this->read_update_rate_configs("pst3_sensor_data_update_rate/", nb_sensor_data, human_readable_sensor_data_types, sensor_data_types);
00138
00139 this->biotac_sensor_update_rate_configs_vector = this->read_update_rate_configs("biotac_sensor_data_update_rate/", nb_sensor_data, human_readable_sensor_data_types, sensor_data_types);
00140
00141 this->ubi0_sensor_update_rate_configs_vector = this->read_update_rate_configs("ubi0_sensor_data_update_rate/", nb_sensor_data, human_readable_sensor_data_types, sensor_data_types);
00142
00143
00144 this->calibration_map = this->read_joint_calibration();
00145
00146
00147
00148 nullify_demand_server_ = nh_tilde.advertiseService("nullify_demand", &SrRobotLib::nullify_demand_callback, this);
00149
00150
00151 self_tests_.reset( new SrSelfTest(false) );
00152 self_test_thread_.reset(new boost::thread(boost::bind(&SrRobotLib::checkSelfTests, this)));
00153 }
00154
00155 template <class StatusType, class CommandType>
00156 void SrRobotLib<StatusType, CommandType>::calibrate_joint(boost::ptr_vector<shadow_joints::Joint>::iterator joint_tmp, StatusType* status_data)
00157 {
00158 sr_actuator::SrActuatorState* actuator_state = get_joint_actuator_state(joint_tmp);
00159
00160 actuator_state->raw_sensor_values_.clear();
00161 actuator_state->calibrated_sensor_values_.clear();
00162
00163 if (joint_tmp->joint_to_sensor.calibrate_after_combining_sensors)
00164 {
00165
00166
00167
00168 double raw_position = 0.0;
00169
00170
00171 BOOST_FOREACH(shadow_joints::PartialJointToSensor joint_to_sensor, joint_tmp->joint_to_sensor.joint_to_sensor_vector)
00172 {
00173 int tmp_raw = status_data->sensors[joint_to_sensor.sensor_id];
00174 actuator_state->raw_sensor_values_.push_back(tmp_raw);
00175 raw_position += static_cast<double>(tmp_raw) * joint_to_sensor.coeff;
00176 }
00177
00178
00179 calibration_tmp = calibration_map.find(joint_tmp->joint_name);
00180 actuator_state->position_unfiltered_ = calibration_tmp->compute(static_cast<double>(raw_position));
00181 }
00182 else
00183 {
00184
00185
00186 double calibrated_position = 0.0;
00187 shadow_joints::PartialJointToSensor joint_to_sensor;
00188 std::string sensor_name;
00189
00190 ROS_DEBUG_STREAM("Combining actuator " << joint_tmp->joint_name);
00191
00192 for (unsigned int index_joint_to_sensor = 0;
00193 index_joint_to_sensor < joint_tmp->joint_to_sensor.joint_to_sensor_vector.size(); ++index_joint_to_sensor)
00194 {
00195 joint_to_sensor = joint_tmp->joint_to_sensor.joint_to_sensor_vector[index_joint_to_sensor];
00196 sensor_name = joint_tmp->joint_to_sensor.sensor_names[index_joint_to_sensor];
00197
00198
00199 int raw_pos = status_data->sensors[joint_to_sensor.sensor_id];
00200
00201 actuator_state->raw_sensor_values_.push_back(raw_pos);
00202
00203
00204 calibration_tmp = calibration_map.find(sensor_name);
00205 double tmp_cal_value = calibration_tmp->compute(static_cast<double>(raw_pos));
00206
00207
00208 actuator_state->calibrated_sensor_values_.push_back(tmp_cal_value);
00209
00210 calibrated_position += tmp_cal_value * joint_to_sensor.coeff;
00211
00212 ROS_DEBUG_STREAM(" -> "<< sensor_name<< " raw = " << raw_pos << " calibrated = " << calibrated_position);
00213 }
00214 actuator_state->position_unfiltered_ = calibrated_position;
00215 ROS_DEBUG_STREAM(" => "<< actuator_state->position_unfiltered_);
00216 }
00217 }
00218
00219 template <class StatusType, class CommandType>
00220 void SrRobotLib<StatusType, CommandType>::reinitialize_sensors()
00221 {
00222
00223 tactiles_init = boost::shared_ptr<tactiles::GenericTactiles<StatusType, CommandType> >( new tactiles::GenericTactiles<StatusType, CommandType>(generic_sensor_update_rate_configs_vector, operation_mode::device_update_state::INITIALIZATION) );
00224 tactile_current_state = operation_mode::device_update_state::INITIALIZATION;
00225 }
00226
00227 template <class StatusType, class CommandType>
00228 bool SrRobotLib<StatusType, CommandType>::nullify_demand_callback( sr_robot_msgs::NullifyDemand::Request& request,
00229 sr_robot_msgs::NullifyDemand::Response& response )
00230 {
00231 if( request.nullify_demand )
00232 ROS_INFO_STREAM("Nullifying the demand sent to the motor. Will ignore the values computed by the controllers and send 0.");
00233 else
00234 ROS_INFO_STREAM("Using the value computed by the controllers to send the demands to the motors.");
00235
00236 nullify_demand_ = request.nullify_demand;
00237 return true;
00238 }
00239
00240 template <class StatusType, class CommandType>
00241 void SrRobotLib<StatusType, CommandType>::process_position_sensor_data(boost::ptr_vector<shadow_joints::Joint>::iterator joint_tmp, StatusType* status_data, double timestamp)
00242 {
00243 sr_actuator::SrActuatorState* actuator_state = get_joint_actuator_state(joint_tmp);
00244
00245
00246 calibrate_joint(joint_tmp, status_data);
00247
00248
00249 actuator_state->timestamp_ = timestamp;
00250
00251
00252 std::pair<double, double> pos_and_velocity = joint_tmp->pos_filter.compute(
00253 actuator_state->position_unfiltered_, timestamp);
00254
00255 actuator_state->position_ = pos_and_velocity.first;
00256
00257 actuator_state->velocity_ = pos_and_velocity.second;
00258 }
00259
00260 template <class StatusType, class CommandType>
00261 sr_actuator::SrActuatorState* SrRobotLib<StatusType, CommandType>::get_joint_actuator_state(boost::ptr_vector<shadow_joints::Joint>::iterator joint_tmp)
00262 {
00263 sr_actuator::SrActuatorState* actuator_state;
00264
00265 if (sr_actuator::SrActuator* motor_actuator = dynamic_cast<sr_actuator::SrActuator*>(joint_tmp->actuator_wrapper->actuator))
00266 {
00267 actuator_state = &motor_actuator->state_;
00268 }
00269 else if (sr_actuator::SrMuscleActuator* muscle_actuator = dynamic_cast<sr_actuator::SrMuscleActuator*>(joint_tmp->actuator_wrapper->actuator))
00270 {
00271 actuator_state = &muscle_actuator->state_;
00272 }
00273 else
00274 {
00275 ROS_FATAL("Unknown actuator type. Known types: sr_actuator::SrActuator, sr_actuator::SrMuscleActuator");
00276 exit(EXIT_FAILURE);
00277 }
00278
00279 return actuator_state;
00280 }
00281
00282 template <class StatusType, class CommandType>
00283 void SrRobotLib<StatusType, CommandType>::build_tactile_command(CommandType* command)
00284 {
00285 if (tactile_current_state == operation_mode::device_update_state::INITIALIZATION)
00286 {
00287 if (tactiles_init->sensor_updater->build_init_command(command)
00288 != operation_mode::device_update_state::INITIALIZATION)
00289 {
00290 tactile_current_state = operation_mode::device_update_state::OPERATION;
00291
00292 switch (tactiles_init->tactiles_vector->at(0).which_sensor)
00293 {
00294 case TACTILE_SENSOR_PROTOCOL_TYPE_PST3:
00295 tactiles = boost::shared_ptr<tactiles::ShadowPSTs<StatusType, CommandType> >(
00296 new tactiles::ShadowPSTs<StatusType, CommandType>(pst3_sensor_update_rate_configs_vector,
00297 operation_mode::device_update_state::OPERATION,
00298 tactiles_init->tactiles_vector));
00299
00300 ROS_INFO("PST3 tactiles initialized");
00301 break;
00302
00303 case TACTILE_SENSOR_PROTOCOL_TYPE_BIOTAC_2_3:
00304 tactiles = boost::shared_ptr<tactiles::Biotac<StatusType, CommandType> >(
00305 new tactiles::Biotac<StatusType, CommandType>(biotac_sensor_update_rate_configs_vector, operation_mode::device_update_state::OPERATION,
00306 tactiles_init->tactiles_vector));
00307
00308 ROS_INFO("Biotac tactiles initialized");
00309 break;
00310
00311 case TACTILE_SENSOR_PROTOCOL_TYPE_UBI0:
00312 tactiles = boost::shared_ptr<tactiles::UBI0<StatusType, CommandType> >(
00313 new tactiles::UBI0<StatusType, CommandType>(ubi0_sensor_update_rate_configs_vector, operation_mode::device_update_state::OPERATION,
00314 tactiles_init->tactiles_vector));
00315
00316 ROS_INFO("UBI0 tactiles initialized");
00317 break;
00318
00319 case TACTILE_SENSOR_PROTOCOL_TYPE_INVALID:
00320 ROS_WARN_STREAM("TACTILE_SENSOR_PROTOCOL_TYPE_INVALID!!");
00321 break;
00322 case TACTILE_SENSOR_PROTOCOL_TYPE_CONFLICTING:
00323 ROS_WARN_STREAM("TACTILE_SENSOR_PROTOCOL_TYPE_CONFLICTING!!");
00324 break;
00325 }
00326 }
00327 }
00328 else
00329 tactile_current_state = tactiles->sensor_updater->build_command(command);
00330 }
00331
00332 template <class StatusType, class CommandType>
00333 void SrRobotLib<StatusType, CommandType>::update_tactile_info(StatusType* status)
00334 {
00335 if (tactile_current_state == operation_mode::device_update_state::INITIALIZATION)
00336 {
00337 if( tactiles_init != NULL )
00338 tactiles_init->update(status);
00339 }
00340 else
00341 {
00342 if( tactiles != NULL )
00343 tactiles->update(status);
00344 }
00345 }
00346
00347 template <class StatusType, class CommandType>
00348 shadow_joints::CalibrationMap SrRobotLib<StatusType, CommandType>::read_joint_calibration()
00349 {
00350 shadow_joints::CalibrationMap joint_calibration;
00351 std::string param_name = "sr_calibrations";
00352
00353 XmlRpc::XmlRpcValue calib;
00354 nodehandle_.getParam(param_name, calib);
00355 ROS_ASSERT(calib.getType() == XmlRpc::XmlRpcValue::TypeArray);
00356
00357 for(int32_t index_cal = 0; index_cal < calib.size(); ++index_cal)
00358 {
00359
00360
00361 ROS_ASSERT(calib[index_cal][0].getType() == XmlRpc::XmlRpcValue::TypeString);
00362 ROS_ASSERT(calib[index_cal][1].getType() == XmlRpc::XmlRpcValue::TypeArray);
00363
00364 std::string joint_name = static_cast<std::string> (calib[index_cal][0]);
00365 std::vector<joint_calibration::Point> calib_table_tmp;
00366
00367
00368 for(int32_t index_table=0; index_table < calib[index_cal][1].size(); ++index_table)
00369 {
00370 ROS_ASSERT(calib[index_cal][1][index_table].getType() == XmlRpc::XmlRpcValue::TypeArray);
00371
00372 ROS_ASSERT(calib[index_cal][1][index_table].size() == 2);
00373 ROS_ASSERT(calib[index_cal][1][index_table][0].getType() == XmlRpc::XmlRpcValue::TypeDouble);
00374 ROS_ASSERT(calib[index_cal][1][index_table][1].getType() == XmlRpc::XmlRpcValue::TypeDouble);
00375
00376
00377 joint_calibration::Point point_tmp;
00378 point_tmp.raw_value = static_cast<double> (calib[index_cal][1][index_table][0]);
00379 point_tmp.calibrated_value = sr_math_utils::to_rad( static_cast<double> (calib[index_cal][1][index_table][1]) );
00380 calib_table_tmp.push_back(point_tmp);
00381 }
00382
00383 joint_calibration.insert(joint_name, boost::shared_ptr<shadow_robot::JointCalibration>(new shadow_robot::JointCalibration(calib_table_tmp)) );
00384 }
00385
00386 return joint_calibration;
00387 }
00388
00389 template <class StatusType, class CommandType>
00390 std::vector<shadow_joints::JointToSensor> SrRobotLib<StatusType, CommandType>::read_joint_to_sensor_mapping()
00391 {
00392 std::vector<shadow_joints::JointToSensor> joint_to_sensor_vect;
00393
00394 std::map<std::string, int> sensors_map;
00395 for(unsigned int i=0; i < SENSORS_NUM_0220; ++i)
00396 {
00397 sensors_map[ sensor_names[i] ] = i;
00398 }
00399
00400 XmlRpc::XmlRpcValue joint_to_sensor_mapping;
00401 nodehandle_.getParam("joint_to_sensor_mapping", joint_to_sensor_mapping);
00402 ROS_ASSERT(joint_to_sensor_mapping.getType() == XmlRpc::XmlRpcValue::TypeArray);
00403 for (int32_t i = 0; i < joint_to_sensor_mapping.size(); ++i)
00404 {
00405 shadow_joints::JointToSensor tmp_vect;
00406
00407 XmlRpc::XmlRpcValue map_one_joint = joint_to_sensor_mapping[i];
00408
00409
00410
00411
00412 int param_index = 0;
00413
00414 if(map_one_joint[param_index].getType() == XmlRpc::XmlRpcValue::TypeInt)
00415 {
00416 if(1 == static_cast<int>(map_one_joint[0]) )
00417 tmp_vect.calibrate_after_combining_sensors = true;
00418 else
00419 tmp_vect.calibrate_after_combining_sensors = false;
00420
00421 param_index ++;
00422 }
00423 else
00424 tmp_vect.calibrate_after_combining_sensors = false;
00425
00426 ROS_ASSERT(map_one_joint.getType() == XmlRpc::XmlRpcValue::TypeArray);
00427 for (int32_t i = param_index; i < map_one_joint.size(); ++i)
00428 {
00429 ROS_ASSERT(map_one_joint[i].getType() == XmlRpc::XmlRpcValue::TypeArray);
00430 shadow_joints::PartialJointToSensor tmp_joint_to_sensor;
00431
00432 ROS_ASSERT(map_one_joint[i][0].getType() == XmlRpc::XmlRpcValue::TypeString);
00433 tmp_vect.sensor_names.push_back( static_cast<std::string>(map_one_joint[i][0]) );
00434 tmp_joint_to_sensor.sensor_id = sensors_map[ static_cast<std::string>(map_one_joint[i][0]) ];
00435
00436 ROS_ASSERT(map_one_joint[i][1].getType() == XmlRpc::XmlRpcValue::TypeDouble);
00437 tmp_joint_to_sensor.coeff = static_cast<double> (map_one_joint[i][1]);
00438 tmp_vect.joint_to_sensor_vector.push_back(tmp_joint_to_sensor);
00439 }
00440 joint_to_sensor_vect.push_back(tmp_vect);
00441 }
00442
00443 return joint_to_sensor_vect;
00444 }
00445
00446 template <class StatusType, class CommandType>
00447 std::vector<generic_updater::UpdateConfig> SrRobotLib<StatusType, CommandType>::read_update_rate_configs(std::string base_param, int nb_data_defined, const char* human_readable_data_types[], const int32u data_types[])
00448 {
00449 std::vector<generic_updater::UpdateConfig> update_rate_configs_vector;
00450 typedef std::pair<std::string, int32u> ConfPair;
00451 std::vector<ConfPair> config;
00452
00453 for(int i=0; i<nb_data_defined; ++i)
00454 {
00455 ConfPair tmp;
00456
00457 ROS_DEBUG_STREAM(" read " << base_param << " config [" << i<< "] = " << human_readable_data_types[i]);
00458
00459 tmp.first = base_param + human_readable_data_types[i];
00460 tmp.second = data_types[i];
00461 config.push_back(tmp);
00462 }
00463
00464 for( unsigned int i = 0; i < config.size(); ++i )
00465 {
00466 double rate;
00467 if (nodehandle_.getParam(config[i].first, rate))
00468 {
00469 generic_updater::UpdateConfig config_tmp;
00470
00471 config_tmp.when_to_update = rate;
00472 config_tmp.what_to_update = config[i].second;
00473 update_rate_configs_vector.push_back(config_tmp);
00474
00475 ROS_DEBUG_STREAM(" read " << base_param <<" config [" << i<< "] = " << "what: "<< config_tmp.what_to_update << " when: " << config_tmp.when_to_update);
00476 }
00477 }
00478
00479 return update_rate_configs_vector;
00480 }
00481
00482 template <class StatusType, class CommandType>
00483 void SrRobotLib<StatusType, CommandType>::checkSelfTests()
00484 {
00485 ros::Rate loop_rate(1);
00486 while (ros::ok())
00487 {
00488
00489
00490 self_tests_->checkTest();
00491 loop_rate.sleep();
00492 }
00493 }
00494
00495
00496 template class SrRobotLib<ETHERCAT_DATA_STRUCTURE_0200_PALM_EDC_STATUS, ETHERCAT_DATA_STRUCTURE_0200_PALM_EDC_COMMAND>;
00497 template class SrRobotLib<ETHERCAT_DATA_STRUCTURE_0230_PALM_EDC_STATUS, ETHERCAT_DATA_STRUCTURE_0230_PALM_EDC_COMMAND>;
00498 template class SrRobotLib<ETHERCAT_DATA_STRUCTURE_0300_PALM_EDC_STATUS, ETHERCAT_DATA_STRUCTURE_0300_PALM_EDC_COMMAND>;
00499
00500 }
00501
00502
00503
00504
00505
00506