Raspberry Pi Powered GPS Tracker

Liam Davies

Issue 54, January 2022

This article includes additional downloadable resources.
Please log in to access.

Log in

Track your valuables from across the street (or country) with this Raspberry Pi Zero-powered GPS Tracker.

If you’ve watched lockpicking videos on YouTube (for entertainment, of course), you’ll know how scarily easy it is to break locks and chains that are generally regarded as secure. Even if it isn’t lockpicking, bolt cutters, a crowbar or a quick run with an angle grinder is usually enough to break into or open most locks.

This makes a quick café stop or shopping browse a bit of a nerve-wracking experience, whether you have an expensive bike sitting on a nearby telegraph pole or your pride-and-joy project car parked in the street.

It’s probably safe to say there is no 100% effective proactive safety measure for theft (i.e. preventing it before it occurs), so reliably tracking the whereabouts of an item after it’s stolen is a very good alternative. The concept of a GPS tracker is becoming increasingly popular, affordable and compact. Thanks to clever low-power tech, Apple recently released their new AirTag system that doesn’t use GPS at all – instead opting for a clever Bluetooth Low Energy network for location detection.

But we aren’t Apple, and we don’t have a gigantic software deployment network to roll out our own new and innovative tracking systems. We’ll have to be a little last-century and opt for old-fashioned GPS.

So then, why have we opted to build our own instead of choosing one of the many commercial options available on the market? As makers, we often have specific needs for the projects and devices we make and use on a regular basis. Sometimes, a pre-made solution won’t cut it. For example, GPS trackers intended for use with cars and caravans often have an inbuilt engine immobiliser signal, but no additional expandable pins if other functionality is desired. From experience, we’ve also seen various software packages offered by manufacturers who design these systems which makes setup slow or confusing.

This project opens the door to integrating this tech into just about any maker project you have in mind. If you need to be able to drive a motor, run a weather station or collect any form of data in a remote area with no WiFi, then the 4G and GPS system we’re going to be using will be a good candidate!

This project will be set up to integrate into an E-Bike which, due to their relatively high value, are frequently stolen or damaged by opportunists. Of course, it could be easily placed in any other vehicle or device with a power source. You may have to get creative and design your own circuit for powering it!

How It Works

Our GPS Tracker will work quite similarly to other GPS modules on the market, with the exception that ours is powered with the Raspberry Pi Zero W! We absolutely love these little guys because of their bang for buck. For the rough price of a coffee and a ham-and-cheese sandwich, you get enough processing power to play Minecraft, run Tensorflow and browse the web. Sure, it’s not a supercomputer and struggles with running large computations, but for something that is literally smaller than an Arduino Uno, nothing really beats it. It only uses around 120mA-150mA in regular use!

To add GPS and 4G connectivity to our project, we’re using the Waveshare 7600 HAT that sits snugly right on top of the Pi Zero, no extra wires needed. There are of course other methods to adding GPS or cellular connectivity to a DIY project, including a multitude of different modules available across most electronics vendors for both Arduino and Raspberry Pi. But considering the modest power draw of 160-180mA, reasonable price and small form factor, we couldn’t go past this little Waveshare module. It also throws in a full 4G and GPS antenna, as well as standoffs and screws.

If you’re looking to make a project with GSM connectivity, it’s very important that you check that mobile service providers in your country support the network you’re planning to use. Here in Australia, there is no longer support or infrastructure for 2G networks. That means that it’s not a great idea buying a module that only has support for 2G, because it won’t work!

3G isn’t off the hook either –Telstra Australia will decommission their 3G networks midyear 2024 so it’s worth thinking about getting a 4G module (as we did) to remain relatively future-proof. If you don’t want to bother with the hassle of getting a GSM module, it’s possible to use local radio communication like LoRA to report the GPS position of your item.

To communicate the GPS to the owner, we’re using a simple SMS messaging system. While there may be easier ways to accomplish position reporting, such as using mobile data to transmit GPS data to a tracking website, we’ve opted to keep it simple and just send an SMS with the trackers current position. Using SMS is, of course, not free. It requires a mobile number and a registered account with a service provider in your area. We opted to go with ALDImobile for this project, and picked up one of their $5 prepaid SIMs. Spoiler alert – we got through the whole development and testing project without even using a dollar in credit!

Power Source

We also need to discuss the power source for this project. It’d be unrealistic to expect a project that can both communicate with the 4G and GPS network to use peanuts for power (At least in 2022!). That puts solutions like coin-cell batteries and small Lithium-Ion batteries out of the equation. Depending on the item you plan to use the tracker with, you’ll need to plan your primary power source accordingly. For a car or caravan, this device could be powered off the battery, with a small backup battery should it be disconnected or run flat.

When it comes to bikes – the other item likely to be used with this device – a little more planning is required. While the installation of our GPS tracker will be done with an E-Bike and so a readily available source of energy can be sourced, it’s nonetheless worth addressing how this could be used with a standard bicycle. One solution is to power the tracker from a Lithium-Ion power bank that provides multiple hours of position reporting. When the bike is at home, it would need to be charged in much the same way as bike lights or electric horns.

Another method to power our tracker is to use a Dynamo, which simply uses the rotational energy of a bike wheel to provide electrical power. Dynamo-powered bike lights have been around for a long time, and while it’s going out of fashion (especially for high-end bikes), a compact Dynamo to power our GPS tracker will save the hassle of charging it all the time.

Regardless of our power source, we need also to consider carefully how much power will be used while the GPS tracker is active and determine a good method of managing this power. From our own experiments, the Raspberry Pi Zero W seems to use around 120-140mA in regular use, which varies under heavy processing loads. With the GPS/4G module attached and transmitting, it increases up to 200-320mA.


Our installation of the project will be done on a Giant E-Bike (A Fathom E+ 3 2019, to be precise) which is a fairly common brand in Australia. Since Ebikes have a huge internal battery of about half a kilowatt-hour or so, there is plenty of juice to keep the GPS Tracker running. If no electric assistance is used, we can keep the tracker running on 1.5W for:

400Wh / 1.5W = 267 Hours

That’s plenty of time to use and communicate with the tracker. From a practical standpoint, we’re only really looking to use the tracker for 5-10 hours in the worst-case scenario – i.e. if it gets stolen.

Giant E-Bikes include a 6V connector internally for use with aftermarket headlights, which can be enabled or disabled from the handlebars. By default, the headlights are turned on when the bike is on and can output 500mA, so about 3W total power. However, because this output is not enabled while the bike is off, we can’t solely rely on this power source. The thief may also inadvertently disable the headlights on the handlebar controller.

To help ‘buffer’ the power required, we’re also adding a small 1100mAh Lithium-Ion battery that can keep the tracker running for a couple of hours without any assistance from the main battery. Together with a Boost/Charge module from DFRobot, this should handle our charging regulation and protection for us. Handy!


Where to put the GPS tracker will, of course, come down to the individual needs of the project. If you want your tracker to be undetectable or very hard to find, it will need to be concealed within the tracked item. In a car, this is fairly simple as there are many cavities that can be used to hide items. The boot lining, behind the glovebox or beneath the centre console comes to mind. 12V battery power can be found in most areas within a car so it’s not hard to get power to the system.

In a bike, this is quite a bit harder since there isn’t much that is hidden from view. E-Bikes, in particular, have enough space for internal cable routing, which if managed carefully can be ran nearby our GPS Tracker. The downtube in Giant E-bikes has nearly an inch of vertical clearance, which is probably enough to jam it in there. This, unfortunately, makes getting to the tracker frustrating, but the main issue with doing this is the signal loss. Since the GPS and 4G antennas would not have a clear view to the sky and are surrounded by metal, it’s likely that a weak or inconsistent signal will result. It would essentially act as a Faraday cage! Some commercial bike GPS trackers are designed to be inserted into the endcaps of the handlebars, which is a pretty clever way of keeping it hidden. You may need to get creative!

The next best solution is to hide it in plain sight. If it looks natural and doesn’t suggest that it communicates remotely, it’s probably safe enough to be used. That’s why in our project, we chose to mount it on the drink bottle holder, shaped as a ‘booster’ box for an E-Bike. It supposedly could "pretend" to have another bank of batteries inside it. To make it even more low-key, the bottle mounts are hollow, so cables can be routed directly inside the seatpost and to the cable harness.


We don’t need to have the tracker active while the owner is using it (on a bike, we need to save all the power we can). That’s why we’re adding the ability for the user to disarm the tracker by holding down a button for a couple of seconds. It’s important that the disarming process is not simple, to prevent thieves from doing it, but also not time consuming – otherwise, we could spend half an hour disarming every time we move the item or go for a ride/drive.

When the tracker is disarmed, it will enter “cooldown” period that expires once no movement is detected for that duration. This prevents the tracker being re-armed again immediately. A period of 5-20 minutes might be best for this, but we’re making all the parameters for this project tweakable in code.

If the tracker was moved and not disarmed after a couple of seconds, we can assume the rider does not know that the bike is being tracked and is of malicious intent. At this point, we can immediately alert the owner via SMS.


If desired, a movement-driven alarm could be added to the bike to be set off whenever it’s continuously moved without first disarming the tracker. This would both alert the owner and startle the thief, however, there are some downsides to this. If a thief is aware the item is tracked or alarmed, they may dispose of it, intentionally damage it, or destroy the tracker. It’s up to you to decide to make the system super stealthy or to make it as loud as the New Years fireworks!

Fundamental Build

Our fundamental build will be dedicated to developing the code and basic power circuit with the ATtiny85. We’ll also make sure the Pi is behaving and we can get some GPS output on it.

Movement Trigger Circuit

The movement trigger circuit we’re going to make is a very handy one – even if making a GPS tracker is not something you find interesting, this would be useful for anything from motion activated lights to a DIY drum kit system. Essentially, its purpose is to turn on a MOSFET for a certain amount of time if motion is detected. Just about any electronic hardware can be driven by a MOSFET, so this is quite a universal circuit! It’s also very accurate and fully configurable thanks to the addition of a sensitivity adjuster and an ATtiny85 for timing.


First up, we’re adding the LM393 voltage comparator to the breadboard and connecting its power pins. This is a low power comparator, so it’s suitable for usage in situations where battery life is of concern. We next added a 1MΩ potentiometer for setting the threshold voltage. This needs a connection to 5V and Ground, and the middle pin can go to Pin 2 on the voltage comparator. We used a large 1MΩ potentiometer (as opposed to 10kΩ, for example) to reduce power draw.

As we’ll shortly see, the purpose of the comparator is to compare the signal of our vibration sensor with a ‘threshold voltage’, set by the potentiometer. If the signal of the vibration sensor exceeds that of the vibration sensor, it triggers the ATtiny85 (which we’ll add shortly) to wake up.

Now we can add our vibration sensor. We opted to use a weighted piezoelectric element that generates a voltage when bent. These are very simple but highly effective devices – if left to free-float in mid-air, any sudden movement will vibrate the closely spaced electrodes, which can then be used for detection.

It’s worth noting that the voltage generated by these units isn’t safe to feed into a microcontroller! We measured spikes of around 40VDC on our oscilloscope when giving the sensor a good whack. Although the current is insignificant, it’ll be jumping about on a bike or car generating large voltages so it’s important we properly handle the signal.

We first added a 1MΩ resistor between the terminals of the sensor to calm down any sudden spikes, and for a little bit of insurance, we popped in two 5.1V Zener diodes to send any remaining voltage to the power rails. If you’ve never seen this configuration before, Zener diodes are handy in that they can be used to reliably kill dangerous voltages from circuits (dangerous to level-sensitive electronics, that is). If a higher reverse voltage than the Zener voltage is applied to it, it’ll become conductive and (hopefully) regulate the original voltage to a safe level. In the configuration we have, any voltage greater than 5.1V or less than -5.1V is shorted to Ground or 5V.

Note that later, we removed the Zener between 5V and the vibration sensor as it was generating a voltage that prevented the vibration sensor from working correctly. It could have been something simple, but we didn’t get around to properly working it out.

fundamental build

Parts Required:JaycarAltronicsPakronics
1 x LM393 Low-Power ComparatorZL3393Z2558-
1 x ATtiny85^ZZ8721Z5105-
2 x 10kΩ Resistors*RR0596R0582SS110990043
1 x 1MΩ Resistor*RR0644R0630SS110990043
1 x 100Ω Resistor*RR0548R0534SS110990043
1 x 1MΩ Linear Horizontal PotentiometerRT4658R2394A-
1 x BC547 (or other similar NPN) Transistor*ZT2326Z1040DF-FIT0322
1 x 12mm x 12mm Pushbutton*SP0609S1135ADA1119
2 x 5.1V Zener Diodes*ZR1403Z0614-
1 x Weighted Vibration Sensor--SS314070001
1 x Raspberry Pi Zero W-Z6303A #-
1 x SIM7600G-H 4G HAT-Core Electronics CE07877-

Parts Required:

Prototyping Equipment Required.
* Quantity shown, may be sold in packs.
^Additional programming equipment required. See Issue 14, August 2018, "ATDEV For ATtiny" for more details.
#Sold as a starter pack

Next up, we’re adding in the humble ATtiny85. The ATtiny85 is one of our favourite microcontrollers, because of its cost and size effectiveness. For a couple of bucks, you get a microcontroller with a decent memory, good processing speed, and a bunch of GPIOs! It really makes the difference with projects like this, as it provides a simple alternative to a much beefer fully-fledged Arduino board.

So, to the point, what are we actually using it for? Essentially, the ATtiny85 will act as a processing centre for deciding whether or not the Pi should be turned on. If the comparator detects a movement, the ATtiny85 will turn on the Pi for a set amount of time. Further movements will also prolong the ‘on’ time, while holding the disarm button will turn off the Pi. This could be done with a much more electrically simple circuit using, for example, a 555 timer. However, if we desire repeatability and accuracy, a microcontroller that is accurate to microseconds will be much better for this type of control. It’s also possible to program better functionality into the system without changing any circuit components.

All the ATtiny85 needs is 5V power, a Ground connection, and a connection to one terminal of a pushbutton. The other terminal can go straight to ground – we’re using the ATtiny’s internal pullup resistors for the button.

On Pin 2, we’re adding the signal from the LM393 comparator, which must have a 10kΩ pullup resistor between Pin 1 and 5V.

Nearly finished! We just need to add the output power stage, which uses a basic NPN transistor and a MOSFET to switch on and off the Pi whenever needed. The transistor isn’t 100% necessary, but it ensures that the MOSFET is properly saturated and won’t operate in its linear region.

The USB connector we’re using is a simple breakout board just to test our setup. It’s not reliable since we haven’t soldered the connectors, but it’ll suffice for the Fundamental Build. From here, just plug a MicroUSB cable into the port and into the Raspberry Pi Zero’s power port!

The Code

This code will remain unchanged for the main build, and most of the important parameters are at the top of the code file. You can see the timeout periods for motion detection, the pin assignments and how long the button needs to be held in order to disarm the tracker. Note that you will need some sort of platform to program the ATtiny85 on! We have a guide in Issue 14 called "ATDEV For ATtiny" if you want to check out how to do that.

#include <avr/sleep.h>
#include <avr/interrupt.h>
//The signal from the LM393
const int switchPin = 3;
//The signal to the MOSFET
const int MOSFETPin= 2;
//The button pin to disarm the tracker.
const int disarmButton = 4;
//The duration where no movement must be detected //to shut down the tracker.
const unsigned long cooldownTime = 300000;
//How long the button must be held for in order to //disarm the tracker.
const int requiredDisarmHold = 3000;
bool hasFired = false;
unsigned long lastMovement = 0;
//Whether the tracker has been disarmed in this 
bool disarmed = false;
unsigned long lastDisarmPress = 0;
bool disarmPressed = false:

This code for the ATtiny85 uses quite a bit of register logic, so if you’re not fluent in low-level microcontroller programming, this might look a bit gibberish. All we’re essentially doing here is manipulating the timer and interrupt registers so it can enter and exit sleep mode the most efficiently. We may make a more in-depth tutorial in the future about what all these assignments are doing, so look out for that!

void sleep() {
    ADCSRA &= ~_BV(ADEN);
    ADCSRA |= _BV(ADEN);
} ISR(PCINT0_vect) {
    hasFired = true;

The upshot of all this code is that we’re able to wake the ATtiny when motion is detected, and put it to sleep either with a timeout or by disarming it with the button. You’ll notice with the loop code below that we’re doing quite a few checks to ensure that we’re not shutting down the Pi for no reason! Whenever we’re writing to the MOSFET pin, we’re literally turning on and off the Pi.

if(hasFired) {
      lastMovement = millis();
      hasFired = false;
    if(lastMovement + cooldownTime 
< millis() || disarmed) {
      disarmed = false;
      digitalWrite(MOSFETPin, LOW);
      lastMovement = millis();
    digitalWrite(MOSFETPin, HIGH);

Assembling the HAT

Depending on whether you’re using a Raspberry Pi Zero W or a regular Pi, connecting the 4G/GPS HAT is different but fairly straightforward either way.

To use it with a Zero W, simply screw on the included metal standoffs to sandwich the HAT. Once on reasonably tight (as vibrations will loosen screws), pop the Zero W on top and screw down. Somewhat uniquely, this HAT includes spring-loaded ‘pogo’ connectors that communicate directly with the Zero W without the use of soldering or obstruction of the GPIO headers. Ensure that the connectors are seated neatly on the correct pads as we had some intermittent connections problems as a result of the connectors not making good contact. There are two for power and two for the data lines on the USB port.

Speaking of the USB port, it’s worth noting that the 4G HAT also includes a 4-way USB hub! This essentially breaks out the single USB port of the Zero W into two USB-A ports, one unsoldered USB port, and one for the SIM module itself. This makes it super simple to hook into the Zero with a keyboard and mouse if necessary.

If you’re making this project with a regular-sized Raspberry Pi like a 3B+ or a 4, just use a Micro-USB cable to connect it directly to the Pi through its standard USB ports. Finally, we need to connect the two antennas required for operation. If you only need internet, phone or SMS functionality, just pop the included WiFi-style antenna SMA connector onto the ‘MAIN’ port. The GPS antenna has a very long cable and is connected to the ‘GNSS’ port in the same way. These are fiddly connectors so be patient, and don’t attempt to resolder them as they are shielded and are tuned to have the correct impedance.

Software Setup

This project already assumes you have a basic grasp of navigating Linux on the Raspberry Pi. We’re only using the command line as opposed to the regular Raspberry Pi Zero desktop environment. If this is confusing or you need a refresher, we have a guide for setting up SSH (Secure Shell) in our Smart Dog Trainer project which you can find in Issue 49 and 50.

We’ll start by installing Minicom. This is a relatively simple program that allows access to Serial ports, and is the equivalent of the Serial Monitor within the Arduino IDE. While we won’t use this for our final program, it’ll be invaluable for programming and debugging.

sudo apt-get install minicom
sudo minicom -D /dev/ttyUSB2

If you have the SIM module stacked on top of the Pi with the pogo pins, the module should be on USB2. Otherwise, you may need to use the ‘lsusb’ command to find it. To control the SIM module, we need to use AT Commands. Broadly, AT Commands are used to control modems of all shapes and sizes. It’s not exactly a new protocol as it’s been around for more than thirty years, but it still remains in use across applications including GSM communication as we’re using.

All AT Commands start with the phrase ‘AT’ (short for ATtention) and is then followed by a plus symbol, the command and then any data if necessary. At this point, we can use AT commands for interfacing with the module like this:

We can also receive GPS data by just using the AT+CGPSINFO command, which returns the latitude and longitude of the tracker's current position. In practice this command seems to have around a 5 metre accuracy. While it wouldn’t be good enough for precise measurement, this is pretty impressive for a relatively low-cost module that doesn’t require any additional hardware or configuration.

If you can’t find any GPS signal, note that it works significantly better when outside and with a clear view to the sky. It usually takes our module about a minute to get a signal fix, and it replies back with the exact latitude and longitude of the GPS module. With our final program, we’ll use the PySerial library to automatically send and receive commands with Python.

Now that we’ve checked our fundamental build is working, we can put together our final build. This process will vary quite a bit depending on the item you’re planning to install it in, so we suggest you account for the area it will be mounted. For example, installing it near an engine or motor may heat up and warp 3D printed plastic.

The Main Build

Bike Disassembly

To get to the 6V connector we’ll be using to power the GPS tracker, we’ll need to do a bit of poking around inside the bike. It should go without saying, you should be confident with voiding your warranty. You’ve been warned! We took off the plastic bashplate underneath the motor, then used 4 different tamperproof Torx bits and enough torque to kickstart a steam train to actually drop the motor.

Once we got to the wiring harness inside, there was a small unassuming white connector with a silicon sleeve for dust protection on it. After popping a multimeter on the terminals, we verified that turning on the bike’s headlights outputs 6V on this connector.

This is where we need to hook into so we can power our GPS Tracker! We stuck some standard jumper cables into the connector and wrapped it with electrical tape to hold it in place. We could’ve de-soldered the connector and attached our own but modifying a factory connector wasn’t something we were keen on.

At this point, we can begin routing the power cables through the seatpost. Since there isn’t any other hole besides the screw holes, we have to use one of the screw holes to route our cable. A bit of double sided tape will make up for the loss of mounting stability!

It’s best to purposely bend the cable downwards and then push it in, which should make sure the cable will make its way down the seatpost towards the motor. Once they are through, we just used two connector blocks to ensure a good connection between the 6V connector and the power wires. We’re not sure how this system will hold up in the wet or when it’s gets bashed about off road, but it should suffice for our project.


Before we use the DFRobot charge/boost board, we need to make a quick modification to it’s circuitry. It’s factory-set charge current is 2.5A, which is way too high for the 0.5A provided by the 6V headlight connector. To fix this, we need to change the Input Current Limit resistor, or Rlim as it’s referred to by the MP2636 datasheet. Instead of the default 15kΩ, we approximated 100kΩ would be a good value according to this equation:

Rlim = 43.3 kΩ / ( I + 0.05)

Rearranged, this gives us 0.383A which gives us headroom below the 500mA limit. To actually swap out the resistors, a little bit of fine solder work is needed to replace the original resistor with another 0603 SMD resistor. These things are deceptively tiny!

Now, the battery charges with a maximum of about 360mA-380mA, which is perfect! When the GPS tracker is active, the current is diverted to power the Raspberry Pi. Whatever is left is used to charge the battery.


To finish the electronics off, we’re making exactly the same circuit we described in the Fundamental Build, just quite a bit more compact and with JST connectors for easy attachment and detachment of components. For more details, check the Fritzing.

We’re using two sets of 8-pin DIP sockets so our ATTiny85 and LM393 can be reinserted when necessary. Since the ATTiny85 needs to be programmed outside of the GPS Tracker with a separate board, IC sockets are vital. The other thing we added was a 1MΩ horizontal trimpot for a sensitivity adjustment, a Zener diode for keeping the vibration sensor signal in check and a 10kΩ for pulling up the comparator output.

At this point, we need to start our power wiring and the transistor circuit. There are is a single white signal wire between the LM393 and the ATTiny85, in addition to a blue wire for turning on the NPN transistor. Don’t forget the red and black wires for 5V and Ground respectively!

We then slotted in the IRFZ44N MOSFET and the three sets of JST male connectors. In order from left to right, the connectors are for the Disarm Button, Power Out (to the Raspberry Pi) and Power In (from the battery board). There are a number of solder connections on the underside of the board, so pay attention to them!

We can now connect everything up! All of our power wiring uses the standard JST power wires which makes assembly a breeze and also fairly resistant to vibrations. Note that for the Raspberry Pi, we soldered two wires to the 5V and Ground solder pads right underneath the power USB port to save space.

We ended up stacking the power control board, the Raspberry Pi and the SIM HAT on top of each other, which we insulated from shorts with electrical and double-sided tape. Check out our 3D printed enclosure for how we put it all together!

Main Build (Parts Required in Addition To Fundamental Build)

Parts Required:IDJaycarAltronicsCore Electronics
1 x Lithium Ion 1100mAh Battery-S4724PAKR-A0300KIT-14478 /
1 x MP2636 Power Booster & Charger Module--DF-DFR0446CE04842
1 x White Dome PushbuttonSP0657S0961SS110990055Special Order
4 x Female JST XH Connectors*PT4457P5752ADA4423-
4 x Male JST XH Connectors*PT4457P5742ADA4423R7040
1 x PerfboardHP9552H0712ADA2670-
1 x 100kΩ 0603 Resistor*-R1740--

Parts Required:

* Quantity shown, may be sold in packs.

Final Program

We can finally get to writing our final program to control our GPS tracker!

This is all written in Python. While it’s not as efficient as Arduino C++/C code (as Python is a high-level language), Python code has access to many very handy libraries and programming tricks to make our lives much easier. To handle the SMS functionality itself, we wrote a Python library called SMServer that can send, receive and parse messages through the SIM7600 module. Here is one of the functions within the library:

def getMessage(self):
    s =
    number =""REC UNREAD","(+61d+)"", s.decode('utf-8'))
    message =
(""rn(.+)rnrnOKrn", s.decode('utf-8'))
    if message and number:
        return [[,]]
    return []

Because the SIM module communicates over Serial, we need to issue and parse the correct commands to receive our information. The first thing we do is we issue the command ‘AT+CMGL=”REC UNREAD”’ which essentially tells the module to return all current valid messages. Next, we read what was sent back on the Serial port and do a Regex search on the information.

Even though we wrote this code, the Regex ‘’ function is still somewhat confusing to us because of all the syntax involved. Essentially, a Regular Expression search will ‘pattern match’ certain parts of a string which allows arbitrary data formats to be parsed without tons of code. Take “"REC UNREAD","(+61d+)” for example. This pattern essentially matches any string that has “REC UNREAD” followed by some phone number with +61 at the beginning (I.e. an Australian number). Since the phone number is in parentheses, we can refer to this ‘group’ later and only pick out the phone number. The message parsing works in much the same way.

Google Maps

Instead of trying to design our own map rendering software or tracking system, Google Maps has us covered with a hilariously easy solution. Just provide the user with a link in this format!{latitude},{longitude}

To accomplish this, we wrote the below code to source the GPS latitude and longitude data from the GPS module. When the module returns its data, it isn’t in a user-friendly format. It is separated by commas and is in a HMS format, rather than decimal as is required by Google Maps. Much of our code is dedicated to filtering out this data and getting the right data points. We have to also account for the different hemispheres across the earth so the current + and – signs are added to the Google Maps link.

def generate_maps_link(self):
  info = str(
  #Removes CGPSINFO header
  info = info.split(": ")[1]
  #Splits into data points
  info = info.split(",")
  latitude_raw = float(info[0])/100
  latitude_raw = int(latitude_raw) + (5/3) * (float)((latitude_raw - int(latitude_raw)))
  if info[1] == 'S':
    latitude_raw *= -1
  longitude_raw = float(info[2])/100
  longitude_raw = int(longitude_raw) + (5/3) * (float)((longitude_raw - int(longitude_raw)))
  if info[3] == 'W':
    longitude_raw *= -1
  return f"{latitude_raw},{longitude_raw}"

The recipient’s device will usually format this as a link, which can be viewed as a red ‘pin’ in Google Maps. This is super accurate and a good visual way of locating where your item is located, down to where it might be in a particular room.

The only shortcoming with this solution is the lack of history tracking. If your item is on the move, there is no previous points to suggest where the item might be going. This could be fixed by using various online services, but you would need to use the 4G data connection instead of or alongside SMS messages.

With all the complicated stuff done, we can finally write our completed control code:

import sms
import time
s = sms.SMServer("/dev/ttyUSB2")
if s.connect():
print("Server running.")
messages = s.getMessage()
for sender,message in messages:
loc_url = s.generate_maps_link()
print(f"Generated Location Link: {loc_url}")
print(f"{sender} sent: {message}")
s.sendMessage(sender, f"Current location: {loc_url}")
except KeyboardInterrupt:
print("Shutting down...")

This code is much easier to read because it uses our SMS library. Because the GPS tracker will always be active when the Pi is online, we want a While loop to continuously poll for new messages and report back the location URL if necessary. This is a pretty basic setup, so a lot of additional functionality could be added here. Right now, we don’t care what the owner sends, as we’ll always return the GPS location. We could quite easily implement other functionality by checking if a message contains “LOCATION”, “SHUTDOWN” and so forth.

One last thing, we also need to go into the /etc/rc.local file and add this to run the GPS Tracker script when the Pi starts:

sudo python /home/pi/Tracker/ &

And we’re done! Lets get to 3D printing!

3D Printing

Depending on how you want to set up this project, you may want to design your own enclosure for your GPS tracker. We opted for a simple enclosure that sits around the seatpost and clamps with the drink bottle holder screws – or one of them, at least. The other holder screw will be used to route power cables for the GPS tracker.

To compact everything down, all parts inside the enclosure are very close together which can make assembly difficult. It’s best to take your time to avoid snapping any Antenna Connectors. The GPS antenna can be double-side taped to the top of the enclosure, and the 4G antenna is attached to the rear side using it’s SMA connector.

The Raspberry Pi itself is screwed to the back side of the enclosure using 4x 2.5mm screws. After that, we used double-sided tape and some glue to keep everything in place. You may wish to use some more robust mounting methods if your GPS tracker will be thrown around!


We’re always happy when projects we finish work decently well, and this is one of them. The Raspberry Pi is very reliable, and the SMS code works very well. While it does take some time to get a GPS fix, it reliably connects with a bit of patience and reports back to the owner.

Depending on the plan you’re using for the tracker, the texting costs can get a bit pricey so don’t go requesting its location every three seconds!

Our power management circuit with the ATtiny85 works perfectly, and the sensitivity adjustment really helps dialling in the right response. We set the sensitivity quite low, since if the bike needed to be moved without riding it, disarming it every single time can get quite annoying. We can’t imagine that a thief would be delicate while at work either – the tracker would surely be set off at some point.

With larger objects like cars, the sensitivity would need to be quite a lot higher to account for the much larger inertia – i.e. not as much vibration propagates through a car as compared to a bike.

We did have some problems packing everything inside the enclosure neatly due to time constraints, but we eventually got it in there and working.

Where To From Here?

If this was a commercial-quality tracker, it’d be important to do much more extensive testing otherwise some weird bugs could slip through. For example, during some of our initial tests, we managed to accidentally crash the Raspberry Pi by sending it an image over SMS. When you try and call it, the Pi freaks out and the program tries to reply to the automated voicemail notification! Of course, all these issues can be fixed if desired with a little elbow grease and some Python. For individual applications though, this tracker is more than adequate.

An additional feature that could be added to our tracker would be an engine immobiliser. This would allow the owner to remotely disable the vehicles operation and prevent it being moved any further. This is primarily targeted towards cars, where the ignition or fuel pump power is cut when a relay is opened. However, it could also be used with bikes to set off an alarm or disable the electric assist in the case of an E-bike.

It would also be possible to use the SIM module’s inbuilt 3.5mm headset/mic jack to communicate with anyone around the item. For example, the tracker could be called over phone to listen and the owner could talk over a loudspeaker if desired.

We were very impressed with the performance, compactness, and power usage of the SIM module we chose in particular. It would be suitable for any form of remote access, even if GPS access isn’t required – it can be used as an internet modem for the Raspberry Pi. Applications involving remote weather stations, environment data logging (e.g. soil or moisture measurements) or even webcams would be a great match for this setup.

Liam Davies

Liam Davies

DIYODE Staff Writer