Colision detection system

Hello guys,

im working on a project that envolves a lot of shields:

Adafruit Fona + adafruit ADXL377 + IteaStudio Gps shield.

The basic idea is get adxl analog input and compare to a value, if that value is reached he sends an sms to a fix number with the coordinates of that value.

I have two question:

First: how to compare variable “float” without matter of the sign - or +;

Second: i pretend to use my module standalone that means no connection with pc, so i really dont know if my code (libraries and resources) are compatible with that effort, if not what i need to change;

#include "TinyGPS.h"
#include "Adafruit_FONA.h"
#include "stdlib.h"


TinyGPS gps;

//Definicao RX/TX/RST FONA
#define FONA_RX 11
#define FONA_TX 10
#define FONA_RST 3

//Definicao RX/TX GPS
#define GPS_TX_DIGITAL_OUT_PIN 5
#define GPS_RX_DIGITAL_OUT_PIN 6


#ifdef __AVR__
#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
#else
HardwareSerial *fonaSerial = &Serial1;
#endif

Adafruit_FONA fona = Adafruit_FONA(FONA_RST);

uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0);

uint8_t type = FONA800L;

int scale = 200;
unsigned int ac1, ac2, ac3;
char sendto[21] = "00000000";
char message[140];
long startMillis;
long secondsToFirstLocation = 0;
float scaledX, scaledY, scaledZ;

#define DEBUG

float latitude = 0.0;
float longitude = 0.0;

char lats[10];
char lons[10];

void setup()

{


Serial.begin(115200);
  Serial.println(F("FONA basic test"));
  Serial.println(F("Initializing....(May take 3 seconds)"));

  fonaSerial->begin(4800);
  if (! fona.begin(*fonaSerial)) {
    Serial.println(F("Couldn't find FONA"));
    while (1);
  }
  type = fona.type();
  Serial.println(F("FONA is OK"));
  Serial.print(F("Found "));
  
  


  
  #ifdef DEBUG
  Serial.begin(19200);
  #endif
  
  // Serial1 GPS
  Serial1.begin(9600);
  // Serial2 ADXL377
  Serial2.begin(9600);
  // Serial3 sms
  Serial3.begin(115200);

  
  // prevent controller pins 5 and 6 from interfering with the comms from GPS
  pinMode(GPS_TX_DIGITAL_OUT_PIN, INPUT);
  pinMode(GPS_RX_DIGITAL_OUT_PIN, INPUT);
  
  startMillis = millis();
  Serial.println("Starting");
}

void flushSerial() {
  while (Serial3.available())
    Serial3.read();
}

void loop()
{
 //Reset da array das coordenadas GPS
 memset(message,0,sizeof(message));

  readLocation();

  int rawX = analogRead(A0);
  int rawY = analogRead(A1);
  int rawZ = analogRead(A2);

  // Scale accelerometer ADC readings into common units
  // Scale map depends on if using a 5V or 3.3V microcontroller
  //float scaledX, scaledY, scaledZ; // Scaled values for each axis
  
    scaledX = mapf(rawX, 0, 1023, -scale, scale);
    scaledY = mapf(rawY, 0, 1023, -scale, scale);
    scaledZ = mapf(rawZ, 0, 1023, -scale, scale);

Serial.print("X: ");
  Serial.println(rawX);
  Serial.print("Y: ");
  Serial.println(rawY);
  Serial.print("Z: ");
  Serial.println(rawZ);
  Serial.println();

  // Print out scaled X,Y,Z accelerometer readings
  Serial.print("X: ");
  Serial.print(scaledX);
  Serial.println(" g");
  Serial.print("Y: ");
  Serial.print(scaledY);
  Serial.println(" g");
  Serial.print("Z: ");
  Serial.print(scaledZ);
  
  Serial.println(" g");
  Serial.println();

 




}

float mapf(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}


//--------------------------------------------------------------------------------------------
void readLocation(){
  
  bool newData = false;
  unsigned long chars = 0;
  unsigned short sentences, failed;

  // For one second we parse GPS data and report some key values
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (Serial1.available())
    {
      int c = Serial1.read();
//      Serial.print((char)c); // if you uncomment this you will see the raw data from the GPS
      ++chars;
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }
  }
  
  if (newData)
  {
    // we have a location fix so output the lat / long and time to acquire
    if(secondsToFirstLocation == 0){
      secondsToFirstLocation = (millis() - startMillis) / 1000;
      Serial.print("Acquired in:");
      Serial.print(secondsToFirstLocation);
      Serial.println("s");
    }
    
    unsigned long age;
    gps.f_get_position(&latitude, &longitude, &age);
    
    latitude == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : latitude;
    longitude == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : longitude;


    Serial.print("Location: ");
    Serial.print(latitude, 6);
    Serial.print(" , ");
    Serial.print(longitude, 6);
    Serial.println("");
    
    dtostrf(latitude, 10, 6, lats);
    Serial.println (lats);
    
    strcat(message, lats);  
    
    dtostrf(longitude, 10, 6, lons);   
    Serial.println (lons);   
    
    strcat(message, lons);

    if (scaledX > 10.0) fona.sendSMS(sendto, message); 
    
   
    

 
  if (chars == 0){
    // if you haven't got any chars then likely a wiring issue
    Serial.println("Check wiring");
  }
  else if(secondsToFirstLocation == 0){
    // still working
  }

  
}




}

compare variable "float" without matter of the sign - or +;

Define "compare". What do you want to know about the variable(s)?

Note: in general, you should avoid comparing floating point variables. Compare integers instead.

Second: i pretend to use my module standalone that means no connection with pc, so i really dont know if my code (libraries and resources) are compatible with that effort, if not what i need to change;

If there is a connection to a PC, what does that connection do and why?

jremington:
Define "compare". What do you want to know about the variable(s)?
If there is a connection to a PC, what does that connection do and why?

The float question stands for this:

if (scaledX > 10.0) fona.sendSMS(sendto, message);

Basicly i want to send the message with the measure is +10G or -10G;

And about the pc conection, actually im testing and looking all happening in the serial monitor working fine so far. The question is how do i know if all that will work standalone, some of the SoftwareSerial stuff i dont know if only works when connected to a pc.

Convert a negative number to a positive one:

if(someVar < 0){
    someVar = -someVar;
}

Delta_G:
Convert a negative number to a positive one:

if(someVar < 0){

someVar = -someVar;
}

Thank you, so simple and i could not see that ! :smiley:

Another lil trouble im having is i get the following coord. from the gps:

Location: -25.428779 , -49.282867

dtostrf(latitude, 10, 6, lats);
dtostrf(latitude, 10, 6, lats);

After using the dtostrf to convert the float to char to send via sms i get those values:

-25.428780
-49.282227

Why this small error ?

Why this small error ?

Because single precision float variables store only 6-7 decimal digits. Single precision floats cannot be used to store GPS coordinates very accurately, as that would require 8-9 decimal digits.

A common workaround is to store latitude and longitude as signed long integers, in degrees multiplied by 106 (10 cm precision) or 107 (1 cm precision).

jremington:
Because single precision float variables store only 6-7 decimal digits. Single precision floats cannot be used to store GPS coordinates very accurately, as that would require 8-9 decimal digits.

A common workaround is to store latitude and longitude as signed long integers, in degrees multiplied by 106 (10 cm precision) or 107 (1 cm precision).

Those first coords. Location: -25.428779 , -49.282867 are 100% precise. The trouble only happens in the conversion of the floats to arrays. And i really dont know why the error in the convertion of the latitude is smaller than longitude.

khaoz87:
First: how to compare variable “float” without matter of the sign - or +;

See avr-libc: <math.h>: Mathematics

You want the ‘fabs’ function.

The math library is part of libc, so all you need to do is

#include <math.h>

Other way to do it is to compare the squares of both values. If you are working with distances, then that’s a matter of not doing the final square root.

IOW: to see if (x,y) is within 20 units of (a,b), use

if(  (x-a)*(x-a) + (y-b)*(y-b) <= 400 ) {
   // x,y is <= 20 units away from (a,b)
}

PaulMurrayCbr:
See avr-libc: <math.h>: Mathematics

You want the ‘fabs’ function.

The math library is part of libc, so all you need to do is

#include <math.h>

Other way to do it is to compare the squares of both values. If you are working with distances, then that’s a matter of not doing the final square root.

IOW: to see if (x,y) is within 20 units of (a,b), use

if(  (x-a)*(x-a) + (y-b)*(y-b) <= 400 ) {

// x,y is <= 20 units away from (a,b)
}

Thanks for the help, i tryed the solution that DeltaG offered:

if(scaledX < 0) scaledX = -scaledX;

and its working so far :slight_smile:

Simply inverting the convertion got better results:

    Serial.print("Location: ");
    Serial.print(latitude, 6);
    Serial.print(" , ");
    Serial.print(longitude, 6);
    Serial.println("");
    
    dtostrf(longitude, 10, 6, lons); 
    Serial.println (lons);   
    strcat(message, lons);
    strncat(message," ",2);
    dtostrf(latitude, 10, 6, lats);
    Serial.println (lats);
    strcat(message, lats);  
    strncat(message," ",2);

Results:

Floats: Location: -25.428840 , -49.282863

Converted char: -49.282864 , -25.428841

I really dont know why.

khaoz87:
Simply inverting the convertion got better results:

    Serial.print("Location: ");

Serial.print(latitude, 6);
    Serial.print(" , ");
    Serial.print(longitude, 6);
    Serial.println("");
   
    dtostrf(longitude, 10, 6, lons);
    Serial.println (lons); 
    strcat(message, lons);
    strncat(message," ",2);
    dtostrf(latitude, 10, 6, lats);
    Serial.println (lats);
    strcat(message, lats); 
    strncat(message," ",2);




Results:

Floats: Location: -25.428840 , -49.282863

Converted char: -49.282864 , -25.428841

I really dont know why.

What is it that you don't know?
Why the order is reversed?

AWOL:
What is it that you don’t know?
Why the order is reversed?

Nope, i dont know why when i reverse the order of variable convertion the values get more acurate of the original float.

#Method 1

Location in float: latitude: -25.428779 , longitude: -49.282867

Converted with:

dtostrf(latitude, 10, 6, lats);
    Serial.println (lats);
    
    strcat(message, lats);  
    
    dtostrf(longitude, 10, 6, lons);   
    Serial.println (lons);   
    
    strcat(message, lons);

Results:

lats = -25.428780
lons = -49.282227

As you may see the lats variable its pretty acurate but the lons has 4 number error.

#Method 2 (doing the dtostrf on longitude first)

Float location: Location: -25.428840 , -49.282863

    dtostrf(longitude, 10, 6, lons); 
    Serial.println (lons);   
    strcat(message, lons);

    strncat(message," ",2);

    dtostrf(latitude, 10, 6, lats);
    Serial.println (lats);
    strcat(message, lats);

Results:
-49.282864 , -25.428841

While inverting the conversion of the variable i get only the last digit different than the original float variable.

char lats[10];
char lons[10];

Stuffing 10 characters and a terminating NULL in a 10 character array as never worked for anyone else. What makes you think you are special?

PaulS:

char lats[10];

char lons[10];



Stuffing 10 characters and a terminating NULL in a 10 character array as never worked for anyone else. What makes you think you are special?

I don't know, i just tryed it and seem to "kinda" work somehow. If this never worked, what is the way that works ?

The way that works is to use a buffer that is big enough to contain all 10 characters and the null terminator.

AWOL:
The way that works is to use a buffer that is big enough to contain all 10 characters and the null terminator.

In addition, I'm a fan of even numbers. I'd make the array size no less than 12. On the other hand, I'm also a chicken, so I'd actually use 16.

PaulS:
In addition, I’m a fan of even numbers. I’d make the array size no less than 12. On the other hand, I’m also a chicken, so I’d actually use 16.

LOL :roll_eyes: now i see what i was trying to do, kinda of a clown car array. Anyway i will change that soon as i get home and post the results. :smiley:

Worked ! :smiley:

How can i compare more than one variable to the same value and do the same action:

Im doing the following:

    if (scaledX > 3.0) fona.sendSMS(sendto, message); 
    if (scaledY > 3.0) fona.sendSMS(sendto, message);
    if (scaledZ > 3.0) fona.sendSMS(sendto, message);

But i want to send only 1 sms if any of 3 reach the value 3.

khaoz87:
Another lil trouble im having is i get the following coord. from the gps:

Location: -25.428779 , -49.282867

dtostrf(latitude, 10, 6, lats);
dtostrf(latitude, 10, 6, lats);

After using the dtostrf to convert the float to char to send via sms i get those values:

-25.428780
-49.282227

Why this small error ?

Arduino 32-bit float is only good for 6 places unless the first digit is small, then 7 places, but you can only count on 6.

If all you’re going to do is send the same number out, why not simply store the text from GPS and send the text as is, untranslated just to turn it back to text anyway? You can even skip the ‘-’ characters if you want.

If you were making a table of values and want to save space, get nothing but the digits into a long.

-25.428780 <<== text arriving from GPS.

long longitude = 0;

then 1st digit in is 2. add 2 to longitude. longitude is now 2
next digit is 5. longitude = longitude * 10 + 5. longitude is now 25
next is 4, same as before but add 4 instead, longitude is now 254
do the same until all the digits are in, longitude becomes 2548780.

adding the decimal point at print time is not rocket math.

And you can detect if your vehicle hits or gets hit by detecting the shock with piezo sensors.
There is a door knock sketch but the circuit isn’t so good. I’ve tested piezo discs as touch sensors with my own circuits, your app would need way less amplification.

But on the plus side, you would know if it got hit even if the whole vehicle did not reach 10 G’s. A whack with a baseball bat might register. These would register shock, not A = M/F.