Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2025:iotelea:stefan.basaram [2025/05/20 01:43]
stefan.basaram [Description]
pm:prj2025:iotelea:stefan.basaram [2025/05/26 20:43] (current)
stefan.basaram added results and references
Line 21: Line 21:
  
 === User input === === User input ===
-  * The **analog joystick** is used to move the characters and the dedicated **module ​button** is used for firing or adjusting the game difficulty.\\  +  * The **analog joystick** is used to move the characters and the dedicated **button** is used for firing or adjusting the game difficulty.\\  
-  * If a player wishes to skip a game, they can do so by pressing twice on the button integrated in the **analog ​joystick** in quick succesion.+  * If a player wishes to skip a game, they can do so by pressing twice on the button integrated in the **joystick** in quick succesion.
  
 === Game loop === === Game loop ===
Line 34: Line 34:
 ===== Hardware Design ===== ===== Hardware Design =====
 === Components === === Components ===
-  * [[https://​www.bitmi.ro/​placa-de-dezvoltare-compatibila-arduino-uno-r3-atmega328p-10358.html|Arduino Uno R3 ATMega328P-AU CH340G]] +  * [[https://​www.bitmi.ro/​placa-de-dezvoltare-compatibila-arduino-uno-r3-atmega328p-10358.html|Arduino Uno R3 ATMega328P-AU CH340G]] ​- The brains of the operation. Conveniently already possessed one and its small size allows it to be stored in a compact construct. 
-  * [[https://​www.optimusdigital.ro/​ro/​butoane-i-comutatoare/​2375-modul-cu-buton-rou.html|Module Button]] +  * [[https://​www.optimusdigital.ro/​ro/​butoane-i-comutatoare/​2375-modul-cu-buton-rou.html|Module Button]] ​- The reason I bought a button with dedicated pins, instead of using one ready-to-go on a breadboard, is precisely because I did not want to use it directly on a breadboard. 
-  * [[https://​altex.ro/​kit-incepatori-arduino-imbunatatit-robofun-in-cutie-din-plastic/​cpd/​6656FC67AE253/​|Analog Joystick]] +  * [[https://​altex.ro/​kit-incepatori-arduino-imbunatatit-robofun-in-cutie-din-plastic/​cpd/​6656FC67AE253/​|Analog Joystick]] ​- With limited controls, a joystick offers a lot of options for movement, along with a normal button in a single package 
-  * [[https://​www.optimusdigital.ro/​ro/​optoelectronice-matrice-de-led-uri/​118-modul-cu-matrice-de-led-uri-max7219.html|Two 8x8 LED Matrices]] +  * [[https://​www.optimusdigital.ro/​ro/​optoelectronice-matrice-de-led-uri/​118-modul-cu-matrice-de-led-uri-max7219.html|Two 8x8 LED Matrices]] ​- The main display of the console. Unlike a typical LED matrix, these display modules have a microcontroller which control the LEDs via just 5 input pins, which not only simplifies the circuitry massively, they also allow to be used independently of a breadboard. They also have 5 output pins which mirror the input ones which allow daisy-chaining displays by assigning every display an address. I decided against using these however in order to favor a smaller console. 
-  * Three LEDs of colors red, yellow and green ([[https://​www.bitmi.ro/​kit-introducere-in-arduino-pentru-incepatori-10170.html|part of kit]]) +  * Three LEDs of colors red, yellow and green ([[https://​www.bitmi.ro/​kit-introducere-in-arduino-pentru-incepatori-10170.html|part of kit]]) ​- Secondary display. Shows extra info about the current game state. 
-  * [[https://​www.bitmi.ro/​modul-buzzer-pasiv-ky-006-10678.html|Passive Buzzer]] +  * Resistors 220Ω ([[https://​www.bitmi.ro/​kit-introducere-in-arduino-pentru-incepatori-10170.html|part of kit]]) - For the LEDs. 
-  * [[https://​www.emag.ro/​baterie-philips-longlife-9v-1-blister-6f22l1b-10/​pd/​DRC1LKBBM/?​ utm_campaign=share_product&​utm_source=mobile_dynamic_share&​utm_medium=android|9V Battery]] + [[https://​www.optimusdigital.ro/​ro/​fire-fire-mufate/​896-fir-pentru-baterie-de-9v.html|Adapter]]+  * [[https://​www.bitmi.ro/​modul-buzzer-pasiv-ky-006-10678.html|Passive Buzzer]] ​- Every respectable console with a small budget should sport an annoying buzzer such as this. 
 +  * [[https://​www.emag.ro/​baterie-philips-longlife-9v-1-blister-6f22l1b-10/​pd/​DRC1LKBBM/?​ utm_campaign=share_product&​utm_source=mobile_dynamic_share&​utm_medium=android|9V Battery]] + [[https://​www.optimusdigital.ro/​ro/​fire-fire-mufate/​896-fir-pentru-baterie-de-9v.html|Adapter]] ​- Allows the console to be used without being tethered to a computer.
   * Cables [[https://​www.optimusdigital.ro/​ro/​fire-fire-mufate/​885-set-fire-tata-tata-10p-10-cm.html|male-male]] and [[https://​www.optimusdigital.ro/​ro/​fire-fire-mufate/​92-fire-colorate-mama-tata-40p.html|male-female]]   * Cables [[https://​www.optimusdigital.ro/​ro/​fire-fire-mufate/​885-set-fire-tata-tata-10p-10-cm.html|male-male]] and [[https://​www.optimusdigital.ro/​ro/​fire-fire-mufate/​92-fire-colorate-mama-tata-40p.html|male-female]]
-  * [[https://​www.bitmi.ro/​electronica/​breadboard-400-puncte-pentru-montaje-electronice-rapide-10633.html|Breadboard]]+  * [[https://​www.bitmi.ro/​electronica/​breadboard-400-puncte-pentru-montaje-electronice-rapide-10633.html|Breadboard]] ​- Used for wiring together the display, player inputs and the buzzer. 
 + 
 +{{pm:​prj2025:​iotelea:​stefan.basaram:​schema_electrica_consola.png?​750 }} 
 +=== Pin configuration === 
 +For all devices, the VCC pins are connected to 5V and GND to a GND pin on the host (Arduino).\\ 
 +The **Host <-> Device** column presents which pins are used, as well as the direction that information flows in. 
 + 
 +^  Name                ^  Type          ^  Host <-> Device ​ ^  Reason ​  ^ 
 +|Module button ​        ​| ​ Digital ​      ​| ​ D2  <- out      |  Binary press state of button is read via INT0 interruption ​       | 
 +|LED Matrix (A)        |  :::           ​| ​ D8  -> DIN    |  Data input, sets the state of any LEDs on the matrix ​             | 
 +|:::                   ​| ​ :::           ​| ​ D9  -> CS    |  Chip select ​                                                      | 
 +|:::                   ​| ​ :::           ​| ​ D10 -> CLK    |  Clock signal ​                                                     | 
 +|LED Matrix (B)        |  :::           ​| ​ D5  -> DIN     ​| ​ Data input, sets the state of any LEDs on the matrix ​             | 
 +|:::                   ​| ​ :::           ​| ​ D6  -> CS     ​| ​ Chip select ​                                                        | 
 +|:::                   ​| ​ :::           ​| ​ D7  -> CLK     ​| ​ Clock signal ​                                                   | 
 +|Red LED               ​| ​ :::           ​| ​ D13 -> LED     ​| ​ Pins power the LED ON/​OFF ​                                      | 
 +|Yellow LED            |  :::           ​| ​ D12 -> LED     ​| ​ :::                                                             | 
 +|Green LED             ​| ​ :::           ​| ​ D11 -> LED     ​| ​ :::                                                                  | 
 +|Joystick ​             |  Analog ​       |  A0  <- VRx      |  Continous input from a potentiometer,​ representing 2D movement ​    | 
 +|:::                   ​| ​ :::           ​| ​ A1  <- VRy      |  :::                                                                  | 
 +|:::                   ​| ​ Digital ​      ​| ​ D4  <- SW      |  Button press state can be read digitally ​                         | 
 +|Passive buzzer ​       |  Digital (PWM)  |  D3  -> Buzzer ​  ​| ​ The use of PWM enables adjusting the volume of the buzzer, along with its tone  | 
 + 
 + 
 + 
 + 
  
 ===== Software Design ===== ===== Software Design =====
 +Source code available on [[https://​github.com/​Bezeram/​Retro-Games-Console|Github]].
 +
 +=== Environment and Libraries ===
 +Development includes the use of both .ino files and C++ files, as such I used two IDEs
 +  * Arduino IDE - for the only .ino file **Console.ino** which is concerned with interacting with the Arduino
 +  * Visual Studio Code (VSCode) - programming the games and integrating them with **Console.ino**. Using VSCode instead of Arduino IDE for source files had many benefits including better syntax highlighting,​ more functional text-editor and accessible version control via Github.
 +
 +For 3rd party libraries I used [[http://​www.wayoda.org/​arduino/​ledcontrol/​|LedControl]] which was a necessary addition in order to use the LED matrices of type **MAX7219** which have a unique hardware interface composed of 5 pins.
 +
 +=== Architecture ===
 +The code is divided into 3 parts:
 +  * [[stefan.basaram#​Console.ino|Console.ino]] - it has the responsibility of instantiating the game's engine and games and updating them. Finally, it is used for compiling and uploading the code which runs on the Arduino.
 +  * [[stefan.basaram#​Games|Games]] - written in C++, implemented as classes which inherit from a base class (Game.h -> Snake.h, Pong.h, Asteroids.h).
 +  * [[stefan.basaram#​Engine|Engine]] - written in C++, it allows the games to interact with the Arduino hardware by using functions : 
 +    * reads user input
 +    * plays sound
 +    * updates screen using two LedControllers,​ provided by the library mentioned above, one for each LED matrix
 +
 +=== Console.ino ===
 +It contains the main loop and has the role of managing and updating the engine and the active game as well as cycling the games.
 +The main functions are **setup()** and **loop()**, with the auxiliary functions: **switchGame()**,​ **handleGames(float deltaTime)** and **startupSequence()**
 +
 +**void setup()**
 +  * runs **startupSequence()** which plays an animation and also plays sounds
 +
 +**void loop()**
 +  * calculates deltaTime using the built-in function **millis()** and keeping track of the time last frame
 +  * runs the game engine: clears the screen, updates the game state and draws it
 +  * makes sure it runs at a fixed framerate
 +
 +**void handleGames(float deltaTime)**
 +  * checks if the game should be switched
 +  * calls **switchGame()** if previous condition is true
 +
 +**void switchGame()**
 +  * cycles the games and instantiates the new game
 +
 +=== Engine ===
 +Acts as the bridge between the games and Console.ino which handles the hardware. Responsible for reading user input and implementing the system which updates the screen. \\
 +
 +== Drawing system ==
 +The drawing system stores 2 arrays of 8 bytes, with one bit for each LED. Each array is associated with an LED matrix and also each LED matrix gets its own controller of type **LedControl** provided by the 3rd library mentioned above. When setting a pixel on the screen, it doesn'​t immediately update the LED matrices. It first determines which LED matrix is affected and updates the correspondent array of bytes using bitwise operations. When the game state is updated, the arrays of bytes are sent row by row to the LED controllers which change the LEDs matrices.\\
 +For performance reasons, we cannot update each LED individually. Also, because the actual LED matrices composing the physical screen have different orientations,​ we must change how each LED matrix is updated.
 +
 +**void updateLoop(float deltaTime)**
 +  * checks for user input
 +
 +**void playSound(int frequency, int duration)**
 +  * plays sound using built-in tone function
 +
 +**void clearScreen()**
 +  * resets LED array of bytes
 +
 +**void setPixel(int x, int y)**
 +  * sets the bit at x, y by calling **setPixelToValue(x,​ y, true)**
 +
 +**void setPixelToValue(int x, int y, bool on)**
 +  * changes corespondent array of bytes depending on the coordinates and sets the provided state
 +
 +**void drawToDisplay()**
 +  * called by Console.ino,​ sends the arrays of bytes to the LED controllers which update the physical LED displays
 +
 +**void setDisplayBrightness(int brightness)**
 +  * utility function for setting the displays brightness using the LED controllers
 +
 +=== Games ===
 +I took an approach inspired by OOP design principles and implemented the games using polymorphism and inheritance. I made a Game interface with an **updateLoop()** function which must be implemented by any game which wishes to be added. Console.ino holds a reference to the current game and calls the **updateLoop()** function which calls the correct derivative function depending on the underlying game class.\\
 +
 +Each game holds a reference to the Engine, fact enforced by the Game interface, which allows it to read the current state of user input, play sounds and update the screen as well as access details about the engine such as the delta time and the time since the last move has occurred.
 +
 +There are 3 games implemented:​
 +  * Snake
 +  * Asteroids
 +  * Pong
 +
 +== Snake ==
 +Classic snake, but the walls are portals. Pac-Man style.\\
 +In the **updateLoop()** function, the snake is moved according to its current direction and updates it according to the joystick. If the snake head touches an apple, it plays a sound and the snake'​s size is increased and it calls **placeFood()** to choose a new apple placement without clipping the snake, using the built-in function **random()**. In this game implementation,​ the snake is not killed if it exits the bounds of the display, instead it is transported to the other side.\\
 +
 +If the head of the snake occupies the same position as one of its body, the snake is killed and one of the player'​s lives is taken. If the player has not run out their 3 lives, they may continue playing from the point just before the collision occured, with the game resuming upon the player'​s next input.
 +When all lives are exausted, an animation is played which shows how large the snake had grown before it died.
 +
 +== Asteroids ==
 +The player encompasses a spaceship on the left side of the screen and must shoot incoming asteroids (presumably,​ since the display resolution allows room for creative interpretation).\\
 +In **updateLoop()**,​ the spaceship is moved up or down with the joystick and fires with a normal button press. Asteroids are spawned randomly on right side of the screen and approach the player'​s ship. Firing makes a noise.\\
 +If the player is clipped by an asteroid, their ship is destroyed. This game does not have lives and the player will simply be prompted to try again or move to the next game.
 +
 +== Pong ==
 +Hang on, isn't pong a 2 player game? Or played with an A.I?\\
 +In my version of Pong, the player controls BOTH paddles, one at a time. After a paddle reflects the ball, control is immediately switched to the other paddle and the player must react fast enough to continue to reflect the ball. The game starts with an active paddle and a random ball trajectory.\\
 +In **updateLoop()**,​ the currently active paddle is moved by the joystick. The paddle is not terribly big, however it moves very fast. If the ball collides with the paddle, the ball is reflected and control is passed to the other paddle. The speed of the ball increases over time.\\
 +If the ball goes past the paddle, the player loses a life. If the player has not run out their 3 lives, they get to keep playing with the last speed of the ball preserved and starting from the losing paddle.
 +
 +===== Results =====
 +  * [[https://​youtube.com/​shorts/​Nj0hMh7GVlk?​feature=share|Prototype video]]
 +
 +===== References =====
 +  * [[https://​www.arduino.cc/​en/​Guide/​ArduinoUno/#​upload-the-program| Getting started with Arduino]]
 +  * [[http://​www.wayoda.org/​arduino/​ledcontrol/​|LED Control Library for LED Display Matrices]]
 +  * [[https://​forum.arduino.cc/​t/​avrdude-ser-open-cant-set-com-state-for-com3-failed-uploading-uploading-error-exit-status-1/​1131626/​18|Driver fix by ptillisch for the Arduino model used here]]
 +  * [[https://​xantorohara.github.io/​led-matrix-editor/#​42844a0035153377|LED Matrix Editor]]
  
pm/prj2025/iotelea/stefan.basaram.1747694592.txt.gz · Last modified: 2025/05/20 01:43 by stefan.basaram
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0