Line data Source code
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 : 7 : This program is distributed in the hope that it will be useful, 8 : but WITHOUT ANY WARRANTY; without even the implied warranty of 9 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 : GNU General Public License for more details. 11 : 12 : You should have received a copy of the GNU General Public License 13 : along with this program. If not, see <http://www.gnu.org/licenses/>. 14 : */ 15 : 16 : /* 17 : * AP_RangeFinder_HC_SR04.cpp - rangefinder for HC_SR04 source 18 : * 19 : * https://cdn.sparkfun.com/datasheets/Sensors/Proximity/HCSR04.pdf 20 : * 21 : * There are two pins involved - one we attach an interrupt handler 22 : * to and use for measuring the supplied interval which is 23 : * proportional to distance. 24 : * 25 : * The second pin we use for triggering the ultransonic pulse 26 : */ 27 : 28 : #include "AP_RangeFinder_HC_SR04.h" 29 : 30 : #if AP_RANGEFINDER_HC_SR04_ENABLED 31 : 32 : #include <AP_HAL/AP_HAL.h> 33 : #include "AP_RangeFinder.h" 34 : #include "AP_RangeFinder_Params.h" 35 : 36 : #include <GCS_MAVLink/GCS.h> 37 : 38 : extern const AP_HAL::HAL& hal; 39 : 40 0 : AP_RangeFinder_HC_SR04::AP_RangeFinder_HC_SR04(RangeFinder::RangeFinder_State &_state, AP_RangeFinder_Params &_params) : 41 0 : AP_RangeFinder_Backend(_state, _params) 42 : { 43 0 : set_status(RangeFinder::Status::NoData); 44 0 : } 45 : 46 0 : bool AP_RangeFinder_HC_SR04::check_pins() 47 : { 48 0 : check_trigger_pin(); 49 0 : return check_echo_pin() && trigger_pin > 0; 50 : } 51 : 52 0 : void AP_RangeFinder_HC_SR04::check_trigger_pin() 53 : { 54 0 : if (params.stop_pin == trigger_pin) { 55 : // no change 56 0 : return; 57 : } 58 0 : trigger_pin = params.stop_pin; 59 : } 60 : 61 0 : bool AP_RangeFinder_HC_SR04::check_echo_pin() 62 : { 63 0 : return pwm_source.set_pin(params.pin, "HC_SR04"); 64 : } 65 : 66 : 67 : 68 : /* 69 : detect if an HC_SR04 rangefinder is connected. The only thing we 70 : can do is check if the pin number is valid. If it is, then assume 71 : that the device is connected 72 : */ 73 0 : bool AP_RangeFinder_HC_SR04::detect(AP_RangeFinder_Params &_params) 74 : { 75 0 : if (_params.pin == -1) { 76 0 : return false; 77 : } 78 0 : if (_params.stop_pin == -1) { 79 0 : return false; 80 : } 81 0 : return true; 82 : } 83 : 84 : 85 : /* 86 : update distance_cm 87 : */ 88 0 : void AP_RangeFinder_HC_SR04::update(void) 89 : { 90 : // check if pin has changed and configure interrupt handlers if required: 91 0 : if (!check_pins()) { 92 : // disabled (either by configuration or failure to attach interrupt) 93 0 : state.distance_m = 0.0f; 94 0 : return; 95 : } 96 : 97 0 : const uint32_t value_us = pwm_source.get_pwm_us(); 98 : 99 0 : const uint32_t now = AP_HAL::millis(); 100 0 : if (value_us == 0) { 101 : // no reading; check for timeout: 102 0 : if (now - state.last_reading_ms > 1000) { 103 : // no reading for a second - something is broken 104 0 : state.distance_m = 0.0f; 105 : } 106 : } else { 107 : // GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "Pong!"); 108 : // a new reading - convert time to distance 109 0 : state.distance_m = (value_us * (1.0/58.0f)) * 0.01f; // 58 is from datasheet, mult for performance 110 : 111 : // glitch remover: measurement is greater than .5m from last. 112 : // the SR-04 seeems to suffer from single-measurement glitches 113 : // which can be removed by a simple filter. 114 0 : if (fabsf(state.distance_m - last_distance_m) > 0.5f) { 115 : // if greater for 5 readings then pass it as new height, 116 : // otherwise use last reading 117 0 : if (glitch_count++ > 4) { 118 0 : last_distance_m = state.distance_m; 119 : } else { 120 0 : state.distance_m = last_distance_m; 121 : } 122 : } else { 123 : // is not greater 0.5m, pass on and reset glitch counter 124 0 : last_distance_m = state.distance_m; 125 0 : glitch_count = 0; 126 : } 127 : 128 0 : state.last_reading_ms = now; 129 : } 130 : 131 : // update range_valid state based on distance measured 132 0 : update_status(); 133 : 134 : // consider sending new ping 135 0 : if (now - last_ping_ms > 67) { // read ~@15Hz - recommended 60ms delay from datasheet 136 0 : last_ping_ms = now; 137 : // GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Ping!"); 138 : // raise stop pin for n-microseconds 139 0 : hal.gpio->pinMode(trigger_pin, HAL_GPIO_OUTPUT); 140 0 : hal.gpio->write(trigger_pin, 1); 141 0 : hal.scheduler->delay_microseconds(10); 142 0 : hal.gpio->write(trigger_pin, 0); 143 : } 144 : } 145 : 146 : #endif // AP_RANGEFINDER_HC_SR04_ENABLED