Introduction: Tracking Module for Cyclists

This tracking module for cyclists is a module that automatically detects crashes in a race, and that detects a mechanical breakdown by touching a touch sensor. When one of these events happen, the module sends the event to a database on a raspberry pi via LoRa. This event will be shown on a LCD display and on a website. You can also search on the website for a specific cycling race with the events, and add cycling races or cyclists to the database. I made this project because I'am very interested in Cycling and IOT, so combining these two subjects was just very exciting for me.

Before you can make a tracking module for cyclists, you need to collect your materials. You can find the tools and supplies in the lists below, or you can download the BOM (Build Of Materials).


  • plexi glass (56mm X 85mm)
  • 10 X 2M bolts 10mm and nuts
  • 10 X 3M bolts 10mm and nuts
  • 2 X 3M bolts 50mm and nuts
  • PLA Filament to 3D-print your LCD case
  • heat shrink
  • Male to Female cables
  • A basic PCB
  • Male headers
  • A Raspberry Pi 3b+
  • A 16GB SD-card
  • A sparkfun 4X20 LCD
  • A capacitive touch sensor
  • A buzzer
  • A 3-axis accelero + gyro meter
  • A GPS module
  • A SODAQ Mbili board
  • A LoRa WAN module
  • A 3.7V 1000mAh battery
  • A Raspberry Pi 3b+ power supply


  • Solder tin
  • Soldering iron
  • Tongs
  • Screwdrivers
  • Jigsaw
  • Drilling machine
  • 2.5 and 3.5 drills
  • Lighter / hot air gun

If you need to buy all the supplies, you will need a €541.67 budget. This project is very expensive because I used a LoRa rappid development kit that costs €299 (I had the chance to use this kit from my school). You can always use a normal Arduino en save a lot of money, but the programs will be different then.

Step 1: Fritzing Scheme

The first step is to build the circuits. For this project we have 2 electrical circuits, one with a Raspberry Pi and one with a SADAQ Mbili board. We will start with the Raspberry Pi circuit.

Raspberry Pi Fritzing scheme:

The Raspberry Pi scheme is pretty simple, the only thing we connect with the Pi is an 4X20 Sparkfun LCD display. The Display works with Serial communication, SPI or I2C. Wich communication protocol you use is up to you. I used the SPI protocol because it is very simple. If you use SPI like me, you need the following connections:

  • VCC LCD --> VCC Raspberry Pi
  • GND LCD --> GND Raspberry Pi
  • SDI LCD --> MOSI (GPIO 10) Raspberry Pi
  • SDO LCD --> MISO (GPIO 9) Raspberry Pi
  • SCK LCD --> SCLK (GPIO 11) Raspberry Pi
  • CS LCD --> CS0 (GPIO 8) Raspberry Pi

On the Fritzing scheme you will see that the LCD display is a 2X16 display. This is because I didn't found a 4X20 LCD on frizting. However, all the connections are the some so it doesn't really matter.

SODAQ Mbili Fritzing scheme:

We will connect 4 electronic components with the SODAQ Mbili board, so this electrical scheme is also very simple. We will start with connecting the Capactive touch sensor. This sensors OUT-pin will be HIGH when the sensor is touched, and will be LOW otherwise. This means the OUT-pin is a digital output that we can connect with a digital input of the Mbili board. The connections are as following:

  • OUT touch sensor --> D5 Mbili
  • VCC touch sensor --> 3.3V Mbili
  • GND Touch sensor --> GND Mbili

The second component is the Triple acces + gyro sensor. I used the GY-521 board that uses the I2C protocol to communicate with the Mbili board. Notice that the AD0-pin of the GY-521 board needs to be connected with the VCC of the Mbili board! This is because the Mbili board has a clock with the same I2C address like the GY-521. By connecting the AD0-pin to VCC we change te I2C address of the GY-521. The connections are as following:

  • VCC GY-521 --> 3.3V Mbili
  • GND GY-521 --> GND Mbili
  • SCL GY-521 --> SCL Mbili
  • SDA GY-521 --> SDA Mbili
  • AD0 GY-521 --> 3.3V Mbili

Thereafter we will connect the Buzzer. I use the standard buzzer that makes a sound when there is a current. This means we can just connect the buzzer to a digital pin of the Mbili board. The connections are as following:

  • + Buzzer --> D4 Mbili
  • - Buzzer --> GND Mbili

Last but not least, we will connect the GPS module. The GPS module communicates via RX and TX. The connections are as following:

  • VCC GPS --> 3.3V Mbili
  • GND GPS --> GND Mbili
  • TX GPS --> RX Mbili
  • RX GPS --> TX Mbili

Step 2: Normalized Database

The second step is to design a normalized Database. I have designed my ERD in Mysql. You will see my database is written in the Dutch language, I will explain the tables over here.

Table 'ploeg':

This table is a table for the cyclings clubs. It contains a cycling club ID and a cycling club name.

Table 'renners':

This table is a table for the cyclists. Every cyclist has a LoRaID wich is also the Primary Key of the table. They also have a surname, first name, Country of origen and a cycling club ID which is linked to the cycling club table.

Table 'plaatsen':

This table is a table that stores the places in Belgium where a cycling race can take place. It contains the name of the city (wich is the Primary Key) and the province where the city is situated.

Table 'wedstrijden':

This table stores all the cycling races. The Primary Key of the table is a ID. The table also contains the name of the cycling race, the city of the race which is linked to the places table, the distance of the race, the category of the cyclists and the date of the race.

Table 'gebeurtenissen':

This tables stores all the events that happen. This means, when a cyclist is involved in a crash or has a mechanical breakdown, the event will be stored in this table. The Primary Key of the table is a ID. The table also contains the datetime of the event, the Latitude of the position, the Longitude of the position, the LoRaID of the cyclist and the type of event (crash or mechanical breakdown).

Table 'wedstrijdrenner':

This table is a table that is needed for a many to many relationship.

Step 3: Register Your LoRa Module

Before you can start with the code, you need to register your LoRa module in a LoRa gateway. I used a telecom company in Belgium called 'Proximus' that arranges the communication for my LoRa module. The data that I send with my LoRa node gathers on the website from AllThingsTalk. If you also want to use the AllThingsTalk API to collect your data, you can register here.

After you registerd on AllThingsTalk, you need to register your LoRa node. To do this, you can follow these steps or you can look on the picture above.

  1. Go the 'Devices' in the main menu
  2. Click on 'New Device'
  3. Select your LoRa node
  4. Fill in all the keys.

Now your done! All the data you send with your LoRa node will appear in your AllThingsTalk maker. If you have any problems with the registration, you can always consult the AllThingsTalk docs.

Step 4: The Code

For this project we will need 5 coding languages: HTML, CSS, Java Script, Python (Flask) and the Arduino language. First I will explain the Arduino program.

  1. The Arduino program:

In the beginnen of the program, I declaire some Global Variables. You will see that I use SoftwareSerial for the connection with my GPS. This is because the Mbili board only have 2 serial ports. You can connect the GPS to Serial0, but you won't be able to use the Arduino terminal for debugging then. This is the reason why I use a SoftwareSerial.

After the Global Variables, I declaire some functions that makes it easy to read the program. They read out the GPS coördinates, make the buzzer sound, sends values via LoRa, ...

The third block is the setup block. This block is the beginning of the program which sets up the pins, serial communication and the I2C communication.

After the setup block comes the main program. In the beginning of this main loop, I check if the touchsensor is active. If so, I make the buzzer sound, gets the GPS data and sends all the values via LoRa or Bluetooth to the Raspberry PI. After the touch sensor, I read out the values of the Accelerometer. With a formula I calculate the exact angle of the X and Y axis. If these values are to big, we can conclude that the cyclist crashed. When a crash happens, I make the buzzer sound again, get the GPS data and send all the values via LoRa or Bluetooth to the Raspberry PI.

You are probably thinking: 'Why do you user bluetooth and LoRa?'. This is because I had some trouble with the license of the LoRa module I used. So to make the program work for my demo's, I had to use Bluetooth for a while.

2. The back end:

The back end is a litle bit complex. I use Flask for my route's that are accessible for the front end, I use socketio to update some of the front end pages automatically, I use the GPIO pins to show messages on a LCD display and receive messages via Bluetooth (not needed if you use LoRa) and I use Threading and Timers to read regularly the AllThinksTalk API and start the flask server.

I also use the SQL database to store all the incomming crashes, read out the cyclists personal data and the races data. This database is connected to the back-end and also runs on the Raspberry Pi. I use a class '' to interact with the database.

As you know from the Fritzing scheme, the lcd is connected to the Raspberry Pi via the SPI protocol. To make it a litle more easy, i wrote a class ''. With this class you can change the contrast, change the backlight color, write messages on the screen, ... . If you want to use Bluetooth, you can use the '' class. This class rules the serial communication between the Bluetooth module and the Raspberry Pi. The only thing you need to do is connect a Bluetooth module to the Raspberry Pi by connecting the RX to the TX and virsa versa.

The routes for the front end are written with the @app.route rule. Here you can make your own custom route to insert or get data into or from the database. Make sure you always have a response at the end of the route. I always return a JSON object to the front end, even when an error occured. You can use a variable in the url by placing <> arround the variable.

I use socketio for the webpage with the crashes of a race. When the Raspberry Pi receives a crash, I emit a message to the front end via socketio. The front end then knows that they have to read out the database again because there was a new crash.

You will see that in my code the LoRa communication are set in command. If you want to use LoRa, you need to start a timer that repetitive sends a request to the AllThinksTalk API. From this API, you will receive the sensor values (GPS, Time, Crash kind) that are send by a specific LoRa node. You can use these values to insert a crash into the database.

3. The frond end:

The frond end consists of 3 languages. HTML for the website text, CSS for the website markup and JavaScript for the communication with the back end. I have 4 website pages for this project:

  • The index.html where you can find all the cycling races.
  • A page with all the crashes and mechanical breakdowns for a spicific race.
  • A page where you can add cylists to the database and edit their team.
  • A page where you can add a new race with all its attendees to the database.

How you design them is fully up to you. You can get some inspiration from my website if you want to. Unfortunately my website is made in the Dutch language, I'm sorry for that one.

I have an separately CSS file and JavaScript file for every page. Every JavaScript file uses fetch to get the data from the database via the back end. When the script receives the data, the html changes dynamically. In the page where you can find the crashes and mechanical breakdowns, you will find a map where all the events happend. I used leaflet to show this map.

You can look at all my code's here on my Github.

Step 5: Build the Constructions

Before we can start with the construction, make sure you have all the materials from the BOM or from the 'Tools + Supplies' page.

  • Raspberry Pi + LCD

We will start with the case for the Raspberry Pi. You can alwas 3D-print a case, this was also my first idea. But because my deadline was comming very close, I decided to make a simple case. I took the standard case from the Raspberry Pi, and I drilled a hole in the case for the wires from my LCD display. To do this, you just follow these simple steps:

  1. Drill a hole into the cover of the case. I did this with a 7mm drill at the side of the cover. You can see this in the picture above.
  2. Take the wires from the LCD display and slide a head shrinks over the wires.
  3. Use a lighter or a hot air gun to make the head shrinks shrink.
  4. Pull the wires with the head shrink through the hole in the case, and connect them back on the LCD.

Now that you are ready with the case for the Raspberry Pi, you can start with the case for the LCD display. I 3D-printed the case for my LCD Display because I found a case online on this link. I only had to make a litle change in the height of the case. When you think you'r drawing is good, you can export the files and start printing. If you don't know how to 3D-print, you can follow this instructable about how to 3D-print with fusion 360.

  • SODAQ MBili construction

I didn't really make a case for the SODAQ Mbili board. I used a plexi glass to place my components on without a case arround the construction. If you want to do this also, you can follow these steps:

  1. Sign off the plexiglass with the dimesnions of the SODAQ Mbili board. The dimensions are: 85mm X 56mm
  2. Cut the plexiglass with a jigsaw.
  3. Place the electronic components on the plexiglass and sign off the holes with a pencil.
  4. Drill the holes you just signed off and the holes for the standoffs with a 3.5mm drill.
  5. Mount all the electronic components on the plexiglass with the 3M 10mm bolts and nuts.
  6. The last step is to mount the plexiglass above the Mbili board. You can do this with standoffs, but I used two 3M 50mm bolts and 8 3M nuts to mount the plexiglass above the board.