Ardusim.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 *
00003 * Software License Agreement (BSD License)
00004 *
00005 *  Copyright (c) 2010, ISR University of Coimbra.
00006 *  All rights reserved.
00007 *
00008 *  Redistribution and use in source and binary forms, with or without
00009 *  modification, are permitted provided that the following conditions
00010 *  are met:
00011 *
00012 *   * Redistributions of source code must retain the above copyright
00013 *     notice, this list of conditions and the following disclaimer.
00014 *   * Redistributions in binary form must reproduce the above
00015 *     copyright notice, this list of conditions and the following
00016 *     disclaimer in the documentation and/or other materials provided
00017 *     with the distribution.
00018 *   * Neither the name of the ISR University of Coimbra nor the names of its
00019 *     contributors may be used to endorse or promote products derived
00020 *     from this software without specific prior written permission.
00021 *
00022 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033 *  POSSIBILITY OF SUCH DAMAGE.
00034 *
00035 * Author: Gonçalo Cabrita on 14/10/2010
00036 *********************************************************************/
00037 #include <stdlib.h>
00038 #include <stdio.h>
00039 #include <math.h>
00040 #include <string.h>
00041 
00042 #include "ardusim/Ardusim.h"
00043 
00044 namespace ardusim
00045 {
00046 
00047         // *****************************************************************************
00048         // Constructor
00049         Ardusim::Ardusim(std::string port_name)
00050         {       
00051                 serial_port_ = new cereal::CerealPort();
00052                 try{ serial_port_->open(port_name.c_str(), 57600); }
00053                 catch(cereal::Exception& e)
00054                 {
00055                         ROS_FATAL("Ardusim -- Could not connect to the Arduino on port %s", port_name.c_str());
00056                         ROS_BREAK();
00057                 }
00058         
00059                 ROS_INFO("Ardusim -- Opening a connection to an Arduino on port %s...", port_name.c_str());     
00060                 usleep(1500000);
00061                 ROS_INFO("Ardusim -- Connection opened!");
00062         
00063                 int version = checkVersion(500);
00064                 if(version==-1)
00065                 {
00066                         ROS_FATAL("Ardusim -- The Arduino is not loaded with the proper software!");
00067                         ROS_BREAK();
00068                 }
00069                 else if(version!=VERSION)
00070                 {
00071                         ROS_FATAL("Ardusim -- The Arduino software version %d is not compatible with Ardusim for ROS version %d!", version, VERSION);
00072                         ROS_BREAK();
00073                 }
00074         
00075                 return;
00076         }
00077 
00078         // *****************************************************************************
00079         // Destructor
00080         Ardusim::~Ardusim()
00081         {
00082                 try{ serial_port_->close(); }
00083                 catch(cereal::Exception& e)
00084                 { 
00085                         ROS_ERROR("Ardusim -- Could not close the serial port!");
00086                 }
00087 
00088                 delete serial_port_;
00089         }
00090 
00091         // *****************************************************************************
00092         // Send a command to the Arduino.
00093         bool Ardusim::sendCommand(int timeout, char mode, std::string * reply)
00094         {
00095                 std::string data(1, STRT);
00096         
00097                 data += SPRT;
00098                 data += mode;
00099                 data += SPRT;
00100                 data += END;
00101                 
00102                 try{ serial_port_->write(data.c_str()); }
00103                 catch(cereal::Exception& e)
00104                 {
00105                         ROS_ERROR("Ardusim - getSensorData - Error writing to the Arduino!");
00106                         return false;
00107                 }
00108         
00109                 try{ serial_port_->readBetween(reply, STRT, END, timeout); }
00110                 catch(cereal::TimeoutException& te)
00111                 { 
00112                         ROS_ERROR("Ardusim - getSensorData - Timeout reading from the Arduino!");
00113                         return false;
00114                 }
00115                 catch(cereal::Exception& e)
00116                 { 
00117                         ROS_ERROR("Ardusim - getSensorData - Error reading from the Arduino: \n%s", e.what());
00118                         return false;
00119                 }
00120         
00121                 return true;
00122         }
00123 
00124         // *****************************************************************************
00125         // Check if the version of the Arduino software is compatible with this lib.
00126         int Ardusim::checkVersion(int timeout)
00127         {
00128                 std::string reply;
00129         
00130                 if(!sendCommand(timeout, ARDUSIM_VERSION, &reply)) return -1;
00131         
00132                 // Take @, out
00133                 reply.erase(0,2);
00134         
00135                 return getValue(&reply);
00136         }
00137 
00138         // *****************************************************************************
00139         // Determine automatically which sensors are connected to the arduino
00140         bool Ardusim::autoRequests(int timeout, char mode)
00141         {
00142                 std::string reply;
00143         
00144                 if(!sendCommand(timeout, mode, &reply)) return false;
00145         
00146                 // Take @, out
00147                 reply.erase(0,2);
00148         
00149                 int n = getValue(&reply);
00150         
00151                 requests_.clear();
00152                 for(int i=0 ; i<n ; i++)
00153                 {
00154                         int sensor = getValue(&reply);
00155                         if(sensor==ARDUSIM_RANGE || sensor==ARDUSIM_NOSE || sensor==ARDUSIM_TPA || sensor==ARDUSIM_ANEMOMETER) requests_.push_back(sensor);
00156                         else if(sensor==ARDUSIM_NUNCHUCK) ROS_WARN("Ardusim GPnode - Discarding Nunchuck: unsupported");
00157                         else if(sensor==ARDUSIM_SHTXX) ROS_WARN("Ardusim GPnode - Discarding SHTxx: unsupported");
00158                         else ROS_WARN("Ardusim GPnode - Discarding unknow_n sensor id %d", sensor);
00159                 }
00160                 requests_.sort();
00161         
00162                 std::string end(1, END);
00163                 if(reply.compare(end)==0) return true;
00164                 else return false;
00165                 return true;
00166         }
00167 
00168         // *****************************************************************************
00169         // Get the current requests_ list
00170         void Ardusim::getRequests(std::list<int> * requests_)
00171         {
00172                 *requests_ = this->requests_;
00173         }
00174 
00175         // *****************************************************************************
00176         // Read data from the serial port
00177         void Ardusim::setRequests(int * requests_, int num_of_requests_)
00178         {
00179                 this->requests_.clear();
00180 
00181                 for(int i=0 ; i<num_of_requests_ ; i++) this->requests_.push_back(requests_[i]);
00182         
00183                 this->requests_.sort();
00184         }
00185 
00186         // *****************************************************************************
00187         // Read data from the serial port
00188         bool Ardusim::getSensorData(int timeout)
00189         {
00190                 std::list<int>::iterator it;
00191                 std::string reply;
00192                 std::string data(1, STRT);
00193         
00194                 data += SPRT;
00195                 data += ARDUSIM_QUERY;
00196                 data += SPRT;
00197                 addValue(&data, requests_.size());
00198                 for(it=requests_.begin() ; it!=requests_.end() ; ++it) addValue(&data, *it);
00199                 data += END;
00200         
00201                 try{ serial_port_->write(data.c_str()); }
00202                 catch(cereal::Exception& e)
00203                 {
00204                         ROS_ERROR("Ardusim - getSensorData - Error writing to the Arduino!");
00205                         return false;
00206                 }
00207         
00208                 try{ serial_port_->readBetween(&reply, STRT, END, timeout); }
00209                 catch(cereal::TimeoutException& te)
00210                 { 
00211                         ROS_ERROR("Ardusim - getSensorData - Timeout reading from the Arduino!");
00212                         return false;
00213                 }
00214                 catch(cereal::Exception& e)
00215                 { 
00216                         ROS_ERROR("Ardusim - getSensorData - Error reading from the Arduino: \n%s", e.what());
00217                         return false;
00218                 }
00219         
00220                 now_ = ros::Time::now();
00221         
00222                 return parseData(&reply);
00223         }
00224 
00225         // *****************************************************************************
00226         // Range getter function
00227         bool Ardusim::getRange(std::vector<lse_sensor_msgs::Range> * range)
00228         {
00229                 std::list<int>::iterator it;
00230         
00231                 for(it=requests_.begin() ; it!=requests_.end() ; ++it)
00232                 {
00233                         if(*it==ARDUSIM_RANGE)
00234                         {
00235                                 *range = range_msgs_;
00236                                 if(range_msgs_.size()==0) return false;
00237                                 return true;
00238                         }
00239                 }
00240                 return false;
00241         }
00242 
00243         // *****************************************************************************
00244         // Nose getter function
00245         bool Ardusim::getNose(std::vector<lse_sensor_msgs::Nostril> * nose)
00246         {
00247                 std::list<int>::iterator it;
00248         
00249                 for(it=requests_.begin() ; it!=requests_.end() ; ++it)
00250                 {
00251                         if(*it==ARDUSIM_NOSE)
00252                         {
00253                                 *nose = nose_msgs_;
00254                                 if(nose_msgs_.size()==0) return false;
00255                                 return true;
00256                         }
00257                 }
00258                 return false;
00259         }
00260 
00261         // *****************************************************************************
00262         // TPA getter function
00263         bool Ardusim::getTPA(std::vector<lse_sensor_msgs::TPA> * tpa)
00264         {
00265                 std::list<int>::iterator it;
00266         
00267                 for(it=requests_.begin() ; it!=requests_.end() ; ++it)
00268                 {
00269                         if(*it==ARDUSIM_TPA)
00270                         {
00271                                 *tpa = tpa_msgs_;
00272                                 if(tpa_msgs_.size()==0) return false;
00273                                 return true;
00274                         }
00275                 }
00276                 return false;
00277         }
00278 
00279         // *****************************************************************************
00280         // Anemometer getter function
00281         bool Ardusim::getAnemometer(std::vector<lse_sensor_msgs::Anemometer> * anemometer)
00282         {
00283                 std::list<int>::iterator it;
00284         
00285                 for(it=requests_.begin() ; it!=requests_.end() ; ++it)
00286                 {
00287                         if(*it==ARDUSIM_ANEMOMETER)
00288                         {
00289                                 *anemometer = anemometer_msgs_;
00290                                 if(anemometer_msgs_.size()==0) return false;
00291                                 return true;
00292                         }
00293                 }
00294                 return false;
00295         }
00296 
00297         // *****************************************************************************
00298         // Anemometer getter function
00299         bool Ardusim::getThermistor(std::vector<lse_sensor_msgs::Thermistor> * thermistor)
00300         {
00301                 std::list<int>::iterator it;
00302         
00303                 for(it=requests_.begin() ; it!=requests_.end() ; ++it)
00304                 {
00305                         if(*it==ARDUSIM_ANEMOMETER)
00306                         {
00307                                 *thermistor = thermistor_msgs_;
00308                                 if(thermistor_msgs_.size()==0) return false;
00309                                 return true;
00310                         }
00311                 }
00312                 return false;
00313         }
00314 
00315 
00316         // *****************************************************************************
00317         // Add an int value to the string
00318         void Ardusim::addValue(std::string * data, int value)
00319         {
00320                 char value_str[8];
00321                 sprintf(value_str, "%d", value);
00322         
00323                 data->append(value_str);
00324                 data->append(1, SPRT);
00325         }
00326 
00327         // *****************************************************************************
00328         // Get an int value from the string
00329         int Ardusim::getValue(std::string * data)
00330         {
00331                 int value;
00332         
00333                 int pos = data->find_first_of(SPRT);
00334                 std::string sub = data->substr(0,pos+1);
00335                 data->erase(0,pos+1);
00336         
00337                 if( sscanf(sub.c_str(), "%d,", &value) == 1) return value;
00338                 else return -1;
00339         }
00340 
00341         // *****************************************************************************
00342         // Parsing function
00343         bool Ardusim::parseData(std::string * data)
00344         {       
00345                 char sensor;
00346         
00347                 // Take @, out
00348                 data->erase(0,2);
00349         
00350                 std::string end(1, END);
00351                 while(data->compare(end)!=0)
00352                 {
00353                         sensor = getValue(data);
00354                 
00355                         if(sensor==ARDUSIM_RANGE) parseRange(data);
00356                         else if(sensor==ARDUSIM_NOSE) parseNose(data);
00357                         else if(sensor==ARDUSIM_TPA) parseTPA(data);
00358                         else if(sensor==ARDUSIM_ANEMOMETER) parseAnemometer(data);
00359                         else
00360                         {
00361                                 ROS_ERROR("Ardusim - parseData - Undefined sensor received!");
00362                                 return false;
00363                         }
00364                         if(data->size()==0)
00365                         {
00366                                 ROS_ERROR("Ardusim - parseData - Reached the end of the buffer!");
00367                                 return false;
00368                         }
00369                 }
00370                 return true;
00371         }
00372 
00373         // *****************************************************************************
00374         // Parsing function
00375         void Ardusim::parseRange(std::string * data)
00376         {
00377                 int n = getValue(data);
00378         
00379                 range_msgs_.clear();
00380                 for(int i=0 ; i<n ; i++)
00381                 {
00382                         lse_sensor_msgs::Range range;
00383                         range.header.stamp = now_;
00384                 
00385                         range.range = (float)(getValue(data)/100.0);
00386                 
00387                         range_msgs_.push_back(range);
00388                 }
00389         }
00390 
00391         // *****************************************************************************
00392         // Parsing function
00393         void Ardusim::parseNose(std::string * data)
00394         {
00395                 int n = getValue(data);
00396         
00397                 nose_msgs_.clear();
00398                 for(int i=0 ; i<n ; i++)
00399                 {
00400                         lse_sensor_msgs::Nostril nose;
00401                         nose.header.stamp = now_;
00402                 
00403                         nose.raw_data = getValue(data);
00404                 
00405                         nose_msgs_.push_back(nose);
00406                 }
00407         }
00408 
00409 
00410         // *****************************************************************************
00411         // Parsing function
00412         void Ardusim::parseTPA(std::string * data)
00413         {
00414                 int n = getValue(data);
00415         
00416                 tpa_msgs_.clear();
00417                 for(int i=0 ; i<n ; i++)
00418                 {
00419                         lse_sensor_msgs::TPA tpa;
00420                         tpa.header.stamp = now_;
00421                 
00422                         tpa.room_temperature = getValue(data);
00423                         for(int j=0 ; j<8 ; j++) tpa.temperature.push_back(getValue(data)); 
00424                 
00425                         tpa_msgs_.push_back(tpa);
00426                 }
00427         }
00428 
00429         // *****************************************************************************
00430         // Parsing function
00431         void Ardusim::parseAnemometer(std::string * data)
00432         {
00433                 int n = getValue(data);
00434         
00435                 thermistor_msgs_.clear();
00436                 anemometer_msgs_.clear();
00437                 for(int i=0 ; i<n ; i++)
00438                 {
00439                         // The raw msg
00440                         lse_sensor_msgs::Thermistor raw;
00441                         raw.header.stamp = now_;
00442                         
00443                         int ch[4];
00444                         for(int j=0 ; j<4 ; j++)
00445                         {
00446                                 ch[j] = getValue(data);
00447                                 raw.reading = ch[j];
00448                                 thermistor_msgs_.push_back(raw);
00449                         }
00450                 
00451                         // And now_ the anemometer msg
00452                         lse_sensor_msgs::Anemometer anemometer;
00453                         anemometer.header.stamp = now_;
00454                         
00455                         if(calib_data_.size()>0)
00456                         {
00457                                 std::vector<TopDistances> candidates;
00458                         
00459                                 float top_distance_sums[2] = {-1, -1};
00460                                 int ind[2];
00461                         
00462                                 for(int k=0 ; k<calib_data_.size() ; k++)
00463                                 {
00464                                         float ch0 = ch[0]-calib_data_[k].ch0;
00465                                         float ch1 = ch[1]-calib_data_[k].ch1;
00466                                         float ch2 = ch[2]-calib_data_[k].ch2;
00467                                         float ch3 = ch[3]-calib_data_[k].ch3;
00468                                         float distance = ch0*ch0 + ch1*ch1 + ch2*ch2 + ch3*ch3;
00469                                 
00470                                         int candidate_ind = -1;
00471                                         for(int c=0 ; c<candidates.size() ; c++)
00472                                         {
00473                                                 if(candidates[c].velocity == calib_data_[k].velocity)
00474                                                 {
00475                                                         candidate_ind = c;
00476                                                         break;
00477                                                 }
00478                                         }
00479                                         
00480                                         if(candidate_ind < 0)
00481                                         {
00482                                                 TopDistances new_candidate;
00483                                                 new_candidate.velocity = calib_data_[k].velocity;
00484                                                 new_candidate.index[0] = k;
00485                                                 new_candidate.distance[0] = distance;
00486                                                 new_candidate.index[1] = -1;
00487                                                 new_candidate.distance[1] = 0.0;
00488                                                 candidates.push_back(new_candidate);
00489                                         }
00490                                         else
00491                                         {
00492                                                 if(distance < candidates[candidate_ind].distance[0])
00493                                                 {
00494                                                         candidates[candidate_ind].distance[1] = candidates[candidate_ind].distance[0];
00495                                                         candidates[candidate_ind].index[1] = candidates[candidate_ind].index[0];
00496                                                         candidates[candidate_ind].distance[0] = distance;
00497                                                         candidates[candidate_ind].index[0] = k;
00498                                                 }
00499                                                 else if(distance < candidates[candidate_ind].distance[1] || candidates[candidate_ind].index[1] == -1)
00500                                                 {
00501                                                         candidates[candidate_ind].distance[1] = distance;
00502                                                         candidates[candidate_ind].index[1] = k;
00503                                                 }
00504                                         
00505                                                 float distance_sum = candidates[candidate_ind].distance[0]+candidates[candidate_ind].distance[1];
00506                                         
00507                                                 if(distance_sum < top_distance_sums[0] || top_distance_sums[0] == -1)
00508                                                 {
00509                                                         top_distance_sums[1] = top_distance_sums[0];
00510                                                         ind[1] = ind[0];
00511                                                         top_distance_sums[0] = distance_sum;
00512                                                         ind[0] = candidate_ind;
00513                                                 }
00514                                                 else if(distance_sum < top_distance_sums[1] || top_distance_sums[1] == -1)
00515                                                 {
00516                                                         top_distance_sums[1] = distance_sum;
00517                                                         ind[1] = candidate_ind;
00518                                                 }
00519                                         }
00520 
00521                                 }
00522                         
00523                                 float mean_weight = (top_distance_sums[0] + top_distance_sums[1]) / 4.0;
00524                                 candidates[ind[0]].weight[0] = candidates[ind[0]].distance[0]==0 ? mean_weight/0.01 : mean_weight/candidates[ind[0]].distance[0];
00525                                 candidates[ind[0]].weight[1] = candidates[ind[0]].distance[1]==0 ? mean_weight/0.01 : mean_weight/candidates[ind[0]].distance[1];
00526                                 candidates[ind[1]].weight[0] = candidates[ind[1]].distance[0]==0 ? mean_weight/0.01 : mean_weight/candidates[ind[1]].distance[0];
00527                                 candidates[ind[1]].weight[1] = candidates[ind[1]].distance[1]==0 ? mean_weight/0.01 : mean_weight/candidates[ind[1]].distance[1];
00528                         
00529                                 float sum = candidates[(int)*ind].weight[0] + candidates[(int)*ind].weight[1] + candidates[(int)*ind+1].weight[0] +candidates[(int)*ind+1].weight[1];
00530                                 candidates[ind[0]].weight[0] /= sum;
00531                                 candidates[ind[0]].weight[1] /= sum;
00532                                 candidates[ind[1]].weight[0] /= sum;
00533                                 candidates[ind[1]].weight[1] /= sum;
00534                         
00535                                 anemometer.wind_direction = calib_data_[candidates[ind[0]].index[0]].angle*candidates[ind[0]].weight[0] + calib_data_[candidates[ind[0]].index[1]].angle*candidates[ind[0]].weight[1] + calib_data_[candidates[ind[1]].index[0]].angle*candidates[ind[1]].weight[0] + calib_data_[candidates[ind[1]].index[1]].angle*candidates[ind[1]].weight[1];
00536                                 anemometer.wind_speed = calib_data_[candidates[ind[0]].index[0]].velocity*candidates[ind[0]].weight[0] + calib_data_[candidates[ind[0]].index[1]].velocity*candidates[ind[0]].weight[1] + calib_data_[candidates[ind[1]].index[0]].velocity*candidates[ind[1]].weight[0] + calib_data_[candidates[ind[1]].index[1]].velocity*candidates[ind[1]].weight[1];
00537                 
00538                                 anemometer_msgs_.push_back(anemometer);
00539                         }
00540                 }
00541         }
00542         
00543         bool Ardusim::loadAnemometerCalibFile(std::string * file_path)
00544         {
00545                 FILE * calib_file;
00546                 
00547                 calib_file = fopen(file_path->c_str(), "r");
00548                 
00549                 if(calib_file==NULL) return false;
00550                 
00551                 while(!feof(calib_file))
00552                 {
00553                         AnemometerCalibData new_calib_data;
00554                         
00555                         fscanf(calib_file, "%f,%d,%d,%d,%d,%f\n", &new_calib_data.angle, &new_calib_data.ch0, &new_calib_data.ch1, &new_calib_data.ch2, &new_calib_data.ch3, &new_calib_data.velocity);
00556                         
00557                         //ROS_INFO("%f,%d,%d,%d,%d,%f", new_calib_data.angle, new_calib_data.ch0, new_calib_data.ch1, new_calib_data.ch2, new_calib_data.ch3, new_calib_data.velocity);
00558                         
00559                         calib_data_.push_back(new_calib_data);
00560                 }
00561                 
00562                 return true;
00563         }
00564 
00565 } // namespace
00566 
00567 // EOF
00568 


ardusim
Author(s): Gonçalo Cabrita and Pedro Sousa
autogenerated on Mon Jan 6 2014 11:26:58