From 7d30ce2e36283ae840f74382055ad6b5eea880c7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 7 Sep 2015 15:32:06 +1000 Subject: [PATCH] AP_RangeFinder: added lightware serial rangefinder --- .../AP_RangeFinder_LightWareSerial.cpp | 99 +++++++++++++++++++ .../AP_RangeFinder_LightWareSerial.h | 32 ++++++ libraries/AP_RangeFinder/RangeFinder.cpp | 13 ++- libraries/AP_RangeFinder/RangeFinder.h | 7 +- .../examples/RFIND_test/RFIND_test.cpp | 4 +- 5 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 libraries/AP_RangeFinder/AP_RangeFinder_LightWareSerial.cpp create mode 100644 libraries/AP_RangeFinder/AP_RangeFinder_LightWareSerial.h diff --git a/libraries/AP_RangeFinder/AP_RangeFinder_LightWareSerial.cpp b/libraries/AP_RangeFinder/AP_RangeFinder_LightWareSerial.cpp new file mode 100644 index 0000000000..6070833ba5 --- /dev/null +++ b/libraries/AP_RangeFinder/AP_RangeFinder_LightWareSerial.cpp @@ -0,0 +1,99 @@ +// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- +/* + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include +#include "AP_RangeFinder_LightWareSerial.h" +#include +#include + +extern const AP_HAL::HAL& hal; + +/* + The constructor also initialises the rangefinder. Note that this + constructor is not called until detect() returns true, so we + already know that we should setup the rangefinder +*/ +AP_RangeFinder_LightWareSerial::AP_RangeFinder_LightWareSerial(RangeFinder &_ranger, uint8_t instance, + RangeFinder::RangeFinder_State &_state, + AP_SerialManager &serial_manager) : + AP_RangeFinder_Backend(_ranger, instance, _state) +{ + uart = serial_manager.find_serial(AP_SerialManager::SerialProtocol_Lidar, 0); + if (uart != nullptr) { + uart->begin(serial_manager.find_baudrate(AP_SerialManager::SerialProtocol_Lidar, 0)); + } +} + +/* + detect if a Lightware rangefinder is connected. We'll detect by + trying to take a reading on Serial. If we get a result the sensor is + there. +*/ +bool AP_RangeFinder_LightWareSerial::detect(RangeFinder &_ranger, uint8_t instance, AP_SerialManager &serial_manager) +{ + return serial_manager.find_serial(AP_SerialManager::SerialProtocol_Lidar, 0) != nullptr; +} + +// read - return last value measured by sensor +bool AP_RangeFinder_LightWareSerial::get_reading(uint16_t &reading_cm) +{ + if (uart == nullptr) { + return false; + } + + // read any available lines from the lidar + float sum = 0; + uint16_t count = 0; + int16_t nbytes = uart->available(); + while (nbytes-- > 0) { + char c = uart->read(); + if (c == '\r') { + linebuf[linebuf_len] = 0; + sum += atof(linebuf); + count++; + linebuf_len = 0; + } else if (isdigit(c) || c == '.') { + linebuf[linebuf_len++] = c; + if (linebuf_len == sizeof(linebuf)) { + // too long, discard the line + linebuf_len = 0; + } + } + } + + // we need to write a byte to prompt another reading + uart->write('\n'); + + if (count == 0) { + return false; + } + reading_cm = 100 * sum / count; + return true; +} + +/* + update the state of the sensor +*/ +void AP_RangeFinder_LightWareSerial::update(void) +{ + if (get_reading(state.distance_cm)) { + // update range_valid state based on distance measured + last_reading_ms = hal.scheduler->millis(); + update_status(); + } else if (hal.scheduler->millis() - last_reading_ms > 200) { + set_status(RangeFinder::RangeFinder_NoData); + } +} diff --git a/libraries/AP_RangeFinder/AP_RangeFinder_LightWareSerial.h b/libraries/AP_RangeFinder/AP_RangeFinder_LightWareSerial.h new file mode 100644 index 0000000000..885e1357e5 --- /dev/null +++ b/libraries/AP_RangeFinder/AP_RangeFinder_LightWareSerial.h @@ -0,0 +1,32 @@ +// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- + +#ifndef __AP_RANGEFINDER_LIGHTWARESERIAL_H__ +#define __AP_RANGEFINDER_LIGHTWARESERIAL_H__ + +#include "RangeFinder.h" +#include "RangeFinder_Backend.h" + +class AP_RangeFinder_LightWareSerial : public AP_RangeFinder_Backend +{ + +public: + // constructor + AP_RangeFinder_LightWareSerial(RangeFinder &ranger, uint8_t instance, RangeFinder::RangeFinder_State &_state, + AP_SerialManager &serial_manager); + + // static detection function + static bool detect(RangeFinder &ranger, uint8_t instance, AP_SerialManager &serial_manager); + + // update state + void update(void); + +private: + // get a reading + bool get_reading(uint16_t &reading_cm); + + AP_HAL::UARTDriver *uart = nullptr; + uint32_t last_reading_ms = 0; + char linebuf[10]; + uint8_t linebuf_len = 0; +}; +#endif // __AP_RANGEFINDER_LIGHTWARESERIAL_H__ diff --git a/libraries/AP_RangeFinder/RangeFinder.cpp b/libraries/AP_RangeFinder/RangeFinder.cpp index 9c991694d1..5c0f91bd31 100644 --- a/libraries/AP_RangeFinder/RangeFinder.cpp +++ b/libraries/AP_RangeFinder/RangeFinder.cpp @@ -22,6 +22,7 @@ #include "AP_RangeFinder_PX4_PWM.h" #include "AP_RangeFinder_BBB_PRU.h" #include "AP_RangeFinder_LightWareI2C.h" +#include "AP_RangeFinder_LightWareSerial.h" // table of user settable parameters const AP_Param::GroupInfo RangeFinder::var_info[] PROGMEM = { @@ -205,10 +206,11 @@ const AP_Param::GroupInfo RangeFinder::var_info[] PROGMEM = { AP_GROUPEND }; -RangeFinder::RangeFinder(void) : +RangeFinder::RangeFinder(AP_SerialManager &_serial_manager) : primary_instance(0), num_instances(0), - estimated_terrain_height(0) + estimated_terrain_height(0), + serial_manager(_serial_manager) { AP_Param::setup_object_defaults(this, var_info); @@ -332,6 +334,13 @@ void RangeFinder::detect_instance(uint8_t instance) } } #endif + if (type == RangeFinder_TYPE_LWSER) { + if (AP_RangeFinder_LightWareSerial::detect(*this, instance, serial_manager)) { + state[instance].instance = instance; + drivers[instance] = new AP_RangeFinder_LightWareSerial(*this, instance, state[instance], serial_manager); + return; + } + } if (type == RangeFinder_TYPE_ANALOG) { // note that analog must be the last to be checked, as it will // always come back as present if the pin is valid diff --git a/libraries/AP_RangeFinder/RangeFinder.h b/libraries/AP_RangeFinder/RangeFinder.h index 9e103c1ec6..cd15e28b1d 100644 --- a/libraries/AP_RangeFinder/RangeFinder.h +++ b/libraries/AP_RangeFinder/RangeFinder.h @@ -21,6 +21,7 @@ #include #include #include +#include // Maximum number of range finder instances available on this platform #define RANGEFINDER_MAX_INSTANCES 2 @@ -35,7 +36,7 @@ class RangeFinder public: friend class AP_RangeFinder_Backend; - RangeFinder(void); + RangeFinder(AP_SerialManager &_serial_manager); // RangeFinder driver types enum RangeFinder_Type { @@ -46,7 +47,8 @@ public: RangeFinder_TYPE_PX4 = 4, RangeFinder_TYPE_PX4_PWM= 5, RangeFinder_TYPE_BBB_PRU= 6, - RangeFinder_TYPE_LWI2C = 7 + RangeFinder_TYPE_LWI2C = 7, + RangeFinder_TYPE_LWSER = 8 }; enum RangeFinder_Function { @@ -182,6 +184,7 @@ private: uint8_t primary_instance:2; uint8_t num_instances:2; float estimated_terrain_height; + AP_SerialManager &serial_manager; void detect_instance(uint8_t instance); void update_instance(uint8_t instance); diff --git a/libraries/AP_RangeFinder/examples/RFIND_test/RFIND_test.cpp b/libraries/AP_RangeFinder/examples/RFIND_test/RFIND_test.cpp index af9d3e4e83..dd2f85bd1c 100644 --- a/libraries/AP_RangeFinder/examples/RFIND_test/RFIND_test.cpp +++ b/libraries/AP_RangeFinder/examples/RFIND_test/RFIND_test.cpp @@ -34,10 +34,12 @@ #include #include #include +#include const AP_HAL::HAL& hal = AP_HAL_BOARD_DRIVER; -static RangeFinder sonar; +static AP_SerialManager serial_manager; +static RangeFinder sonar {serial_manager}; void setup() {