sr_board_adc16.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2013, Shadow Robot Company, All rights reserved.
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 3.0 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library.
00016  */
00017 
00024 #include <sr_ronex_drivers/sr_board_adc16.hpp>
00025 #include <ros_ethercat_model/robot_state.hpp>
00026 #include <ros_ethercat_hardware/ethercat_hardware.h>
00027 
00028 #include <sstream>
00029 #include <iomanip>
00030 #include <boost/lexical_cast.hpp>
00031 #include <math.h>
00032 #include <string>
00033 
00034 #include "sr_ronex_drivers/ronex_utils.hpp"
00035 
00036 PLUGINLIB_EXPORT_CLASS(SrBoardADC16, EthercatDevice);
00037 
00038 const std::string SrBoardADC16::product_alias_ = "adc16";
00039 using boost::lexical_cast;
00040 
00041 
00042 SrBoardADC16::SrBoardADC16() :
00043   node_("~"), cycle_count_(0), has_stacker_(false)
00044 {}
00045 
00046 SrBoardADC16::~SrBoardADC16()
00047 {
00048   // remove parameters from server
00049   string device_id = "/ronex/devices/" + lexical_cast<string>(parameter_id_);
00050   ros::param::del(device_id);
00051 
00052   string adc16_device_name = "/ronex/adc16/" + serial_number_;
00053   ros::param::del(adc16_device_name);
00054 
00055   string controller_name = "/ronex_" + serial_number_ + "_passthrough";
00056 }
00057 
00058 void SrBoardADC16::construct(EtherCAT_SlaveHandler *sh, int &start_address)
00059 {
00060   sh_ = sh;
00061   serial_number_ = ronex::get_serial_number(sh);
00062 
00063   // get the alias from the parameter server if it exists
00064   std::string path_to_alias, alias;
00065   path_to_alias = "/ronex/mapping/" + serial_number_;
00066   if ( ros::param::get(path_to_alias, alias))
00067   {
00068     ronex_id_ = alias;
00069   }
00070   else
00071   {
00072     // no alias found, using the serial number directly.
00073     ronex_id_ = serial_number_;
00074   }
00075 
00076   device_name_ = ronex::build_name(product_alias_, ronex_id_);
00077 
00078   command_base_  = start_address;
00079   command_size_  = COMMAND_ARRAY_SIZE_BYTES;
00080 
00081   start_address += command_size_;
00082   status_base_   = start_address;
00083   status_size_   = STATUS_ARRAY_SIZE_BYTES;
00084 
00085   start_address += status_size_;
00086 
00087   // ETHERCAT_COMMAND_DATA
00088   //
00089   // This is for data going TO the board
00090   //
00091 
00092   if ( (PROTOCOL_TYPE) == (EC_BUFFERED) )
00093   {
00094     ROS_INFO("Using EC_BUFFERED");
00095   }
00096   else if ( (PROTOCOL_TYPE) == (EC_QUEUED) )
00097   {
00098     ROS_INFO("Using EC_QUEUED");
00099   }
00100 
00101   ROS_INFO("First FMMU (command) : Logical address: 0x%08X ; size: %3d bytes ; ET1200 address: 0x%08X", command_base_,
00102            command_size_, static_cast<int>(COMMAND_ADDRESS) );
00103   EC_FMMU *commandFMMU = new EC_FMMU( command_base_,            // Logical Start Address    (in ROS address space?)
00104                                       command_size_,
00105                                       0x00,                   // Logical Start Bit
00106                                       0x07,                   // Logical End Bit
00107                                       COMMAND_ADDRESS,        // Physical Start Address   (in ET1200 address space?)
00108                                       0x00,                   // Physical Start Bit
00109                                       false,                   // Read Enable
00110                                       true,                    // Write Enable
00111                                       true);                     // Channel Enable
00112 
00113 
00114 
00115   // WARNING!!!
00116   // We are leaving (command_size_ * 4) bytes in the physical memory of the device, but strictly we only need to
00117   // leave (command_size_ * 3). This change should be done in the firmware as well, otherwise it won't work.
00118   // This triple buffer is needed in the ethercat devices to work in EC_BUFFERED mode (in opposition to the other mode
00119   // EC_QUEUED, the so called mailbox mode)
00120 
00121   // ETHERCAT_STATUS_DATA
00122   //
00123   // This is for data coming FROM the board
00124   //
00125   ROS_INFO("Second FMMU (status) : Logical address: 0x%08X ; size: %3d bytes ; ET1200 address: 0x%08X", status_base_,
00126            status_size_, static_cast<int>(STATUS_ADDRESS) );
00127   EC_FMMU *statusFMMU = new EC_FMMU(  status_base_,
00128                                       status_size_,
00129                                       0x00,
00130                                       0x07,
00131                                       STATUS_ADDRESS,
00132                                       0x00,
00133                                       true,
00134                                       false,
00135                                       true);
00136 
00137 
00138   EtherCAT_FMMU_Config *fmmu = new EtherCAT_FMMU_Config(2);
00139 
00140   (*fmmu)[0] = *commandFMMU;
00141   (*fmmu)[1] = *statusFMMU;
00142 
00143   sh->set_fmmu_config(fmmu);
00144 
00145   EtherCAT_PD_Config *pd = new EtherCAT_PD_Config(2);
00146 
00147 // SyncMan takes the physical address
00148   (*pd)[0] = EC_SyncMan(COMMAND_ADDRESS,              command_size_,    PROTOCOL_TYPE, EC_WRITTEN_FROM_MASTER);
00149   (*pd)[1] = EC_SyncMan(STATUS_ADDRESS,               status_size_,     PROTOCOL_TYPE);
00150 
00151 
00152   (*pd)[0].ChannelEnable = true;
00153   (*pd)[0].ALEventEnable = true;
00154   (*pd)[0].WriteEvent    = true;
00155 
00156   (*pd)[1].ChannelEnable = true;
00157 
00158   sh->set_pd_config(pd);
00159 
00160   ROS_INFO("Finished constructing the SrBoardADC16 driver");
00161 }
00162 
00163 int SrBoardADC16::initialize(hardware_interface::HardwareInterface *hw, bool allow_unprogrammed)
00164 {
00165   digital_commands_ = 0;
00166   ROS_INFO("Device #%02d: Product code: %u (%#010X) , Serial #: %u (%#010X)",
00167             sh_->get_ring_position(),
00168             sh_->get_product_code(),
00169             sh_->get_product_code(),
00170             sh_->get_serial(),
00171             sh_->get_serial());
00172 
00173   device_offset_ = sh_->get_ring_position();
00174 
00175   // add the RoNeX ADC16 module to the hw interface
00176   ros_ethercat_model::RobotState *robot_state = static_cast<ros_ethercat_model::RobotState*>(hw);
00177   robot_state->custom_hws_.insert(device_name_, new ronex::ADC16());
00178   adc16_ = static_cast<ronex::ADC16*>(robot_state->getCustomHW(device_name_));
00179 
00180   build_topics_();
00181 
00182   ROS_INFO_STREAM("Adding an ADC16 RoNeX module to the hardware interface: " << device_name_);
00183   // Using the name of the ronex to prefix the state topic
00184   feedback_flag_ = 0;
00185 
00186   return 0;
00187 }
00188 
00189 void SrBoardADC16::packCommand(unsigned char *buffer, bool halt, bool reset)
00190 {
00191   RONEX_COMMAND_02000008* command = reinterpret_cast<RONEX_COMMAND_02000008*>(buffer);
00192 
00193   if (!config_received_)
00194   {
00195     command->command_type = RONEX_COMMAND_02000008_COMMAND_TYPE_GET_CONFIG_INFO;
00196   }
00197   else if (reg_flag_)
00198   {
00199     switch (reg_state_)
00200     {
00201       case 0:
00202         if (!command_queue_.empty())
00203         {
00204           command->command_type = RONEX_COMMAND_02000008_COMMAND_TYPE_SET_REG_VAL;
00205           command->address = command_queue_.front().address;
00206           for (int i = 0; i < 3; ++i)
00207           {
00208             command->values[i] = command_queue_.front().values[i];
00209           }
00210           feedback_flag_ += 1;
00211           command_queue_.pop();
00212         }
00213         else
00214         {
00215           command->command_type = RONEX_COMMAND_02000008_COMMAND_TYPE_WRITE_REGS;
00216           reg_state_ = 1;
00217           feedback_flag_ += 1;
00218         }
00219         break;
00220       case 1:
00221         command->command_type = RONEX_COMMAND_02000008_COMMAND_TYPE_NORMAL;
00222         reg_flag_ = false;
00223         break;
00224     }
00225   }
00226 
00227   else
00228   {
00229     command->command_type = RONEX_COMMAND_02000008_COMMAND_TYPE_NORMAL;
00230     // digital command
00231     feedback_flag_ = 0;
00232     for (size_t i = 0; i < adc16_->command_.digital_.size(); ++i)
00233     {
00234       if (input_mode_[i])
00235       {
00236         // Just set the pin to input mode, gets read in the status
00237         ronex::set_bit(digital_commands_, i*2, 1);
00238       }
00239       else
00240       { // Output
00241         ronex::set_bit(digital_commands_, i*2, 0);
00242         ronex::set_bit(digital_commands_, i*2+1, adc16_->command_.digital_[i]);
00243       }
00244     }
00245     command->pin_output_states = static_cast<int32u>(digital_commands_);
00246   }
00247 }
00248 
00249 bool SrBoardADC16::unpackState(unsigned char *this_buffer, unsigned char *prev_buffer)
00250 {
00251   RONEX_STATUS_02000008* status_data = reinterpret_cast<RONEX_STATUS_02000008 *>(this_buffer+  command_size_);
00252 
00253   // Checking that the received command type matches RONEX_COMMAND_02000001_COMMAND_TYPE_NORMAL
00254   // (the one that was used in the command). The ronex firmware will answer with whatever command type we send.
00255   // The purpose of this is to filter those status_data structures that come filled with zeros due to the jitter
00256   // in the realtime loop. The jitter causes that the host tries to read the status when the microcontroller in the
00257   // ronex module has not finished writing it to memory yet.
00258 
00259   if (status_data->command_type == RONEX_COMMAND_02000008_COMMAND_TYPE_NORMAL)
00260   {
00261     for (size_t i = 0; i < adc16_->state_.analogue_.size(); ++i)
00262     {
00263       adc16_->state_.analogue_[i] = status_data->info_type.status_data.analogue_in[i];
00264     }
00265 
00266     for (size_t i = 0; i < adc16_->state_.digital_.size(); ++i)
00267     {
00268       adc16_->state_.digital_[i] = ronex::check_bit(status_data->info_type.status_data.pin_input_states_DIO, i);
00269     }
00270 
00271     int mask = 1;
00272     int count = 15;
00273     int bits_count = 0;
00274 
00275     // pin order comes back the reverse of values on the data sheet, so 7->0 for differential and 15->0 for single
00276     for (int j = 0; j < stack; j++)
00277     {
00278       uint16_t differential = values_d_[j];
00279       uint16_t single_ended = (values_s1_[j] << 8) | values_s0_[j];
00280       uint16_t padded_single_ended = (padded_s1_[j] << 8) | padded_s0_[j];
00281       for (int n = 0; n < 8; n++)
00282       {
00283         if (differential & mask << n)
00284         {
00285           adc16_->state_.adc_[count] = status_data->info_type.status_data.adc16[bits_count].U16;
00286           adc16_->state_.adc_[count -1] = status_data->info_type.status_data.adc16[bits_count].U16;
00287           bits_count += 1;
00288         }
00289         count = count -2;
00290       }
00291       count = ((j + 1) * 16) - 1;  // start at 15, 31 or 47
00292       for (int n = 0; n < 16; n++)
00293       {
00294         if (single_ended & mask << n)
00295         {
00296           adc16_->state_.adc_[count] = status_data->info_type.status_data.adc16[bits_count].U16;
00297           bits_count += 1;
00298         }
00299         else if (padded_single_ended & mask << n)
00300         {
00301           bits_count += 1;
00302         }
00303         count -= 1;
00304       }
00305     }
00306   }
00307   else if (status_data->command_type == RONEX_COMMAND_02000008_COMMAND_TYPE_SET_REG_VAL)
00308   {
00309     adc16_->state_.address_ = status_data->info_type.register_feedback.address;
00310 
00311     // check the feedback address value against the flag number, if feedback incorrect, reset queue
00312     if (((feedback_flag_ == 2) & (adc16_->state_.address_ != 4)) | ((feedback_flag_ == 3) &
00313             (adc16_->state_.address_ != 5)) | ((feedback_flag_ == 4) & (adc16_->state_.address_ != 3)))
00314     {
00315       reg_state_ = 0;
00316       command_queue_ = queue_backup_;
00317     }
00318   }
00319   else if (status_data->command_type == RONEX_COMMAND_02000008_COMMAND_TYPE_GET_CONFIG_INFO)
00320   {
00321     if (adc16_->state_.analogue_.empty())
00322     {
00323       size_t nb_adc_pub;
00324       // The publishers haven't been initialised yet.
00325       // Checking if the stacker board is plugged in or not
00326       // to determine the number of publishers.
00327       if (status_data->info_type.config_info.flags & RONEX_02000008_FLAGS_STACKER_0_PRESENT)
00328       {
00329         has_stacker_ = true;
00330         nb_adc_pub = NUM_ADC16_INPUTS / 3;
00331       }
00332       if (status_data->info_type.config_info.flags & RONEX_02000008_FLAGS_STACKER_1_PRESENT)
00333       {
00334         has_stacker_ = true;
00335         nb_adc_pub = (NUM_ADC16_INPUTS * 2) / 3;
00336       }
00337       if (status_data->info_type.config_info.flags & RONEX_02000008_FLAGS_STACKER_2_PRESENT)
00338       {
00339         has_stacker_ = true;
00340         nb_adc_pub = NUM_ADC16_INPUTS;
00341       }
00342 
00343       // resizing the ADC in the HardwareInterface
00344       adc16_->state_.analogue_.resize(NUM_ANALOGUE_INPUTS);
00345       adc16_->state_.digital_.resize(NUM_DIGITAL_IO);
00346       adc16_->state_.adc_.resize(nb_adc_pub);
00347       adc16_->command_.digital_.resize(NUM_DIGITAL_IO);
00348 
00349       input_mode_.assign(NUM_DIGITAL_IO, true);
00350       pin_mode_.assign(nb_adc_pub, 0);
00351 
00352       // init the state message
00353       state_msg_.analogue.resize(NUM_ANALOGUE_INPUTS);
00354       state_msg_.digital.resize(NUM_DIGITAL_IO);
00355       state_msg_.adc.resize(nb_adc_pub);
00356       state_msg_.input_mode.resize(NUM_DIGITAL_IO);
00357 
00358       // dynamic reconfigure server is instantiated here
00359       // as we need the different vectors to be initialised
00360       // before running the first configuration.
00361       dynamic_reconfigure_server_.reset(
00362               new dynamic_reconfigure::Server<sr_ronex_drivers::ADC16Config>(ros::NodeHandle(device_name_)));
00363       function_cb_ = boost::bind(&SrBoardADC16::dynamic_reconfigure_cb, this, _1, _2);
00364       dynamic_reconfigure_server_->setCallback(function_cb_);
00365     }  // end first time, the sizes are properly initialised, simply fill in the data
00366 
00367     config_received_ = true;
00368   }
00369 
00370   adc16_->state_.command_type_ = status_data->command_type;
00371 
00372   // publishing at 100Hz
00373   if (cycle_count_ > 9)
00374   {
00375     state_msg_.header.stamp = ros::Time::now();
00376 
00377     // update state message
00378     for (size_t i = 0; i < adc16_->state_.analogue_.size(); ++i)
00379     {
00380       state_msg_.analogue[i] = adc16_->state_.analogue_[i];
00381     }
00382 
00383     for (size_t i = 0; i < adc16_->state_.digital_.size(); ++i)
00384     {
00385       state_msg_.digital[i] = adc16_->state_.digital_[i];
00386       state_msg_.input_mode[i] = input_mode_[i];
00387     }
00388     for (size_t i = 0; i < adc16_->state_.adc_.size(); ++i)
00389     {
00390       state_msg_.adc[i] = adc16_->state_.adc_[i];
00391     }
00392 
00393     state_msg_.command_type = adc16_->state_.command_type_;
00394 
00395     // publish
00396     if ( state_publisher_->trylock() )
00397     {
00398       state_publisher_->msg_ = state_msg_;
00399       state_publisher_->unlockAndPublish();
00400     }
00401 
00402     cycle_count_ = 0;
00403   }
00404 
00405   cycle_count_++;
00406   return true;
00407 }
00408 
00409 void SrBoardADC16::diagnostics(diagnostic_updater::DiagnosticStatusWrapper &d, unsigned char *buffer)
00410 {
00411   d.name = device_name_;
00412   d.summary(d.OK, "OK");
00413   d.hardware_id = serial_number_;
00414 
00415   d.clear();
00416   if (has_stacker_)
00417     d.addf("Stacker Board", "True");
00418   else
00419     d.addf("Stacker Board", "False");
00420 }
00421 
00422 void SrBoardADC16::dynamic_reconfigure_cb(sr_ronex_drivers::ADC16Config &config, uint32_t level)
00423 {
00424   // not very pretty but I couldnt think of an easy way to set them up
00425   // (dynamic reconfigure doesn't seem to support arrays)
00426   if (adc16_->command_.digital_.size() > 0)
00427     input_mode_[0] = config.input_mode_0;
00428   if (adc16_->command_.digital_.size() > 1)
00429     input_mode_[1] = config.input_mode_1;
00430   if (adc16_->command_.digital_.size() > 2)
00431     input_mode_[2] = config.input_mode_2;
00432   if (adc16_->command_.digital_.size() > 3)
00433     input_mode_[3] = config.input_mode_3;
00434   if (adc16_->command_.digital_.size() > 4)
00435     input_mode_[4] = config.input_mode_4;
00436   if (adc16_->command_.digital_.size() > 5)
00437     input_mode_[5] = config.input_mode_5;
00438 
00439   stack = 0;
00440 
00441   // pins are paired for 1 mode of either differential or single ended configuration
00442   if (adc16_->state_.adc_.size() >= 16)
00443   {
00444     pin_mode_[0] = config.pins_0_1;
00445     pin_mode_[1] = config.pins_2_3;
00446     pin_mode_[2] = config.pins_4_5;
00447     pin_mode_[3] = config.pins_6_7;
00448     pin_mode_[4] = config.pins_8_9;
00449     pin_mode_[5] = config.pins_10_11;
00450     pin_mode_[6] = config.pins_12_13;
00451     pin_mode_[7] = config.pins_14_15;
00452     stack = 1;
00453   }
00454   if (adc16_->state_.adc_.size() >= 32)
00455   {
00456     pin_mode_[8] = config.pins_16_17;
00457     pin_mode_[9] = config.pins_18_19;
00458     pin_mode_[10] = config.pins_20_21;
00459     pin_mode_[11] = config.pins_22_23;
00460     pin_mode_[12] = config.pins_24_25;
00461     pin_mode_[13] = config.pins_26_27;
00462     pin_mode_[14] = config.pins_28_29;
00463     pin_mode_[15] = config.pins_30_31;
00464     stack = 2;
00465   }
00466   if (adc16_->state_.adc_.size() == 48)
00467   {
00468     pin_mode_[16] = config.pins_32_33;
00469     pin_mode_[17] = config.pins_34_35;
00470     pin_mode_[18] = config.pins_36_37;
00471     pin_mode_[19] = config.pins_38_39;
00472     pin_mode_[20] = config.pins_40_41;
00473     pin_mode_[21] = config.pins_42_43;
00474     pin_mode_[22] = config.pins_44_45;
00475     pin_mode_[23] = config.pins_46_47;
00476     stack = 3;
00477   }
00478 
00479   // set values for each of the 3 registers,
00480   values_s0_.assign(3, 0);
00481   values_s1_.assign(3, 0);
00482   values_d_.assign(3, 0);
00483   // values to pad out the bits
00484   fake_values_s0_.assign(3, 0);
00485   fake_values_s1_.assign(3, 0);
00486   // value that is sent, sum of user requested and padding
00487   padded_s0_.assign(3, 0);
00488   padded_s1_.assign(3, 0);
00489 
00490   int bit = 1;
00491   int pin_count = (adc16_->state_.adc_.size()/(stack*2)) -1;
00492 
00493   // set values for s1 and d, first set of 8 pins. NOTE the pin order is in the reverse order
00494   // given on the data sheet for the chip 15->0 rather than 0->15
00495 
00496   for (int i = 0; i < stack; i++)  // loop for each stack
00497   {
00498     for (signed int pin = 0; pin <= pin_count; pin++)  // first 8 pins
00499     {
00500       if (pin <= pin_count - 4)  // 4 pairs make up the 8 pins
00501       {
00502         if (pin_mode_[pin] == 0)  // no input
00503         {
00504           values_s1_[i] <<=2;
00505           values_d_[i] <<=1;
00506           fake_values_s1_[i] <<=2;
00507           fake_values_s1_[i] |= bit * 3;
00508         }
00509         else if (pin_mode_[pin] == 1)  // single ended ADC input
00510         {
00511           values_s1_[i] <<=2;
00512           values_d_[i] <<=1;
00513           fake_values_s1_[i] <<=2;
00514           values_s1_[i] |= bit * 3;
00515         }
00516         else  // differential ADC input
00517         {
00518           values_s1_[i] <<=2;
00519           values_d_[i] <<=1;
00520           fake_values_s1_[i] <<=1;
00521           values_d_[i] |= bit;
00522           fake_values_s1_[i] |= bit;
00523         }
00524       }
00525 
00526       // set values for s0 and d, second set of 8 pins
00527       else if (pin <= pin_count)
00528       {
00529         if (pin_mode_[pin] == 0)  // no input
00530         {
00531           values_s0_[i] <<=2;
00532           values_d_[i] <<=1;
00533           fake_values_s0_[i] <<=2;
00534           fake_values_s0_[i] |= bit * 3;
00535         }
00536         else if (pin_mode_[pin] == 1)  // single ended ADC input
00537         {
00538           values_s0_[i] <<=2;
00539           values_d_[i] <<=1;
00540           fake_values_s0_[i] <<=2;
00541           values_s0_[i] |= bit * 3;
00542         }
00543         else  // differential ADC input
00544         {
00545           values_s0_[i] <<=2;
00546           values_d_[i] <<=1;
00547           fake_values_s0_[i] <<=1;
00548           values_d_[i] |= bit;
00549           fake_values_s0_[i] |= bit;
00550         }
00551       }
00552     }
00553     pin_count = pin_count + 8;
00554     padded_s0_[i] = values_s0_[i] | fake_values_s0_[i];
00555     padded_s1_[i] = values_s1_[i] | fake_values_s1_[i];
00556   }
00557 
00558   // set register values
00559   reg_flag_ = true;
00560   reg_state_ = 0;
00561 
00562   RONEX_COMMAND_02000008 command;
00563 
00564   // queue commands for the 3 registers
00565   command.address = RONEX_02000008_ADS1158_REGISTER_MUXSG0;
00566   command.values[0] = padded_s0_[0];
00567   command.values[1] = padded_s0_[1];
00568   command.values[2] = padded_s0_[2];
00569 
00570   command_queue_.push(command);
00571 
00572   command.address = RONEX_02000008_ADS1158_REGISTER_MUXSG1;
00573   command.values[0] = padded_s1_[0];
00574   command.values[1] = padded_s1_[1];
00575   command.values[2] = padded_s1_[2];
00576 
00577   command_queue_.push(command);
00578 
00579   command.address = RONEX_02000008_ADS1158_REGISTER_MUXDIF;
00580   command.values[0] = values_d_[0];
00581   command.values[1] = values_d_[1];
00582   command.values[2] = values_d_[2];
00583 
00584   // send last register values twice to catch all feedback (delayed by 1)
00585   command_queue_.push(command);
00586   command_queue_.push(command);
00587 
00588   // create backup to reset queue if any packets lost
00589   queue_backup_ = command_queue_;
00590 }
00591 
00592 
00593 void SrBoardADC16::build_topics_()
00594 {
00595   // loading everything into the parameter server
00596   parameter_id_ = ronex::get_ronex_param_id("");
00597   std::stringstream param_path, tmp_param;
00598   param_path << "/ronex/devices/" << parameter_id_ << "/";
00599   tmp_param << ronex::get_product_code(sh_);
00600   ros::param::set(param_path.str() + "product_id", tmp_param.str());
00601   ros::param::set(param_path.str() + "product_name", product_alias_);
00602   ros::param::set(param_path.str() + "ronex_id", ronex_id_);
00603 
00604   // the device is stored using path as the key in the CustomHW map
00605   ros::param::set(param_path.str() + "path", device_name_);
00606   ros::param::set(param_path.str() + "serial", serial_number_);
00607 
00608   // Advertising the realtime state publisher
00609   state_publisher_.reset(new realtime_tools::RealtimePublisher<sr_ronex_msgs::ADC16State>(node_, device_name_ +
00610           "/state", 1));
00611 }
00612 
00613 /* For the emacs weenies in the crowd.
00614    Local Variables:
00615    c-basic-offset: 2
00616    End:
00617 */


sr_ronex_drivers
Author(s): Ugo Cupcic, Toni Oliver, Mark Pitchless
autogenerated on Thu Jun 6 2019 21:22:00