select a single character out of a variable

Hi everybody, I'm working with a GPS and I'm receiving the latitude/longitude data in this format: lat: 3107.6157N long: 3927.1389W I need to use these values in a tan() function, so the N/S E/W have to be converted to positive/negative values. In this case, the longitude have to be converted to a negative. How can I do that? I have almost none experience with Arduino, but I'm able to understand some medium arduino codes and function. Possibly, if needed, some terms will have to be explained to me since I don't understand some things like char, char array, string. I'm used to work with int function. Thank you all!

Post the program code you are using.

Now that you know all the terms "Things like char, char array, string" you will have no trouble getting explanations with Google.

...R

Just google “Arduino C data types” and start reading a few until you find one that makes sense to you. I just did that and got 200K hits, so there are plenty of choices. I kinda like this one and then click on the Look Inside banner on the book cover.

I’m using this

// Test code for Adafruit GPS modules/shields using MTK3329/MTK3339 driver
//
// This code shows how to listen to the GPS module in an interrupt
// which allows the program to have more 'freedom' - just parse
// when a new NMEA sentence is available! Then access data when
// desired. -ada
//
// Added verbosity and corrections by PhantomYoYo in A.D. 2014 ;)

/******************* CONSTANTS AND VARIABLES *******************
****************************************************************/

#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>

// If you're using a bare GPS module:
// Connect the GPS Power pin to 5V
// Connect the GPS Ground pin to ground
// Then wire for software serial (sketch example default):
//   Connect the GPS TX (transmit) pin to Digital 3
//   Connect the GPS RX (receive) pin to Digital 2
// Or wire for hardware serial (e.g. Arduino Mega):
//   Connect the GPS TX (transmit) pin to Arduino RX1, RX2 or RX3
//   Connect the GPS RX (receive) pin to matching TX1, TX2 or TX3

// If you're using the Adafruit GPS shield, change 
// SoftwareSerial mySerial(3, 2); -> SoftwareSerial mySerial(8, 7);
// and make sure the switch is set to SoftSerial
// This shield is *not* capable of software serial on a Mega!
// Instead add 2 jumper wires:
// Connect jumper from TX pad to Arduino RX1, RX2 or RX3
// Connect jumper from RX pad to Arduino TX1, TX2 or TX3

// To use software serial, keep these two lines enabled
// (you can change the pin numbers to match your wiring):
//SoftwareSerial mySerial(3, 2);
//Adafruit_GPS GPS(&mySerial);
//
// To use hardware serial (e.g. Arduino Mega), comment
// out the above two lines and enable these two lines instead:
HardwareSerial mySerial = Serial1;
Adafruit_GPS GPS(&Serial1);


// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' if you want to debug and listen to the raw GPS sentences. 
#define GPSECHO  true

// this keeps track of whether we're using the interrupt
// off by default!
boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy


/************************ ARDUINO SETUP  ***********************
****************************************************************/

void setup()  
{
    
  // connect at 115200 so we can read the GPS fast enough and echo without dropping chars
  // also spit it out
  // make sure your Serial Monitor is set to 115200 to see data visually
  Serial.begin(115200);
  Serial.println("Adafruit GPS library basic test!");

  // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
  GPS.begin(9600);
  
  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  // uncomment this line to turn on only the "minimum recommended" data
  //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  // For parsing data, we don't suggest using anything but either RMC only or RMC+GGA since
  // the parser doesn't care about other sentences at this time
  
  // Set the update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz update rate
  // For the parsing code to work nicely and have time to sort thru the data, and
  // print it out we don't suggest using anything higher than 1 Hz

  // Request updates on antenna status, comment out to keep quiet
  GPS.sendCommand(PGCMD_ANTENNA);

  // the nice thing about this code is you can have a timer0 interrupt go off
  // every 1 millisecond, and read data from the GPS for you. that makes the
  // loop code a heck of a lot easier!
  useInterrupt(true);

  delay(1000);
  // Ask for firmware version
  mySerial.println(PMTK_Q_RELEASE);
}


// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
  // if you want to debug, this is a good time to do it!
#ifdef UDR0
  if (GPSECHO)
    if (c) UDR0 = c;  
    // writing direct to UDR0 is much much faster than Serial.print 
    // but only one character can be written at a time. 
#endif
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  } else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
}

uint32_t timer = millis();


/******************** MAIN LOOP ********************************
****************************************************************/

void loop()                     // run over and over again
{
  // in case you are not using the interrupt above, you'll
  // need to 'hand query' the GPS, not suggested :(
  if (! usingInterrupt) {
    // read data from the GPS in the 'main loop'
    char c = GPS.read();
    // if you want to debug, this is a good time to do it!
    if (GPSECHO)
      if (c) Serial.print(c);
  }
  
  // if a sentence is received, we can check the checksum, parse it...
  if (GPS.newNMEAreceived()) {
    // a tricky thing here is if we print the NMEA sentence, or data
    // we end up not listening and catching other sentences! 
    // so be very wary if using OUTPUT_ALLDATA and trying to print out data
    //Serial.println(GPS.lastNMEA());   // this also sets the newNMEAreceived() flag to false
  
    if (!GPS.parse(GPS.lastNMEA()))   // this also sets the newNMEAreceived() flag to false
      return;  // we can fail to parse a sentence in which case we should just wait for another
  }

  // if millis() or timer wraps around, we'll just reset it
  if (timer > millis())  timer = millis();

  // approximately every 2 seconds or so, print out the current stats
  if (millis() - timer > 2000) { 
    timer = millis(); // reset the timer
    
    Serial.print("\nTime: ");
    Serial.print(GPS.hour, DEC); Serial.print(':');
    Serial.print(GPS.minute, DEC); Serial.print(':');
    Serial.print(GPS.seconds, DEC); Serial.print('.');
    Serial.println(GPS.milliseconds);
    Serial.print("Date: ");
    Serial.print(GPS.day, DEC); Serial.print('/');
    Serial.print(GPS.month, DEC); Serial.print("/20");
    Serial.println(GPS.year, DEC);
    Serial.print("Fix: "); Serial.print((int)GPS.fix);
    Serial.print(" quality: "); Serial.println((int)GPS.fixquality); 
    if (GPS.fix) {
      Serial.print("Location: ");
      Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
      Serial.print(", "); 
      Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
      
      Serial.print("Speed (knots): "); Serial.println(GPS.speed);
      Serial.print("Angle: "); Serial.println(GPS.angle);
      Serial.print("Altitude: "); Serial.println(GPS.altitude);
      Serial.print("Satellites: "); Serial.println((int)GPS.satellites);
    }
  }
}

my problem is to convert the N/S and E/W to positive/negative, respectively

That looks like an unnecessarily complex way to receive serial data.

I think there are other GPS librarys that may be more user friendly.

...R Serial Input Basics

That looks like an unnecessarily complex way to receive serial data.

It’s fine. It actually works quite well.

PaulS: It's fine. It actually works quite well.

it does, and it is the code provided by the manufacturer, so I took advantage of it Now I don't know how to, in the same value (xxxx.xxxxW), separate in two and convert into -xxxx.xxxx or erase the W and use it to convert into a negative number..

Now I don't know how to, in the same value (xxxx.xxxxW), separate in two and convert into -xxxx.xxxx or erase the W and use it to convert into a negative number..

Why do you presume that the parse method doesn't already do that?

    // parse out longitude
    p = strchr(p, ',')+1;
    if (',' != *p)
    {
      strncpy(degreebuff, p, 3);
      p += 3;
      degreebuff[3] = '\0';
      degree = atol(degreebuff) * 10000000;
      strncpy(degreebuff, p, 2); // minutes
      p += 3; // skip decimal point
      strncpy(degreebuff + 2, p, 4);
      degreebuff[6] = '\0';
      minutes = 50 * atol(degreebuff) / 3;
      longitude_fixed = degree + minutes;
      longitude = degree / 100000 + minutes * 0.000006F;
      longitudeDegrees = (longitude-100*int(longitude/100))/60.0;
      longitudeDegrees += int(longitude/100);
    }
    
    p = strchr(p, ',')+1;
    if (',' != *p)
    {
      if (p[0] == 'W') longitudeDegrees *= -1.0;
      if (p[0] == 'W') lon = 'W';
      else if (p[0] == 'E') lon = 'E';
      else if (p[0] == ',') lon = 0;
      else return false;
    }

I found this on the .cpp file next to the library itself but I don't know why is this file important, since I do not include it in the IDE, but I presume it is something like the calculations to handle the data received by the GPS. I guess that in the last segment I can configurate the data and receive in the format +/- besides N/S or E/W, but I don't know how.

I found this on the .cpp file next to the library itself but I don't know why is this file important, since I do not include it in the IDE

If you don't understand that the functions that are defined in a header file must be implemented somewhere, and that that somewhere is the corresponding cpp file, then this project is far too complex for you.

I guess that in the last segment I can configurate the data and receive in the format +/- besides N/S or E/W, but I don't know how.

What you NEED to do is look at the raw data that the GPS reports. NOWHERE in the string that the GPS sends will you find N or S. NOWHERE in the string that the GPS sends will you find E or W.

The N or S, E or W, are added by the code, and the - signs removed by the code you have to print the values parsed from the sentences.

Use the damned values returned in gps.latitude and gps.longitude and get over thinking that you need to deal with N, S, E, or W, or that you need to add - signs to the values!

If you don't understand that the functions that are defined in a header file must be implemented somewhere, and that that somewhere is the corresponding cpp file, then this project is far too complex for you.

I found this code online, and if it is too complex, I need to learn, but aparently ANYONE wants to.

What you NEED to do is look at the raw data that the GPS reports. NOWHERE in the string that the GPS sends will you find N or S. NOWHERE in the string that the GPS sends will you find E or W.

i found something but I'm getting no help to get this right...

The N or S, E or W, are added by the code, and the - signs removed by the code you have to print the values parsed from the sentences.

in the code it only prints the GPS.lat and GPS.lon, which is in the form N/S (...). I've looked in the library and now in the .cpp file and I found that piece of code, and I know it is in here that I have to change the code.

Use the damned values returned in gps.latitude and gps.longitude and get over thinking that you need to deal with N, S, E, or W, or that you need to add - signs to the values!

I would like to know how am I supposed to do a tangent function with N, S, E or W, really!!

Thank You for the (so far, inexistent) help...

Hedwig87: I would like to know how am I supposed to do a tangent function with N, S, E or W, really!!

Let's go back to basics.

If you receive a single line of data from the GPS what does it look like - post an example here.

Also, have a look at the neoGPS and tinyGPS libraries - maybe they would meet your needs more easily.

...R

i found something but I’m getting no help to get this right…

You have completely FAILED to show us a lick of output.

in the code it only prints the GPS.lat and GPS.lon, which is in the form N/S (…).

Nonsense. The code prints FOUR pieces of information, of which you recognize 2.

Print each piece of information with prefix, between delimiters, so you can recognize what is in GPS.latitude, GPS.longitude, GPS.lat, and GPS.lon.

And, if they are not to your liking, use a different library.

Answering both of you, ok, i wasn't really clear on what I'm doing: I'm working on a project named CanSat, in which I have to do a mini-satellite inside a normal soda can (115mm height by 66mm diameter) and have to do a 1000m fall and receive data of temperature and pressure and send it via telemetry to our ground station, in the obligatory primary mission. The secondary mission is on our will, and my team is working on a CanSat that can control its horizontal movement and land on a pre-chosen place. So I need to get a servo rotating (and controlling the direction of the paraglider, and then the way it needs to go to get in the right spot) depending on the compass (that tells where is the CanSat pointed at) and the vector composed by the location it is and the location it needs to go (and this is why I need the values of the GPS in positive/negative, so it can calculate the tangent between the two direction and get the vector it needs to be pointed at!).

"Time: 19:32:30.0 Date: 20/3/2017 Fix: 1 quality: 2 Location: 3923.9294N, 3109.4404W Speed (knots): 0.59 Angle: 39.21 Altitude: 125.50 Satellites: 6"

So, my direct GPS code gives me this data. As you can see in the code I posted above, the GPS.lat is the 3923.9294N and the GPS.lon is the 3109.4404W. As you, PaulS, said the GPS.lat and GPS.lon are composed by 2 pieces of info each. In the library I found nothing, and in the .cpp file I found the piece I also showed you before. How can I change it to get the pretended info?

Hedwig87: So, my direct GPS code gives me this data.

Are you saying that you get all of that data as a single message?

If so you can use strstr() to find different strings within that text, If you find "Location" and "Speed" you will know that the latt and long are between those two points and you can copy out that chunk of data. Then you can use strtok() to split the latt and long (see the parse example in Serial Input Basics) and then you can go to the last character to pick out the 'N' or 'W' and use atof() to convert the number part to a float. After that you can decide whether it should be positive or negative depending on whether it was N or S or E or W.

However before spending time on that I suggest you study the other libraries I gave you links for to find out if they can do all that for you.

...R

So, my direct GPS code gives me this data.

No, it does not.

After GPS.parse() gets done parsing one of the sentences from the GPS, you print the parsed data. THAT is what you show. The line that starts with Location is where you print GPS.latitude, GPS.longitude, GPS.lat, and GPS.lon. The parsing of the data is ... I keep wanting to say stupid, but I'll settle for "original".

Dump that library, and use TinyGPSPlus or NeoGPS to read, store, and properly parse the data.

this code was provided by the manufacturer (I'm using Adafruit Ultimate GPS breakout v3) and I thought no other code would work this well. I'll search for those libraries.

If you want to use Adafruit's weird parsing method, you have 2 values related to latitude - GPS.latitude and GPS.lat. I can't see how difficult it could be to decide that N means positive and S means negative, or vice versa, and multiply, or not, the GPS.latitude value by -1.0.

Similarly, you have two values related to longitude. It's not rocket science to use them to get a positive number or a negative number based on E or W.

omg I think I just figure it out, I was reading the code badly, now I see the 2 pieces of code i have (GPS.latitude and GPS.lat, and (...))!!!

sorry for your waste of time and thank you for the help! I searched for the libraries and found pieces of code that seemed easy to use, since I just need latitude and longitude. unfortunately, I'm not yet able to write a piece of code having the library as a starting point.

unfortunately, I'm not yet able to write a piece of code having the library as a starting point.

Lets start over. What, exactly, is it you are trying to do? You have a GPS spitting out data. You feed that data to a library that says "Hey, yeah, that's valid data, and I've broken the data down into some usable pieces, including latitude (always positive), lat (N or S), longitude (always positive), and lon (E or W)".

Now, what do you want to do?