AP_RangeFinder_Bebop.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /*
  2. This program is free software: you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation, either version 3 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program. If not, see <http://www.gnu.org/licenses/>.
  12. */
  13. #include <AP_HAL/AP_HAL.h>
  14. #include <utility>
  15. #if (CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_BEBOP || \
  16. CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_DISCO) && \
  17. defined(HAVE_LIBIIO)
  18. #include <stdlib.h>
  19. #include <unistd.h>
  20. #include <stdio.h>
  21. #include <fcntl.h>
  22. #include <string.h>
  23. #include <sys/mman.h>
  24. #include <linux/types.h>
  25. #include <errno.h>
  26. #include <sys/ioctl.h>
  27. #include <float.h>
  28. #include <math.h>
  29. #include <time.h>
  30. #include <iio.h>
  31. #include "AP_RangeFinder_Bebop.h"
  32. #include <AP_HAL_Linux/Thread.h>
  33. #include <AP_HAL_Linux/GPIO.h>
  34. /*
  35. * this mode is used at low altitude
  36. * send 4 wave patterns
  37. * gpio in low mode
  38. */
  39. #define RNFD_BEBOP_DEFAULT_MODE 1
  40. /*
  41. * the number of p7s in the iio buffer
  42. */
  43. #define RNFD_BEBOP_P7_COUNT 8192
  44. extern const AP_HAL::HAL& hal;
  45. static const uint16_t waveform_mode0[14] = {
  46. 4000, 3800, 3600, 3400, 3200, 3000, 2800,
  47. 2600, 2400, 2200, 2000, 1800, 1600, 1400,
  48. };
  49. static const uint16_t waveform_mode1[32] = {
  50. 4190, 4158, 4095, 4095, 4095, 4095, 4095, 4095, 4095,
  51. 4095, 4090, 4058, 3943, 3924, 3841, 3679, 3588, 3403,
  52. 3201, 3020, 2816, 2636, 2448, 2227, 2111, 1955, 1819,
  53. 1675, 1540, 1492, 1374, 1292
  54. };
  55. AP_RangeFinder_Bebop::AP_RangeFinder_Bebop(RangeFinder::RangeFinder_State &_state, AP_RangeFinder_Params &_params) :
  56. AP_RangeFinder_Backend(_state, _params),
  57. _thread(new Linux::Thread(FUNCTOR_BIND_MEMBER(&AP_RangeFinder_Bebop::_loop, void)))
  58. {
  59. _init();
  60. _freq = RNFD_BEBOP_DEFAULT_FREQ;
  61. _filtered_capture_size = _adc.buffer_size / _filter_average;
  62. _filtered_capture = (unsigned int*) calloc(1, sizeof(_filtered_capture[0]) *
  63. _filtered_capture_size);
  64. _mode = RNFD_BEBOP_DEFAULT_MODE;
  65. /* SPI and IIO can not be initialized just yet */
  66. memset(_tx[0], 0xF0, 16);
  67. memset(_tx[1], 0xF0, 4);
  68. memset(_purge, 0xFF, RNFD_BEBOP_NB_PULSES_PURGE);
  69. _tx_buf = _tx[_mode];
  70. }
  71. AP_RangeFinder_Bebop::~AP_RangeFinder_Bebop()
  72. {
  73. iio_buffer_destroy(_adc.buffer);
  74. _adc.buffer = nullptr;
  75. iio_context_destroy(_iio);
  76. _iio = nullptr;
  77. }
  78. bool AP_RangeFinder_Bebop::detect()
  79. {
  80. return true;
  81. }
  82. unsigned short AP_RangeFinder_Bebop::get_threshold_at(int i_capture)
  83. {
  84. uint16_t threshold_value = 0;
  85. /*
  86. * We define several kinds of thresholds signals ; for an echo to be
  87. * recorded, its maximum amplitude has to be ABOVE that threshold.
  88. * There is one kind of threshold per mode (mode 0 is "low" and mode 1 is
  89. * "high")
  90. * Basically they look like this :
  91. *
  92. * on this part
  93. * of the capture
  94. * amplitude we use
  95. * ^ the waveform
  96. * | <---------->
  97. * 4195 +-----+
  98. * |
  99. * |
  100. * |
  101. * |
  102. * 1200| +----------------+
  103. * +-------------------------------------->
  104. * + low high time
  105. * limit limit
  106. *
  107. * */
  108. switch (_mode) {
  109. case 0:
  110. if (i_capture < 139) {
  111. threshold_value = 4195;
  112. } else if (i_capture < 153) {
  113. threshold_value = waveform_mode0[i_capture - 139];
  114. } else {
  115. threshold_value = 1200;
  116. }
  117. break;
  118. case 1:
  119. if (i_capture < 73) {
  120. threshold_value = 4195;
  121. } else if (i_capture < 105) {
  122. threshold_value = waveform_mode1[i_capture - 73];
  123. } else if (i_capture < 617) {
  124. threshold_value = 1200;
  125. } else {
  126. threshold_value = 4195;
  127. }
  128. break;
  129. default:
  130. break;
  131. }
  132. return threshold_value;
  133. }
  134. int AP_RangeFinder_Bebop::_apply_averaging_filter(void)
  135. {
  136. int i_filter = 0; /* index in the filtered buffer */
  137. int i_capture = 0; /* index in the capture buffer : starts incrementing when
  138. the captured data first exceeds
  139. RNFD_BEBOP_THRESHOLD_ECHO_INIT */
  140. unsigned int filtered_value = 0;
  141. bool first_echo = false;
  142. unsigned char *data;
  143. unsigned char *start;
  144. unsigned char *end;
  145. ptrdiff_t step;
  146. step = iio_buffer_step(_adc.buffer);
  147. end = (unsigned char *) iio_buffer_end(_adc.buffer);
  148. start = (unsigned char *) iio_buffer_first(_adc.buffer, _adc.channel);
  149. for (data = start; data < end; data += step) {
  150. unsigned int current_value = 0;
  151. iio_channel_convert(_adc.channel, &current_value, data);
  152. /* We keep on advancing in the captured buffer without registering the
  153. * filtered data until the signal first exceeds a given value */
  154. if (!first_echo && current_value < threshold_echo_init) {
  155. continue;
  156. } else {
  157. first_echo = true;
  158. }
  159. filtered_value += current_value;
  160. if (i_capture % _filter_average == 0) {
  161. _filtered_capture[i_filter] = filtered_value / _filter_average;
  162. filtered_value = 0;
  163. i_filter++;
  164. }
  165. i_capture++;
  166. }
  167. return 0;
  168. }
  169. int AP_RangeFinder_Bebop::_search_local_maxima(void)
  170. {
  171. int i_echo = 0; /* index in echo array */
  172. for (int i_capture = 1; i_capture <
  173. (int)_filtered_capture_size - 1; i_capture++) {
  174. if (_filtered_capture[i_capture] >= get_threshold_at(i_capture)) {
  175. unsigned short curr = _filtered_capture[i_capture];
  176. unsigned short prev = _filtered_capture[i_capture - 1];
  177. unsigned short next = _filtered_capture[i_capture + 1];
  178. if (curr >= prev && (curr > next || prev <
  179. get_threshold_at(i_capture - 1))) {
  180. _echoes[i_echo].max_index = i_capture;
  181. i_echo++;
  182. if (i_echo >= RNFD_BEBOP_MAX_ECHOES) {
  183. break;
  184. }
  185. }
  186. }
  187. }
  188. _nb_echoes = i_echo;
  189. return 0;
  190. }
  191. int AP_RangeFinder_Bebop::_search_maximum_with_max_amplitude(void)
  192. {
  193. unsigned short max = 0;
  194. int max_idx = -1;
  195. for (int i_echo = 0; i_echo < _nb_echoes ; i_echo++) {
  196. unsigned short curr = _filtered_capture[_echoes[i_echo].max_index];
  197. if (curr > max) {
  198. max = curr;
  199. max_idx = i_echo;
  200. }
  201. }
  202. if (max_idx >= 0) {
  203. return _echoes[max_idx].max_index;
  204. } else {
  205. return -1;
  206. }
  207. }
  208. void AP_RangeFinder_Bebop::_loop(void)
  209. {
  210. int max_index;
  211. while(1) {
  212. _launch();
  213. _capture();
  214. if (_apply_averaging_filter() < 0) {
  215. hal.console->printf(
  216. "AR_RangeFinder_Bebop: could not apply averaging filter");
  217. }
  218. if (_search_local_maxima() < 0) {
  219. hal.console->printf("Did not find any local maximum");
  220. }
  221. max_index = _search_maximum_with_max_amplitude();
  222. if (max_index >= 0) {
  223. _altitude = (float)(max_index * RNFD_BEBOP_SOUND_SPEED) /
  224. (2 * (RNFD_BEBOP_DEFAULT_ADC_FREQ / _filter_average));
  225. }
  226. _mode = _update_mode(_altitude);
  227. }
  228. }
  229. void AP_RangeFinder_Bebop::update(void)
  230. {
  231. static bool first_call = true;
  232. if (first_call) {
  233. _thread->start("RangeFinder_Bebop", SCHED_FIFO, 11);
  234. first_call = false;
  235. }
  236. state.distance_cm = (uint16_t) (_altitude * 100);
  237. state.last_reading_ms = AP_HAL::millis();
  238. update_status();
  239. }
  240. /*
  241. * purge is used when changing mode
  242. */
  243. int AP_RangeFinder_Bebop::_launch_purge()
  244. {
  245. iio_device_attr_write(_adc.device, "buffer/enable", "1");
  246. _spi->transfer(_purge, RNFD_BEBOP_NB_PULSES_PURGE, nullptr, 0);
  247. return 0;
  248. }
  249. void AP_RangeFinder_Bebop::_configure_gpio(int value)
  250. {
  251. switch (value) {
  252. case 1: // high voltage
  253. _gpio->write(LINUX_GPIO_ULTRASOUND_VOLTAGE, 1);
  254. break;
  255. case 0: // low voltage
  256. _gpio->write(LINUX_GPIO_ULTRASOUND_VOLTAGE, 0);
  257. break;
  258. default:
  259. hal.console->printf("bad gpio value (%d)", value);
  260. break;
  261. }
  262. }
  263. /*
  264. * reconfigure the pulse that will be sent over spi
  265. * first send a purge then configure the new pulse
  266. */
  267. void AP_RangeFinder_Bebop::_reconfigure_wave()
  268. {
  269. /* configure the output buffer for a purge */
  270. /* perform a purge */
  271. if (_launch_purge() < 0) {
  272. hal.console->printf("purge could not send data overspi");
  273. }
  274. if (_capture() < 0) {
  275. hal.console->printf("purge could not capture data");
  276. }
  277. _tx_buf = _tx[_mode];
  278. switch (_mode) {
  279. case 1: /* low voltage */
  280. _configure_gpio(0);
  281. break;
  282. case 0: /* high voltage */
  283. _configure_gpio(1);
  284. break;
  285. default:
  286. hal.console->printf("WARNING, invalid value to configure gpio\n");
  287. break;
  288. }
  289. }
  290. /*
  291. * First configuration of the the pulse that will be send over spi
  292. */
  293. int AP_RangeFinder_Bebop::_configure_wave()
  294. {
  295. _spi->set_speed(AP_HAL::Device::SPEED_HIGH);
  296. _configure_gpio(0);
  297. return 0;
  298. }
  299. /*
  300. * Configure the adc to get the samples
  301. */
  302. int AP_RangeFinder_Bebop::_configure_capture()
  303. {
  304. const char *adcname = "p7mu-adc_2";
  305. const char *adcchannel = "voltage2";
  306. /* configure adc interface using libiio */
  307. _iio = iio_create_local_context();
  308. if (!_iio) {
  309. return -1;
  310. }
  311. _adc.device = iio_context_find_device(_iio, adcname);
  312. if (!_adc.device) {
  313. hal.console->printf("Unable to find %s", adcname);
  314. goto error_destroy_context;
  315. }
  316. _adc.channel = iio_device_find_channel(_adc.device, adcchannel,
  317. false);
  318. if (!_adc.channel) {
  319. hal.console->printf("Fail to init adc channel %s", adcchannel);
  320. goto error_destroy_context;
  321. }
  322. iio_channel_enable(_adc.channel);
  323. _adc.freq = RNFD_BEBOP_DEFAULT_ADC_FREQ >> RNFD_BEBOP_FILTER_POWER;
  324. _adc.threshold_time_rejection = 2.0 / RNFD_BEBOP_SOUND_SPEED *
  325. _adc.freq;
  326. /* Create input buffer */
  327. _adc.buffer_size = RNFD_BEBOP_P7_COUNT;
  328. if (iio_device_set_kernel_buffers_count(_adc.device, 1)) {
  329. hal.console->printf("cannot set buffer count");
  330. goto error_destroy_context;
  331. }
  332. _adc.buffer = iio_device_create_buffer(_adc.device,
  333. _adc.buffer_size, false);
  334. if (!_adc.buffer) {
  335. hal.console->printf("Fail to create buffer : %s", strerror(errno));
  336. goto error_destroy_context;
  337. }
  338. return 0;
  339. error_destroy_context:
  340. iio_buffer_destroy(_adc.buffer);
  341. _adc.buffer = nullptr;
  342. iio_context_destroy(_iio);
  343. _iio = nullptr;
  344. return -1;
  345. }
  346. void AP_RangeFinder_Bebop::_init()
  347. {
  348. _spi = std::move(hal.spi->get_device("bebop"));
  349. _gpio = AP_HAL::get_HAL().gpio;
  350. if (_gpio == nullptr) {
  351. AP_HAL::panic("Could not find GPIO device for Bebop ultrasound");
  352. }
  353. if (_configure_capture() < 0) {
  354. return;
  355. }
  356. _configure_wave();
  357. return;
  358. }
  359. /*
  360. * enable the capture buffer
  361. * send a pulse over spi
  362. */
  363. int AP_RangeFinder_Bebop::_launch()
  364. {
  365. iio_device_attr_write(_adc.device, "buffer/enable", "1");
  366. _spi->transfer(_tx_buf, RNFD_BEBOP_NB_PULSES_MAX, nullptr, 0);
  367. return 0;
  368. }
  369. /*
  370. * read the iio buffer
  371. * iio_buffer_refill is blocking by default, so this function is also
  372. * blocking until samples are available
  373. * disable the capture buffer
  374. */
  375. int AP_RangeFinder_Bebop::_capture()
  376. {
  377. int ret;
  378. ret = iio_buffer_refill(_adc.buffer);
  379. iio_device_attr_write(_adc.device, "buffer/enable", "0");
  380. return ret;
  381. }
  382. int AP_RangeFinder_Bebop::_update_mode(float altitude)
  383. {
  384. switch (_mode) {
  385. case 0:
  386. if (altitude < RNFD_BEBOP_TRANSITION_HIGH_TO_LOW
  387. && !is_zero(altitude)) {
  388. if (_hysteresis_counter > RNFD_BEBOP_TRANSITION_COUNT) {
  389. _mode = 1;
  390. _hysteresis_counter = 0;
  391. _reconfigure_wave();
  392. } else {
  393. _hysteresis_counter++;
  394. }
  395. } else {
  396. _hysteresis_counter = 0;
  397. }
  398. break;
  399. default:
  400. case 1:
  401. if (altitude > RNFD_BEBOP_TRANSITION_LOW_TO_HIGH
  402. || is_zero(altitude)) {
  403. if (_hysteresis_counter > RNFD_BEBOP_TRANSITION_COUNT) {
  404. _mode = 0;
  405. _hysteresis_counter = 0;
  406. _reconfigure_wave();
  407. } else {
  408. _hysteresis_counter++;
  409. }
  410. } else {
  411. _hysteresis_counter = 0;
  412. }
  413. break;
  414. }
  415. return _mode;
  416. }
  417. #endif