AP_RangeFinder_Benewake_TFMiniPlus.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * Copyright (C) 2019 Lucas De Marchi <lucas.de.marchi@gmail.com>
  3. *
  4. * This file is free software: you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the
  6. * Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This file is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. * See the GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "AP_RangeFinder_Benewake_TFMiniPlus.h"
  18. #include <utility>
  19. #include <AP_HAL/AP_HAL.h>
  20. extern const AP_HAL::HAL& hal;
  21. #define DRIVER "TFMiniPlus"
  22. /*
  23. * Command format:
  24. *
  25. * uint8_t header;
  26. * uint8_t len;
  27. * uint8_t id;
  28. * uint8_t data[];
  29. * uint8_t checksum;
  30. */
  31. AP_RangeFinder_Benewake_TFMiniPlus::AP_RangeFinder_Benewake_TFMiniPlus(
  32. RangeFinder::RangeFinder_State &_state,
  33. AP_RangeFinder_Params &_params,
  34. AP_HAL::OwnPtr<AP_HAL::I2CDevice> dev)
  35. : AP_RangeFinder_Backend(_state, _params)
  36. , _dev(std::move(dev))
  37. {
  38. }
  39. AP_RangeFinder_Backend *AP_RangeFinder_Benewake_TFMiniPlus::detect(
  40. RangeFinder::RangeFinder_State &_state, AP_RangeFinder_Params &_params,
  41. AP_HAL::OwnPtr<AP_HAL::I2CDevice> dev)
  42. {
  43. if (!dev) {
  44. return nullptr;
  45. }
  46. AP_RangeFinder_Benewake_TFMiniPlus *sensor
  47. = new AP_RangeFinder_Benewake_TFMiniPlus(_state, _params, std::move(dev));
  48. if (!sensor || !sensor->init()) {
  49. delete sensor;
  50. return nullptr;
  51. }
  52. return sensor;
  53. }
  54. bool AP_RangeFinder_Benewake_TFMiniPlus::init()
  55. {
  56. const uint8_t CMD_FW_VERSION[] = { 0x5A, 0x04, 0x01, 0x5F };
  57. const uint8_t CMD_SYSTEM_RESET[] = { 0x5A, 0x04, 0x04, 0x62 };
  58. const uint8_t CMD_OUTPUT_FORMAT_CM[] = { 0x5A, 0x05, 0x05, 0x01, 0x65 };
  59. const uint8_t CMD_ENABLE_DATA_OUTPUT[] = { 0x5A, 0x05, 0x07, 0x01, 0x67 };
  60. const uint8_t CMD_FRAME_RATE_100HZ[] = { 0x5A, 0x06, 0x03, 0x64, 0x00, 0xC7 };
  61. const uint8_t CMD_SAVE_SETTINGS[] = { 0x5A, 0x04, 0x11, 0x6F };
  62. const uint8_t *cmds[] = {
  63. CMD_OUTPUT_FORMAT_CM,
  64. CMD_FRAME_RATE_100HZ,
  65. CMD_ENABLE_DATA_OUTPUT,
  66. CMD_SAVE_SETTINGS,
  67. };
  68. uint8_t val[12], i;
  69. bool ret;
  70. _dev->get_semaphore()->take_blocking();
  71. _dev->set_retries(0);
  72. /*
  73. * Check we get a response for firmware version to detect if sensor is there
  74. */
  75. ret = _dev->transfer(CMD_FW_VERSION, sizeof(CMD_FW_VERSION), nullptr, 0);
  76. if (!ret) {
  77. goto fail;
  78. }
  79. hal.scheduler->delay(100);
  80. ret = _dev->transfer(nullptr, 0, val, 7);
  81. if (!ret || val[0] != 0x5A || val[1] != 0x07 || val[2] != 0x01 ||
  82. !check_checksum(val, 7)) {
  83. goto fail;
  84. }
  85. if (val[5] * 10000 + val[4] * 100 + val[3] < 10706) {
  86. hal.console->printf(DRIVER ": minimum required FW version 1.7.6, but version %u.%u.%u found\n",
  87. val[5], val[4], val[3]);
  88. goto fail;
  89. }
  90. hal.console->printf(DRIVER ": found fw version %u.%u.%u\n",
  91. val[5], val[4], val[3]);
  92. for (i = 0; i < ARRAY_SIZE(cmds); i++) {
  93. ret = _dev->transfer(cmds[i], cmds[i][1], nullptr, 0);
  94. if (!ret) {
  95. hal.console->printf(DRIVER ": Unable to set configuration register %u\n",
  96. cmds[i][2]);
  97. goto fail;
  98. }
  99. hal.scheduler->delay(100);
  100. }
  101. _dev->transfer(CMD_SYSTEM_RESET, sizeof(CMD_SYSTEM_RESET), nullptr, 0);
  102. _dev->get_semaphore()->give();
  103. hal.scheduler->delay(100);
  104. _dev->register_periodic_callback(10000,
  105. FUNCTOR_BIND_MEMBER(&AP_RangeFinder_Benewake_TFMiniPlus::timer, void));
  106. return true;
  107. fail:
  108. _dev->get_semaphore()->give();
  109. return false;
  110. }
  111. void AP_RangeFinder_Benewake_TFMiniPlus::update()
  112. {
  113. WITH_SEMAPHORE(_sem);
  114. if (accum.count > 0) {
  115. state.distance_cm = accum.sum / accum.count;
  116. state.last_reading_ms = AP_HAL::millis();
  117. accum.sum = 0;
  118. accum.count = 0;
  119. update_status();
  120. } else if (AP_HAL::millis() - state.last_reading_ms > 200) {
  121. set_status(RangeFinder::RangeFinder_NoData);
  122. }
  123. }
  124. bool AP_RangeFinder_Benewake_TFMiniPlus::process_raw_measure(le16_t distance_raw, le16_t strength_raw,
  125. uint16_t &output_distance_cm)
  126. {
  127. uint16_t strength = le16toh(strength_raw);
  128. output_distance_cm = le16toh(distance_raw);
  129. if (strength < 100 || strength == 0xFFFF) {
  130. return false;
  131. }
  132. output_distance_cm = constrain_int16(output_distance_cm, 10, 1200);
  133. return true;
  134. }
  135. bool AP_RangeFinder_Benewake_TFMiniPlus::check_checksum(uint8_t *arr, int pkt_len)
  136. {
  137. uint8_t checksum = 0;
  138. int i;
  139. /* sum them all except the last (the checksum) */
  140. for (i = 0; i < pkt_len - 1; i++) {
  141. checksum += arr[i];
  142. }
  143. return checksum == arr[pkt_len - 1];
  144. }
  145. void AP_RangeFinder_Benewake_TFMiniPlus::timer()
  146. {
  147. uint8_t CMD_READ_MEASUREMENT[] = { 0x5A, 0x05, 0x00, 0x07, 0x66 };
  148. union {
  149. struct PACKED {
  150. uint8_t header1;
  151. uint8_t header2;
  152. le16_t distance;
  153. le16_t strength;
  154. le32_t timestamp;
  155. uint8_t checksum;
  156. } val;
  157. uint8_t arr[11];
  158. } u;
  159. bool ret;
  160. uint16_t distance;
  161. ret = _dev->transfer(CMD_READ_MEASUREMENT, sizeof(CMD_READ_MEASUREMENT), nullptr, 0);
  162. if (!ret || !_dev->transfer(nullptr, 0, (uint8_t *)&u, sizeof(u))) {
  163. return;
  164. }
  165. if (u.val.header1 != 0x59 || u.val.header2 != 0x59 || !check_checksum(u.arr, sizeof(u)))
  166. return;
  167. if (process_raw_measure(u.val.distance, u.val.strength, distance)) {
  168. WITH_SEMAPHORE(_sem);
  169. accum.sum += distance;
  170. accum.count++;
  171. }
  172. }