GPS data to PWM/PPM output for servo using UNO board

Hi everyone,

Is it possible to convert GPS input serial data to PWM/PPM output data for servo with UNO board?

My intention is to use GPS speed data to control servo motored needle to show speed on gauge. So that the speed (km/h) would directly drive the angle of the servo 0 km/h -> 0 degrees, 90km/h -> 90 degrees and so on.

I've tried some codes but the servo seems to make some sort of unwanted movement due to the serial-data timing or something?

I've heard that this might be related to UNOs single UART limit and timing clock things but for my skills this is quite dead end at the moment. Does anyone have code that works for this purpose in UNO board?

Yes and I have just started with Arduino/Genuino in general so I'm not that familiar with the whole coding yet :slight_smile:

I hope someone could help me a little bit with this case.

Best Regards,

-Bertolli-

This is something I've tried:

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <Servo.h>

static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;

SoftwareSerial ss(RXPin, TXPin);

TinyGPSPlus gps;

Servo myservo;

void setup()
{
Serial.begin(115200);
ss.begin(GPSBaud);

myservo.attach(2);
}

void loop()
{
myservo.write(gps.speed.kmph());
delay(1000);
}

Assuming the gps.speed.kmph() function returns a usable value, you could use map() to convert it to degrees for the servo. You'll need to decide on a realistic maximum to be full deflection.

Hi,

I think the gps.speed.kmph() gives values like 0.1, 10.6, 100.8 and so on according to the speed.

But I think the problem is not related to the value because even if I set static value to the code like this myservo.write(90); still the unwanted movement occurs.

So it must be related to the UNOs serial data handling somehow?

Are you powering the servo from the Arduino?

Hi,

No, I have separate power source which gives 5V to Vin via connection board and the servo leads + - are connected to the separate connection board also.

I think the problem is not related to power source either.

void loop()
{
   myservo.write(gps.speed.kmph());
   delay(1000);                            
}

Since you never read anything from the GPS, it seems unlikely that the gps object will ever have any valid data.

I have separate power source which gives 5V to Vin via connection board and the servo leads + - are connected to the separate connection board also.

and a common GND ?

Yes, common ground.

Anybody who knows solution to the problem in this post? After hours and hours of searching I wasn't able to find any working code or combination of code and custom library for UNO board that could handle the initial desired function described in this post?

Anybody who knows solution to the problem in this post?

Have you read reply # 5? Have you done anything about it?

To PaulS:

Hi, I have tried to do that but I'm not sure if I have done the right things here....

This is the last version of code I have tried. I changed speed to altitude cause it is easier to get higher values as I'm not moving that fast all the time..

//*********************************************************************

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <Servo.h>

Servo myservo;

static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;

TinyGPSPlus gps;

SoftwareSerial ss(RXPin, TXPin);

void setup()
{
Serial.begin(115200);
ss.begin(GPSBaud);
myservo.attach(9);
}

void loop()
{

// int ALT=gps.altitude.meters(); not implemented ints to code
// int SATS=gps.satellites.value(); not implemented ints to code

if (gps.altitude.isUpdated() || gps.satellites.isUpdated())
{
Serial.print(F("Altitude (m) = ")); Serial.println(gps.altitude.meters());
Serial.print(F("Satellites (amount) = ")); Serial.println(gps.satellites.value());

//myservo.write(ALT); not implemented servo write to code

myservo.write(gps.altitude.meters());
delay(1000);
}

while (ss.available() > 0)
gps.encode(ss.read());
}

//*********************************************************************

Here is a sample of the data that I see in the serial monitor:

Satellites (amount) = 5
Altitude (m) = 98.10
Satellites (amount) = 4
Altitude (m) = 97.00
Satellites (amount) = 5
Altitude (m) = 93.70
Satellites (amount) = 5
Altitude (m) = 90.90
Satellites (amount) = 6
Altitude (m) = 88.10
Satellites (amount) = 6
Altitude (m) = 86.60
Satellites (amount) = 6
Altitude (m) = 85.40

I'm not sure what you're asking now. You started off wanting to control the servo with speed, now it's alt. But basically same thing. Seems you are making a dashboard so need speed and alt.

You have the commented out line where you read the gps sensor into an int called ALT. Uncomment it then you have the altitude in ALT.

Then decide what upper altitude you want for your altimeter. Let's say for argument's sake that's 200m

Then use map ala reply #1 to map alt to another variable (let's sat ALTpos) making 0 alt mean 0 degrees and your maximum altitude (200m or whatever you decided) to be 180 degrees.

To JimboZA:

Hi,

like I said in the previous post it is easier to use alt for testing because you don't have to move physically to get reasonable values from the GPS. It is easier write servo angle according to 88 meters compared to small speed values like 0.1km/h or so on.

And the main purpose of the project is still to build a speedometer; My intention is to use GPS speed data to control servo motored needle to show speed on gauge (text from the start message of this post, I wrote).

Those uncommented lines are versions that I tested in the code but did not want to remove yet....

About the mapping..I have understand that the alt value in this case does not need mapping cause the value it self is reasonable for servo.write(88) (88m) should turn servo to 88 degrees....

And the main problem is not the mapping here...it is the UNOs capability to use serial communication and at the same time give PWMs to servo without glitches or any unwanted movement of servo. The serial traffic from GPS causes very big unwanted movements to the servo....

The problem exists even if the servo.write value is constant like this servo.write(90). So the problem is not the mapping, not the voltage, it is something else...

-Bertolli-

Here is an image of the setup:

After two months of searching and investigating I must say that for Uno board a working PWM signal output for servo simultaneously with GPS connected via serial is nearly impossible or at least extremely difficult. No working code exists as far as I know. I wouldn't waste more time for trying to solve the case anymore. Just use Mega or some other board instead.

for Uno board a working PWM signal output for servo simultaneously with GPS connected via serial is nearly impossible or at least extremely difficult.

CHALLENGE ACCEPTED.

Your main problem is using SoftwareSerial. It's terrible. It disables interrupts for a looooong time.

Solution? Pick one:

1) Put the GPS on pins 0 & 1 and use two other pins (2 & 3?) for debug printing to a NeoSWSerial instance. Requires an RS-232 TTL-to-USB adapater module (aka FTDI module) on pins 2&3. You will have to disconnect the GPS TX (UNO RX) wire to reprogram the UNO over USB.

2) Put the GPS on pins 8 & 9 and use AltSoftSerial instead of SoftwareSerial. Prevents PWM on pin 10, but this is almost as good as using Serial.

I'm surprised nobody else suggested this!

A secondary problem is the structure of the sketch. Using delay(1000) is never going to work. You must use an structure like the NeoGPS examples for reading the GPS data, and combine it with a Blink Without Delay technique for updating the servo.

NMEAblink.ino is very close to what you need. Instead of blinking the LED, you would update the servo with the gps.fix().spd.whole value, scaled appropriately.

But I suggest you start with main NeoGPS page and read through the docs, especially the Troubleshooting section. Then follow the Installation instructions and try NMEA.ino and NMEAloc.ino. At that point, you should be able to modify NMEAblink to do what you want.

Cheers,
/dev