Categories
Electronics

Learning Python via GPS – Part 1

This shouldn’t be seen as a tutorial – there’s enough of them on the internet. This is just my notes as I wrote some stuff. Part 3 should have a complete write up with full code examples!

My last foray with Python turned out pretty neat – but you could tell I literally copied and pasted code together to make it work. Thats fine and all – but I wanted to actually start learning Python.

My first step in any language is the ubiquitous “Hello World!”, which, in Python, isn’t that difficult. Its a simple

print("Hello World")

Next, I figure out how to display the Fibonacci Sequence. I normally try this one as it starts to involve setting and getting variables, loops, includes math operators and combines it with outputting data. Again, not overly difficult.

loopCount = 1
num1 = 0
num2 = 1
maxIter = 100
print("0: 0")
while loopCount < maxIter:
    output = num1 + num2
    display = str(loopCount) + ": " + str(output)
    print(display)
    num1 = num2
    num2 = output
    loopCount = loopCount + 1

I still prefer CamelCase for my variables. I’ve been doing it for years and probably won’t stop.

I don’t use any shortcuts for this program and no shorthand for iterations – its designed just so I get used to the basic principles.

So after that I choose a project and dive into. Given the release of the Raspberry Pi Pico on 21/01/2021 that runs on either C++ or MicroPython I figured that it was the best tool for the job!

I grabbed one of the (many) cheap GPS Modules, paired it with a Pico, an Omnibus Board and a Pico Display (the last three all from Pimoroni) and set about making something.

I have a soft spot for GPS. I’m completely fascinated by it. I think it stems from my interest in the whole concept of time. GPS is known for (and its in its name) as a Positioning System – maps and directions. But it’s also a very very accurate time source. So accurate that when working out positions calculations have to be computed to figure out if parts of the earths atmosphere will interfere with time measurements. I’ve completed a fair few GPS projects in the past – and still working on others so with some limited knowledge of how these GPS Receivers works I figured it was the best to ease me into a new language.

The GPS receiver I’m using in this example is a Neo-6M. It has 4 pins, Power, Ground, TX and RX. The receiver can take a varying voltage level, but I’m used to providing it with 5V. Pins are, as best as I can figure from various internet searches, both 3.3 and 5v tolerant. I did have a level shifter ready to go should it be required but there’s been no real issues yet.

To make working with receiver and Pico Display easier I’m using the Omnibus Board. This just exposes the Pico’s pins for easier prototyping.

I started by program by laying out the basics. The Pico has a built in UART with pins defined for serial transmission and receiving. Hooking my receivers power, then TX up to the Pico’s RX, and likewise the RX up to the Picos TX was all the wiring required.

Using MicroPython getting the UART enabled is as simple as

from machine import UART,Pin
uart = UART(0,baudrate=9600, tx=Pin(0), rx=Pin(1), bits=8, parity=None, stop=1)
if uart.any(): rcvChar = uart.readline()
    line = rcvChar.decode("ascii") #print(line)

and that nets you some responses:

$GPRMC,112435.00,V,,,,,,,120321,,,N*7E
$GPGGA,112435.00,,,,,0,00,99.99,,,,,,*66
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30

These responses confirm to the NMEA (National Marine Electronics Association) 0183 standard . Each one begins with a $ symbol, the next 5 characters is made up of a two then three character code. The two character code called an Identifier – GP in this case – lets us know that this data has came from a Global Positioning System receiver.

GPS isn’t the only system in use – you also have BeiDou (China), Galileo (Europe), GLONASS (Russia), QZSS (Japan), and others. Some only work in certain regional areas, others provide worldwide coverage. The majority of receivers I have only work with GPS but I’m eyeing up a GLOSNASS one next – hopefully with a Galileo receiver also (as long as it dissent go down).

The next 3 are the Sentence Identifier – and signal what kind of information is being transmitted. The most common are RMC, GSA, GGA, GSV, GLL, VTG. Each one provides relevant information for use – some more relevant than others.

RMC – Recommended Minimum Navigation Information C
GSA – GPS DOP and active satellites
GGA – Global Positioning System Fix Data
GSV – Satellites in view
GLL – Geographic Position – Latitude/Longitude
VTG – Track made good and Ground speed

A phenomenal resource I use while dealing with NMEA sentence sis gpsd service daemon. I’ve used that program itself numerous times but the documentation they provide is excellent – view all about the sentences here.

In my example above I have only selected 3 specific sentences. All have came from a GPS receiver. The first, RMC is Recommended Minimum Navigation Information C, GGA is Global Positioning System Fix Data and GSA is GPS DOP and active satellites.

With the three sentences above (when I have a good signal) this allows me to get the current location , speed (in knots), type of GPS Signal, quality of GPS Signal, date and time. To filter all these sentences into the three I need a simple

if "$GPGSA" in line or "$GPRMC" in line or "$GPGGA" in line:

can be used. This was my first “Gotcha” in Python. I spent an unreasonable amount of time trying to figure out why

if "$GPGSA" or "$GPRMC" or "$GPGGA" in line:

wasn’t working and I didn’t realise I had to explicitly confirm each part of the or statement. Thanks to the Python Discord I was swiftly corrected!

An actual set of sentences (with my location removed) would look similar to

$GPRMC,102011.00,A,4444.55555,N,55555.55555,W,0.471,,120321,,,A*6D $GPGGA,102011.00,4444.55555,N,55555.55555,W,1,05,3.20,63.5,M,50.7,M,,*76
$GPGSA,A,3,24,10,23,12,15,,,,,,,,5.59,3.20,4.58*02

and then picking out what I need in Python turned out to be pretty simple. As each sentence is comma delimitated, I just had to split the sentence into an array using that comma. The end portion (with the *) is a checksum but I’ll come to that later.

if "$GPRMC" in line:
    RMC = line.split(",")
    fixTypeB = RMC[2] # FixTypeB : Status, A = Valid, V = Warning
    dateGPS = RMC[9] # dateGPS : Date, ddmmyy
    timeGPS = RMC[1] # timeGPS : UTC Time of position, hhmmss.ss
    speedKnots = RMC[7] # speedKnots : Speed over ground, knots

and this allowed me to access each item in this array individually.

I’m going to cap this post here as I think its getting long enough already. Without revealing all the code this should be enough to get you hooked up and receiving what data you need. Some loops and print statements will get you data right onto your terminal. Part 2 will cover the screen and dealing with errors (hopefully!).

Categories
Electronics Raspberry Pi

The Raspberry Pi Dash Cam Project – Post 1

I’ve been toying with the idea of building a dash cam using a Raspberry Pi for a while. Every now and then I’ll buy something I think I’ll need for the project, hoping that I would get some time to work on it.

I’ve had a few days holiday, and one of my aims was to at least build a prototype in the days I had off.

I haven’t built a prototype, but I have the majority of parts together and verified that they worked! And it was surprisingly easy, apart from a 1.8″ Display (more on that later!).

Firstly, why not just buy one? Because I think I can build this, and I think I can enhance it and add to it, especially if I splash out and buy a Raspberry Pi 2! Also, why not?

My plan is to have the Raspberry Pi Camera Module recording as soon as the Pi boots to an acceptable state. A GPS receiver should then log the current GPS Position, heading and speed to a text file, and hopefully output some of that to a display. Likewise, an accelerometer and gyroscope should hopefully offer some additional readings to show the standard of driving.I plan to power the Pi via the cars 12v source (the accessory port or cigarette lighter). I will also have to create a safe power circuit so that once the vehicle has been switched off, the Pi shutdown gracefully. I will also have to make sure that when the vehicle starts there won’t be any sharp spikes in electricity which could fry the Pi.

So far I have:
The Raspberry Pi (Model B – Model B Rev 2 if required)
Raspberry Pi Camera Module
A DS3231 RTC (i2c)
A GPS Receiver (UART)
1.8″ Display (SPI).

I have backed a BerryIMU, which has an accelerometer, gyroscope and magnetometer, which will connect over i2c, but that has still to be delivered.

To mount the camera to the window, I purchased some suction pads (the ones with nuts) and I’ll create a custom camera mount to use them with.

Yesterday and today I spent some time with the equipment I have to make sure it all works together, which, excluding the camera, it does! I’ve excluded the camera during this round of testing I want to get everything else working first. Heres the equipment, breadboard style. Please excuse the dust! The Pi was stuck behind my TV.

Heres a quick video of the Pi being powered up in my car, using the equipment I already had to hand. Sorry about the black box, but this GPS Receiver is pretty accurate!

Just now I’m running stock Raspbian, but I have also been playing with buildroot, specifically gamaral’s pre-built image.

https://www.youtube.com/watch?v=4Fjfqz6FxC8

It really does boot that quick. Once I have everything set up in Raspbian, i’m hoping a few more days of compiling will get me a full featured Dash Cam that boots that quickly using buildroot. I’m hoping that the recording will start within 5 seconds of power being applied.

All my goals for the system as pretty much listed above. I just have to start learning Python! Good think I backed another Kickstarter project!

With regards to the 1.8″ Display, that was a bit harder to set up.

I was under the impression the Display I had used a ST7735 driver, as everywhere online said thats what the display used. It doesn’t. It actually uses a HX8353 driver.

There is some commands below. Each command is on a separate line and should be executed separately.

I had to install a custom version of the Raspberry Pi’s firmware, developed by notro using this command:

sudo REPO_URI=https://github.com/notro/rpi-firmware rpi-update

and then

sudo reboot

This custom firmware contains all the drivers needed to use the screen on the Pi. I could compile the software myself, but this is a proof-of-concept to make sure everything works. I then shut down the Pi, and hooked up the display as per this wiring diagram (please excuse the rubbish 5 minute job):

hx8353d

One thing to note is that I hooked the Backlight directly to 5v, so the backlight is always on when power is applied to the screen.

I then fired the Pi up, and typed the following commands:

sudo modprobe fbtft dma
sudo modprobe fbtft_device custom name=fb_hx8353d  gpios=reset:25,dc:24 speed=16000000 rotate=270 bgr=1
con2fbmap 1 1

This gave me the console on the screen. I then modified /etc/modules  (using sudo nano /etc/modules), and inserted the following lines at the end

fbtft dma
fbtft_device custom name=fb_hx8353d  gpios=reset:25,dc:24 speed=16000000 rotate=270 bgr=1

It’s as easy as that!

Now, to learn Python!

Categories
Electronics Equipment Raspberry Pi

A case for my Raspberry Pi!

Heres a quick 7 minute video about a case I purchased for the Raspberry Pi that only cost £4 from eBay!