Main MRPT website > C++ reference for MRPT 1.9.9
CEnoseModular.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "hwdrivers-precomp.h" // Precompiled headers
11 
12 #include <mrpt/system/os.h>
14 #include <mrpt/utils/CMessage.h>
15 
16 #include <thread>
17 
18 using namespace mrpt::utils;
19 using namespace mrpt::math;
20 using namespace mrpt::obs;
21 using namespace mrpt::poses;
22 using namespace mrpt::hwdrivers;
23 using namespace std;
24 
26 
27 /*-------------------------------------------------------------
28  CEnoseModular
29 -------------------------------------------------------------*/
31  : m_usbSerialNumber("ENOSE002"), m_COM_port(), m_COM_baud(115200)
32 {
33  m_sensorLabel = "EnoseModular";
34  first_reading = true;
35 }
36 
37 /*-------------------------------------------------------------
38  loadConfig_sensorSpecific
39 -------------------------------------------------------------*/
40 void CEnoseModular::loadConfig_sensorSpecific(
41  const mrpt::utils::CConfigFileBase& configSource,
42  const std::string& iniSection)
43 {
45 
46  m_usbSerialNumber =
47  configSource.read_string(iniSection, "USB_serialname", "", false);
48 
49 #ifdef MRPT_OS_WINDOWS
50  m_COM_port = configSource.read_string(iniSection, "COM_port_WIN", "COM1");
51 #else
52  m_COM_port =
53  configSource.read_string(iniSection, "COM_port_LIN", m_COM_port);
54 #endif
55  m_COM_baud =
56  configSource.read_uint64_t(iniSection, "COM_baudRate", m_COM_baud);
57 
58  MRPT_END
59 }
60 
61 /*-------------------------------------------------------------
62  checkConnectionAndConnect
63 -------------------------------------------------------------*/
64 CStream* CEnoseModular::checkConnectionAndConnect()
65 {
66  // Make sure one of the two possible pipes is open:
67  if (!m_stream_FTDI && !m_stream_SERIAL)
68  {
69  if (!m_COM_port.empty())
70  m_stream_SERIAL.reset(new mrpt::comms::CSerialPort);
71  else
72  m_stream_FTDI.reset(new mrpt::comms::CInterfaceFTDI);
73  }
74 
75  if (m_stream_FTDI)
76  { // FTDI pipe ==================
77  if (m_stream_FTDI->isOpen()) return m_stream_FTDI.get();
78  try
79  {
80  m_stream_FTDI->OpenBySerialNumber(m_usbSerialNumber);
81  std::this_thread::sleep_for(10ms);
82  m_stream_FTDI->Purge();
83  std::this_thread::sleep_for(10ms);
84  m_stream_FTDI->SetLatencyTimer(1);
85  m_stream_FTDI->SetTimeouts(10, 100);
86  return m_stream_FTDI.get();
87  }
88  catch (...)
89  { // Error opening device:
90  m_stream_FTDI->Close();
91  return nullptr;
92  }
93  }
94  else
95  { // Serial pipe ==================
96  ASSERT_(m_stream_SERIAL)
97  if (m_stream_SERIAL->isOpen()) return m_stream_SERIAL.get();
98  try
99  {
100  m_stream_SERIAL->open(m_COM_port);
101  m_stream_SERIAL->setConfig(m_COM_baud);
102  // m_stream_SERIAL->setTimeouts(25,1,100, 1,20);
103  m_stream_SERIAL->setTimeouts(50, 1, 100, 1, 20);
104  std::this_thread::sleep_for(10ms);
105  m_stream_SERIAL->purgeBuffers();
106  std::this_thread::sleep_for(10ms);
107  return m_stream_SERIAL.get();
108  }
109  catch (...)
110  { // Error opening device:
111  m_stream_SERIAL->close();
112  return nullptr;
113  }
114  }
115 }
116 
117 /*-------------------------------------------------------------
118  getObservation
119 -------------------------------------------------------------*/
121 {
122  try
123  {
124  // Connected?
125  CStream* comms = checkConnectionAndConnect();
126 
127  if (!comms)
128  {
129  cout << "ERORR: Problem connecting to Device." << endl;
130  return false;
131  }
132 
134  obs.m_readings.clear();
135 
136  //---------------------------- Enose Modular FRAME
137  //--------------------------------------------------
138  // Wait for e-nose frame: <0x69><0x91><lenght><body><0x96> "Bytes"
139  // Where <body> = <temp>[<SensorID_H><SensorID_L><Sensor_Value>] x
140  // N_senosrs
141  // Modular-nose provides a 4B+body frame lenght
142 
144  bool time_out = false;
146  double time_out_val = 1; // seconds
147 
148  while (!comms->receiveMessage(msg) && !time_out)
149  {
151  t1, mrpt::system::getCurrentLocalTime()) > time_out_val)
152  time_out = true;
153  }
154 
155  if (time_out)
156  {
157  cout << "[CEnoseModular - getObservation] measurement Timed-Out"
158  << endl;
159  return false;
160  }
161 
162  if (msg.content.size() > 0)
163  {
164  // Each sensor reading is composed of 3 Bytes
165  // [<SensorID_H><SensorID_L><Sensor_Value>]
166  ASSERT_((msg.content.size() - 1) % 3 == 0)
167  size_t numSensors = (msg.content.size() - 1) / 3;
168 
169  // Prepare the Enose observation
170  newRead.sensorTypes.clear();
171  newRead.readingsVoltage.clear();
172  newRead.hasTemperature = true;
173  newRead.isActive = true;
174 
175  // Do we have the sensor position?
176  if (enose_poses_x.size() != 0)
177  {
178  newRead.eNosePoseOnTheRobot = CPose3D(
179  enose_poses_x[0], enose_poses_y[0], enose_poses_z[0],
180  enose_poses_yaw[0], enose_poses_pitch[0],
181  enose_poses_roll[0]);
182  }
183  else
184  newRead.eNosePoseOnTheRobot = CPose3D(0, 0, 0);
185 
186  // Get Temperature (degrees C)
187  newRead.temperature = msg.content[0] * 1.65214 - 277.74648;
188 
189  // process all sensors
190  for (size_t idx = 0; idx < numSensors; idx++)
191  {
192  // Copy ID (2 BYTES) To integer
193  int sensorType_temp = 0;
194  // memcpy( &sensorType, &msg.content[idx*3+1],
195  // 2*sizeof(msg.content[0]) );
196  memcpy(
197  &sensorType_temp, &msg.content[idx * 3 + 1],
198  sizeof(msg.content[0]));
199  int sensorType = sensorType_temp << (8);
200  memcpy(
201  &sensorType, &msg.content[idx * 3 + 2],
202  sizeof(msg.content[0]));
203 
204  // Add sensor Type (ID)
205  newRead.sensorTypes.push_back(sensorType);
206 
207  // Transform from ADC value[8bits] to [0-0.6] volt range:
208  newRead.readingsVoltage.push_back(
209  (msg.content[idx * 3 + 3] * 0.6f) / 255.0f);
210  }
211 
212  // Purge buffers
213  purgeBuffers();
214 
215  // Add data to observation:
216  obs.m_readings.push_back(newRead);
217  obs.sensorLabel = m_sensorLabel;
219  return !obs.m_readings.empty(); // Done OK!
220  }
221  else
222  {
223  cout << "Message was empty" << endl;
224  return false;
225  }
226  }
227  catch (exception& e)
228  {
229  cerr << "[CEnoseModular::getObservation] Returning false due to "
230  "exception: "
231  << endl;
232  cerr << e.what() << endl;
233  return false;
234  }
235  catch (...)
236  {
237  return false;
238  }
239 }
240 
241 /*-------------------------------------------------------------
242  doProcess
243 -------------------------------------------------------------*/
244 /** This method should be called periodically (at least at 1Hz to capture ALL
245 * the real-time data)
246 * It is thread safe, i.e. you can call this from one thread, then to other
247 * methods from other threads.
248 */
249 void CEnoseModular::doProcess()
250 {
252  mrpt::make_aligned_shared<CObservationGasSensors>();
253 
254  if (getObservation(*obs))
255  {
256  m_state = ssWorking;
257  appendObservation(obs);
258  }
259  else
260  {
261  m_state = ssError;
262  cout << "No observation received from the USB board!" << endl;
263  // THROW_EXCEPTION("No observation received from the USB board!");
264  }
265 }
266 
267 /*-------------------------------------------------------------
268  purgeBuffers
269 -------------------------------------------------------------*/
270 void CEnoseModular::purgeBuffers()
271 {
272  if (!checkConnectionAndConnect()) return;
273 
274  if (m_stream_FTDI)
275  { // FTDI pipe
276  m_stream_FTDI->Purge();
277  }
278  else
279  { // Serial pipe
280  m_stream_SERIAL->purgeBuffers();
281  }
282 }
uint64_t TTimeStamp
A system independent time type, it holds the the number of 100-nanosecond intervals since January 1...
Definition: datetime.h:32
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
A communications serial port built as an implementation of a utils::CStream.
Definition: CSerialPort.h:47
mrpt::system::TTimeStamp getCurrentTime()
Returns the current (UTC) system time.
Definition: datetime.cpp:73
float temperature
Sensed temperature in Celcius (valid if hasTemperature=true only)
Contains classes for various device interfaces.
vector_int sensorTypes
The kind of sensors in the array (size of "sensorTypes" is the same that the size of "readingsVoltage...
std::string read_string(const std::string &section, const std::string &name, const std::string &defaultValue, bool failIfNotFound=false) const
STL namespace.
mrpt::system::TTimeStamp getCurrentLocalTime()
Returns the current (local) time.
Definition: datetime.cpp:173
This class allows loading and storing values and vectors of different types from a configuration text...
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:41
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:19
std::shared_ptr< CObservationGasSensors > Ptr
math::TPose3D eNosePoseOnTheRobot
The pose of the sensors on the robot.
#define MRPT_END
bool hasTemperature
Must be true for "temperature" to contain a valid measurement.
This namespace contains representation of robot actions and observations.
Declares a class derived from "CObservation" that represents a set of readings from gas sensors...
GLsizei const GLchar ** string
Definition: glext.h:4101
#define IMPLEMENTS_GENERIC_SENSOR(class_name, NameSpace)
This must be inserted in all CGenericSensor classes implementation files:
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Definition: CPoint.h:17
#define MRPT_START
std::string sensorLabel
An arbitrary label that can be used to identify the sensor.
Definition: CObservation.h:60
bool isActive
True if the input to this chamber/enose is poluted air, False if clean air.
mrpt::system::TTimeStamp timestamp
The associated UTC time-stamp.
Definition: CObservation.h:58
bool receiveMessage(utils::CMessage &msg)
Tries to receive a message from the device.
Definition: CStream.cpp:686
A definition of a CStream actually representing a USB connection to a FTDI chip.
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:88
std::vector< TObservationENose > m_readings
One entry per e-nose on the robot.
OBSERVATION_T::Ptr getObservation(mrpt::obs::CSensoryFrame::Ptr &observations, mrpt::obs::CObservation::Ptr &observation, bool priority_to_sf=true)
Given an mrpt::obs::CSensoryFrame and a mrpt::obs::CObservation pointer if a OBSERVATION_T type obser...
Definition: obs_utils.h:36
#define ASSERT_(f)
uint64_t read_uint64_t(const std::string &section, const std::string &name, uint64_t defaultValue, bool failIfNotFound=false) const
std::vector< uint8_t > content
The contents of the message (memory is automatically handled by the std::vector object) ...
Definition: CMessage.h:39
double timeDifference(const mrpt::system::TTimeStamp t_first, const mrpt::system::TTimeStamp t_later)
Returns the time difference from t1 to t2 (positive if t2 is posterior to t1), in seconds...
Definition: datetime.cpp:208
std::vector< float > readingsVoltage
The set of readings (in volts) from the array of sensors (size of "sensorTypes" is the same that the ...
A class that contain generic messages, that can be sent and received from a "CClientTCPSocket" object...
Definition: CMessage.h:31
A class for interfacing an e-NoseModular via a FTDI USB link.
Definition: CEnoseModular.h:56
void memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) noexcept
An OS and compiler independent version of "memcpy".
Definition: os.cpp:355



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019