GPS Stationary Algorithm
Hello,
I have an interesting problem. I have a Raspberry Pi 5 with a GPS receiver mounted to a tractor. I am trying to create an algorithm to determine if the tractor is truly moving or is stationary. The complexity comes in with GPS drift. When logging the GPS data, when stationary, I can see the GPVTG message returning speeds in the .1 mph -> 3 mph range. My original approach was too simple, if gps_speed_mph > 1 then isMoving = true. This approach led to many false positives. To further complicate the issue, the tractor could be driving through a field under trees, or may be parked inside a garage, leading to noisy GPS data. I have speed / lat / long / heading /etc available, but need to come up with a reliable algorithm. Here is a dump of some random log data when stationary, parked inside a garage:
Appreciate the help
I have an interesting problem. I have a Raspberry Pi 5 with a GPS receiver mounted to a tractor. I am trying to create an algorithm to determine if the tractor is truly moving or is stationary. The complexity comes in with GPS drift. When logging the GPS data, when stationary, I can see the GPVTG message returning speeds in the .1 mph -> 3 mph range. My original approach was too simple, if gps_speed_mph > 1 then isMoving = true. This approach led to many false positives. To further complicate the issue, the tractor could be driving through a field under trees, or may be parked inside a garage, leading to noisy GPS data. I have speed / lat / long / heading /etc available, but need to come up with a reliable algorithm. Here is a dump of some random log data when stationary, parked inside a garage:
Code: Select all
system_date_time gps_date_time speed_mph lat long gps_quality gps_num_sats distance_traveled_ft heading hdop
2025年10月22日T21:52:12.701970+00:00 21:52:12+00:00 0.66 37.02134033 -120.598327 1 7 19.904 64.486 2.26
2025年10月22日T21:53:42.273312+00:00 21:53:42+00:00 0.35 37.02141267 -120.5981348 1 7 15.464 254.497 2.33
2025年10月22日T21:53:04.264424+00:00 21:53:04+00:00 0.97 37.02142317 -120.5980593 1 7 9.194 71.876 2.3
2025年10月22日T21:53:46.274223+00:00 21:53:46+00:00 0.13 37.02140133 -120.5981608 1 7 8.629 241.353 2.33
2025年10月22日T21:53:25.269364+00:00 21:53:25+00:00 0.32 37.0214265 -120.5980785 1 7 7.774 254.121 2.31
2025年10月22日T21:51:53.151844+00:00 21:51:52+00:00 1.02 37.02130767 -120.5984167 1 7 7.664 67.617 2.24
2025年10月22日T21:52:17.703209+00:00 21:52:17+00:00 1.53 37.02135083 -120.5982912 1 7 7.186 63.92 2.26
2025年10月22日T21:55:07.450906+00:00 21:55:07+00:00 0.18 37.0213305 -120.5982068 1 7 7.009 262.012 2.39
2025年10月22日T21:52:58.712870+00:00 21:52:58+00:00 0.4 37.02141467 -120.5980925 1 7 6.792 70.645 2.29
2025年10月22日T21:53:38.272412+00:00 21:53:38+00:00 1.25 37.021424 -120.5980837 1 7 6.678 255.22 2.32
2025年10月22日T21:53:50.275118+00:00 21:53:50+00:00 0.17 37.02139283 -120.5981797 1 6 6.303 240.53 3.3
2025年10月22日T21:50:58.629426+00:00 21:50:58+00:00 0.21 37.02132517 -120.5984745 1 7 6.05 251.253 2.2
2025年10月22日T21:55:20.453969+00:00 21:55:20+00:00 1.01 37.02133633 -120.598229 1 7 5.928 255.13 2.4
2025年10月22日T21:49:11.178277+00:00 21:49:10+00:00 0.21 37.02131317 -120.598494 1 9 5.894 71.336 1.21
2025年10月22日T21:51:29.145976+00:00 21:51:28+00:00 0.78 37.02132217 -120.5984242 1 7 5.768 75.346 2.22
2025年10月22日T21:50:46.626419+00:00 21:50:46+00:00 0.17 37.02133 -120.5984487 1 7 5.201 258.55 2.19
2025年10月22日T21:49:19.180239+00:00 21:49:18+00:00 0.2 37.02132067 -120.5984757 1 7 5.17 61.922 2.13
2025年10月22日T21:55:53.461651+00:00 21:55:53+00:00 0.41 37.02135667 -120.5981983 1 7 5.074 66.706 2.43
2025年10月22日T21:51:58.153052+00:00 21:51:57+00:00 1.45 37.02131467 -120.5984018 1 7 4.746 44.109 2.25
2025年10月22日T21:50:33.623124+00:00 21:50:33+00:00 0.09 37.02132517 -120.5984098 1 7 4.675 265.524 2.18
2025年10月22日T21:52:21.704206+00:00 21:52:21+00:00 1.26 37.0213535 -120.5982765 1 7 4.383 77.158 2.26
2025年10月22日T21:51:43.149294+00:00 21:51:43+00:00 1.37 37.02130517 -120.5984408 1 7 4.332 48.681 2.23
2025年10月22日T21:52:28.705825+00:00 21:52:28+00:00 1.9 37.021362 -120.5982517 1 7 4.17 66.815 2.27
2025年10月22日T21:55:47.460227+00:00 21:55:47+00:00 0.18 37.02135117 -120.5982143 1 7 4.104 59.735 2.43
2025年10月22日T21:52:13.702215+00:00 21:52:13+00:00 0.34 37.02134217 -120.5983133 1 7 4.038 80.431 2.26
2025年10月22日T21:50:08.617066+00:00 21:50:08+00:00 0.81 37.021316 -120.5984188 1 7 4.011 78.617 2.16
2025年10月22日T21:52:55.712159+00:00 21:52:55+00:00 0.51 37.0214085 -120.5981145 1 7 3.82 72.379 2.29
2025年10月22日T21:51:39.148364+00:00 21:51:38+00:00 0.82 37.02129733 -120.598452 1 7 3.655 226.947 2.23
2025年10月22日T21:49:50.187411+00:00 21:49:49+00:00 0.09 37.02131583 -120.598459 1 7 3.574 243.703 2.15
2025年10月22日T21:55:08.451157+00:00 21:55:08+00:00 1.26 37.0213325 -120.598195 1 7 3.522 78.044 2.39
2025年10月22日T21:55:57.462608+00:00 21:55:57+00:00 0.18 37.0213595 -120.5981905 1 7 3.517 69.79 2.43
2025年10月22日T21:53:28.270058+00:00 21:53:28+00:00 0.41 37.02142717 -120.5980682 1 7 3.316 75.081 2.32
2025年10月22日T21:56:01.463641+00:00 21:56:01+00:00 0.55 37.02135833 -120.5982035 1 6 3.164 265.569 7.67
Re: GPS Stationary Algorithm
Can you average out the drift over a few readings?
Re: GPS Stationary Algorithm
Maybe you have to accept that GPS technology is inherently unreliable with respect to absolute position at any given time. And that as a consequence, since you cannot determine change of position, you cannot calculate speed either.
Perhaps you need recourse to a 'Second Opinion.' An accelerometer maybe?
Beware of the Leopard
- terribleted
- Posts: 2025
- Joined: Tue Oct 06, 2020 8:07 pm
Re: GPS Stationary Algorithm
well, pseodo-random error. there is random error (uncertainty) plus changing atmospheric could be a small effect.
differential GPS is an option, but i like the averaging approach.
i have GPS on my camper (RV), and speeds of up to a few miles per hour are occasional when i'm stationary. the camper colllects one/hr.
but you could also ask for 2 in a row above 1 to set the "moving flag". thats way less likely.
differential GPS is an option, but i like the averaging approach.
i have GPS on my camper (RV), and speeds of up to a few miles per hour are occasional when i'm stationary. the camper colllects one/hr.
but you could also ask for 2 in a row above 1 to set the "moving flag". thats way less likely.
The only people that don't make mistakes are people that don't do anything.
Re: GPS Stationary Algorithm
This is a common problem and one that has been dealt with by many different industries including agricultural machinery.
As you've discovered a GPS signal is "noisy". The position jumps about but in the long term, the average will be close to your actual position.
Inertial Motion Units (including accelerometers and gyroscopes) have the opposite problem, over the long term they will drift but they are stable in the short term.
The solution is to mathematically combine the data from both to give a more stable and long term accurate position. Kalman filters are common in this area.
Edit: Another solution is odometery. If the wheels aren't turning, you aren't moving. The speed of the wheels is fed in to the navigation algorithm and used to aid the position accuracy
As mentioned above, DGPS can help too.
Another consideration is the position of your antenna. If it is on the end of a long pole held above your tractor and the fields are bumpy and uneven, the antenna can often be tilted +/- 2m either direction from where the wheels are. You need to also take in to account the tilt of the vehicle to adjust for the effect of this.
As you've discovered a GPS signal is "noisy". The position jumps about but in the long term, the average will be close to your actual position.
Inertial Motion Units (including accelerometers and gyroscopes) have the opposite problem, over the long term they will drift but they are stable in the short term.
The solution is to mathematically combine the data from both to give a more stable and long term accurate position. Kalman filters are common in this area.
Edit: Another solution is odometery. If the wheels aren't turning, you aren't moving. The speed of the wheels is fed in to the navigation algorithm and used to aid the position accuracy
As mentioned above, DGPS can help too.
Another consideration is the position of your antenna. If it is on the end of a long pole held above your tractor and the fields are bumpy and uneven, the antenna can often be tilted +/- 2m either direction from where the wheels are. You need to also take in to account the tilt of the vehicle to adjust for the effect of this.
Last edited by scotty101 on Fri Oct 24, 2025 10:54 am, edited 1 time in total.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter
Pi Interests: Home Automation, IOT, Python and Tkinter
Re: GPS Stationary Algorithm
The time stamps seem erratic.
Last time I looked at NMEA data (a long time ago) it was a very steady one report per second.
Is the irregularity on time sue to how you are sampling the data?
It's showing up to 19ft distance in some readings. I would think that if you use a rolling average of position over 10 to 30 seconds the jitter might average out and you can check the displacement between P(T=0) and P(T=20). If you don't need to know position with absolute high accuracy that might do to tell if the tractor is moving or stationary. You might exclude big distance readings, or reading with low gps_quality or low gps_num_stats.
Limit distance values to what makes sense for a tractor.
(削除) All that data shows only one satellite, which is junk data. (削除ここまで) Check the antenna. What do you get with the receiver mounted with a good view of the sky, off the tractor and away from sources of interference?
Code: Select all
2025年10月22日T21:52:55.712159+00:00 21:52:55+00:00 0.51 37.0214085 -120.5981145 1 7 3.82 72.379 2.29
2025年10月22日T21:51:39.148364+00:00 21:51:38+00:00 0.82 37.02129733 -120.598452 1 7 3.655 226.947 2.23
2025年10月22日T21:49:50.187411+00:00 21:49:49+00:00 0.09 37.02131583 -120.598459 1 7 3.574 243.703 2.15
Is the irregularity on time sue to how you are sampling the data?
It's showing up to 19ft distance in some readings. I would think that if you use a rolling average of position over 10 to 30 seconds the jitter might average out and you can check the displacement between P(T=0) and P(T=20). If you don't need to know position with absolute high accuracy that might do to tell if the tractor is moving or stationary. You might exclude big distance readings, or reading with low gps_quality or low gps_num_stats.
Limit distance values to what makes sense for a tractor.
Last edited by PiGraham on Fri Oct 24, 2025 3:33 pm, edited 1 time in total.
Re: GPS Stationary Algorithm
I tried a cheap USB gps on my pi and I get good results, have you got a reception problem ?
Code: Select all
Location: 34.619266 N 1.0541566 W Time: 13:03:22 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:23 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:24 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:25 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:26 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:27 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:28 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:29 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:30 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:31 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:32 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:33 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:34 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:35 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:36 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:37 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:38 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:39 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:40 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:41 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:42 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:43 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:44 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:45 Date: 25/10/24 Speed: 0.00 Fix: 1
Location: 34.619266 N 1.0541566 W Time: 13:03:46 Date: 25/10/24 Speed: 0.00 Fix: 1Code: Select all
#!/usr/bin/python3
import serial
import os, sys
import time
import datetime
import re
import shutil
from decimal import *
getcontext().prec = 8
gps_period = 1 # time ,in seconds, between logged gps data
# log data
log = 1 # set log = 1 to log data
# set variables
gpsfound = 2
fix = 0
start = time.time()
gps_data = ""
gps_text = ""
gps_date = ""
gps_time = ""
gps2 = ["?"] * 12
if os.path.exists('/dev/ttyUSB0') == True:
gpsfound = 0
ser = serial.Serial('/dev/ttyUSB0',4800,timeout = 10)
elif os.path.exists('/dev/ttyUSB1') == True:
gpsfound = 1
ser = serial.Serial('/dev/ttyUSB1',4800,timeout = 10)
while True:
# read gps data
if gpsfound < 2:
try:
gps_data = ser.readline()
#print (gps_data)
if sys.version_info[0] == 3:
gps_data = gps_data.decode("utf-8","ignore")
except OSError:
try:
fix = 0
gps_text = ""
if os.path.exists('/dev/ttyUSB0') == True:
gpsfound = 0
ser = serial.Serial('/dev/ttyUSB0',4800,timeout = 10)
elif os.path.exists('/dev/ttyUSB1') == True:
gpsfound = 1
ser = serial.Serial('/dev/ttyUSB1',4800,timeout = 10)
except OSError:
pass
else:
try:
fix = 0
gps_text = ""
if os.path.exists('/dev/ttyUSB0') == True:
gpsfound = 0
ser = serial.Serial('/dev/ttyUSB0',4800,timeout = 10)
elif os.path.exists('/dev/ttyUSB1') == True:
gpsfound = 1
ser = serial.Serial('/dev/ttyUSB1',4800,timeout = 10)
except OSError:
pass
# check checksum
if gps_data[0:1] == "$":
gps_data = gps_data.rstrip('\n')
cksum = gps_data[len(gps_data) - 3:]
chksumdata = re.sub("(\n|\r\n)","", gps_data[gps_data.find("$")+1:gps_data.find("*")])
csum = 0
for c in chksumdata:
csum ^= ord(c)
if hex(csum) == hex(int(cksum, 16)):
# check for GPGGA sentences
if gps_data[1:6] == "GPGGA":
fix = 0
gps_data2 = gps_data
gps1 = gps_data.split(',',12)
if len(gps_data) > 68 and (gps1[3] == "N" or gps1[3] == "S"):
fix = int(gps1[6])
if fix > 0:
lat1 = int(gps1[2][0:2])
lat2 = float(gps1[2]) - (lat1*100)
lat = lat1 + lat2/60
lon1 = int(gps1[4][0:3])
lon2 = float(gps1[4]) - (lon1*100)
lon = lon1 + lon2/60
gps_time = gps1[1][0:6]
gps_text = "Location: "+str(lat)[0:9]+" "+gps1[3]+" "+str(lon)[0:9]+" "+gps1[5]+" Time: "+gps_time[0:2]+":"+gps_time[2:4]+":"+gps_time[4:6]+" Date: "+gps_date[4:6]+"/"+ gps_date[2:4]+"/"+ gps_date[0:2] + " Speed: " + str(gps2[7]) + " Fix: " + str(fix)
print(gps_text)
# log data if enabled
if log == 1 :
with open("log.txt", "a") as file:
file.write(gps_text + "\n")
time.sleep(0.1)
if fix > 0 and gps_text != "":
if gps_data[1:6] == "GPRMC":
gps2 = gps_data.split(',',12)
gps_date = gps2[9]
Re: GPS Stationary Algorithm
I know nothing much about tractors but would the obvious test for being stationary not be that the gear box is in neutral ?
Re: GPS Stationary Algorithm
At work a few years ago I made a prototype GPS application where I used a Moving Average function to dampen the noise of the GPS coordinates. I averaged latitude and longitude separately of course.
Return to "Automation, sensing and robotics"
Jump to
- Community
- General discussion
- Announcements
- Other languages
- Deutsch
- Español
- Français
- Italiano
- Nederlands
- 日本語
- Polski
- Português
- Русский
- Türkçe
- User groups and events
- Raspberry Pi Official Magazine
- Using the Raspberry Pi
- Beginners
- Troubleshooting
- Advanced users
- Assistive technology and accessibility
- Education
- Picademy
- Teaching and learning resources
- Staffroom, classroom and projects
- Astro Pi
- Mathematica
- High Altitude Balloon
- Weather station
- Programming
- C/C++
- Java
- Python
- Scratch
- Other programming languages
- Windows 10 for IoT
- Wolfram Language
- Bare metal, Assembly language
- Graphics programming
- OpenGLES
- OpenVG
- OpenMAX
- General programming discussion
- Projects
- Networking and servers
- Automation, sensing and robotics
- Graphics, sound and multimedia
- Other projects
- Media centres
- Gaming
- AIY Projects
- Hardware and peripherals
- Camera board
- Compute Module
- Official Display
- HATs and other add-ons
- Device Tree
- Interfacing (DSI, CSI, I2C, etc.)
- Keyboard computers (400, 500, 500+)
- Raspberry Pi Pico
- General
- SDK
- MicroPython
- Other RP2040 boards
- Zephyr
- Rust
- AI Accelerator
- AI Camera - IMX500
- Hailo
- Software
- Raspberry Pi OS
- Raspberry Pi Connect
- Raspberry Pi Desktop for PC and Mac
- Beta testing
- Other
- Android
- Debian
- FreeBSD
- Gentoo
- Linux Kernel
- NetBSD
- openSUSE
- Plan 9
- Puppy
- Arch
- Pidora / Fedora
- RISCOS
- Ubuntu
- Ye Olde Pi Shoppe
- For sale
- Wanted
- Off topic
- Off topic discussion