2011-04-30 05:29:28 -03:00
/*
AP_OpticalFlow_ADNS3080 . cpp - ADNS3080 OpticalFlow Library for Ardupilot Mega
Code by Randy Mackay . DIYDrones . com
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 .
External ADNS3080 OpticalFlow is connected via Serial port 2 ( in SPI mode )
TXD2 = MOSI = pin PH1
RXD2 = MISO = pin PH0
XCK2 = SCK = pin PH2
Chip Select pin is PC4 ( 33 ) [ PH6 ( 9 ) ]
We are using the 16 clocks per conversion timming to increase efficiency ( fast )
The sampling frequency is 400 Hz ( Timer2 overflow interrupt )
So if our loop is at 50 Hz , our needed sampling freq should be 100 Hz , so
we have an 4 x oversampling and averaging .
Methods :
Init ( ) : Initialization of interrupts an Timers ( Timer2 overflow interrupt )
Read ( ) : Read latest values from OpticalFlow and store to x , y , surface_quality parameters
*/
# include "AP_OpticalFlow_ADNS3080.h"
2011-05-11 09:49:19 -03:00
# include "WProgram.h"
2011-04-30 05:29:28 -03:00
# include "../SPI/SPI.h"
# define AP_SPI_TIMEOUT 1000
union NumericIntType
{
int intValue ;
unsigned int uintValue ;
2011-09-16 23:24:57 -03:00
byte byteValue [ 2 ] ;
2011-04-30 05:29:28 -03:00
} ;
2011-09-16 23:24:57 -03:00
// Constructors ////////////////////////////////////////////////////////////////
2011-04-30 05:29:28 -03:00
AP_OpticalFlow_ADNS3080 : : AP_OpticalFlow_ADNS3080 ( )
{
2011-09-16 23:24:57 -03:00
num_pixels = ADNS3080_PIXELS_X ;
field_of_view = AP_OPTICALFLOW_ADNS3080_08_FOV ;
2011-05-11 09:49:19 -03:00
scaler = AP_OPTICALFLOW_ADNS3080_SCALER ;
2011-04-30 05:29:28 -03:00
}
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// Public Methods //////////////////////////////////////////////////////////////
// init - initialise sensor
// initCommAPI parameter controls whether SPI interface is initialised (set to false if other devices are on the SPI bus and have already initialised the interface)
2011-05-11 09:49:19 -03:00
bool
AP_OpticalFlow_ADNS3080 : : init ( bool initCommAPI )
2011-04-30 05:29:28 -03:00
{
2011-07-31 01:31:36 -03:00
int retry = 0 ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
pinMode ( AP_SPI_DATAOUT , OUTPUT ) ;
pinMode ( AP_SPI_DATAIN , INPUT ) ;
pinMode ( AP_SPI_CLOCK , OUTPUT ) ;
pinMode ( ADNS3080_CHIP_SELECT , OUTPUT ) ;
pinMode ( ADNS3080_RESET , OUTPUT ) ;
digitalWrite ( ADNS3080_CHIP_SELECT , HIGH ) ; // disable device (Chip select is active low)
// reset the device
reset ( ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// start the SPI library:
if ( initCommAPI ) {
SPI . begin ( ) ;
}
2011-09-16 23:24:57 -03:00
2011-07-31 01:31:36 -03:00
// check the sensor is functioning
if ( retry < 3 ) {
if ( read_register ( ADNS3080_PRODUCT_ID ) = = 0x17 )
return true ;
else
retry + + ;
} else
return false ;
2011-04-30 05:29:28 -03:00
}
//
// backup_spi_settings - checks current SPI settings (clock speed, etc), sets values to what we need
//
2011-05-11 09:49:19 -03:00
byte
AP_OpticalFlow_ADNS3080 : : backup_spi_settings ( )
2011-09-16 23:24:57 -03:00
{
2011-04-30 05:29:28 -03:00
// store current spi values
orig_spi_settings_spcr = SPCR & ( DORD | CPOL | CPHA ) ;
orig_spi_settings_spsr = SPSR & SPI2X ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// set the values that we need
SPI . setBitOrder ( MSBFIRST ) ;
SPI . setDataMode ( SPI_MODE3 ) ;
2011-09-16 23:24:57 -03:00
SPI . setClockDivider ( SPI_CLOCK_DIV8 ) ; // sensor running at 2Mhz. this is it's maximum speed
2011-04-30 05:29:28 -03:00
return orig_spi_settings_spcr ;
}
// restore_spi_settings - restores SPI settings (clock speed, etc) to what their values were before the sensor used the bus
2011-05-11 09:49:19 -03:00
byte
AP_OpticalFlow_ADNS3080 : : restore_spi_settings ( )
2011-04-30 05:29:28 -03:00
{
byte temp ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// restore SPSR
temp = SPSR ;
temp & = ~ SPI2X ;
temp | = orig_spi_settings_spsr ;
SPSR = temp ;
// restore SPCR
temp = SPCR ;
temp & = ~ ( DORD | CPOL | CPHA ) ; // zero out the important bits
temp | = orig_spi_settings_spcr ; // restore important bits
SPCR = temp ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
return temp ;
}
// Read a register from the sensor
2011-05-11 09:49:19 -03:00
byte
2011-09-16 23:24:57 -03:00
AP_OpticalFlow_ADNS3080 : : read_register ( byte address )
2011-04-30 05:29:28 -03:00
{
byte result = 0 , junk = 0 ;
backup_spi_settings ( ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// take the chip select low to select the device
digitalWrite ( ADNS3080_CHIP_SELECT , LOW ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// send the device the register you want to read:
junk = SPI . transfer ( address ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// small delay
delayMicroseconds ( 50 ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// send a value of 0 to read the first byte returned:
result = SPI . transfer ( 0x00 ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// take the chip select high to de-select:
digitalWrite ( ADNS3080_CHIP_SELECT , HIGH ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
restore_spi_settings ( ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
return result ;
}
// write a value to one of the sensor's registers
2011-05-11 09:49:19 -03:00
void
AP_OpticalFlow_ADNS3080 : : write_register ( byte address , byte value )
2011-04-30 05:29:28 -03:00
{
byte junk = 0 ;
2011-09-16 23:24:57 -03:00
backup_spi_settings ( ) ;
2011-04-30 05:29:28 -03:00
// take the chip select low to select the device
digitalWrite ( ADNS3080_CHIP_SELECT , LOW ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// send register address
junk = SPI . transfer ( address | 0x80 ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// small delay
2011-09-16 23:24:57 -03:00
delayMicroseconds ( 50 ) ;
2011-04-30 05:29:28 -03:00
// send data
junk = SPI . transfer ( value ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// take the chip select high to de-select:
digitalWrite ( ADNS3080_CHIP_SELECT , HIGH ) ;
2011-09-16 23:24:57 -03:00
restore_spi_settings ( ) ;
2011-04-30 05:29:28 -03:00
}
// reset sensor by holding a pin high (or is it low?) for 10us.
2011-05-11 09:49:19 -03:00
void
AP_OpticalFlow_ADNS3080 : : reset ( )
2011-04-30 05:29:28 -03:00
{
digitalWrite ( ADNS3080_RESET , HIGH ) ; // reset sensor
delayMicroseconds ( 10 ) ;
digitalWrite ( ADNS3080_RESET , LOW ) ; // return sensor to normal
}
// read latest values from sensor and fill in x,y and totals
2011-05-11 09:49:19 -03:00
int
AP_OpticalFlow_ADNS3080 : : read ( )
2011-04-30 05:29:28 -03:00
{
surface_quality = ( unsigned int ) read_register ( ADNS3080_SQUAL ) ;
delayMicroseconds ( 50 ) ; // small delay
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// check for movement, update x,y values
if ( ( read_register ( ADNS3080_MOTION ) & 0x80 ) ! = 0 ) {
2011-05-11 09:49:19 -03:00
raw_dx = ( ( char ) read_register ( ADNS3080_DELTA_X ) ) ;
2011-04-30 05:29:28 -03:00
delayMicroseconds ( 50 ) ; // small delay
2011-05-11 09:49:19 -03:00
raw_dy = ( ( char ) read_register ( ADNS3080_DELTA_Y ) ) ;
2011-04-30 05:29:28 -03:00
_motion = true ;
} else {
2011-05-11 09:49:19 -03:00
raw_dx = 0 ;
raw_dy = 0 ;
2011-04-30 05:29:28 -03:00
}
2011-09-16 23:24:57 -03:00
2011-05-11 09:49:19 -03:00
last_update = millis ( ) ;
2011-09-16 23:24:57 -03:00
2011-05-11 09:49:19 -03:00
apply_orientation_matrix ( ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
return OPTICALFLOW_SUCCESS ;
}
// get_led_always_on - returns true if LED is always on, false if only on when required
2011-05-11 09:49:19 -03:00
bool
AP_OpticalFlow_ADNS3080 : : get_led_always_on ( )
2011-04-30 05:29:28 -03:00
{
return ( ( read_register ( ADNS3080_CONFIGURATION_BITS ) & 0x40 ) > 0 ) ;
}
// set_led_always_on - set parameter to true if you want LED always on, otherwise false for only when required
2011-05-11 09:49:19 -03:00
void
AP_OpticalFlow_ADNS3080 : : set_led_always_on ( bool alwaysOn )
2011-04-30 05:29:28 -03:00
{
byte regVal = read_register ( ADNS3080_CONFIGURATION_BITS ) ;
regVal = regVal & 0xBf | ( alwaysOn < < 6 ) ;
delayMicroseconds ( 50 ) ; // small delay
write_register ( ADNS3080_CONFIGURATION_BITS , regVal ) ;
}
// returns resolution (either 400 or 1200 counts per inch)
2011-05-11 09:49:19 -03:00
int
AP_OpticalFlow_ADNS3080 : : get_resolution ( )
2011-04-30 05:29:28 -03:00
{
if ( ( read_register ( ADNS3080_CONFIGURATION_BITS ) & 0x10 ) = = 0 )
return 400 ;
else
return 1200 ;
}
// set parameter to 400 or 1200 counts per inch
2011-05-11 09:49:19 -03:00
void
AP_OpticalFlow_ADNS3080 : : set_resolution ( int resolution )
2011-04-30 05:29:28 -03:00
{
byte regVal = read_register ( ADNS3080_CONFIGURATION_BITS ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
if ( resolution = = ADNS3080_RESOLUTION_400 ) {
regVal & = ~ 0x10 ;
2011-09-16 23:24:57 -03:00
} else if ( resolution = = ADNS3080_RESOLUTION_1200 ) {
2011-04-30 05:29:28 -03:00
regVal | = 0x10 ;
}
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
delayMicroseconds ( 50 ) ; // small delay
write_register ( ADNS3080_CONFIGURATION_BITS , regVal ) ;
}
// get_frame_rate_auto - return whether frame rate is set to "auto" or manual
2011-05-11 09:49:19 -03:00
bool
AP_OpticalFlow_ADNS3080 : : get_frame_rate_auto ( )
2011-04-30 05:29:28 -03:00
{
byte regVal = read_register ( ADNS3080_EXTENDED_CONFIG ) ;
if ( regVal & 0x01 > 0 ) {
return false ;
} else {
return true ;
}
}
// set_frame_rate_auto - set frame rate to auto (true) or manual (false)
2011-05-11 09:49:19 -03:00
void
AP_OpticalFlow_ADNS3080 : : set_frame_rate_auto ( bool auto_frame_rate )
2011-04-30 05:29:28 -03:00
{
byte regVal = read_register ( ADNS3080_EXTENDED_CONFIG ) ;
delayMicroseconds ( 50 ) ; // small delay
if ( auto_frame_rate = = true ) {
// set specific frame period
write_register ( ADNS3080_FRAME_PERIOD_MAX_BOUND_LOWER , 0xE0 ) ;
delayMicroseconds ( 50 ) ; // small delay
write_register ( ADNS3080_FRAME_PERIOD_MAX_BOUND_UPPER , 0x1A ) ;
delayMicroseconds ( 50 ) ; // small delay
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// decide what value to update in extended config
regVal = ( regVal & ~ 0x01 ) ;
} else {
// decide what value to update in extended config
regVal = ( regVal & ~ 0x01 ) | 0x01 ;
}
write_register ( ADNS3080_EXTENDED_CONFIG , regVal ) ;
}
// get frame period
2011-05-11 09:49:19 -03:00
unsigned int
AP_OpticalFlow_ADNS3080 : : get_frame_period ( )
2011-04-30 05:29:28 -03:00
{
2011-09-16 23:24:57 -03:00
NumericIntType aNum ;
2011-04-30 05:29:28 -03:00
aNum . byteValue [ 1 ] = read_register ( ADNS3080_FRAME_PERIOD_UPPER ) ;
delayMicroseconds ( 50 ) ; // small delay
aNum . byteValue [ 0 ] = read_register ( ADNS3080_FRAME_PERIOD_LOWER ) ;
return aNum . uintValue ;
}
// set frame period
2011-05-11 09:49:19 -03:00
void
AP_OpticalFlow_ADNS3080 : : set_frame_period ( unsigned int period )
2011-04-30 05:29:28 -03:00
{
NumericIntType aNum ;
aNum . uintValue = period ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// set frame rate to manual
set_frame_rate_auto ( false ) ;
delayMicroseconds ( 50 ) ; // small delay
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// set specific frame period
write_register ( ADNS3080_FRAME_PERIOD_MAX_BOUND_LOWER , aNum . byteValue [ 0 ] ) ;
delayMicroseconds ( 50 ) ; // small delay
write_register ( ADNS3080_FRAME_PERIOD_MAX_BOUND_UPPER , aNum . byteValue [ 1 ] ) ;
}
2011-05-11 09:49:19 -03:00
unsigned int
AP_OpticalFlow_ADNS3080 : : get_frame_rate ( )
2011-04-30 05:29:28 -03:00
{
unsigned long clockSpeed = ADNS3080_CLOCK_SPEED ;
unsigned int rate = clockSpeed / get_frame_period ( ) ;
return rate ;
}
2011-05-11 09:49:19 -03:00
void
AP_OpticalFlow_ADNS3080 : : set_frame_rate ( unsigned int rate )
2011-04-30 05:29:28 -03:00
{
unsigned long clockSpeed = ADNS3080_CLOCK_SPEED ;
unsigned int period = ( unsigned int ) ( clockSpeed / ( unsigned long ) rate ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
set_frame_period ( period ) ;
}
// get_shutter_speed_auto - returns true if shutter speed is adjusted automatically, false if manual
2011-05-11 09:49:19 -03:00
bool
AP_OpticalFlow_ADNS3080 : : get_shutter_speed_auto ( )
2011-04-30 05:29:28 -03:00
{
byte regVal = read_register ( ADNS3080_EXTENDED_CONFIG ) ;
if ( ( regVal & 0x02 ) > 0 ) {
return false ;
} else {
return true ;
}
}
// set_shutter_speed_auto - set shutter speed to auto (true), or manual (false)
2011-05-11 09:49:19 -03:00
void
AP_OpticalFlow_ADNS3080 : : set_shutter_speed_auto ( bool auto_shutter_speed )
2011-04-30 05:29:28 -03:00
{
byte regVal = read_register ( ADNS3080_EXTENDED_CONFIG ) ;
delayMicroseconds ( 50 ) ; // small delay
if ( auto_shutter_speed ) {
// return shutter speed max to default
2011-09-16 23:24:57 -03:00
write_register ( ADNS3080_SHUTTER_MAX_BOUND_LOWER , 0x8c ) ;
delayMicroseconds ( 50 ) ; // small delay
2011-04-30 05:29:28 -03:00
write_register ( ADNS3080_SHUTTER_MAX_BOUND_UPPER , 0x20 ) ;
2011-09-16 23:24:57 -03:00
delayMicroseconds ( 50 ) ; // small delay
2011-04-30 05:29:28 -03:00
// determine value to put into extended config
regVal = regVal & ~ 0x02 ;
} else {
// determine value to put into extended config
regVal = regVal & ~ 0x02 | 0x02 ;
}
write_register ( ADNS3080_EXTENDED_CONFIG , regVal ) ;
2011-09-16 23:24:57 -03:00
delayMicroseconds ( 50 ) ; // small delay
2011-04-30 05:29:28 -03:00
}
// get_shutter_speed_auto - returns true if shutter speed is adjusted automatically, false if manual
2011-05-11 09:49:19 -03:00
unsigned int
AP_OpticalFlow_ADNS3080 : : get_shutter_speed ( )
2011-04-30 05:29:28 -03:00
{
2011-09-16 23:24:57 -03:00
NumericIntType aNum ;
2011-04-30 05:29:28 -03:00
aNum . byteValue [ 1 ] = read_register ( ADNS3080_SHUTTER_UPPER ) ;
delayMicroseconds ( 50 ) ; // small delay
aNum . byteValue [ 0 ] = read_register ( ADNS3080_SHUTTER_LOWER ) ;
return aNum . uintValue ;
}
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// set_shutter_speed_auto - set shutter speed to auto (true), or manual (false)
2011-05-11 09:49:19 -03:00
unsigned int
AP_OpticalFlow_ADNS3080 : : set_shutter_speed ( unsigned int shutter_speed )
2011-04-30 05:29:28 -03:00
{
NumericIntType aNum ;
aNum . uintValue = shutter_speed ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// set shutter speed to manual
set_shutter_speed_auto ( false ) ;
delayMicroseconds ( 50 ) ; // small delay
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// set specific shutter speed
2011-09-16 23:24:57 -03:00
write_register ( ADNS3080_SHUTTER_MAX_BOUND_LOWER , aNum . byteValue [ 0 ] ) ;
delayMicroseconds ( 50 ) ; // small delay
2011-04-30 05:29:28 -03:00
write_register ( ADNS3080_SHUTTER_MAX_BOUND_UPPER , aNum . byteValue [ 1 ] ) ;
delayMicroseconds ( 50 ) ; // small delay
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// larger delay
delay ( 50 ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// need to update frame period to cause shutter value to take effect
aNum . byteValue [ 1 ] = read_register ( ADNS3080_FRAME_PERIOD_UPPER ) ;
delayMicroseconds ( 50 ) ; // small delay
aNum . byteValue [ 0 ] = read_register ( ADNS3080_FRAME_PERIOD_LOWER ) ;
delayMicroseconds ( 50 ) ; // small delay
write_register ( ADNS3080_FRAME_PERIOD_MAX_BOUND_LOWER , aNum . byteValue [ 0 ] ) ;
delayMicroseconds ( 50 ) ; // small delay
write_register ( ADNS3080_FRAME_PERIOD_MAX_BOUND_UPPER , aNum . byteValue [ 1 ] ) ;
delayMicroseconds ( 50 ) ; // small delay
}
// clear_motion - will cause the Delta_X, Delta_Y, and internal motion registers to be cleared
2011-05-11 09:49:19 -03:00
void
AP_OpticalFlow_ADNS3080 : : clear_motion ( )
2011-04-30 05:29:28 -03:00
{
write_register ( ADNS3080_MOTION_CLEAR , 0xFF ) ; // writing anything to this register will clear the sensor's motion registers
x = 0 ;
y = 0 ;
dx = 0 ;
dy = 0 ;
_motion = false ;
}
// get_pixel_data - captures an image from the sensor and stores it to the pixe_data array
2011-05-11 09:49:19 -03:00
int
AP_OpticalFlow_ADNS3080 : : print_pixel_data ( Stream * serPort )
2011-04-30 05:29:28 -03:00
{
int i , j ;
2011-05-11 09:49:19 -03:00
bool isFirstPixel = true ;
2011-04-30 05:29:28 -03:00
byte regValue ;
byte pixelValue ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// write to frame capture register to force capture of frame
write_register ( ADNS3080_FRAME_CAPTURE , 0x83 ) ;
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// wait 3 frame periods + 10 nanoseconds for frame to be captured
delayMicroseconds ( 1510 ) ; // min frame speed is 2000 frames/second so 1 frame = 500 nano seconds. so 500 x 3 + 10 = 1510
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// display the pixel data
for ( i = 0 ; i < ADNS3080_PIXELS_Y ; i + + ) {
for ( j = 0 ; j < ADNS3080_PIXELS_X ; j + + ) {
regValue = read_register ( ADNS3080_FRAME_CAPTURE ) ;
if ( isFirstPixel & & ( regValue & 0x40 = = 0 ) ) {
serPort - > println ( " failed to find first pixel " ) ;
}
isFirstPixel = false ;
pixelValue = ( regValue < < 2 ) ;
serPort - > print ( pixelValue , DEC ) ;
if ( j ! = ADNS3080_PIXELS_X - 1 )
serPort - > print ( " , " ) ;
delayMicroseconds ( 50 ) ;
}
serPort - > println ( ) ;
}
2011-09-16 23:24:57 -03:00
2011-04-30 05:29:28 -03:00
// hardware reset to restore sensor to normal operation
reset ( ) ;
}