PX4 Firmware
PX4 Autopilot Software http://px4.io
ets_airspeed.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2013, 2014 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file ets_airspeed.cpp
36  * @author Simon Wilks
37  *
38  * Driver for the Eagle Tree Airspeed V3 connected via I2C.
39  */
40 
41 #include <float.h>
42 
44 #include <px4_platform_common/getopt.h>
45 
46 /* I2C bus address */
47 #define I2C_ADDRESS 0x75 /* 7-bit address. 8-bit address is 0xEA */
48 #define ETS_PATH "/dev/ets_airspeed"
49 
50 /* Register address */
51 #define READ_CMD 0x07 /* Read the data */
52 
53 /**
54  * The Eagle Tree Airspeed V3 cannot provide accurate reading below speeds of 15km/h.
55  * You can set this value to 12 if you want a zero reading below 15km/h.
56  */
57 #define MIN_ACCURATE_DIFF_PRES_PA 0
58 
59 /* Measurement rate is 100Hz */
60 #define CONVERSION_INTERVAL (1000000 / 100) /* microseconds */
61 
62 class ETSAirspeed : public Airspeed
63 {
64 public:
65  ETSAirspeed(int bus, int address = I2C_ADDRESS, const char *path = ETS_PATH);
66 
67 protected:
68 
69  /**
70  * Perform a poll cycle; collect from the previous measurement
71  * and start a new one.
72  */
73  void Run() override;
74  int measure() override;
75  int collect() override;
76 
77 };
78 
79 /*
80  * Driver 'main' command.
81  */
82 extern "C" __EXPORT int ets_airspeed_main(int argc, char *argv[]);
83 
84 ETSAirspeed::ETSAirspeed(int bus, int address, const char *path) : Airspeed(bus, address,
85  CONVERSION_INTERVAL, path)
86 {
87  _device_id.devid_s.devtype = DRV_DIFF_PRESS_DEVTYPE_MS4525;
88 }
89 
90 int
92 {
93  int ret;
94 
95  /*
96  * Send the command to begin a measurement.
97  */
98  uint8_t cmd = READ_CMD;
99  ret = transfer(&cmd, 1, nullptr, 0);
100 
101  if (OK != ret) {
103  }
104 
105  return ret;
106 }
107 
108 int
110 {
111  int ret = -EIO;
112 
113  /* read from the sensor */
114  uint8_t val[2] = {0, 0};
115 
117 
118  ret = transfer(nullptr, 0, &val[0], 2);
119 
120  if (ret < 0) {
122  return ret;
123  }
124 
125  float diff_pres_pa_raw = (float)(val[1] << 8 | val[0]);
126 
128  report.timestamp = hrt_absolute_time();
129 
130  if (diff_pres_pa_raw < FLT_EPSILON) {
131  // a zero value indicates no measurement
132  // since the noise floor has been arbitrarily killed
133  // it defeats our stuck sensor detection - the best we
134  // can do is to output some numerical noise to show
135  // that we are still correctly sampling.
136  diff_pres_pa_raw = 0.001f * (report.timestamp & 0x01);
137  }
138 
139  // The raw value still should be compensated for the known offset
140  diff_pres_pa_raw -= _diff_pres_offset;
141 
143 
144  // XXX we may want to smooth out the readings to remove noise.
145  report.differential_pressure_filtered_pa = diff_pres_pa_raw;
146  report.differential_pressure_raw_pa = diff_pres_pa_raw;
147  report.temperature = -1000.0f;
148  report.device_id = _device_id.devid;
149 
150  if (_airspeed_pub != nullptr && !(_pub_blocked)) {
151  /* publish it */
152  orb_publish(ORB_ID(differential_pressure), _airspeed_pub, &report);
153  }
154 
155  ret = OK;
156 
158 
159  return ret;
160 }
161 
162 void
164 {
165  int ret;
166 
167  /* collection phase? */
168  if (_collect_phase) {
169 
170  /* perform collection */
171  ret = collect();
172 
173  if (OK != ret) {
175  /* restart the measurement state machine */
176  start();
177  _sensor_ok = false;
178  return;
179  }
180 
181  /* next phase is measurement */
182  _collect_phase = false;
183 
184  /*
185  * Is there a collect->measure gap?
186  */
188 
189  /* schedule a fresh cycle call when we are ready to measure again */
190  ScheduleDelayed(_measure_interval - CONVERSION_INTERVAL);
191 
192  return;
193  }
194  }
195 
196  /* measurement phase */
197  ret = measure();
198 
199  if (OK != ret) {
200  DEVICE_DEBUG("measure error");
201  }
202 
203  _sensor_ok = (ret == OK);
204 
205  /* next phase is collection */
206  _collect_phase = true;
207 
208  /* schedule a fresh cycle call when the measurement is done */
209  ScheduleDelayed(CONVERSION_INTERVAL);
210 }
211 
212 /**
213  * Local functions in support of the shell command.
214  */
215 namespace ets_airspeed
216 {
217 
218 ETSAirspeed *g_dev = nullptr;
219 
220 int start();
221 int start_bus(int i2c_bus);
222 int stop();
223 int reset();
224 int info();
225 
226 /**
227  * Attempt to start driver on all available I2C busses.
228  *
229  * This function will return as soon as the first sensor
230  * is detected on one of the available busses or if no
231  * sensors are detected.
232  *
233  */
234 int
236 {
237  for (unsigned i = 0; i < NUM_I2C_BUS_OPTIONS; i++) {
238  if (start_bus(i2c_bus_options[i]) == PX4_OK) {
239  return PX4_OK;
240  }
241  }
242 
243  return PX4_ERROR;
244 
245 }
246 
247 /**
248  * Start the driver on a specific bus.
249  *
250  * This function only returns if the sensor is up and running
251  * or could not be detected successfully.
252  */
253 int
254 start_bus(int i2c_bus)
255 {
256  int fd;
257 
258  if (g_dev != nullptr) {
259  PX4_ERR("already started");
260  return PX4_ERROR;
261  }
262 
263  /* create the driver */
264  g_dev = new ETSAirspeed(i2c_bus);
265 
266  if (g_dev == nullptr) {
267  goto fail;
268  }
269 
270  if (OK != g_dev->init()) {
271  goto fail;
272  }
273 
274  /* set the poll rate to default, starts automatic data collection */
275  fd = px4_open(AIRSPEED0_DEVICE_PATH, O_RDONLY);
276 
277  if (fd < 0) {
278  goto fail;
279  }
280 
282  goto fail;
283  }
284 
285  return PX4_OK;
286 
287 fail:
288 
289  if (g_dev != nullptr) {
290  delete g_dev;
291  g_dev = nullptr;
292  }
293 
294  return PX4_ERROR;
295 }
296 
297 /**
298  * Stop the driver
299  */
300 int
302 {
303  if (g_dev != nullptr) {
304  delete g_dev;
305  g_dev = nullptr;
306 
307  } else {
308  PX4_ERR("driver not running");
309  return PX4_ERROR;
310  }
311 
312  return PX4_OK;
313 }
314 
315 /**
316  * Reset the driver.
317  */
318 int
320 {
321  int fd = px4_open(ETS_PATH, O_RDONLY);
322 
323  if (fd < 0) {
324  PX4_ERR("failed");
325  return PX4_ERROR;
326  }
327 
328  if (px4_ioctl(fd, SENSORIOCRESET, 0) < 0) {
329  PX4_ERR("driver reset failed");
330  return PX4_ERROR;
331  }
332 
334  PX4_ERR("driver poll restart failed");
335  return PX4_ERROR;
336  }
337 
338  return PX4_OK;
339 }
340 
341 } // namespace
342 
343 
344 static void
346 {
347  PX4_INFO("usage: ets_airspeed command [options]");
348  PX4_INFO("options:");
349  PX4_INFO("\t-b --bus i2cbus (%d)", PX4_I2C_BUS_DEFAULT);
350  PX4_INFO("\t-a --all");
351  PX4_INFO("command:");
352  PX4_INFO("\tstart|stop|reset|info");
353 }
354 
355 int
356 ets_airspeed_main(int argc, char *argv[])
357 {
358  int i2c_bus = PX4_I2C_BUS_DEFAULT;
359 
360  int myoptind = 1;
361  int ch;
362  const char *myoptarg = nullptr;
363  bool start_all = false;
364 
365  while ((ch = px4_getopt(argc, argv, "ab:", &myoptind, &myoptarg)) != EOF) {
366  switch (ch) {
367  case 'b':
368  i2c_bus = atoi(myoptarg);
369  break;
370 
371  case 'a':
372  start_all = true;
373  break;
374 
375  default:
377  return 0;
378  }
379  }
380 
381  if (myoptind >= argc) {
383  return -1;
384  }
385 
386  /*
387  * Start/load the driver.
388  */
389  if (!strcmp(argv[myoptind], "start")) {
390  if (start_all) {
391  return ets_airspeed::start();
392 
393  } else {
394  return ets_airspeed::start_bus(i2c_bus);
395  }
396  }
397 
398  /*
399  * Stop the driver
400  */
401  if (!strcmp(argv[myoptind], "stop")) {
402  return ets_airspeed::stop();
403  }
404 
405  /*
406  * Reset the driver.
407  */
408  if (!strcmp(argv[myoptind], "reset")) {
409  return ets_airspeed::reset();
410  }
411 
413  return 0;
414 }
orb_advert_t _airspeed_pub
Definition: airspeed.h:81
void stop()
Stop the automatic measurement state machine.
Definition: airspeed.cpp:210
virtual int init()
Definition: airspeed.cpp:92
ETSAirspeed(int bus, int address=I2C_ADDRESS, const char *path=ETS_PATH)
#define AIRSPEED0_DEVICE_PATH
Definition: drv_airspeed.h:52
#define CONVERSION_INTERVAL
#define SENSOR_POLLRATE_DEFAULT
poll at driver normal rate
Definition: drv_sensor.h:136
Definition: I2C.hpp:51
__EXPORT int ets_airspeed_main(int argc, char *argv[])
int reset()
Reset the driver.
Local functions in support of the shell command.
#define FLT_EPSILON
#define SENSORIOCSPOLLRATE
Set the driver polling rate to (arg) Hz, or one of the SENSOR_POLLRATE constants. ...
Definition: drv_sensor.h:134
static constexpr uint8_t PX4_I2C_BUS_DEFAULT
Definition: airspeed.h:48
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
void perf_count(perf_counter_t handle)
Count a performance event.
#define ETS_PATH
ETSAirspeed * g_dev
perf_counter_t _sample_perf
Definition: airspeed.h:88
void perf_end(perf_counter_t handle)
End a performance event.
int fd
Definition: dataman.cpp:146
int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)
Definition: uORB.cpp:70
int _measure_interval
Definition: airspeed.h:77
static const int i2c_bus_options[]
Definition: i2c.h:46
int stop()
Stop the driver.
void Run() override
Perform a poll cycle; collect from the previous measurement and start a new one.
int collect() override
#define DRV_DIFF_PRESS_DEVTYPE_MS4525
Definition: drv_sensor.h:97
int measure() override
int px4_open(const char *path, int flags,...)
float _diff_pres_offset
Definition: airspeed.h:79
#define I2C_ADDRESS
#define SENSORIOCRESET
Reset the sensor to its default configuration.
Definition: drv_sensor.h:141
uint64_t perf_event_count(perf_counter_t handle)
Return current event_count.
int start_bus(int i2c_bus)
Start the driver on a specific bus.
#define OK
Definition: uavcan_main.cpp:71
bool _collect_phase
Definition: airspeed.h:78
static void ets_airspeed_usage()
#define READ_CMD
#define NUM_I2C_BUS_OPTIONS
Definition: i2c.h:61
int start()
Attempt to start driver on all available I2C busses.
bool _sensor_ok
Definition: airspeed.h:76
void perf_begin(perf_counter_t handle)
Begin a performance event.
#define DEVICE_DEBUG(FMT,...)
Definition: Device.hpp:52
perf_counter_t _comms_errors
Definition: airspeed.h:89
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
void start()
Initialise the automatic measurement state machine and start it.
Definition: airspeed.cpp:200
int info()
Print a little info about the driver.
int px4_ioctl(int fd, int cmd, unsigned long arg)