Rapid Roads (Racing Game)
by RubenVierstraete in Circuits > Raspberry Pi
105 Views, 1 Favorites, 0 Comments
Rapid Roads (Racing Game)
You all know the big crazy fun arcade racing games you can keep playing just getting that tiny bit closer to the high score every time. Well I have made a compact version of one of these iconic games, so you can compete with you're friends to get the highest score.
all the code:
https://github.com/howest-mct/2023-2024-projectone-mct-VierstraeteRuben
Supplies
Sensors & Components:
- Raspberry Pi 4
https://www.kiwi-electronics.com/nl/raspberry-pi-4-model-b-2gb-4267?country=BE&gad_source=1
- 8x8 LED display
https://www.conrad.be/nl/p/tru-components-tc-9072480-8-x-8-matrix-displaymodule-max7219-voor-arduino-2268120.html?adcampaign=google&tid=16860426636_pla-2268120&gad_source=1&gclid=CjwKCAiAxaCvBhBaEiwAvsLmWJvWVZVBWe2zF1OFg3fTD6OyEPq2S_EPUvNeMr0Xsm88Yj7AYsXhehoCA8wQAvD_BwE
- MPU 6050
https://www.otronic.nl/nl/acceleratie-versnellingsmeter-en-gyroscoop-i2c-mpu.html?source=googlebase&gad_source=1&gclid=CjwKCAiAxaCvBhBaEiwAvsLmWI8CgDMpM1Phslt7-T7MPUgbAUR6YMSyCJX53aB2ZjKw3FfI2AgicBoCWJ8QAvD_BwE
- buttons
https://www.amazon.com.be/-/nl/tijdelijke-drukknopschakelaar-geassorteerde-automatische-mini-schakelaar/dp/B09MBQSM44/ref=sr_1_25?crid=SKLK2QV0CX81&dib=eyJ2IjoiMSJ9.uOoe-7TIeAlB4U2SH1UkuJ2muSiTrUDuCShz_KF_t5EIZ_FWLOVIVoTQ-GbO1GPDxXzayxIlj4OlRqqWu-u_LmLBSgz53aOi7a3Rw8-QrbPFnPHyIof6209Hx_L55F3WFffDYS3AwDQ_eFkkkjifh8NHUCYCUsMs5Nh7RdPm5Aarrk6k5CqlOy1-pNw2JrP3TG32a5gK-wprpWoaWtx-3eqSAQJRTJSIdqR-CJ88HldjbzfdrNTKXed1lRKi5DsJKCsPLa8ZVKtWmy188rXSDmh_e0sfnNvfqpb1MMxi-0A.FwoLCXIuhp_NkWK0ICmAxt3_J9hWETMoOu890FlF-Xw&dib_tag=se&keywords=drukknop%2Barduino&qid=1714027594&sprefix=drukknop%2Barduino%2Caps%2C126&sr=8-25&th=1
- LCD screen
https://www.digikey.be/nl/products/detail/sunfounder/CN0293/18668626?utm_adgroup=&utm_source=google&utm_medium=cpc&utm_campaign=PMax%20Shopping_Product_Low%20ROAS&utm_term=&productid=18668626&utm_content=&utm_id=go_cmp-20168770009_adg-_ad-__dev-c_ext-_prd-18668626_sig-CjwKCAiAxaCvBhBaEiwAvsLmWLtYK_JK1gb4B76QoiESvUlAH25AC3J_1FBN8C5v3N8Y4aUV6wKgqRoC68wQAvD_BwE&gad_source=1&gclid=CjwKCAiAxaCvBhBaEiwAvsLmWLtYK_JK1gb4B76QoiESvUlAH25AC3J_1FBN8C5v3N8Y4aUV6wKgqRoC68wQAvD_BwE
- RFID reader (and badges)
https://www.conrad.be/nl/p/joy-it-sbc-rfid-rc522-rfid-chip-rfid-set-1-stuk-s-1503746.html?adcampaign=google&tid=16860426636_pla-1503746&gad_source=1&gclid=CjwKCAiAxaCvBhBaEiwAvsLmWN25lgaS1V0mY8oELSowjGpl9-0WIb9fpwk28G3EN3_DOzztut06fRoCMb8QAvD_BwE
- MCP
https://www.distrelec.be/nl/mcp3008-kanaals-10-bits-adc-met-spi-interface-adafruit-856/p/30139253?ext_cid=shgooaqbenl-P-Shopping-PMax&cq_src=google_ads&cq_cmp=17730351004&cq_con=&cq_term=&cq_med=pla&cq_plac=&cq_net=x&cq_pos=&cq_plt=gp&gad_source=1&gclid=Cj0KCQjwsaqzBhDdARIsAK2gqnfWo5WgRJpd6FjnJgo6aSV63aNmwdbRpy5yRXedIQbqSl-xuSJYu8kaAgS0EALw_wcB&gclsrc=aw.ds
- PCF
https://www.digikey.be/nl/products/detail/texas-instruments/PCF8574AN/484958?utm_adgroup=&utm_source=google&utm_medium=cpc&utm_campaign=PMax%20Shopping_Product_Low%20ROAS&utm_term=&productid=484958&utm_content=&utm_id=go_cmp-20168770009_adg-_ad-__dev-c_ext-_prd-484958_sig-Cj0KCQjwsaqzBhDdARIsAK2gqnfZQp6Haz16ivxo9L89P5RFiMp3ylHjm6r-2sIsNDfeGktQiPNJbR8aAqZVEALw_wcB&gad_source=1&gclid=Cj0KCQjwsaqzBhDdARIsAK2gqnfZQp6Haz16ivxo9L89P5RFiMp3ylHjm6r-2sIsNDfeGktQiPNJbR8aAqZVEALw_wcB
- Potentiometer
https://www.allekabels.be/potmeter/11469/1066233/potmeter.html?mc=nl-be&gad_source=1&gclid=CjwKCAiAxaCvBhBaEiwAvsLmWDEVZAYKFeETR539dNpimSSs144TkA-MYVI4gGa4E720mbKii8wd_RoCN64QAvD_BwE&lang=nl-be
- Hall Sensor
https://www.amazon.nl/AZDelivery-Magnetische-Hallsensormodule-compatibel-Inclusief/dp/B07ZZ8N4VC?th=1
- Cables
https://www.amazon.com.be/-/nl/Breadboard-kabels-mannelijk-vrouwelijk-stekker-testplaat/dp/B01JD5WCG2/ref=asc_df_B01JD5WCG2/?tag=begogshpadd0d-21&linkCode=df0&hvadid=633391988539&hvpos=&hvnetw=g&hvrand=11645996038449690857&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1001270&hvtargid=pla-1940049636127&psc=1&mcid=79a0b16f093f3d598cd94cc6c34adbaf
- nylon bolts and screws
https://www.amazon.com.be/-/nl/schroeven-waterdicht-elektrische-mechanische-apparatuur/dp/B07LD6G622/ref=asc_df_B07LD6G622/?tag=begogshpadd0d-21&linkCode=df0&hvadid=632929277223&hvpos=&hvnetw=g&hvrand=17296251334319963104&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1001270&hvtargid=pla-635055483275&psc=1&mcid=998c78fb03ee3657b24f24b2383ec22f
- Pi power supply
https://www.sossolutions.nl/originele-raspberry-pi-foundation-usbc-3a-voeding-zwart?gad_source=1&gclid=CjwKCAiAxaCvBhBaEiwAvsLmWPC8594y4N0PCTAJCFqhyGUIUaBYqXX-6U_IdfBGWS4LF0844Ow40RoCYvkQAvD_BwE
- SD 16GB
https://www.bol.com/nl/nl/p/sandisk-micro-sd-16gb-geheugenkaart-class-10/9200000084792189/?Referrer=ADVNLGOO002020-S--9200000084792189&gad_source=1&gclid=CjwKCAiAxaCvBhBaEiwAvsLmWNkA31Ns3mQVjDqfFnytRY-B5ZGKABk8zXsDOsjFXEcULnBIoxkJbhoCm1MQAvD_BwE
- Raspberry PI GPIO extension board T
&hvpos=&hvnetw=g&hvrand=8201943129760031346&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1001259&hvtargid=pla-681507229800&psc=1&mcid=aa595e2a0f993fb49a21ad84aa91780d
- external source
https://www.temu.com/ul/kuiper/un9.html?subj=coupon-un&_bg_fs=1&_p_jump_id=895&_x_vst_scene=adg&goods_id=601099522152697&sku_id=17592240489685&adg_ctx=a-a90ad0f7~c-7dd19b44~f-50e0726a&_x_ads_sub_channel=shopping&_p_rfs=1&_x_ns_prz_type=-1&_x_ns_sku_id=17592240489685&mrk_rec=1&_x_ads_channel=google&_x_gmc_account=760631223&_x_login_type=Google&_x_ads_account=9370551288&_x_ads_set=20727373909&_x_ads_id=154927248653&_x_ads_creative_id=678767718393&_x_ns_source=g&_x_ns_gclid=CjwKCAiAxaCvBhBaEiwAvsLmWLyk4PiGnBAhENpOHMRz-6pDDd66Jq-T28ThdNgzOKZZiS7u4Q6NkhoCd-gQAvD_BwE&_x_ns_placement=&_x_ns_match_type=&_x_ns_ad_position=&_x_ns_product_id=760631223-en-17592240489685&_x_ns_target=&_x_ns_devicemodel=&_x_ns_wbraid=Cj4KCAiAopuvBhADEi4A5iS5mgTbbo7FX1yXfuO5c4fShwBB1owYd_A1wQW4wiaCfs4t3mdu5sSk1KC9GgLhEQ&_x_ns_gbraid=0AAAAAo4mICF0vDWatMJkJb3vA8IUYeP7p&_x_ns_targetid=pla-2233208089375&gad_source=1&gclid=CjwKCAiAxaCvBhBaEiwAvsLmWLyk4PiGnBAhENpOHMRz-6pDDd66Jq-T28ThdNgzOKZZiS7u4Q6NkhoCd-gQAvD_BwE
- external source adapter
https://www.bax-shop.be/nl/voedingen/devine-ad-03-adapter-voor-diverse-casio-keyboards?gclsrc=aw.ds&utm_source=google&utm_medium=cpc&utm_campaign=18344795213&utm_term=&adgroup=&creative=&gad_source=1&gclid=CjwKCAiAxaCvBhBaEiwAvsLmWHK5amJYsM_l08sX0M4yBk9mIxgz3eP3ji_O-_7Rk0xAlsyfIEq7wRoC5-EQAvD_BwE
- wood rod (2 pieces with a diameter of 48 mm and a length of 125 mm, and 2 pieces with a diameter of 8 mm, one with a length of about 30 mm and the other with a length of around 75-100 mm)
https://www.gamma.be/nl/assortiment/ronde-stok-grenen-45-mm-270-cm/p/B509776
- ball bearing (2)
https://www.temu.com/ul/kuiper/un9.html?subj=coupon-un&_bg_fs=1&_p_jump_id=895&_x_vst_scene=adg&goods_id=601099518459656&sku_id=17592224352186&adg_ctx=a-f0daf8ba~c-13a617a7~f-50e0726a&_x_ads_sub_channel=shopping&_p_rfs=1&_x_ns_prz_type=-1&_x_ns_sku_id=17592224352186&mrk_rec=1&_x_ads_channel=google&_x_gmc_account=760631223&_x_login_type=Google&_x_ads_account=9370551288&_x_ads_set=20842663190&_x_ads_id=159466397987&_x_ads_creative_id=683739518761&_x_ns_source=g&_x_ns_gclid=CjwKCAiAxaCvBhBaEiwAvsLmWHRFSA3l-bq8FgzoAFUQOTvacGTwxzV63Y6bGyayySmadPR5-1AOBBoCG9MQAvD_BwE&_x_ns_placement=&_x_ns_match_type=&_x_ns_ad_position=&_x_ns_product_id=760631223-nl-17592224352186&_x_ns_target=&_x_ns_devicemodel=&_x_ns_wbraid=Cj4KCAiAopuvBhADEi4A5iS5mrezlrKBCSLjfe0K_FATF7FgqT9pJfvhSMpdzEcZgzMGpflmVjAyRFFfGgLNFA&_x_ns_gbraid=0AAAAAo4mICHivJm9rJeA8kXpuK9jx7X1M&_x_ns_targetid=pla-2279904018156&gad_source=1&gclid=CjwKCAiAxaCvBhBaEiwAvsLmWHRFSA3l-bq8FgzoAFUQOTvacGTwxzV63Y6bGyayySmadPR5-1AOBBoCG9MQAvD_BwE&fbclid=IwAR1IaF4nN9R_lFM3PVmVxrJTDWbKG7i9dOY5PWgVxQo0ezFl-_uF5N-4KUU
- lasercutted exterior (illustrator and dfx files included)
Testing Sensors & Components
The first thing I did for my project was testing each sensor individually.
I started with the sensors I was familiar with namely: the potentiometer and hall sensor witch are attached to a MCP, a MPU6050, a RFID scanner and some buttons.
I also tested other components like: a LCD screen wich is attached to a PCF and a 8x8 LED display wich displays a simple game.
MCP (hall sensor & potentiometer):
To use this Micro controller I imported the library spidev in python, with this library we can use the SPI pins on the PI. (because I'm using 3 components that need SPI I changed the pinning of my PI to use SPI 1, the pin nummering can be found on this site: https://pinout.xyz/)
Now by connecting the MCP like on the scheme (see step 3 Making A Full Circuit to see the full circuit) we can use the command .xfer2(bytes to send to mcp) with bytes to send to mcp = [0b00000001,(0b10000000 | (ch<<4)), 0b00000000] and ch is the channel we want to read (0 = potentiometer and 1 = hall sensor)
MPU:
For this sensor I also imported something, SMbus from smbus. With this we can communicate with the I2C bus on the Pi, for this we will need the address of the MPU. Normally this is 68 but to check this you can run this command: 'i2cdetect -y 1' in the terminal of your Pi.
The mpu has multiple things it can measure, for this project I only needed the accelero measurments wich shows how much g's on each axis there is. This is a value between -1 and 1. I used the y axis because of how the MPU was positioned in the steering wheel. then if it read more towards the -1 that means the wheel was turned to one side, if it read close to 0 then it was balanced and if it read more towards the 1 it would be turned to the other side.
We can use the SMbus.read_i2c_block_data(address, channel, amount) to read the values of the accelero of each axis. the address as previously mentioned is most liky 68, the first channel for accelero is 0x3B and the amount means how many channels it needs to read (this is beacause the values are stored throughout multiple channels).
the value we get from this fuction than has to be processed to be something we can interpreted. I made a function that does this.
8x8 display:
This component also uses the SPI bus, the important thing about using multiple SPI busses is to connect each one to a different chip select. Then to use multiple ones in one single code you simply open a SPI bus of the needed chip select en then when you did everything you needed with that one you immediately close it.
To use this display we need to first run some setup code (you can find this exact code in the class 8x8 display code). In this class you will see that i have made a function to show a 8x8 matrix on the screen. To set the matrix correct we have to send per line of the display the right byte.
RFID:
For this sensor I imported a library, the MRFC522 library, I used the SimpleRFID as I don't need to do difficult things with the RFID reader. I did change these libraries a tiny bit, I added in the SimplRFID a function that closed the SPI bus, and I changed it to use SPI 1 and also witch chip select it uses.
Now with this library using the RFID reader is very easy, you have a read and write function, both are very straight forward. The read function waits until a badge is in range of the reader, then it reads the RFID number and the data on it (in my case the data is just the name of the user). The write function takes one argument, a string, it waits until a badge is in range of the reader, then it chages the data on it to the string you give it.
LCD screen (with PCF in 4 bits mode):
The LCD screen has 2 modes 8 bits and 4 bits, I used the 4bits mode because this uses less pins. I also connected it with a PCF, the reason for this is because a PCF only uses 2 pins on the Pi, the SDA and SCL, we can then connect the pins of our LCD to the PCF and save a lot of pins on our Pi.
We can send a byte to the PCF and the corresponding pins will be put high on it. Now we can by sening the wright byte to our pcf and putting the right pins high on our LCD screen write stuff on it.
Test code for the game loop:
The last test code I made was the first iteration of the game.By using all the code I made for each component separate, and combining it I have made something that runs 1 game. Now I can use this code in my backend so that the game can be played while the website is also running.
Making a Database
The second step is to make a database where all the data will be stored. The stored data will be used to show certain things on the website like tables with all the games played and their measurements of the sensors. In this database there will also be games stored, so all the games that were played are stored with who played it, the score and date.
All the data of the badges is also stored in this database, data like high scores and total amount of games played is not stored here because these things are easily calculated.
There are also relations between some tables, like between the table Badges and Games. This links a Badge to one or more games. There are also relations between Games and Measurements, and Measurements and Sensors. These relations connect the data together.
Making a Full Circuit
Now i made the whole circuit, i connected everything together to make a beginning of the game. I used 2 breadboards in total and a external source.
the important thing is that I changed the SPI bus that my Pi uses, its normally using 0 but I changed it to 1. The reason for this is because the 1 bus has 3 chip selects and the 0 only has 2, and I have 3 components that use SPU.
There are pdf's that show how to connect everything, one for with a breadboard like I did, and one that just shows the connections.
Making a Website
I also needed to make a website witch is connected to my project, I decided to go with a website that has 3 pages: one for all info during the game, one with all the historic data of the games and one with info about the users/badges.
info about pages
The page with info is named Racing Game, here there is a small tutorial of how to start and play the game. On this page there are also a picture of the steering wheel witch shows the directions the wheel is turned and a speedometer witch shows how "fast" you are going. The 8x8 led display is also shown on this page and the last 3 measurements of the current game are also shown (of each sensor 1).
In the page Historic Data there are 4 tables of data shown. The first table is the one with the 3 highest scores and who has that score. The second table shows all the info over the sensors, there are 3 sensors: Potentiometer this one is used to measure how far the gas handle has been turned, a hall sensor witch measures how for the break is from the grip (this works because there is a magnet in the break and a hall sensor measures magnetic fields) and the last sensor is the MPU witch measures the gravity of the steering wheel witch is used to decide witch way the steering wheel is turned.
The third table of the page historic data has all the games with their data in it, this data includes: the game number, who played it, the score and how many seconds the game lasted. Each record in this table also has a button that when pressed fills the fourth table with all the measurements that were recorded during this game. The data of each record of the fourth table are: the measurements number, witch sensor it belongs to, the value of the measurement and the timestamp of when it was measured.
The last page with user info has 1 table, a table with all the info of the badges and their user. This table shows the name, high score, amount of games played and their ID's. Each record of this table has a button, when pressed this will show 2 graphs. One with the time of per game and the other one shows the score per game.
making a working backend and frontend
To make the website get all the right data and display it in the right way I needed to make a backend file (coded in python) and a frontend file for each html page (coded in javascript). The backend runs all the code for the sensors and components and also makes the frontend be able to get the data of the sensors and the data that is stored in the database.
The backend uses API routes and socketio to talk to the frontend, the frontend also sends messages via socketio to the backend.
The frontend of each page makes it so that the right data is displayed at the right place, it also makes the buttons work and other things like displaying the graphs on the user info age.
styling the website
The last step of making the website was styling it, I used SCSS code that I then converted to CSS with an extesion in visual studio code (I used Live SASS Compiler). I chose to make a simple styling that is user friendly, my main color is a light blue (RGB: 116 143 252) and the other colors I used are a few grey values and a blue and red for the graphs.
Apache:
To make it so that when you surf my IP address (witch is displayed on the LCD screen) that you get on the website I needed to change some things in a config file on my Pi.
The file i needed to edit was: /etc/apache2/apache2.conf, I needed to change the following lines:
<Directory />
Options FollowSymLinks
AllowOverride All
Require all denied
</Directory>
to this:
<Directory />
Options Indexes FollowSymLinks Includes ExecCGI
AllowOverride All
Require all granted
</Directory>
I edited this in nano so to save this I had to do ctrl + x and then y. Then I had to set the permission good, this can be done with a few commands:
sudo chmod o+x /home/user/<name of github repo>
sudo chmod o+x /home/user/<name of github repo>/front
Then I restarted apache with the following command: service apache2 restart. You can check the apache with the command: service apache2 status, if everything works you should see active (running) somewhere.
Making a Case
To fit all the electronics togheter I laser cutted a case I drew in solid egde. The dxf en illustrator files can be found in supplies.
I used edge joints and some glue to fix everything together. To make the steering wheel be able to turn i used 2 bearings with a metal pipe to connect the case and bearings. I then bolted the bearings to a leftover sheet from the laser cutting to act like a support
i made various hales in the case to bolt components and sensor to with nylon bolts, I used nylon bolts because metal ones can conduct electricity witch can be dangerous with components because it could conduct a signal and short circuit the component.
The last thing I added where 2 supporting beams that are connected to the base with a hinge, this makes them able to move. I bolted them to the base with the hinge positioned so that they can stand up just under the grips of the steering wheel, and when moved they are laying out of the way of the steering wheel. The reason I added these supports is to have a nice way to display the steering wheel without it turned all the way to one side because its very top heavy.
Automatically Starting the Backend
The last thing I needed to do was make it so that when the Pi starts up it needs to run the backend by itself. Now you need to manually start the backend by making a SSH connection with a laptop and opening the code and run it.
You can make this do it automatically by adding a file and enabling this. The first to do is make a new .service file in /etc/systemd/system/, in this file the following lines have to be in there:
[Unit]
Description=ProjectOne Project
After=network.target
[Service]
ExecStart=/home/user/<name of github repo>/<name of virtual envirement>/bin/python -u /home/user/<name of github repo>/backend/app.py
WorkingDirectory=/home/user/<name of github repo>/backend
StandardOutput=inherit
StandardError=inherit
Restart=always
User=user
CPUSchedulingPolicy=rr
CPUSchedulingPriority=99
[Install]
WantedBy=multi-user.target
When this file is made in the right place you can test it with the following commands:
sudo systemctl start <name file>.service this will start the backend
sudo systemctl stop <name file>.service this will stop the backend
When this wroks you can make it start the backend automatically by enabling this file, this can be done with the following command:
sudo systemctl enable <name file>.service
Now when you start up the Pi the backend will also start up, you can check the status of this file or look at the journal with following commands:
sudo service <name file> status
sudo journalctl -u <name file>
You can also disable the file so that the backend doesn't start automatically, you can do this with the following command:
sudo systemctl disable<name file>.service