2013-02-28 20:19:02 -04:00
// -*- tab-width: 4; Mode: C++; c-basic-offset: 3; indent-tabs-mode: t -*-
/*
* AP_RangeFinder_analog . cpp - rangefinder for analog source
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
*/
# include <AP_HAL.h>
# include "AP_RangeFinder_analog.h"
extern const AP_HAL : : HAL & hal ;
2013-05-02 21:09:54 -03:00
# define SONAR_DEFAULT_PIN 0
2013-02-28 20:19:02 -04:00
// table of user settable parameters
const AP_Param : : GroupInfo AP_RangeFinder_analog : : var_info [ ] PROGMEM = {
// @Param: PIN
// @DisplayName: Sonar pin
2013-05-02 21:09:54 -03:00
// @Description: Analog pin that sonar is connected to.
2013-02-28 20:19:02 -04:00
AP_GROUPINFO ( " PIN " , 0 , AP_RangeFinder_analog , _pin , SONAR_DEFAULT_PIN ) ,
// @Param: SCALING
// @DisplayName: Sonar scaling
// @Description: Scaling factor between sonar reading and distance. For the linear and inverted functions this is in meters per volt. For the hyperbolic function the units are meterVolts.
// @Units: meters/Volt
// @Increment: 0.001
AP_GROUPINFO ( " SCALING " , 1 , AP_RangeFinder_analog , _scaling , 3.0 ) ,
// @Param: OFFSET
// @DisplayName: Sonar offset
// @Description: Offset in volts for zero distance
// @Units: Volts
// @Increment: 0.001
AP_GROUPINFO ( " OFFSET " , 2 , AP_RangeFinder_analog , _offset , 0.0 ) ,
// @Param: FUNCTION
// @DisplayName: Sonar function
2013-03-07 17:27:18 -04:00
// @Description: Control over what function is used to calculate distance. For a linear function, the distance is (voltage-offset)*scaling. For a inverted function the distance is (offset-voltage)*scaling. For a hyperbolic function the distance is scaling/(voltage-offset). The functions return the distance in meters.
2013-02-28 20:19:02 -04:00
// @Values: 0:Linear,1:Inverted,2:Hyperbolic
AP_GROUPINFO ( " FUNCTION " , 3 , AP_RangeFinder_analog , _function , 0 ) ,
// @Param: MIN_CM
// @DisplayName: Sonar minimum distance
// @Description: minimum distance in centimeters that sonar can reliably read
// @Units: centimeters
// @Increment: 1
AP_GROUPINFO ( " MIN_CM " , 4 , AP_RangeFinder_analog , _min_distance_cm , 20 ) ,
// @Param: MAX_CM
// @DisplayName: Sonar maximum distance
// @Description: maximum distance in centimeters that sonar can reliably read
// @Units: centimeters
// @Increment: 1
AP_GROUPINFO ( " MAX_CM " , 5 , AP_RangeFinder_analog , _max_distance_cm , 700 ) ,
2013-03-21 17:52:51 -03:00
// @Param: ENABLE
// @DisplayName: Sonar enabled
// @Description: set to 1 to enable this sonar
// @Values: 0:Disabled,1:Enabled
AP_GROUPINFO ( " ENABLE " , 6 , AP_RangeFinder_analog , _enabled , 0 ) ,
2013-04-26 01:53:15 -03:00
// @Param: STOP_PIN
// @DisplayName: Sonar stop pin
// @Description: Digital pin that enables/disables sonar measurement. A value of -1 means no pin. If this is set, then the pin is set to 1 to enable the sonar and set to 0 to disable it. This can be used to ensure that multiple sonars don't interfere with each other.
AP_GROUPINFO ( " STOP_PIN " , 7 , AP_RangeFinder_analog , _stop_pin , - 1 ) ,
// @Param: SETTLE_MS
// @DisplayName: Sonar settle time
// @Description: The time in milliseconds that the sonar reading takes to settle. This is only used when a STOP_PIN is specified. It determines how long we have to wait for the sonar to give a reading after we set the STOP_PIN high. For a sonar with a range of around 7m this would need to be around 50 milliseconds to allow for the sonar pulse to travel to the target and back again.
2013-05-08 01:21:19 -03:00
// @Units: milliseconds
// @Increment: 1
2013-04-26 01:53:15 -03:00
AP_GROUPINFO ( " SETTLE_MS " , 8 , AP_RangeFinder_analog , _settle_time_ms , 0 ) ,
2013-02-28 20:19:02 -04:00
AP_GROUPEND
} ;
// Constructor
AP_RangeFinder_analog : : AP_RangeFinder_analog ( void )
{
AP_Param : : setup_object_defaults ( this , var_info ) ;
}
/* Initialisation:
we pass the analog source in at Init ( ) time rather than in the
constructor as otherwise the object could not have parameters , as
only static objects can have parameters , but the analog sources in
AP_HAL are allocated at runtime
*/
void AP_RangeFinder_analog : : Init ( void * adc )
{
2013-03-21 17:52:51 -03:00
if ( ! _enabled ) {
return ;
}
2013-02-28 20:19:02 -04:00
if ( _source ! = NULL ) {
return ;
}
_source = hal . analogin - > channel ( _pin ) ;
2013-04-26 01:53:15 -03:00
_source - > set_stop_pin ( ( uint8_t ) _stop_pin ) ;
_source - > set_settle_time ( ( uint16_t ) _settle_time_ms ) ;
2013-02-28 20:19:02 -04:00
}
/*
return raw voltage
*/
float AP_RangeFinder_analog : : voltage ( void )
{
2013-03-21 17:52:51 -03:00
if ( ! _enabled ) {
return 0.0f ;
}
2013-02-28 20:19:02 -04:00
if ( _source = = NULL ) {
2013-03-21 17:52:51 -03:00
return 0.0f ;
2013-02-28 20:19:02 -04:00
}
2013-04-26 01:53:15 -03:00
// cope with changed settings
_source - > set_pin ( _pin ) ;
_source - > set_stop_pin ( ( uint8_t ) _stop_pin ) ;
_source - > set_settle_time ( ( uint16_t ) _settle_time_ms ) ;
2013-03-07 17:27:18 -04:00
return _source - > voltage_average ( ) ;
2013-02-28 20:19:02 -04:00
}
/*
return distance in centimeters
*/
float AP_RangeFinder_analog : : distance_cm ( void )
{
2013-03-21 17:52:51 -03:00
if ( ! _enabled ) {
return 0.0f ;
}
2013-02-28 20:19:02 -04:00
/* first convert to volts */
float v = voltage ( ) ;
float dist_m = 0 ;
switch ( ( AP_RangeFinder_analog : : RangeFinder_Function ) _function . get ( ) ) {
case FUNCTION_LINEAR :
dist_m = ( v - _offset ) * _scaling ;
break ;
case FUNCTION_INVERTED :
2013-03-07 17:27:18 -04:00
dist_m = ( _offset - v ) * _scaling ;
2013-02-28 20:19:02 -04:00
break ;
case FUNCTION_HYPERBOLA :
if ( v < = _offset ) {
dist_m = 0 ;
}
dist_m = _scaling / ( v - _offset ) ;
if ( isinf ( dist_m ) | | dist_m > _max_distance_cm ) {
dist_m = _max_distance_cm * 0.01 ;
}
break ;
}
if ( dist_m < 0 ) {
dist_m = 0 ;
}
2013-04-17 08:33:08 -03:00
return dist_m * 100.0f ;
2013-02-28 20:19:02 -04:00
}
/*
return true if we are in the configured range of the device
*/
bool AP_RangeFinder_analog : : in_range ( void )
{
2013-03-21 17:52:51 -03:00
if ( ! _enabled ) {
return false ;
}
2013-02-28 20:19:02 -04:00
float dist_cm = distance_cm ( ) ;
if ( dist_cm > = _max_distance_cm ) {
return false ;
}
if ( dist_cm < = _min_distance_cm ) {
return false ;
}
return true ;
}