00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
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
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
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
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
00126 int Ardusim::checkVersion(int timeout)
00127 {
00128 std::string reply;
00129
00130 if(!sendCommand(timeout, ARDUSIM_VERSION, &reply)) return -1;
00131
00132
00133 reply.erase(0,2);
00134
00135 return getValue(&reply);
00136 }
00137
00138
00139
00140 bool Ardusim::autoRequests(int timeout, char mode)
00141 {
00142 std::string reply;
00143
00144 if(!sendCommand(timeout, mode, &reply)) return false;
00145
00146
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
00170 void Ardusim::getRequests(std::list<int> * requests_)
00171 {
00172 *requests_ = this->requests_;
00173 }
00174
00175
00176
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
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
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
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
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
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
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
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
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
00343 bool Ardusim::parseData(std::string * data)
00344 {
00345 char sensor;
00346
00347
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
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
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
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
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
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
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
00558
00559 calib_data_.push_back(new_calib_data);
00560 }
00561
00562 return true;
00563 }
00564
00565 }
00566
00567
00568