I THINK ∴ I'M DANGEROUS

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
sonar [2016/03/07 17:50]
zashi
sonar [2016/11/09 15:12] (current)
zashi [Software]
Line 149: Line 149:
 Will test and update once I get some hardware. Once I verify the code works (or rather, once I test it and fix all the bugs I find) I'll restructure the code out into more manageable functions. Will test and update once I get some hardware. Once I verify the code works (or rather, once I test it and fix all the bugs I find) I'll restructure the code out into more manageable functions.
  
-<file c sonartest.c>​ +<file c sonar.h>
-/* Compile: gcc -Wall -std=gnu11 -lportaudio -lm sonartest.c -o sonartest */ +
-#include <​stdio.h>​ +
-#include <​stdlib.h>​ +
-#include <​stdint.h>​ +
-#include <​time.h>​ +
-#include <​math.h>​ +
-#include <​portaudio.h> +
 #define MACH 343 // speed of sound in m/s #define MACH 343 // speed of sound in m/s
-#define ds 0.3 // distance between sensors in m (should be in equilateral triangle shape)+/*#define ds 0.3 // distance between sensors in m (should be in equilateral triangle shape)*/
 #define ns_to_s(x) (x / 1000000000) // convert nanoseconds to seconds #define ns_to_s(x) (x / 1000000000) // convert nanoseconds to seconds
-#define pi 3.14159265358979323 ​// ... pi. Like the constant, y'​know?​+#define pi 3.14159265358979323846 ​// ... pi. Like the constant, y'​know?​
  
- 
-typedef struct { 
- double x; 
- double y; 
-} coord; 
  
 /* relative positions of sensors */ /* relative positions of sensors */
Line 178: Line 165:
 #define RIGHTTOP 2 #define RIGHTTOP 2
  
-/* actual positions of sensors *midpoints* in meters from origin point*/ 
  
 +typedef struct {
 + double x;
 + double y;
 +} coord;
 +
 +typedef struct {
 +    int sensor_id[3];​
 +    PaStream *sensor_stream[2];​
 +    double ds;
 +    int16_t sensor_data[2];​
 + int16_t threshold;
 +} sonar_config;​
 +
 +void sonar_init (void);
 +void sonar_listdev (void);
 +void sonar_getloc ( coord *loc, sonar_config conf );
 +int sonar_coord_cmp (coord a, coord b);
 +
 +</​file>​
 +
 +<file c sonar.c>
 +#include <​stdio.h>​
 +#include <​stdlib.h>​
 +#include <​stdint.h>​
 +#include <​time.h>​
 +#include <​math.h>​
 +#include <​portaudio.h>​
  
 +#include "​sonar.h"​
  
-void initaudiohardware ​(void)+void sonar_init ​(void)
 { {
  /* init portaudio */  /* init portaudio */
Line 195: Line 209:
  atexit((void (*)(void))Pa_Terminate);​  atexit((void (*)(void))Pa_Terminate);​
  
- if ( 0 ) +
- {+ 
 +void sonar_set_midpoints ​(coord *mps, double l) 
 +
 +    /* determine the midpoints of a triangle of length l. 
 +     * This assumes the triangle is equilateral and centered 
 +     * on the origin point. 
 +     */ 
 + 
 +    double h_bigt; /* height of big triangle */ 
 +    double r_bigt; /* radius of big triangle */ 
 + 
 +    /* small triangle = triangle formed by midpoints of big triangle */ 
 + 
 +    double r_smallt; /* radius of small triangle */ 
 +    double l_smallt; /* length of side of small t */ 
 +    double m; /*  gives midpoint y coord. */ 
 + 
 +    /* use pythagoras to determine height of equilateral triangle */ 
 +    h_bigt = sqrt( pow(l, 2) - pow( l/2, 2) ); 
 + 
 +    /* radius of an equilateral triangle = length of side / sqrt(3) */ 
 +    r_bigt = l / sqrt(3); 
 + 
 +    /* the difference in the height of bigt and its radius gives radius of smallt */ 
 +    r_smallt = h_bigt - r_bigt; 
 + 
 +    l_smallt = sqrt(3) * r_smallt; 
 + 
 +    /* use pythagoras again */ 
 +    m = sqrt( pow(r_smallt,​ 2) - pow( l_smallt / 2, 2) ); 
 + 
 +    mps[TOPLEFT].x = -l_smallt / 2; 
 +    mps[TOPLEFT].y = m; 
 + 
 +    mps[RIGHTTOP].x = l_smallt / 2; 
 +    mps[RIGHTTOP].y = m; 
 + 
 +    mps[LEFTRIGHT].x = 0
 +    mps[LEFTRIGHT].y = -r_smallt;​ 
 +
 + 
 +void sonar_listdev (void
 +{
  /* Figure out input devices we have */  /* Figure out input devices we have */
  PaDeviceIndex dev;  PaDeviceIndex dev;
Line 215: Line 271:
  dev_info->​defaultLowInputLatency );  dev_info->​defaultLowInputLatency );
  }  }
- } 
- 
 } }
  
-extern inline ​int coord_cmp ​(coord a, coord b)+int sonar_coord_cmp ​(coord a, coord b)
 { {
  return (a.x == b.x && a.y == b.y);  return (a.x == b.x && a.y == b.y);
 } }
  
-int main()+void sonar_getloc ​coord *loc, sonar_config conf )
 { {
- coord midpoint[2];   /* array to store midpoints */ + unsigned int i; 
- coord mp_order[2];   /* array to store the order of midpoints */ + PaError err; 
- coord mp_map[2][2];  /* 2 dim array to make mapping of sensors to midpoint *much* easier */ + coord midpoint[3]; 
- coord loc; /* where the sound source is */+ coord mp_order[3]; 
 + coord mp_map[3][3];
  
- + sonar_set_midpoints ​(midpoint, conf.ds);
- /* Equilateral triangle 300 mm per side, with center of area on origin */ +
- midpoint[TOPLEFT].x ​  ​= ​(-0.075); +
- midpoint[TOPLEFT].y ​  ​= ​ (0.042); +
- +
- midpoint[RIGHTTOP].x ​ =  (0.075); +
- midpoint[RIGHTTOP].y ​ =  (0.042); +
- +
- midpoint[LEFTRIGHT].x =  (0.0); +
- midpoint[LEFTRIGHT].y = (-0.088);+
  
  mp_map[LEFT][RIGHT] = midpoint[LEFTRIGHT];​  mp_map[LEFT][RIGHT] = midpoint[LEFTRIGHT];​
  mp_map[RIGHT][LEFT] = midpoint[LEFTRIGHT];​  mp_map[RIGHT][LEFT] = midpoint[LEFTRIGHT];​
- +
  mp_map[TOP][LEFT] = midpoint[TOPLEFT];​  mp_map[TOP][LEFT] = midpoint[TOPLEFT];​
  mp_map[LEFT][TOP] = midpoint[TOPLEFT];​  mp_map[LEFT][TOP] = midpoint[TOPLEFT];​
- +
  mp_map[RIGHT][TOP] = midpoint[RIGHTTOP];​  mp_map[RIGHT][TOP] = midpoint[RIGHTTOP];​
  mp_map[TOP][RIGHT] = midpoint[RIGHTTOP];​  mp_map[TOP][RIGHT] = midpoint[RIGHTTOP];​
  
- PaError err; + PaStreamParameters sparams[2];
- initaudiohardware();+
  
- PaStream *sensor_stream[2];​ + for ( i = 0; i < 3i++ )
-  +
- PaStreamParameters sparams[2];​ +
-  +
- struct timespec t[2]; +
-  +
- sparams[0].device ​= 0; +
- sparams[0].channelCount = 1; +
- sparams[0].sampleFormat = paInt16; +
- sparams[0].suggestedLatency = 0; +
- sparams[0].hostApiSpecificStreamInfo = NULL; +
-  +
- if ( (err = Pa_OpenStream ( +
- &​sensor_stream[0],​ +
- &​sparams[0],​ +
- NULL, +
- 44100, +
- paFramesPerBufferUnspecified,​ +
- paNoFlag,​ +
- NULL, +
- NULL )) )+
  {  {
- printf ( "​Failed to open stream: %s\n", Pa_GetErrorText ( err ) )+ sparams[i].device = conf.sensor_id[i]
- exit ( -2 );+ sparams[i].channelCount = 1; 
 + sparams[i].sampleFormat = paInt16; 
 + sparams[i].suggestedLatency = 0; 
 + sparams[i].hostApiSpecificStreamInfo = NULL;
  }  }
-  
- int16_t sensor_data[2];​ 
  
 + for ( i = 0; i < 3; i++ )
 + if ( (err = Pa_OpenStream (
 + &​conf.sensor_stream[i],​
 + &​sparams[i],​
 + NULL,
 + 44100,
 + paFramesPerBufferUnspecified,​
 + paNoFlag,​
 + NULL,
 + NULL )) )
 + {
 + printf ( "​Failed to open stream for device %d: %s\n", conf.sensor_id[i],​ Pa_GetErrorText ( err ) );
 + exit ( -2 );
 + };
   
- double theta[2]; // thetas and adjusted thetas + struct timespec t[3]; 
- double b[2]; // y-intercepts + double theta[3]; 
- int t_to_m[2]; // map timestamp to microphone+ double b[3]; 
 + int t_to_m[3];
  int order = 0;  int order = 0;
   
- for ( int i = 0; i < 1; i++ )+ for ( i = 0; i < 3; i++ )
  t[i].tv_sec = 0;  t[i].tv_sec = 0;
  
 + for ( i = 0; i < 3; i++ )
 + Pa_StartStream ( conf.sensor_stream[i] );
   
- Pa_StartStream ( sensor_stream[0] ); 
  for (;;)  for (;;)
  {  {
- for ( int i = 0; i < 1; i++ )+ for ( i = 0; i < 3; i++ )
  {  {
- err = Pa_ReadStream ( sensor_stream[i],​ &​sensor_data[i],​ 1); + err = Pa_ReadStream ( conf.sensor_stream[i],​ &conf.sensor_data[i],​ 1 ); 
- if (! ( err == paInputOverflowed ​|| err == paNoError))+ if (! ( paInputOverflowed ​== err || err == paNoError ) )
  {  {
- printf ​( "​Failed to read stream: %s\n", Pa_GetErrorText ( err ) );+ fprintf ​stderr, ​"​Failed to read stream: %s\n", Pa_GetErrorText ( err ) );
  exit ( -3 );  exit ( -3 );
  }  }
  }  }
- +  
- for ( int i = 0; i < 1; i++ )+ for ( i = 0; i <= 2; i++ )
  {  {
- if ( abs( sensor_data[i] ) > 20000 && t[i].tv_sec != 0)+ if ( abs( conf.sensor_data[i] ) > conf.threshold ​&& t[i].tv_sec != 0 )
  {  {
  clock_gettime ( CLOCK_REALTIME,​ &t[i] );  clock_gettime ( CLOCK_REALTIME,​ &t[i] );
Line 314: Line 356:
  }  }
   
- if (order > 2)+ if ( order > 2 )
  {  {
  order = 0;  order = 0;
- for ( int i = 0; i < 1; i++ )+ for ( i = 0; i < 3; i++ )
  t[i].tv_sec = 0;  t[i].tv_sec = 0;
- +  
- /* + /*
  *  Find Thetas  *  Find Thetas
  */  */
   
- /* find theta between t0 and t1 */ + /* between t0 and t1 */ 
- theta[0] = acos ( (ns_to_s(t[1].tv_nsec - t[0].tv_nsec) * MACH) / ds ); + theta[0] = acos ( (ns_to_s(t[1].tv_nsec - t[0].tv_nsec) * MACH) / conf.ds ); 
- +
  /* between t1 and t2 */  /* between t1 and t2 */
- theta[1] = acos ( (ns_to_s(t[2].tv_nsec - t[1].tv_nsec) * MACH) / ds ); + theta[1] = acos ( (ns_to_s(t[2].tv_nsec - t[1].tv_nsec) * MACH) / conf.ds );
-  +
- /* between t0 and t2 */ +
- theta[2] = acos ( (ns_to_s(t[2].tv_nsec - t[0].tv_nsec) * MACH) / ds );+
  
 + /* between t0 and t2 */
 + theta[2] = acos ( (ns_to_s(t[2].tv_nsec - t[0].tv_nsec) * MACH) / conf.ds );
 +
  /*  /*
- * Map midpoints to sensors+ Map midpoints to sensors
  */  */
  mp_order[0] = mp_map[t_to_m[0]][t_to_m[1]];​  mp_order[0] = mp_map[t_to_m[0]][t_to_m[1]];​
Line 341: Line 383:
   
  /*  /*
- * Adjust thetas depending on midpoint+ Adjust thetas depending on midpoint
  */  */
- for ( int i = 0; i < 3; i++ )+ for ( i = 0; i < 3; i++ )
  {  {
- if ( coord_cmp ​( mp_order[i],​ midpoint[TOPLEFT] ) )+ if ( sonar_coord_cmp ​( mp_order[i],​ midpoint[TOPLEFT] ) )
  {  {
- theta[i] +=  pi / 3;+ theta[i] += pi / 3;
  }  }
- else if ( coord_cmp ​( mp_order[i],​ midpoint[RIGHTTOP] ) )+ else if ( sonar_coord_cmp ​( mp_order[i],​ midpoint[RIGHTTOP] ) )
  {  {
  theta[i] -= pi / 3;  theta[i] -= pi / 3;
  }  }
 +
  }  }
   
  /*  /*
- * Determine b[]s (y-intercepts)+ Determine b[]s (y-intercepts)
  */  */
- for ( int i = 0; i < 3; i++ )+ for ( i = 0; i < 3; i++ )
  b[i] = mp_order[i].y - tan(theta[i]) * mp_order[i].x;​  b[i] = mp_order[i].y - tan(theta[i]) * mp_order[i].x;​
 +
  /*  /*
- * Determine X of loc+ Determine X of loc (TODO: Average together all loc.x)
  */  */
-  loc.x = ( b[1] - b[0] ) / ( tan(theta[0]) - tan(theta[1]) ); + loc->x = ( b[1] - b[0] ) / ( tan(theta[0]) - tan(theta[1]) ); 
-  +  
 +
  /*  /*
- * Determine Y of loc+ Determine Y of loc (TODO: Average together all loc.y)
  */  */
-  + loc->y = tan(theta[0]) * loc->x + b[0];
-  loc.y = tan(theta[0]) * loc.x + b[0]+
-  +
- printf ( "​LOCATION:​ %f meters x %f meters away from origin\n",​ loc.x, loc.y );+
  }  }
-  
  }  }
- +
 +</​file>​ 
 + 
 +<file c main.c>​ 
 +/* gcc -Wall -std=gnu11 -O2 -fno-aggressive-loop-optimizations -pedantic -lportaudio -lm *.c -o sonar */ 
 + 
 +#include <​stdio.h>​ 
 +#include <​stdlib.h>​ 
 +#include <​unistd.h>​ 
 + 
 +#include "​sonar.h"​ 
 + 
 + 
 +int main ( int argc, char **argv ) 
 +
 +    int opt; 
 +    int sensor_id[3] = {-1, -1, -1}; 
 +    int verbose=0;​ 
 +     
 +    sonar_config conf; 
 +    conf.ds = 0; 
 +     
 +    while ( (opt = getopt(argc,​ argv, "​t:​l:​r:​d:​vs"​)) != -1 ) 
 +    { 
 +        switch (opt) 
 +        { 
 +            /* specify sensor */ 
 +            case '​t':​ 
 +            case '​l':​ 
 +            case '​r':​ 
 +            /* not clever, just lazy */ 
 +                if ( 1 != sscanf(optarg,​ "​%d",​ &​sensor_id[(opt == '​t'​) ? 0 : (opt == '​l'​) ? 1 : 2]) )  
 +                { 
 +                    perror("​Failed to parse -<​t|l|r>​ argument"​);​ 
 +                    exit(-1); 
 +                } 
 +                break; 
 +            case '​d':​ /* specify ds (distance between sensors) */ 
 +                conf.ds = strtod(optarg,​ NULL); 
 +                if ( conf.ds > 343 ) 
 +                { 
 +                    fprintf ( stderr, "​Specified sensor distance is too large. Must be < 343\n" ); 
 +                    exit(-1); 
 +                } 
 +                if (conf.ds <  0.1) 
 +                { 
 +                    fprintf ( stderr, "​Specified sensor distance is too small. Must be > 0.1\n" ); 
 +                    exit(-1); 
 +                } 
 +                break; 
 +            case '​s':​ /* list audio input devices */ 
 +                sonar_init();​ 
 +                sonar_listdev();​ 
 +                exit(0); 
 +                break; 
 +            case '​v':​ 
 +                verbose = 1; 
 +                break; 
 +            default: 
 +                //fprintf ( stderr, "​Usage:​ %s -l | -s <​sensor1>​ -s <​sensor2>​ -s <​sensor3>​ -d <​distance in meters> \n", argv[0] ); 
 +                exit(-1); 
 +        } 
 +    } 
 +     
 +    /* done processing arguments, make sure arguments make sense */ 
 +    if ( -1 == sensor_id[0] || -1 == sensor_id[1] || -1 == sensor_id[2] ) 
 +    { 
 +        fprintf ( stderr, "​Error:​ 3 sensors, -t (top) -l (left) and -r (right) must be specified.\n"​ ); 
 +        exit(-1); 
 +    } 
 +     
 +    if ( conf.ds == 0 ) 
 +    { 
 +        fprintf ( stderr, "​Error:​ Sensor distance (-d) must be set.\n"​ ); 
 +        exit(-1); 
 +    } 
 +     
 +    if ( sensor_id[0] == sensor_id[1] || sensor_id[0] == sensor_id[2] || sensor_id[1] == sensor_id[2] ) 
 +    { 
 +        fprintf ( stderr, "​Error:​ Each sensor (-t,-l,-r) must be unique.\n"​ ); 
 +        exit(-1); 
 +    } 
 +     
 +    if ( verbose ) 
 +    { 
 +        printf ( "​Sensors:​ %d, %d, and %d\n"​ 
 +                 "​Distance between sensors: %fm",​ 
 +                 ​sensor_id[0],​ sensor_id[1],​ sensor_id[2],​ 
 +                 ​conf.ds 
 +               ); 
 +    } 
 +     
 +    /* init audio hardware */ 
 +    sonar_init();​ 
 +/* 
 +    sonar_openstreams(sensor_id);​ 
 +     
 +    sonar_ 
 +*/     
 +    coord loc; 
 +    for (;;) 
 +    { 
 +        sonar_getloc(&​loc,​ conf); 
 +        sleep(1); 
 +    } 
 +    return 0;
 } }
 </​file>​ </​file>​