http://socialledge.com/sjsu/api.php?action=feedcontributions&user=Proj+user2&feedformat=atomEmbedded Systems Learning Academy - User contributions [en]2024-03-29T07:34:27ZUser contributionsMediaWiki 1.27.1http://socialledge.com/sjsu/index.php?title=S22:_Testla&diff=69096S22: Testla2022-08-27T05:29:37Z<p>Proj user2: </p>
<hr />
<div>== Testla ==<br />
[[File:Bunch of handsome young men.jpeg |800px|middle]]<br />
<br />
<br />
<HR><br />
<BR/><br />
<br />
== Abstract ==<br />
The Testla project is the culmination of our efforts to create an autonomously operated RC Car by pooling together our experience in software design, hardware design, power systems, and mobile application development. Project development started in February of 2022 and ended in May.<br />
<br />
=== Introduction ===<br />
<br />
The project was divided into 5 modules:<br />
<br />
* Sensor Information<br />
* Motor Operation<br />
* Geological Information<br />
* Driver & LCD Manager<br />
* Bridge & Android Application<br />
<br />
=== Team Members & Responsibilities ===<br />
<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle Gitlab Project Link]<br />
<BR/><br />
<br />
[[File:DevinAlexander.jpeg|200px|middle]]<br />
*'''''[https://www.linkedin.com/in/devin-b-alexander/ Devin Alexander]''''' '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Geographical Controller<br />
** Master Controller (NEEDS TO FINISH HIS SECTION ON DRIVER)<br />
<br />
[[File:Sinan.jpg|200px|middle]]<br />
* Sinan Bayati '''''[https://gitlab.com/sinan.bayati Gitlab]'''''<br />
** PCB Design<br />
** Motor Controller<br />
<br />
[[File:MichaelHatzi.PNG|200px|middle]]<br />
* Michael Hatzikokolakis '''''[https://gitlab.com/mikehatzi8 Gitlab]'''''<br />
** Motor Controller<br />
** Testing<br />
<br />
[[File:scott_locascio.jpeg|200px|middle]]<br />
* Scott LoCascio '''''[https://gitlab.com/scottlocascio Gitlab]'''''<br />
** Geographical Controller<br />
** Car Construction<br />
** Testing<br />
<br />
[[File:Thinh-avatar.jpg|200px|middle]]<br />
* Thinh Lu '''''[https://gitlab.com/lphucthinh40 Gitlab]'''''<br />
** Android Application<br />
** Sensor and Bridge Controller<br />
<br />
[[File:BangNguyen.jpg|200px|middle]]<br />
* Bang Nguyen '''''[https://gitlab.com/karosious Gitlab]'''''<br />
** Sensor and Bridge Controller<br />
** LCD Display<br />
<br />
<BR/><br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
|+ Legend<br />
|-<br />
! Description !! Color<br />
|-<br />
| General || Black<br />
|-<br />
| Bridge & Mobile App || <span style="color:RoyalBlue">Blue</span><br />
|-<br />
| Driver || <span style="color:Coral">Orange</span><br />
|-<br />
| GEO || <span style="color:MediumSeaGreen">Green</span><br />
|-<br />
| Motor || <span style="color:Crimson">Red</span><br />
|-<br />
| Sensor || <span style="color:Violet">Violet</span><br />
|-<br />
|}<br />
<br />
{| class="wikitable" <br />
|-<br />
! Week #<br />
! Start Date<br />
! End Date<br />
! Task<br />
! Status<br />
|-<br />
| 1<br />
| 2/15/2022<br />
| 2/21/2022<br />
|<br />
*<span>Read previous projects, gather information and discuss among the group members</span><br />
| Complete<br />
|-<br />
| 2<br />
| 2/22/2022<br />
| 2/28/2022<br />
|<br />
*<span>Distribute modules to each team member</span><br />
| Complete<br />
|-<br />
| 3<br />
| 3/1/2022<br />
| 3/7/2022<br />
|<br />
*<span style="color:Crimson">Purchase the RC Car</span><br />
*<span style="color:Violet"> Purchase sensors</span><br />
| Complete<br />
|-<br />
| 4<br />
| 3/8/2022<br />
| 3/14/2022<br />
|<br />
*<span>Learning to use CAN BUSMASTER</span><br />
| Complete<br />
|-<br />
| 5<br />
| 3/15/2022<br />
| 3/21/2022<br />
|<br />
*<span>DBC file discussed and implemented</span><br />
| Complete<br />
|-<br />
| 6<br />
| 3/22/2022<br />
| 3/28/2022<br />
|<br />
*<span>Discuss modules needed for PCB, any feature requests</span><br />
| Complete<br />
|-<br />
| 7<br />
| 3/29/2022<br />
| 4/4/2022<br />
|<br />
*<span>Finalize preparations and research</span><br />
| Complete<br />
|-<br />
| 8<br />
| 4/5/2022<br />
| 4/11/2022<br />
|<br />
*<span style="color:Black"> Begin testing with single vs dual power supplies</span><br />
*<span style="color:RoyalBlue"> Interface ESP8266 for bridge controller</span><br />
*<span style="color:Coral"> Complete the Driver sensor using analog readings</span><br />
*<span style="color:MediumSeaGreen">Integrate the GEO sensor with the GEO controller</span><br />
*<span style="color:Crimson"> Interface with RC car and hack steering and motor</span><br />
*<span style="color:Crimson"> Establish CAN transmit and receive functionality, start formatting DBC messages</span><br />
*<span style="color:Violet"> Write a basic implementation of the sensor controller</span><br />
| Complete<br />
|-<br />
| 9<br />
| 4/12/2022<br />
| 4/18/2022<br />
|<br />
*<span style="color:Black"> Finalize power supply choice</span><br />
*<span style="color:Black"> Finish PCB designs for each subsystem</span><br />
*<span style="color:RoyalBlue"> Setup NodeJS server to communicate with the Bridge controller via TCP/IP</span><br />
*<span style="color:RoyalBlue"> Start Mobile Application development</span><br />
*<span style="color:MediumSeaGreen">Configure GPS to run at 10Hz, 115200 baud and only parse $GPGGA strings on startup</span><br />
*<span style="color:MediumSeaGreen">Integrate compass</span><br />
*<span style="color:Crimson"> Linearly map pseudo Driver speed/turn commands to the ESC/Servo</span><br />
*<span style="color:Violet"> Test alternate sonar sensor (I2C)</span><br />
*<span> First outdoor tests commence</span><br />
| Complete<br />
|-<br />
| 10<br />
| 4/19/2022<br />
| 4/25/2022<br />
|<br />
*<span style="color:Black"> Finish 1st vehicle prototype</span><br />
*<span style="color:Black"> Start populating BUSMASTER with more general debug messages</span><br />
*<span style="color:RoyalBlue"> Complete basic mobile application</span><br />
*<span style="color:RoyalBlue"> Write various motor test routines to define in mobile application</span><br />
*<span style="color:MediumSeaGreen">Verify timing and correctness of GEO controller messages</span><br />
*<span style="color:MediumSeaGreen">Produce debug messages for Geo controller</span><br />
*<span style="color:Crimson"> Interface with real Driver commands</span><br />
*<span style="color:Crimson"> Install RPM Sensor</span><br />
*<span style="color:Violet"> Finalize sensor choice and complete integration of all three sensors</span><br />
*<span> Continue outdoor test</span><br />
| Complete<br />
|-<br />
| 11<br />
| 4/26/2022<br />
| 5/2/2022<br />
|<br />
*<span style="color:Black"> Populate PCB and prepare for installation</span><br />
*<span style="color:Black"> Test message timing and propagation with Bus Master</span><br />
*<span style="color:RoyalBlue">Integration testing Driver controller with Mobile App</span><br />
*<span style="color:Coral"> Improve existing navigation algorithm with state estimation and localization</span><br />
*<span style="color:Crimson"> Fix and validate RPM sensor output</span><br />
*<span style="color:Crimson"> Add ESC calibration feature, activated by SW0</span><br />
*<span> Continue outdoor tests</span><br />
| Complete<br />
|-<br />
| 12<br />
| 5/3/2022<br />
| 5/9/2022<br />
|<br />
*<span style="color:RoyalBlue">Finish mobile application</span><br />
*<span style="color:Crimson"> Interface RPM sensor with Interrupt Service Routine</span><br />
*<span style="color:Crimson"> Add functionality to SJ2-C LEDs</span><br />
*<span > First North Garage tests commence</span><br />
| Complete<br />
|-<br />
| 13<br />
| 5/10/2022<br />
| 5/16/2022<br />
| <br />
*<span style="color:Crimson">Implement PID Controller</span><br />
*<span style="color:Crimson">Add debug messages to CAN related to PID</span><br />
*<span >More North Garage tests</span><br />
| Complete<br />
|-<br />
| 14<br />
| 5/17/2022<br />
| 5/25/2022<br />
|<br />
*<span style="color:Crimson">Rewrite conditional logic into state machine</span><br />
*<span style="color:Crimson">Final code cleanup</span><br />
*<span >Final North Garage tests</span><br />
| Complete<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Parts List & Cost ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item#<br />
! scope="col"| Part Desciption<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost/Item<br />
|-<br />
! scope="row"| 1<br />
| Unassembled RC Car <br />
| Traxxas [https://traxxas.com/products/models/electric/stampede-4x4-assembly-kit]<br />
| 1<br />
| $279.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 4<br />
| $8.99<br />
|-<br />
! scope="row"| 3<br />
| PCB <br />
| JLCPCB [https://jlcpcb.com/]<br />
| 1<br />
| $40.00<br />
|-<br />
! scope="row"| 4<br />
| Sensors <br />
| DFRobot [https://www.dfrobot.com/product-1832.html]<br />
| 4<br />
| $12.90<br />
|-<br />
! scope="row"| 5<br />
| GPS<br />
| Amazon [https://www.amazon.com/Adafruit-Ultimate-GPS-Breakout-channel/dp/B01H1R8BK0]<br />
| 1<br />
| $29.92<br />
|-<br />
! scope="row"| 6<br />
| RPM Sensor <br />
| Traxxas [https://traxxas.com/sites/default/files/Rustler-Bandit-Stampede-Slash%20RPM%20Sensor%20Installation.pdf]<br />
| 1<br />
| $19.00<br />
|-<br />
! scope="row"| 7<br />
| WT901 IMU <br />
| Amazon[https://www.amazon.com/Accelerometer-Acceleration-Gyroscope-Electronic-Magnetometer/dp/B07GBRTB5K]<br />
| 1<br />
| $32.00<br />
|-<br />
! scope="row"| 8<br />
| 1kΩ Pull-Up Resistor<br />
| N/A<br />
| 1<br />
| N/A<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Printed Circuit Board ==<br />
<br />
The preliminary design consisted of neatly routes wires on a breadboard connecting all the various components. It still looked confusing due to the sheer amount of connections that had to be made, this complexity was to be handled by a custom PCB designed in EasyEDA. <br />
<br />
[[File:Inital wiring.png|1000px|center|thumb|Drawn Schematic]]<br />
[[File:Initial_wiring_testla.PNG|1000px|center|thumb|Breadboard Wiring]]<br />
<br />
<br />
=== Challenges ===<br />
We found that some wires we used were faulty and were not conducting electricity properly. This resulted in a lot of time spent physically debugging connections. To avoid this type of scenario, a continuity check with a multimeter to ensure wire integrity can be performed. We chose to design a PCB to provide a clean look to the car and have higher pin connection strength, as bread board connections tend to be less reliable.<br />
<br />
<hr><br />
<br><br />
<br />
<br />
<br />
<br />
[[File:Master_diagram.PNG|1000px|center|thumb|PCB Schematic]]<br />
<br />
<br />
[[File:Pcb wiring testla.PNG|1000px|center|thumb|PCB Layout showing traces (red are front side, blue are back side)]]<br />
<br />
<br />
The design has many holes for mounting and pinouts for various peripherals (GPS, LCD, Buttons, etc.)<br />
<br />
Steps to design PCB:<br />
Following this general guideline will help you avoid any obstacles.<br />
<br />
* Finish preliminary breadboard wiring and track changes along the way<br />
* Identify desired mounting topology and make measurements<br />
* Use PCB software to make schematic diagram (not PCB wiring)<br />
* Make holes in the PCB for desired mounting locations (the more the merrier)<br />
* Start positioning the components, then begin making traces<br />
<br />
<br />
[[File:Pcb_irl_testla_90.PNG|1000px|center|thumb|Pre-populated PCB]]<br />
<br />
<br />
<br />
[[File:Final_car.png|1000px|center|thumb|Final Design]]<br />
<br />
== CAN Communication ==<br />
<Talk about your message IDs or communication strategy, such as periodic transmission, MIA management etc.><br />
<br />
=== Hardware Design ===<br />
<Show your CAN bus hardware design><br />
<br />
=== DBC File ===<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/blob/master/dbc/testla_proto1.dbc DBC Link]<br />
<br />
<pre><br />
VERSION ""<br />
<br />
NS_ :<br />
BA_<br />
BA_DEF_<br />
BA_DEF_DEF_<br />
BA_DEF_DEF_REL_<br />
BA_DEF_REL_<br />
BA_DEF_SGTYPE_<br />
BA_REL_<br />
BA_SGTYPE_<br />
BO_TX_BU_<br />
BU_BO_REL_<br />
BU_EV_REL_<br />
BU_SG_REL_<br />
CAT_<br />
CAT_DEF_<br />
CM_<br />
ENVVAR_DATA_<br />
EV_DATA_<br />
FILTER<br />
NS_DESC_<br />
SGTYPE_<br />
SGTYPE_VAL_<br />
SG_MUL_VAL_<br />
SIGTYPE_VALTYPE_<br />
SIG_GROUP_<br />
SIG_TYPE_REF_<br />
SIG_VALTYPE_<br />
VAL_<br />
VAL_TABLE_<br />
<br />
BS_:<br />
<br />
BU_: DRIVER MOTOR SENSOR GEO DEBUG<br />
<br />
<br />
BO_ 100 DRIVER_HEARTBEAT: 3 DRIVER<br />
SG_ DRIVER_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" DBG<br />
<br />
BO_ 110 DRIVER_STEERING: 3 DRIVER<br />
SG_ DRIVER_STEERING_yaw : 0|12@1+ (0.001,-2) [-10|10] "radians" MOTOR<br />
SG_ DRIVER_STEERING_velocity : 12|12@1+ (0.01,-20) [-20|20] "kph" MOTOR<br />
<br />
BO_ 120 MOTOR_HEARTBEAT: 5 MOTOR<br />
SG_ MOTOR_HEARTBEAT_speed_raw : 0|8@1+ (1,0) [0|0] "count" DEBUG<br />
SG_ MOTOR_HEARTBEAT_speed_rpm : 8|10@1+ (1,0) [0|0] "rpm" DEBUG<br />
SG_ MOTOR_HEARTBEAT_speed_kph : 18|10@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_HEARTBEAT_angle_duty : 28|10@1+ (0.001,-2) [-10|10] "duty" MOTOR<br />
<br />
<br />
BO_ 125 MOTOR_DEBUG: 8 MOTOR<br />
SG_ MOTOR_DEBUG_speed_target : 0|26@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_DEBUG_speed_kph : 26|10@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_DEBUG_speed_duty : 36|10@1+ (0.1,0) [0|0] "duty" DEBUG<br />
SG_ MOTOR_DEBUG_integral_error : 46|10@1+ (0.1,-10) [-10|10] "error" DEBUG<br />
SG_ MOTOR_DEBUG_current_state : 56|3@1+ (1,0) [0|5] "state" DEBUG<br />
SG_ MOTOR_DEBUG_next_state : 59|3@1+ (1,0) [0|5] "state" DEBUG<br />
<br />
<br />
<br />
<br />
BO_ 128 MOTOR_ESC_CALIBRATED: 1 MOTOR<br />
SG_ MOTOR_ESC_CALIBRATED_calibration_status : 0|4@1+ (1,0) [0|3] "esc_calibration_e" DRIVER<br />
SG_ MOTOR_ESC_CALIBRATED_start_calibration_ack_to_driver : 4|1@1+ (1,0) [0|1] "bool" DRIVER<br />
<br />
<br />
BO_ 129 DRIVER_START_ESC_CALIBRATION: 1 DRIVER<br />
SG_ MOTOR_ESC_CALIBRATED_begin_esc_calibration : 0|1@1+ (1,0) [0|3] "bool" MOTOR<br />
<br />
BO_ 130 MOTOR_ACK: 1 MOTOR<br />
SG_ MOTOR_ACK_cmd : 0|8@1+ (1,0) [0|0] "" DRIVER<br />
<br />
<br />
BO_ 200 SENSOR_SONARS: 8 SENSOR<br />
SG_ SENSOR_SONARS_left : 0|10@1+ (1,0) [0|800] "inch" DRIVER<br />
SG_ SENSOR_SONARS_right : 10|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_middle : 20|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_back : 30|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_frame_id : 42|16@1+ (1,0) [0|0] "" DRIVER<br />
<br />
BO_ 210 SENSOR_DESTINATION_LOCATION: 8 SENSOR<br />
SG_ SENSOR_DESTINATION_latitude : 0|28@1+ (0.000001,-90.000000) [-90|90] "Degrees" GEO<br />
SG_ SENSOR_DESTINATION_longitude : 28|28@1+ (0.000001,-180.000000) [-180|180] "Degrees" GEO<br />
<br />
BO_ 218 NAVIGATION_MESSAGE: 1 GEO<br />
SG_ NAVIGATION_STATUS_navigation_status : 0|8@1+ (1,0) [0|3] "navigation_status_e" DRIVER<br />
<br />
BO_ 219 CHECKPOINT_MESSAGE: 8 GEO<br />
SG_ CHECKPOINT_MESSAGE_compass_heading : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_destination_bearing : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_destination_distance : 24|16@1+ (0.1,0) [0|0] "Meters" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_curr_checkpoint_num : 40|8@1+ (1,0) [0|255] "Integer" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_total_checkpoint_num : 48|8@1+ (1,0) [0|255] "Integer" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_checkpoint_status : 56|8@1+ (1,0) [0|3] "checkpoint_status_e" DRIVER<br />
<br />
BO_ 220 GEO_STATUS: 8 GEO<br />
SG_ GEO_STATUS_compass_heading : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_destination_bearing : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_destination_distance : 24|16@1+ (0.1,0) [0|0] "Meters" DRIVER<br />
<br />
BO_ 520 DEBUG_GPS_CURRENT_LOCATION: 8 GEO<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_latitude : 0|28@1+ (0.000001,-90.000000) [-90|90] "Degrees" DEBUG<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_longitude : 28|28@1+ (0.000001,-180.000000) [-180|180] "Degrees" DEBUG<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_fix : 56|2@1+ (1,0) [0|2] "" DEBUG<br />
<br />
BO_ 521 DEBUG_GEO_GPS_UPDATE: 8 GEO<br />
SG_ DEBUG_GEO_GPS_UPDATE_count : 0|16@1+ (1,0) [0|0] "" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_max_period : 16|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_min_period : 32|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_average_period : 48|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
<br />
BO_ 522 DEBUG_GEO_COMPASS_UPDATE: 8 GEO<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_count : 0|16@1+ (1,0) [0|0] "" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_max_period : 16|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_min_period : 32|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_average_period : 48|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
<br />
CM_ BU_ DRIVER "The driver controller driving the car";<br />
CM_ BU_ MOTOR "The motor controller of the car";<br />
CM_ BU_ SENSOR "The sensor controller of the car";<br />
CM_ BU_ GEO "the geographical controller of the car";<br />
CM_ BU_ DEBUG "the debug topic that all controllers can publish to";<br />
CM_ BO_ 100 "Sync message used to synchronize the controllers";<br />
CM_ SG_ 100 DRIVER_HEARTBEAT_cmd "Heartbeat command from the driver";<br />
<br />
BA_DEF_ "BusType" STRING ;<br />
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 0;<br />
BA_DEF_ SG_ "FieldType" STRING ;<br />
<br />
BA_DEF_DEF_ "BusType" "CAN";<br />
BA_DEF_DEF_ "FieldType" "";<br />
BA_DEF_DEF_ "GenMsgCycleTime" 0;<br />
<br />
BA_ "GenMsgCycleTime" BO_ 100 1000;<br />
BA_ "GenMsgCycleTime" BO_ 200 50;<br />
BA_ "FieldType" SG_ 100 DRIVER_HEARTBEAT_cmd "DRIVER_HEARTBEAT_cmd";<br />
<br />
VAL_ 100 DRIVER_HEARTBEAT_cmd 2 "DRIVER_HEARTBEAT_cmd_REBOOT" 1 "DRIVER_HEARTBEAT_cmd_SYNC" 0 "DRIVER_HEARTBEAT_cmd_NOOP" ;<br />
<br />
<br />
</pre><br />
<HR><br />
<BR/><br />
<br />
== Sensor & LCD ==<br />
* Sensor '''''[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/tree/master/projects/lpc40xx_freertos_Bridge_Sensor_Controller Gitlab]'''''<br />
*LCD '''''[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/tree/master/projects/lpc40xx_freertos_LCD_I2C Gitlab]'''''<br />
<br />
=== Sensor Hardware Design ( SJ-2 Bridge Control Board) ===<br />
<br />
'''Block Diagram'''<br />
[[File:sensor_1.jpg |600px|middle]]<br />
<br />
'''Ultrasonic Sensor''' <br />
[[File:sensor_2.jpg |600px|middle]]<br />
<br />
* Ultra-Sonic Sensor URM09 (I2C Protocol)<br />
• '''Supply Voltage:''' 3.3~5.5V DC<br />
• '''Operating Current:''' 20mA<br />
• '''Operating Temperature Range:''' -10℃~+70℃<br />
• '''Measurement Range:''' 2cm~500cm (can be set)<br />
• '''Resolution:''' 1cm<br />
• '''Accuracy:''' 1%<br />
• '''Frequency:''' 50Hz Max<br />
• '''Dimension:''' 47mm × 22 mm/1.85” × 0.87”<br />
<br />
'''Sensor Mount''' <br />
[[File:sensor_3.jpg |600px|middle]]<br />
<br />
=== Sensor Software Design ===<br />
* '''Low level - peripheral driver'''<br />
** Peripheral Initialize function <br />
*** I2C Clock 100KHz<br />
*** I2C Pin: <br />
**** SCL: P0_10<br />
**** SDA: P0_11<br />
** I2C single byte read function <br />
*** Input parameter <br />
**** Slave address (7-bit + R/W-bit) <br />
**** Register address (1 byte) <br />
*** Output parameter <br />
**** Register value (1 byte)<br />
*** Return true if success else return false <br />
** I2C single byte write function <br />
*** Input parameter <br />
**** Slave address (7-bit + R\W bit) <br />
**** Register address (1 byte) <br />
**** Written value (1 byte) <br />
*** Return true if success else return false<br />
<br />
<br />
* ''' Mid-level -sensor ''' <br />
* Defined data struct <br />
** Sonar_sensor__sample_sum_s <br />
*** Left<br />
*** Middle <br />
*** Right <br />
*** Back <br />
** Sonar_sensor__sample_queue_s<br />
*** Left<br />
*** Middle <br />
*** Right <br />
*** Back <br />
** Sonar_sensor__address_e<br />
*** Left (7-bits - 0x26)<br />
*** Middle (7-bits – 0x22)<br />
*** Right (7-bits – 0x24)<br />
*** Back (7-bits – 0x20)<br />
** Sonar_sensor_measure_mode_e<br />
*** Automatic<br />
*** Passive <br />
** Sonar_sensor__measure_range_e<br />
*** 150 cm <br />
*** 300 cm <br />
*** 500 cm<br />
<br />
* Initialize sensor function <br />
** Init I2C peripheral<br />
** Init all the sensors with the following configurations: <br />
*** Passive measure mode <br />
*** 150 cm range <br />
* Sensor collects sample function <br />
** To avoid the sensor's crosstalk, we implement the following sequence<br />
*** Start the measurement left sensor <br />
*** Delay 25ms <br />
*** Collect data from the left sensor <br />
*** Start the measurement right sensor <br />
*** Delay 25ms <br />
*** Collect data from the right sensor <br />
*** Start the measurement back and middle <br />
*** Delay 25ms <br />
*** Collect data from the back and middle sensor<br />
<br />
<br />
<br />
=== Sensor Technical Challenges ===<br />
<br />
*'''Issue:''' we cannot read or write on the default address.<br />
*'''Reason:''' After using the logical analyzer, we realize the init clock at 400Khz was too fast for this sensor even though the datasheet did not mention it. <br />
*''' Solution:''' we reduce the I2C Clock speed to 100kHz <br />
<br />
<br />
*'''Issue:''' These nearby ultra-sonic sensors receive each other’s bounce-back signal. <br />
*'''Reason:''' We config the sensor in automatic mode, and it causes the sensors to crosstalk.<br />
*''' Solution:''' we config the sensor in passive mode and tested them with many test cases to come up with the best sequence, and the sensor must operate at 10hz frequency. <br />
<br />
<br />
*'''Issue:''' Sensor noise is getting worse with bad mounting <br />
*'''Reason:''' the sensors are mounted with the bean down to the ground.<br />
*''' Solution:''' we come to design a mechanical mount with the ability of 60 degrees horizontal and vertical adjustment<br />
<br />
<br />
== Motor ECU ==<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/tree/master/projects/lpc40xx_freertos_Motor_Controller Motor Controller Link]<br />
<br />
=== Hardware Design ===<br />
<br />
[[File:Car_diagram.PNG|1000px|center|thumb|Car Diagram]]<br />
<br />
A single SJ2-C board was placed in charge of handling all interactions with the Traxxas parts. This included an ESC (Electronic Speed Control) connected to a brushed DC motor, a servo motor for steering control, and a wheel encoder installed adjacent to the gear shaft (CHECK).<br />
<br />
===== Defining Signals =====<br />
While Traxxas does provide support for hobby RC car enthusiasts, they do not provide clear documentation on signal inputs and outputs to all of their electrical components. To understand what signals would need to be generated by the SJ2-C, the output of the receiver was intercepted. Manipulating the Traxxas remote would generate PWM signals at the output of the receiver. By reading these signals on an oscilloscope, it was determined that both the ESC and servo motor both operated with a 100 Hz PWM signal on a range of duty cycles between 10 - 20%.<br />
<br />
*For the ESC: 10% DC = full reverse speed, 15% DC = idle/zero speed, 20% DC - full forward speed<br />
<br />
*For the servo motor: 10% DC = wheels fully turned to the left, 15% DC = wheels turned straight ahead, 20% DC = wheels turned fully to the right.<br />
<br />
===== Setting up the PWM channels =====<br />
The PWM channels on pins P2.0 and P2.1 were both enabled on single edge mode at a frequency of 100 Hz with a duty cycle of 15%. Initial tests were conducted by mapping the buttons of the SJ2-C to modifying the duty cycles on both PWM channels. These tests were successful in changing the motor speed and wheel direction.<br />
<br />
===== RPM Sensor =====<br />
In order to give real-time feedback on the speed the car is traveling at, an RPM sensor was installed. For ease of compatibility, the Traxxas 6520 RPM Sensor (long variant) was purchased for this task. It was installed with the Traxxas 6538 Telemetry Trigger Magnet Holder for Spur Gear by following this [https://youtu.be/-26ZSgDqwQQ?t=82 tutorial]. While this was expected to provide proper signal output with no extra components, initial testing of the sensor yielded an 0.4 Vpp signal comprised of an unstable, noisy signal. Doing further research led us to find that a 1kΩ pull-up resistor connecting the data pin to a 3.3V rail was required to pull the signal high instead of letting it float. This corrected the output signal to give the expected result.<br />
<br />
===== SJ2-C LED Breakdown =====<br />
Normal Operation:<br />
*LED 0: Toggle on CAN receive<br />
*LED 1: Toggle on CAN transmit<br />
*LED 2: Unused<br />
*LED 3: Driver signal Missing-in-Action<br />
<br />
ESC Calibration<br />
*LEDs 0-2: Used to detail current step in calibration process<br />
*LED 3: Unused<br />
<br />
===== SJ2-C Switch Breakdown =====<br />
*SW 0: Start ESC Calibration Sequence<br />
*SW 1: Disable Motor<br />
*SW 2: Disable Steering<br />
*SW 3: Enable both Motor and Steering<br />
(Note: Motor and Steering are disabled on startup by default)<br />
<br />
<br/><br />
<br />
=== Software Design ===<br />
===== CAN Bus Interactions =====<br />
The Motor Controller receives two different values from the Driver Controller: an angle to turn the wheels to (DRIVER_STEERING__yaw) and the speed at which to drive (DRIVER_STEERING__velocity).<br />
The Motor Controller sends a multitude of signals addressed to “Debug”, as well as one signal to the Driver pertaining to the status of ESC calibration. These debug signals include a variety of formats of the current speed given by the RPM sensor, the error calculation used in the PID logic, and the operations of the state machine within the motor logic handler.<br />
===== RPM Sensor =====<br />
With a proper data output from the sensor, the output was attached to pin 2.6 (CAP0) for operation with Timer2. The initial plan was to measure the time between pulses and perform calculations to extrapolate the current speed, but another unexpected issue was experienced. When configuring the interrupt handler on the pin in either rising-edge or falling-edge detection, the interrupt handler would be triggered repeatedly on what appeared to be a steady low signal. This was observed by configuring Bus Master to show the interrupt count in combination with viewing a logic analyzer to see the signal state. This was especially concerning as it was noticed that if the car wheels stopped turning at a specific position, the sensor would permanently hold a low signal until further rotation occurred, causing even more potential for inaccuracy in any given speed reading. After hours of trying different interrupt configuration settings, efforts to find a direct solution were put on pause. A workaround was discovered by essentially disregarding any interrupts that were deemed to be physically too fast to have been caused by the actual rotation of the tires. This resulted in proper software operation of the interrupt handler, but it required a new method for ascertaining the speed. The final implementation revolved around counting the amount of sensor pulses within a 5 Hz window. This timing was specifically chosen as a compromise between two tradeoffs. A quicker window would allow for faster updates to the ESC, but a slower window would allow for more pulse data collection and higher accuracy.<br />
{| style="margin-left: auto; margin-right: auto; border: none;"<br />
|[[File:Sensorwire.PNG|400px|400px|center|thumb|Hall Effect Sensor for RPM]] || [[File:Magnetholder.PNG|400px|400px|center|thumb|Magnet Holder for RPM]] || [[File:Gear.PNG|400px|400px|center|thumb|Install location for Magnet Holder]]<br />
|<br />
|}<br />
===== PID Controller =====<br />
While an objective of the car is to implement a “PID” controller, in reality a simple “P” controller is enough for an effective control system. This means that all that is needed is the target speed, the current speed, and a gain factor. If the current speed is far from the target speed, a higher error value is produced. When multiplied with the gain, this results in the car making larger changes to its speed to reach the target speed, while using smaller changes to modulate the speed as forces on the car change due to varying terrain or surface angle changes.<br />
// -------------Error Calculations-------------//<br />
if (next_state == FORWARD) {<br />
error = target_motor__kph - current_speed;<br />
} else if (next_state == REVERSE) {<br />
error = target_motor__kph + current_speed;<br />
}<br />
<br />
} else if (next_state == FORWARD) {<br />
speed_for_motor__kph += gain * error;<br />
}<br />
===== ESC Calibration =====<br />
When demoing the second prototype, the ESC fell out of calibration for the first time in operation. This created an undesirable situation where the Traxxas receiver had to be connected back to the motor so it could be calibrated with the Traxxas remote. This led to the need for the calibration sequence to be programmable from the board with no need to rewire components. It was observed that to calibrate the ESC, the remote trigger would need to follow a certain procedure:<br />
Neutral position<br />
Full forward speed<br />
Full reverse speed<br />
Neutral position<br />
This procedure was copied by the Motor Controller with a preparation delay inserted into the beginning of the sequence and can be activated by pressing switch 0 at any time. Note that the ESC should be placed in calibration mode just after pressing switch 0. Failure to do so could cause the car to attempt to reach its maximum speed and hold it for two seconds.<br />
<br />
===== State Machine =====<br />
The final version of the Motor Controller logic included a state machine:<br />
<br />
[[File:Fir3.png|1000px|center|thumb|Main States]]<br />
<br />
Each state is defined in the following enumeration:<br />
typedef enum {<br />
IDLE = 0,<br />
FORWARD = 1,<br />
BRAKING = 2,<br />
START_NEUTRAL_FOR_REVERSE = 3,<br />
NEUTRAL_FOR_REVERSE = 4,<br />
REVERSE = 5,<br />
} CAR_MOTION_STATUS;<br />
<br />
Things to note:<br />
*Braking is the same as sending a reverse signal to the ESC. This is different from sending an idle signal that stops applying current to the motor and allows the car to coast to a halt.<br />
*The START_NEUTRAL_FOR_REVERSE, NEUTRAL_FOR_REVERSE, and REVERSE states are all necessary for the car to perform reverse motion if the car had been moving forward just prior.<br />
<br />
The state machine starts by checking the speed the Driver Controller wants to obtain. This can be one of three states: 0 speed, forward speed, or reverse speed:<br />
if (target_motor__kph >= -0.1f && target_motor__kph <= 0.1f) {<br />
...<br />
} else if (target_motor__kph > 0.1f) {<br />
...<br />
} else if (target_motor__kph < -0.1f) {<br />
...<br />
}<br />
<br />
Within a speed value, the current state is checked and the next state is assigned based off of this. There's coverage for every case here, as the car should be able to go ''from'' any state ''to'' any state.<br />
<br />
if (target_motor__kph >= -0.1f && target_motor__kph <= 0.1f) {<br />
if (current_state == IDLE) {<br />
next_state = IDLE;<br />
} else if (current_state == FORWARD) {<br />
next_state = BRAKING;<br />
} else if (current_state == BRAKING) {<br />
if (current_speed >= -0.1f && current_speed <= 0.1f) {<br />
next_state = IDLE;<br />
} else {<br />
next_state = BRAKING;<br />
}<br />
} else if (current_state == START_NEUTRAL_FOR_REVERSE) {<br />
next_state = IDLE;<br />
} else if (current_state == NEUTRAL_FOR_REVERSE) {<br />
next_state = IDLE;<br />
} else if (current_state == REVERSE) {<br />
next_state = IDLE;<br />
}<br />
}<br />
<br />
=== Technical Challenges ===<br />
*RPM Sensor gave low voltage, improper signal (see: Hardware Design - RPM Sensor)<br />
*Interrupt handler generated interrupts on stable signal (see: Software Design - RPM Sensor)<br />
*ESC would require calibration on startup every time - Sending a neutral signal (15% Duty Cycle) to the ESC for the first three seconds gave the ESC a signal to lock on to and not require calibration<br />
<br />
<HR><br />
<BR/><br />
<br />
== Geographical Controller ==<br />
The geographical (geo) controller is used to provide the vehicle with a sense of location. To do this, the controller is interfaced to a compass which provides a heading, and a GPS module which provides a latitude, longitude, and GPS fix. GPS fix indicates that the GPS unit is connected to enough sattelites to provide accurate location data. The controller reads a destination off the CAN bus and calculates the distance from its current position. Additionally, it calculates a bearing, which is the degrees from north that the car must point to be facing the destination. If the car aligns its heading with the bearing and drives in a straight line for the number of meters described by the distance calculation, then the car will arrive at its destination.<br />
<br />
However, the vehicle will not be driving in a straight line because of obstacle avoidance. To deal with this, the distance and bearing are updated regularly at a rate of 10Hz. When an obstacle forces the vehicle to deviate from the desired course, it will recalculate the bearing and distance from its new location. This distance and location is then broadcast on the CAN bus, and digested by the driver controller.<br />
<br />
=== Hardware Design ===<br />
<br />
[[File:adafruit_gps.jpg]]<br />
<br />
An Adafruit Ultimate GPS breakout module using the MTK3339 chipset is interfaced over UART to the Geographical controller to provide latitude and longitude updates.<br />
<br />
<br />
[[File:wt901_compass.jpg]]<br />
<br />
A Witmotion WT901 IMU is connected over I2C to provide access to the vehicles heading.<br />
<br />
=== Software Design ===<br />
The general software flow is shown in the diagram below. This loop is run in a 10Hz periodic callback set up in FreeRTOS.<br />
<br />
[[File:geo_flow.jpg]]<br />
<br />
==== Initialization ====<br />
On startup the GPS module is configured. The GPS module sends data at 9600 bps after powering on but must be set to 115200 bps to support 10Hz updates. The controller must send a command to increase the GPS module's baud rate then change the baud rate on its own UART interface. Initially, the GPS sends out several different NMEA strings on every update. The vehicle only needs latitude , longitude and GPS fix data so the GPS is configured to only send GPGGA strings. This prevents the geo controller from wasting time to intake data that it is uninterested in. Finally, the GPS module is configured to send updated data at a rate of 10Hz. After this process is complete, the controller enters its main loop.<br />
<br />
==== Main Loop ====<br />
The geo controller runs at a frequency of 10Hz. A FreeRTOS task uses vTaskDelayUntil() to define a finite period of 100 milliseconds between invocations of the periodic callback.<br />
<br />
The GPS module is read by reading characters out of the UART into a line buffer. If a full line has been deposited into the buffer then the latitude, longitude and GPS Fix are updated. Additionally, a min and max time between GPS updates field is filled in as well as a count of updates. This debug information is published on the bus to analyze fidelity of the module.<br />
<br />
Next, the compass is read over an I2C interface to acquire the heading. The WT901 is an IMU which actually has a good deal more information available besides heading. Currently we are only reading the compass heading but can expand expand in the future to read acceleration and orientation. This module does need to be calibrated one time to ensure it is correctly reporting the heading. The module has a UART interface which can be used to interface between a TTL to USB converter to a software suite. This software can also be used for debugging and calibration.<br />
<br />
After reading the position the CAN interface checks if there are any changes to the destination being published by the bridge controller. After obtaining the most recent desired destination, the geographical module is invoked to calculate a distance and bearing. The section below goes into more detail on the geo calculation. After a distance and bearing are calculated, they are published onto the bis along with the current heading and dubug information. <br />
<br />
==== Geo process ====<br />
<br />
The desired and current position are used to calculate a distance and bearing using the haversine formula shown below.<br />
<br />
'''Distance'''<br />
<br />
[[File:haversine.PNG]]<br />
<br />
'''Bearing'''<br />
<br />
[[File:Bearing_calculations.PNG]]<br />
<br />
[https://www.movable-type.co.uk/scripts/latlong.html Moveable Type Scripts: Calculate distance, bearing and more between Latitude/Longitude points]<br />
<br />
<br />
<br />
=== Technical Challenges ===<br />
<br />
There were several challenges in developing a reliable geographical controller.<br />
<br />
Initially, connecting to the GPS was a challenge because the format of the ASCII lines were not well understood.<br />
<br />
'''Expected string'''<br />
<br />
$GPGGA,064951.000,2307.1256,N,12016.4438,E,1,8,0.95,39.9,M,17.8,M,,*65<br />
<br />
'''Actual string'''<br />
<br />
$GPGGA,,,,,,,5,,,,M,,*65<br />
<br />
There were also issues with verifying that the command strings being sent were achieving their desired results<br />
<br />
Both these problems were solved by attaching the tx line of the GPS to an oscilloscope and decoding the UART messages. This allowed us to fully characterize the output of the GPS and its response to command strings.<br />
<br />
<br />
<br />
<HR><br />
<BR/><br />
<br />
<HR><br />
<BR/><br />
<br />
== LCD & Communication Bridge Controller ==<br />
*Bridge '''''[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/tree/master/projects/lpc40xx_freertos_Bridge_Sensor_Controller Gitlab]'''''<br />
*LCD '''''[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/tree/master/projects/lpc40xx_freertos_LCD_I2C Gitlab]'''''<br />
<br />
=== LCD Hardware Design ===<br />
[[File:lcd_1.jpg |500px|middle]]<br />
<br />
LCD Circuit with 8-bit I/O expander for I2C-bus<br />
[[File:lcd_2.jpg |500px|middle]]<br />
[[File:lcd_3.jpg |500px|middle]]<br />
<br />
=== LCD Software Design ( SJ2- Driver Board) ===<br />
<br />
* '''Low level - peripheral driver'''<br />
** Peripheral Initialize function <br />
*** I2C Clock 400KHz<br />
*** I2C Pin: <br />
**** SCL: P0_10<br />
**** SDA: P0_11<br />
** I2C single byte write function <br />
*** Input parameter <br />
**** Slave address (7-bit + R\W bit) <br />
**** Register address (dummy byte - we always write directly into VRAM ) <br />
**** Written value (1 byte) <br />
*** Return true if success else return false<br />
<br />
** Toggle Enable Pin Function <br />
*** Input parameter<br />
**** byte value<br />
<br />
<br />
* '''Mid-level - LCD driver Command Byte vs Data Byte '''<br />
** Transfer command byte function <br />
*** Input parameter<br />
**** byte value<br />
<br />
** Transfer data byte function <br />
*** Input parameter<br />
**** byte value<br />
<br />
* '''High-level - LCD driver '''<br />
** LCD init function ( backlight ON )<br />
*** Input parameter<br />
**** Colum <br />
**** Row<br />
**** Character Size <br />
<br />
** LCD clear function <br />
<br />
** LCD clear particular location function <br />
*** Input parameter<br />
**** Start Colum <br />
**** Start Row<br />
**** Number of character need to clear <br />
<br />
** LCD set cursor location function <br />
*** Input parameter<br />
**** Start Colum <br />
**** Start Row<br />
<br />
** LCD print char function <br />
*** Input parameter <br />
**** Start Colum<br />
**** Start Row<br />
**** Pointer to first index of char array<br />
<br />
=== Bridge Controller ===<br />
The Bridge Controller is used to establish wireless communication between our vehicle and mobile app. This is a bi-directional communication where the bridge controller will send vehicle states (GPS location, heading, speed & sensor data) to the mobile app, and also receive command messages (gps destination) to broadcast back to the vehicle CAN bus. We decided to use an ESP8266 to connect the bridge controller to the local WIFI network. We picked ESP8266 because SJTwo board already provides an open slot to install this module. Instead of connecting the vehicle directly to the mobile app which may require managing low-level network sockets on mobile devices, we use a NodeJS server as a mediator to maintain a more reliable communication between these two end-points. This design decision also makes it possible to monitor the vehicle state and send commands from multiple devices at the same time.<br />
<br />
=== Bridge Hardware Design ===<br />
<br />
[[File:Sjtwo-esp8266.png]]<br />
ESP-8266 (ESP-01) slot on SJTwo board<br />
<br />
[[File:Esp8266-01.png]]<br />
ESP-8266 module pinouts<br />
<br />
The ESP-8266 is a low-cost WIFI with a built-in TCP/IP software stack. ESP-8266 is connected to the SJTwo board via UART3. SJ-Two board communicates with ESP8266 using AT Command Set Interface.<br />
<br />
=== Bridge Software Design ===<br />
<br />
There are two key components in our setup for the bridge controller:<br />
Local Bridge Node<br />
Remote Server<br />
Our local bridge node is a FreeRTOS task that runs continuously (with a 100ms sleep period). When being run, the task will start by performing an initialization sequence on ESP8266. When a WIFI connection is established, the bridge node will use new data collected from the CAN bus to compose a new message and send it to the server via a TCP/IP socket. Along with that, the task also monitors the current status of this TCP/IP connection and network status and attempts to reconnect whenever the connection dropped for any reason. <br />
The remote server is a NodeJS server running on an AWS EC2 instance. The server accepts raw TCP/IP communication with the local bridge node and broadcasts the data to any clients via topic channels (‘location’, ‘sensor’, ‘steering’, etc.) powered by socket.io. Since the local bridge node runs periodically at around 2Hz, we make use of the server response message as a way to send commands back to the bridge node. With this approach, we don’t have to configure ESP8266 as a server and create another TCP/IP socket just for sending commands from the server back to the local bridge node.<br />
<br />
=== Technical Challenges ===<br />
When implementing the bridge controller with the provided ESP-32 library, our board was reset occasionally due to the retry-and-timeout mechanism for sending TCP/IP packets more reliably. We were able to bypass this issue by running the bridge controller as an independent FreeRTOS task instead of running it inside the periodic scheduler.<br />
<br />
<HR><br />
<BR/><br />
<br />
== Master Module ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<br />
The main software design for the master controller comprises of taking in communication from all of the other controllers on the bus in order to figure out the status of the car and act accordingly. <br />
<br />
The purpose of the master controller’s branch of logic is for it to be used for responding to navigation sequences that are established by Bridge and Geo controller. From this, we can explain that there are two main branches of the car’s driver logic: Obstacle Avoidance Logic and Navigation to the Next Checkpoint logic.<br />
<br />
In Obstacle Avoidance mode, the main objective is for the car to avoid crashing into obstacles such as people, walls, etc throughout the course of the navigation sequence. This logic branch triggers only when there is a threshold of 0, 1, or 2 for any of the front sensors. <br />
<br />
In Navigation Towards next checkpoint mode, the car will navigate towards the next checkpoint until there are no checkpoints left. It will only do this if there are sensor readings above 150cm. If an object is detected at threshold 3, the car can still navigate towards the target, but it will do so at half of the speed so that it can apply breaks prematurely to help it avoid obstacles more smoothly.<br />
<br />
The way that we read the sensor thresholds is that we use 4 different values, 25cm for sensor threshold 0, 50cm for sensor threshold 1, 135cm for sensor threshold 2, and 149cm for sensor threshold 3.<br />
<br />
/// Check sensor values against defined constant thresholds and return bitfields for sensors corresponding to the convention below.<br />
<br />
/// Helper function called by all 4 function above to provide required output value using (0b0000BRML) bit convention<br />
obstacle_detected_on_sensors_e driver__helper_check_sensors_under_OBJECT_THRESHOLD_N(uint16_t left_sensor, uint16_t middle_sensor, uint16_t right_sensor, uint16_t back_sensor, uint16_t threshold) {<br />
obstacle_detected_on_sensors_e ret_sensors_trig = no_sensor_triggered; // Init to 0 for no obstacles detected<br />
// Sensor Bitmasks<br />
const uint8_t no_sensor_bitmask = 0b00000000;<br />
const uint8_t left_sensor_bitmask = 0b00000001;<br />
const uint8_t middle_sensor_bitmask = 0b00000010;<br />
const uint8_t right_sensor_bitmask = 0b00000100;<br />
const uint8_t back_sensor_bitmask = 0b00001000;<br />
// Bitwise OR each sensor below threshold passed in with it's respective bitmask<br />
ret_sensors_trig |= (left_sensor < threshold) ? left_sensor_bitmask : no_sensor_bitmask;<br />
ret_sensors_trig |= (middle_sensor < threshold) ? middle_sensor_bitmask : no_sensor_bitmask;<br />
ret_sensors_trig |= (right_sensor < threshold) ? right_sensor_bitmask : no_sensor_bitmask;<br />
ret_sensors_trig |= (back_sensor < threshold) ? back_sensor_bitmask : no_sensor_bitmask;<br />
return ret_sensors_trig;<br />
}<br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Mobile Application ==<br />
<br />
[[File: Testla-app-1.jpg |600px ]]<br />
[[File: App-2.jpg |600px ]]<br />
<br />
=== Software Design ===<br />
Our mobile app was developed using Flutter framework. We were able to release both Android and iOS version.<br />
The app is connected to our AWS server using Socket.IO and continue to listen to topics related to the vehicle. Whenever user select a new destination on the map, the app will send a new command message to server so that the new destination will be sent to the bridge controller.<br />
<br />
<BR/><br />
<HR><br />
<HR><br />
<BR/><br />
<br />
== Conclusion ==<br />
Testla, at its simplest, is a combination of four micro-controllers on an RC car chassis to accomplish autonomous driving. To drive autonomously there are several necessary components: local real-time awareness, big picture planning, actuation, and limited human input. <br />
<br />
Local real-time awareness in this project is handled by the sonar sensor array, geo controller and driver controller. This pathway takes in immediate, on the ground information to respond to a dynamic environment. <br />
<br />
Big picture planning is handled by our way point mapping scheme. By having a knowledge of the static elements of our environment we can constrain and scope out the behavior of the vehicle into a more reasonable subset of reactions. That sounds pretty vague, but the big picture aspect of the project is by definition vague. We use the known elements to set expectations and apply real-time on the ground sensing to deal with deviations from the expected environment.<br />
<br />
In order to move this vehicle from point-a to point-b we need a sophisticated drive train and driver. The motor controller provides effective execution of desired speed set-points regardless of terrain. Additionally, the driver reads in all of the static and dynamic environmental information to give actuator set-points.<br />
<br />
Finally, we have the human input. Our android application and wireless interface allows the user to select desired destinations and observe the vehicle's response. Our application provides a satellite map where way points can be applied and provides diagnostic information for the sonar, compass, and motors.<br />
<br />
==== What We Learned ====<br />
We learned a great deal in this quick semester. <br />
<br />
We learned how the CAN bus is used to network several subsystems together. There are a lot of networking options available: Ethernet, CAN, LIN, and a host of wireless options. CAN is a predictable and reasonable standard that is proliferated throughout industry and is worth adding to your skill set.<br />
<br />
We learned how to break a complex project down into several smaller problems to utilize multiple parallel development tracks. By breaking the project down into several sub-systems we were able to delegate parts of the larger system to each of our team members.<br />
<br />
We also learned not to get comfortable with early successes. We had some early progress and relaxed but had problems later on and ended up falling behind for it. When you feel like things are going well, that is the time to double down and push harder, not the time to rest.<br />
<br />
"On the plains of hesitation bleach the bones of countless millions who, at the dawn of decision, sat down to wait, and waiting died." - George W. Cecil<br />
<br />
=== Project Video ===<br />
https://drive.google.com/file/d/1JcqAspXMEF0LxYeYpAiJtjhLEtfNJ3-H/view?usp=sharing<br />
<br />
=== Project Source Code ===<br />
<br />
https://gitlab.com/testla_sjsu/autonomous_vehicle<br />
<br />
=== Advice for Future Students ===<br />
===== General Message =====<br />
This is a car project, so the best way to phrase advice for future students is through a car metaphor. <br />
<br />
This project is a destination that you are a reasonable distance away from. You can race and drive recklessly towards your destination to try and get there on time but at the end of the day, leaving earlier is what puts you farther ahead on the road. Take the project seriously from day one and make realistic progress every week and you will have a great experience. Leave late and the journey will be a stressful catch-up game.<br />
<br />
===== Specific Tips =====<br />
*Attach a '''dog leash''' to your chassis when testing. This will probably be needed in every test session until the final week before the demo.<br />
*Put a massive amount of '''focus into the hardware setup at the beginning''' of the project. By the first prototype deadline we had a hardware setup that would’ve been acceptable as a final version. By focusing on the hardware, it was completely trustworthy while working on the software.<br />
*Set a '''consistent schedule for meeting up''' outside of class. What worked for us was Thursdays at 6pm and Sundays at about 1pm. Be prepared to spend '''one day of your weekend on a weekly basis''' focused on this project.<br />
*There will need to be at least a couple of '''meetings just to discern responsibilities and a schedule''' for the project everyone can agree on. This should be done before the class material fully shifts into project coverage.<br />
*Make sure '''everyone’s roles are clearly defined''' from the start, including controller assignments. The Geo, Sensor, and Bridge controllers can all be handled by one person per controller. The Motor controller is possible with one person, but ideally could use two people collaborating. The Driver controller needs two people. Note that someone should be leading the charge on wiring and physical packaging, but everyone should contribute to it where they can.<br />
*The people in charge of their controllers should '''be the master of their controller''' and able to answer any questions the group presents them. This will make collaboration between controllers smooth. Adding to this though, let each group member be in charge of their node. While communication and discussion is always encouraged, the final say of a decision of any controller should be left to the owner of that controller. They will be most familiar with their systems and know what they need to do.<br />
*Utilize '''Visual Studio Live Share for pair-programming''' sessions. If this is not available, make use of any screen-sharing applications (Slack, Zoom, Discord).<br />
*Work on the wheel encoder / rpm sensor early and make it stable. Working speed readings are imperative for a smooth PID controller. Many groups including ours had trouble getting this part to work.<br />
*Using an ultrasonic sensor which returns an analog value might cause more trouble and require more work to analyze the signal. While it could provide better resolution, it might need extra work to improve the signal integrity. This could be done using an OP-AMP as a buffer or for subtracting the offset voltage. You might run out of time trying to make this work.<br />
<br />
=== Acknowledgement ===<br />
First and foremost we have to acknowledge all the teams who came before us. The largest source of information and inspiration came from them. There are an immense amount of well documented attempts at solving this problem. We truly in debt to the teams that came before us and hope we added something to the knowledge base here at Social Ledge.<br />
<br />
Next, we have to acknowledge Professor Preetpal Kang. CmpE 243 is the product of a lot of hard work on his part. Preet makes himself available for all the students and shares his many years of experience and expertise. This is one of the most valuable part of the SJSU computer engineering masters program.<br />
<br />
We also need to acknowledge the former students and others who work on the SJTwo repository and the Social Ledge website. This is another wealth of information and we could not have built this project without this resource.<br />
<br />
Finally, We should (and do) acknowledge all of the teams in our class this semester. We were lucky to have an engaged group of teams working together and sharing knowledge and experiences.<br />
<br />
=== References ===<br />
https://www.movable-type.co.uk/scripts/latlong.html <br><br />
https://www.youtube.com/watch?v=-26ZSgDqwQQ</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=69095F21: Space Rage2022-08-27T02:43:05Z<p>Proj user2: </p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
{|<br />
|[[File:Lives screen.gif |thumb|800px|'''Player Lives Screen''']]<br />
|[[File:Gameplay_countdown.gif |thumb|800px|'''Gameplay Countdown Sequence''']]<br />
|[[File:Title_screen.gif |thumb|800px|'''Gameover to Title Screen Sequence''']]<br />
|}<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly for up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/devin-b-alexander/ Devin Alexander]''''' '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Throughout the implementation project, we found that we had utilized many concepts that we had learned from this course. The concepts taught in the weeks leading up to the project allowed for us to be prepared to apply them into building Space Rage. The concept of multi-threaded code was newer to some of us, but we feel that it prepares us for our future careers as embedded software engineers. The use of prioritizing various blocks of code over others and how the impacts it has on the scheduling of tasks is an important concept to understand. The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block moving forward in our careers.<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reaching those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=S22:_Testla&diff=69006S22: Testla2022-05-28T07:39:54Z<p>Proj user2: /* Team Members & Responsibilities */</p>
<hr />
<div>== Testla ==<br />
[[File:Bunch of handsome young men.jpeg |800px|middle]]<br />
<br />
<br />
<HR><br />
<BR/><br />
<br />
== Abstract ==<br />
The Testla project is the culmination of our efforts to create an autonomously operated RC Car by pooling together our experience in software design, hardware design, power systems, and mobile application development. Project development started in February of 2022 and ended in May.<br />
<br />
=== Introduction ===<br />
<br />
The project was divided into 5 modules:<br />
<br />
* Sensor Information<br />
* Motor Operation<br />
* Geological Information<br />
* Driver & LCD Manager<br />
* Bridge & Android Application<br />
<br />
=== Team Members & Responsibilities ===<br />
<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle Gitlab Project Link]<br />
<BR/><br />
<br />
[[File:DevinAlexander.jpeg|200px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Leader<br />
** Geographical Controller<br />
** Master Controller<br />
<br />
[[File:Sinan.jpg|200px|middle]]<br />
* Sinan Bayati '''''[https://gitlab.com/sinan.bayati Gitlab]'''''<br />
** PCB Design<br />
** Motor Controller<br />
<br />
[[File:MichaelHatzi.PNG|200px|middle]]<br />
* Michael Hatzikokolakis '''''[https://gitlab.com/mikehatzi8 Gitlab]'''''<br />
** Co-Leader<br />
** Motor Controller<br />
** Testing<br />
<br />
[[File:scott_locascio.jpeg|200px|middle]]<br />
* Scott LoCascio '''''[https://gitlab.com/scottlocascio Gitlab]'''''<br />
** Geographical Controller<br />
** Car Construction<br />
** Testing<br />
<br />
[[File:Thinh-avatar.jpg|200px|middle]]<br />
* Thinh Lu '''''[https://gitlab.com/lphucthinh40 Gitlab]'''''<br />
** Android Application<br />
** Sensor and Bridge Controller<br />
<br />
[[File:BangNguyen.jpg|200px|middle]]<br />
* Bang Nguyen '''''[https://gitlab.com/karosious Gitlab]'''''<br />
** Sensor and Bridge Controller<br />
** LCD Display<br />
<br />
<BR/><br />
<br />
== Schedule ==<br />
<br />
<br />
{| class="wikitable" <br />
|-<br />
! Week #<br />
! Start Date<br />
! End Date<br />
! Task<br />
! Status<br />
|-<br />
| 1<br />
| 2/15/2022<br />
| 2/21/2022<br />
| Read previous projects, gather information and discuss among the group members.<br />
| Complete<br />
|-<br />
| 2<br />
| 2/22/2022<br />
| 2/28/2022<br />
| style="background-color:#F9F9F9;" | Distribute modules to each team member.<br />
| Complete<br />
|-<br />
| 3<br />
| 3/1/2022<br />
| 3/7/2022<br />
| Purchase the RC Car<br />Purchase sensors<br />
| Complete<br />
|-<br />
| 4<br />
| 3/8/2022<br />
| 3/14/2022<br />
| style="background-color:#F9F9F9;" | Learning to use CAN BUSMASTER<br />
| Complete<br />
|-<br />
| 5<br />
| 3/15/2022<br />
| 3/21/2022<br />
| style="background-color:#F9F9F9;" | DBC file discussed and implemented<br />
| Complete<br />
|-<br />
| 6<br />
| 3/22/2022<br />
| 3/28/2022<br />
| style="background-color:#F9F9F9;" | Discuss modules needed for PCB, any feature requests<br />
| Complete<br />
|-<br />
| 7<br />
| 3/29/2022<br />
| 4/4/2022<br />
| Finalize preparations and research<br />
| Complete<br />
|-<br />
| 8<br />
| 4/5/2022<br />
| 4/11/2022<br />
| Interface with RC car and hack steering and motor<br />Integrate the GEO sensor with the GEO controller<br />Complete the Driver sensor using analog readings<br />Write a basic implementation of the sensor controller<br />Interface ESP8266 for bridge controller<br />Begin testing with single vs dual power supplies<br />
| Complete<br />
|-<br />
| 9<br />
| 4/12/2022<br />
| 4/18/2022<br />
| Install wheel encoder, implement, implement PID into velocity processing, and establish collaboration between the Motor and Sensor Controllers<br />Test alternate sonar sensor (I2C)<br />Configure GPS to run at 10Hz, 115200 baud and only parse $GPGGA strings on startup<br />Integrate compass<br />Setup NodeJS server to communicate with the Bridge controller via TCP/IP<br />Start Mobile Application development.<br />Finalize power supply choice<br />Finish PCB designs for each subsystem<br />
| Complete<br />
|-<br />
| 10<br />
| 4/19/2022<br />
| 4/25/2022<br />
| Finish 1st vehicle prototype - include PCBs if possible<br />Complete basic mobile application<br />Write various motor test routines to define in mobile application<br />Verify timing and correctness of GEO controller messages. Produce debug messages for Geo controller<br />Generate debug messages for all controllers.<br />Finalize sensor choice and complete integration of all three sensors.<br />
| Complete<br />
|-<br />
| 11<br />
| 4/26/2022<br />
| 5/2/2022<br />
| Identify first PCB design inefficiencies/failures and submit the second and final draft for production<br />Thoroughly test the motor's performance on sloped terrain and refine PID controller<br />Test message timing and propagation with Bus Master<br />Improve existing navigation algorithm with state estimation and localization<br />Integration testing Driver controller with Mobile App<br />
| Complete<br />
|-<br />
| 12<br />
| 5/3/2022<br />
| 5/9/2022<br />
| Finished mobile application<br />More testing, update schedule as needed<br />
| Complete<br />
|-<br />
| 13<br />
| 5/10/2022<br />
| 5/16/2022<br />
| Final prototype complete<br />
| Complete<br />
|-<br />
| 14<br />
| 5/17/2022<br />
| 5/25/2022<br />
| Last tests<br />
| Incomplete<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Parts List & Cost ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item#<br />
! scope="col"| Part Desciption<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost/Item<br />
|-<br />
! scope="row"| 1<br />
| Unassembled RC Car <br />
| Traxxas [https://traxxas.com/products/models/electric/stampede-4x4-assembly-kit]<br />
| 1<br />
| $279.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 4<br />
| $8.99<br />
|-<br />
! scope="row"| 3<br />
| PCB <br />
| JLCPCB [https://jlcpcb.com/]<br />
| 1<br />
| $40.00<br />
|-<br />
! scope="row"| 4<br />
| Sensors <br />
| DFRobot [https://www.dfrobot.com/product-1832.html]<br />
| 4<br />
| $12.90<br />
|-<br />
! scope="row"| 5<br />
| GPS<br />
| Amazon [https://www.amazon.com/Adafruit-Ultimate-GPS-Breakout-channel/dp/B01H1R8BK0]<br />
| 1<br />
| $29.92<br />
|-<br />
! scope="row"| 6<br />
| RPM Sensor <br />
| Traxxas [https://traxxas.com/sites/default/files/Rustler-Bandit-Stampede-Slash%20RPM%20Sensor%20Installation.pdf]<br />
| 1<br />
| $19.00<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Printed Circuit Board ==<br />
<br />
The preliminary design consisted of neatly routes wires on a breadboard connecting all the various components. It still looked confusing due to the sheer amount of connections that had to be made, this complexity was to be handled by a custom PCB designed in EasyEDA. <br />
<br />
[[File:Inital wiring.png|1000px|center|thumb|Drawn Schematic]]<br />
[[File:Initial_wiring_testla.PNG|1000px|center|thumb|Breadboard Wiring]]<br />
<br />
<br />
=== Challenges ===<br />
We found that some wires we used were faulty and did not conduct electricity, this led to alot of debug time which could have been avoided by using another wire. To avoid this type of scenario, you can do a continuity check with a multimeter to ensure wire integrity. We chose to design a PCB to have a clean on the car and have higher pin connection strength, since bread board connections are too loose.<br />
<br />
<hr><br />
<br><br />
<br />
<br />
<br />
<br />
[[File:Master_diagram.PNG|1000px|center|thumb|PCB Schematic]]<br />
<br />
<br />
[[File:Pcb wiring testla.PNG|1000px|center|thumb|PCB Layout showing traces (red are front side, blue are back side)]]<br />
<br />
<br />
The design has many holes for mounting and pinouts for various peripherals (GPS, LCD, Buttons, etc.)<br />
<br />
Steps to design PCB:<br />
Following this general guideline will help you avoid any blockers.<br />
<br />
* Finish preliminary breadboard wiring and track changes along the way<br />
* Identify desired mounting topology and make measurements<br />
* Use pcb software to make schematic diagram (not PCB wiring)<br />
* Make holes in the pcb for desired mounting locations (The more the merrier)<br />
* Start positioning the components, then begin making traces<br />
<br />
<br />
[[File:Pcb_irl_testla_90.PNG|1000px|center|thumb|Pre-populated PCB]]<br />
<br />
<br />
<br />
[[File:Final_car.png|1000px|center|thumb|Final Design]]<br />
<br />
== CAN Communication ==<br />
<Talk about your message IDs or communication strategy, such as periodic transmission, MIA management etc.><br />
<br />
=== Hardware Design ===<br />
<Show your CAN bus hardware design><br />
<br />
=== DBC File ===<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/blob/master/dbc/testla_proto1.dbc DBC Link]<br />
<br />
<pre><br />
VERSION ""<br />
<br />
NS_ :<br />
BA_<br />
BA_DEF_<br />
BA_DEF_DEF_<br />
BA_DEF_DEF_REL_<br />
BA_DEF_REL_<br />
BA_DEF_SGTYPE_<br />
BA_REL_<br />
BA_SGTYPE_<br />
BO_TX_BU_<br />
BU_BO_REL_<br />
BU_EV_REL_<br />
BU_SG_REL_<br />
CAT_<br />
CAT_DEF_<br />
CM_<br />
ENVVAR_DATA_<br />
EV_DATA_<br />
FILTER<br />
NS_DESC_<br />
SGTYPE_<br />
SGTYPE_VAL_<br />
SG_MUL_VAL_<br />
SIGTYPE_VALTYPE_<br />
SIG_GROUP_<br />
SIG_TYPE_REF_<br />
SIG_VALTYPE_<br />
VAL_<br />
VAL_TABLE_<br />
<br />
BS_:<br />
<br />
BU_: DRIVER MOTOR SENSOR GEO DEBUG<br />
<br />
<br />
BO_ 100 DRIVER_HEARTBEAT: 3 DRIVER<br />
SG_ DRIVER_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" DBG<br />
<br />
BO_ 110 DRIVER_STEERING: 3 DRIVER<br />
SG_ DRIVER_STEERING_yaw : 0|12@1+ (0.001,-2) [-10|10] "radians" MOTOR<br />
SG_ DRIVER_STEERING_velocity : 12|12@1+ (0.01,-20) [-20|20] "kph" MOTOR<br />
<br />
BO_ 120 MOTOR_HEARTBEAT: 5 MOTOR<br />
SG_ MOTOR_HEARTBEAT_speed_raw : 0|8@1+ (1,0) [0|0] "count" DEBUG<br />
SG_ MOTOR_HEARTBEAT_speed_rpm : 8|10@1+ (1,0) [0|0] "rpm" DEBUG<br />
SG_ MOTOR_HEARTBEAT_speed_kph : 18|10@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_HEARTBEAT_angle_duty : 28|10@1+ (0.001,-2) [-10|10] "duty" MOTOR<br />
<br />
<br />
BO_ 125 MOTOR_DEBUG: 8 MOTOR<br />
SG_ MOTOR_DEBUG_speed_target : 0|26@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_DEBUG_speed_kph : 26|10@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_DEBUG_speed_duty : 36|10@1+ (0.1,0) [0|0] "duty" DEBUG<br />
SG_ MOTOR_DEBUG_integral_error : 46|10@1+ (0.1,-10) [-10|10] "error" DEBUG<br />
SG_ MOTOR_DEBUG_current_state : 56|3@1+ (1,0) [0|5] "state" DEBUG<br />
SG_ MOTOR_DEBUG_next_state : 59|3@1+ (1,0) [0|5] "state" DEBUG<br />
<br />
<br />
<br />
<br />
BO_ 128 MOTOR_ESC_CALIBRATED: 1 MOTOR<br />
SG_ MOTOR_ESC_CALIBRATED_calibration_status : 0|4@1+ (1,0) [0|3] "esc_calibration_e" DRIVER<br />
SG_ MOTOR_ESC_CALIBRATED_start_calibration_ack_to_driver : 4|1@1+ (1,0) [0|1] "bool" DRIVER<br />
<br />
<br />
BO_ 129 DRIVER_START_ESC_CALIBRATION: 1 DRIVER<br />
SG_ MOTOR_ESC_CALIBRATED_begin_esc_calibration : 0|1@1+ (1,0) [0|3] "bool" MOTOR<br />
<br />
BO_ 130 MOTOR_ACK: 1 MOTOR<br />
SG_ MOTOR_ACK_cmd : 0|8@1+ (1,0) [0|0] "" DRIVER<br />
<br />
<br />
BO_ 200 SENSOR_SONARS: 8 SENSOR<br />
SG_ SENSOR_SONARS_left : 0|10@1+ (1,0) [0|800] "inch" DRIVER<br />
SG_ SENSOR_SONARS_right : 10|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_middle : 20|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_back : 30|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_frame_id : 42|16@1+ (1,0) [0|0] "" DRIVER<br />
<br />
BO_ 210 SENSOR_DESTINATION_LOCATION: 8 SENSOR<br />
SG_ SENSOR_DESTINATION_latitude : 0|28@1+ (0.000001,-90.000000) [-90|90] "Degrees" GEO<br />
SG_ SENSOR_DESTINATION_longitude : 28|28@1+ (0.000001,-180.000000) [-180|180] "Degrees" GEO<br />
<br />
BO_ 218 NAVIGATION_MESSAGE: 1 GEO<br />
SG_ NAVIGATION_STATUS_navigation_status : 0|8@1+ (1,0) [0|3] "navigation_status_e" DRIVER<br />
<br />
BO_ 219 CHECKPOINT_MESSAGE: 8 GEO<br />
SG_ CHECKPOINT_MESSAGE_compass_heading : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_destination_bearing : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_destination_distance : 24|16@1+ (0.1,0) [0|0] "Meters" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_curr_checkpoint_num : 40|8@1+ (1,0) [0|255] "Integer" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_total_checkpoint_num : 48|8@1+ (1,0) [0|255] "Integer" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_checkpoint_status : 56|8@1+ (1,0) [0|3] "checkpoint_status_e" DRIVER<br />
<br />
BO_ 220 GEO_STATUS: 8 GEO<br />
SG_ GEO_STATUS_compass_heading : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_destination_bearing : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_destination_distance : 24|16@1+ (0.1,0) [0|0] "Meters" DRIVER<br />
<br />
BO_ 520 DEBUG_GPS_CURRENT_LOCATION: 8 GEO<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_latitude : 0|28@1+ (0.000001,-90.000000) [-90|90] "Degrees" DEBUG<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_longitude : 28|28@1+ (0.000001,-180.000000) [-180|180] "Degrees" DEBUG<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_fix : 56|2@1+ (1,0) [0|2] "" DEBUG<br />
<br />
BO_ 521 DEBUG_GEO_GPS_UPDATE: 8 GEO<br />
SG_ DEBUG_GEO_GPS_UPDATE_count : 0|16@1+ (1,0) [0|0] "" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_max_period : 16|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_min_period : 32|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_average_period : 48|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
<br />
BO_ 522 DEBUG_GEO_COMPASS_UPDATE: 8 GEO<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_count : 0|16@1+ (1,0) [0|0] "" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_max_period : 16|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_min_period : 32|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_average_period : 48|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
<br />
CM_ BU_ DRIVER "The driver controller driving the car";<br />
CM_ BU_ MOTOR "The motor controller of the car";<br />
CM_ BU_ SENSOR "The sensor controller of the car";<br />
CM_ BU_ GEO "the geographical controller of the car";<br />
CM_ BU_ DEBUG "the debug topic that all controllers can publish to";<br />
CM_ BO_ 100 "Sync message used to synchronize the controllers";<br />
CM_ SG_ 100 DRIVER_HEARTBEAT_cmd "Heartbeat command from the driver";<br />
<br />
BA_DEF_ "BusType" STRING ;<br />
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 0;<br />
BA_DEF_ SG_ "FieldType" STRING ;<br />
<br />
BA_DEF_DEF_ "BusType" "CAN";<br />
BA_DEF_DEF_ "FieldType" "";<br />
BA_DEF_DEF_ "GenMsgCycleTime" 0;<br />
<br />
BA_ "GenMsgCycleTime" BO_ 100 1000;<br />
BA_ "GenMsgCycleTime" BO_ 200 50;<br />
BA_ "FieldType" SG_ 100 DRIVER_HEARTBEAT_cmd "DRIVER_HEARTBEAT_cmd";<br />
<br />
VAL_ 100 DRIVER_HEARTBEAT_cmd 2 "DRIVER_HEARTBEAT_cmd_REBOOT" 1 "DRIVER_HEARTBEAT_cmd_SYNC" 0 "DRIVER_HEARTBEAT_cmd_NOOP" ;<br />
<br />
<br />
</pre><br />
<HR><br />
<BR/><br />
<br />
== Sensor & LCD ==<br />
* Sensor '''''[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/tree/master/projects/lpc40xx_freertos_Bridge_Sensor_Controller Gitlab]'''''<br />
*LCD '''''[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/tree/master/projects/lpc40xx_freertos_LCD_I2C Gitlab]'''''<br />
<br />
=== Sensor Hardware Design ( SJ-2 Bridge Control Board) ===<br />
<br />
'''Block Diagram'''<br />
[[File:sensor_1.jpg |600px|middle]]<br />
<br />
'''Ultrasonic Sensor''' <br />
[[File:sensor_2.jpg |600px|middle]]<br />
<br />
* Ultra-Sonic Sensor URM09 (I2C Protocol)<br />
• '''Supply Voltage:''' 3.3~5.5V DC<br />
• '''Operating Current:''' 20mA<br />
• '''Operating Temperature Range:''' -10℃~+70℃<br />
• '''Measurement Range:''' 2cm~500cm (can be set)<br />
• '''Resolution:''' 1cm<br />
• '''Accuracy:''' 1%<br />
• '''Frequency:''' 50Hz Max<br />
• '''Dimension:''' 47mm × 22 mm/1.85” × 0.87”<br />
<br />
'''Sensor Mount''' <br />
[[File:sensor_3.jpg |600px|middle]]<br />
<br />
=== Sensor Software Design ===<br />
* '''Low level - peripheral driver'''<br />
** Peripheral Initialize function <br />
*** I2C Clock 100KHz<br />
*** I2C Pin: <br />
**** SCL: P0_10<br />
**** SDA: P0_11<br />
** I2C single byte read function <br />
*** Input parameter <br />
**** Slave address (7-bit + R/W-bit) <br />
**** Register address (1 byte) <br />
*** Output parameter <br />
**** Register value (1 byte)<br />
*** Return true if success else return false <br />
** I2C single byte write function <br />
*** Input parameter <br />
**** Slave address (7-bit + R\W bit) <br />
**** Register address (1 byte) <br />
**** Written value (1 byte) <br />
*** Return true if success else return false<br />
<br />
<br />
* ''' Mid-level -sensor ''' <br />
* Defined data struct <br />
** Sonar_sensor__sample_sum_s <br />
*** Left<br />
*** Middle <br />
*** Right <br />
*** Back <br />
** Sonar_sensor__sample_queue_s<br />
*** Left<br />
*** Middle <br />
*** Right <br />
*** Back <br />
** Sonar_sensor__address_e<br />
*** Left (7-bits - 0x26)<br />
*** Middle (7-bits – 0x22)<br />
*** Right (7-bits – 0x24)<br />
*** Back (7-bits – 0x20)<br />
** Sonar_sensor_measure_mode_e<br />
*** Automatic<br />
*** Passive <br />
** Sonar_sensor__measure_range_e<br />
*** 150 cm <br />
*** 300 cm <br />
*** 500 cm<br />
<br />
* Initialize sensor function <br />
** Init I2C peripheral<br />
** Init all the sensors with the following configurations: <br />
*** Passive measure mode <br />
*** 150 cm range <br />
* Sensor collects sample function <br />
** To avoid the sensor's crosstalk, we implement the following sequence<br />
*** Start the measurement left sensor <br />
*** Delay 25ms <br />
*** Collect data from the left sensor <br />
*** Start the measurement right sensor <br />
*** Delay 25ms <br />
*** Collect data from the right sensor <br />
*** Start the measurement back and middle <br />
*** Delay 25ms <br />
*** Collect data from the back and middle sensor<br />
<br />
<br />
<br />
=== Sensor Technical Challenges ===<br />
<br />
*'''Issue:''' we cannot read or write on the default address.<br />
*'''Reason:''' After using the logical analyzer, we realize the init clock at 400Khz was too fast for this sensor even though the datasheet did not mention it. <br />
*''' Solution:''' we reduce the I2C Clock speed to 100kHz <br />
<br />
<br />
*'''Issue:''' These nearby ultra-sonic sensors receive each other’s bounce-back signal. <br />
*'''Reason:''' We config the sensor in automatic mode, and it causes the sensors to crosstalk.<br />
*''' Solution:''' we config the sensor in passive mode and tested them with many test cases to come up with the best sequence, and the sensor must operate at 10hz frequency. <br />
<br />
<br />
*'''Issue:''' Sensor noise is getting worse with bad mounting <br />
*'''Reason:''' the sensors are mounted with the bean down to the ground.<br />
*''' Solution:''' we come to design a mechanical mount with the ability of 60 degrees horizontal and vertical adjustment<br />
<br />
<br />
=== Advice for future students === <br />
<br />
Using an ultrasonic sensor, which returns analog value might cause more trouble and require more work to analyze the analog signal. It could provide better resolution, but it might need extra work to improve the signal integrity such as using OP-AMP as a buffer or OP-AMP subtracting the offset voltage. You might run out time for other part <br />
<br />
<br />
<HR><br />
<BR/><br />
<br />
== Motor ECU ==<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/tree/master/projects/lpc40xx_freertos_Motor_Controller Motor Controller Link]<br />
<br />
=== Hardware Design ===<br />
<br />
[[File:Car_diagram.PNG|1000px|center|thumb|Car Diagram]]<br />
<br />
A single SJ2-C board was placed in charge of handling all interactions with the Traxxas parts. This included an ESC (Electronic Speed Control) connected to a brushed DC motor, a servo motor for steering control, and a wheel encoder installed adjacent to the gear shaft (CHECK).<br />
<br />
===== Defining Signals =====<br />
While Traxxas does provide support for hobby RC car enthusiasts, they do not provide clear documentation on signal inputs and outputs to all of their electrical components. To understand what signals would need to be generated by the SJ2-C, the output of the receiver was intercepted. Manipulating the Traxxas remote would generate PWM signals at the output of the receiver. By reading these signals on an oscilloscope, it was determined that both the ESC and servo motor both operated with a 100 Hz PWM signal on a range of duty cycles between 10 - 20%.<br />
<br />
*For the ESC: 10% DC = full reverse speed, 15% DC = idle/zero speed, 20% DC - full forward speed<br />
<br />
*For the servo motor: 10% DC = wheels fully turned to the left, 15% DC = wheels turned straight ahead, 20% DC = wheels turned fully to the right.<br />
<br />
===== Setting up the PWM channels =====<br />
The PWM channels on pins P2.0 and P2.1 were both enabled on single edge mode at a frequency of 100 Hz with a duty cycle of 15%. Initial tests were conducted by mapping the buttons of the SJ2-C to modifying the duty cycles on both PWM channels. These tests were successful in changing the motor speed and wheel direction.<br />
<br />
===== RPM Sensor =====<br />
In order to give real-time feedback on the speed the car is traveling at, an RPM sensor was installed. For ease of compatibility, the Traxxas 6520 RPM Sensor (long variant) was purchased for this task. It was installed with the Traxxas 6538 Telemetry Trigger Magnet Holder for Spur Gear by following this [https://youtu.be/-26ZSgDqwQQ?t=82 tutorial]. While this was expected to provide proper signal output with no extra components, initial testing of the sensor yielded an 0.4 Vpp signal comprised of an unstable, noisy signal. Doing further research led us to find that a 1kΩ pull-up resistor connecting the data pin to a 3.3V rail was required to pull the signal high instead of letting it float. This corrected the output signal to give the expected result.<br />
<br />
===== SJ2-C LED Breakdown =====<br />
Normal Operation:<br />
*LED 0: Toggle on CAN receive<br />
*LED 1: Toggle on CAN transmit<br />
*LED 2: Unused<br />
*LED 3: Driver signal Missing-in-Action<br />
<br />
ESC Calibration<br />
*LEDs 0-2: Used to detail current step in calibration process<br />
*LED 3: Unused<br />
<br />
===== SJ2-C Switch Breakdown =====<br />
*SW 0: Start ESC Calibration Sequence<br />
*SW 1: Disable Motor<br />
*SW 2: Disable Steering<br />
*SW 3: Enable both Motor and Steering<br />
(Note: Motor and Steering are disabled on startup by default)<br />
<br />
<br/><br />
<br />
=== Software Design ===<br />
===== CAN Bus Interactions =====<br />
The Motor Controller receives two different values from the Driver Controller: an angle to turn the wheels to (DRIVER_STEERING__yaw) and the speed at which to drive (DRIVER_STEERING__velocity).<br />
<br />
The Motor Controller sends a multitude of signals addressed to “Debug”, as well as one signal to the Driver pertaining to the status of ESC calibration. These debug signals include a variety of formats of the current speed given by the RPM sensor, the error calculation used in the PID logic, and the operations of the state machine within the motor logic handler.<br />
<br />
<br />
===== RPM Sensor =====<br />
With a proper data output from the sensor, the output was attached to pin CHECK for operation with Timer2. The initial plan was to measure the time between pulses and perform calculations to extrapolate the current speed, but another unexpected issue was experienced. When configuring the interrupt handler on the pin (CHECK) in either rising-edge or falling-edge detection, the interrupt handler would be triggered repeatedly on what appeared to be a steady low signal. This was observed by configuring Bus Master the interrupt count in combination with viewing a logic analyzer to see the signal state. This was especially concerning as it was noticed that if the car wheels stopped turning at a specific position, the sensor would permanently hold a low signal until further rotations, causing even further potential for inaccuracy in any given speed reading. After hours of trying different interrupt configuration settings, it was decided to work with the given conditions. A workaround was discovered by essentially disregarding any interrupts that were deemed to be physically too fast to have been caused by the actual rotation of the tires. This resulted in proper software operation of the interrupt handler, but it required a new method for ascertaining the speed. The final implementation revolved around counting the amount of sensor pulses within a 5 Hz window. This timing was specifically chosen as the proper middle ground for two choices (CHECK). A quicker window would allow for faster updates to the ESC, but a slower window would allow for more pulse data collection and higher accuracy.<br />
<br />
<br />
<br />
[[File:Sensorwire.PNG|1000px|center|thumb|Hall Effect Sensor for RPM]]<br />
<br />
<br />
[[File:Magnetholder.PNG|1000px|center|thumb|Magnet Holder for RPM]]<br />
<br />
[[File:Gear.PNG|1000px|center|thumb|Install location for Magnet Holder]]<br />
<br />
===== PID Controller =====<br />
While an objective of the car is to implement a “PID” controller, in reality a simple “P” controller is enough for an effective control system. This means that all that is needed is the target speed, the current speed, and a gain factor. If the current speed is far from the target speed, a higher error value is produced. When multiplied with the gain, this results in the car making larger changes to its speed to reach the target speed, while using smaller changes to modulate the speed as forces on the car change due to varying terrain or surface angle changes.<br />
// -------------Error Calculations-------------//<br />
if (next_state == FORWARD) {<br />
error = target_motor__kph - current_speed;<br />
} else if (next_state == REVERSE) {<br />
error = target_motor__kph + current_speed;<br />
}<br />
<br />
} else if (next_state == FORWARD) {<br />
speed_for_motor__kph += gain * error;<br />
}<br />
===== ESC Calibration =====<br />
When demoing the second prototype, the ESC fell out of calibration for the first time in operation. This created an undesirable situation where the Traxxas receiver had to be connected back to the motor so it could be calibrated with the Traxxas remote. This led to the need for the calibration sequence to be programmable from the board with no need to rewire components. It was observed that to calibrate the ESC, the remote trigger would need to follow a certain procedure:<br />
Neutral position<br />
Full forward speed<br />
Full reverse speed<br />
Neutral position<br />
This procedure was copied by the Motor Controller with a preparation delay inserted into the beginning of the sequence and can be activated by pressing switch 0 at any time. Note that the ESC should be placed in calibration mode just after pressing switch 0. Failure to do so could cause the car to attempt to reach its maximum speed and hold it for two seconds.<br />
<br />
===== State Machine =====<br />
The final version of the Motor Controller logic included a state machine. Each state is defined in the code below.<br />
<br />
[[File:Fir.png|1000px|center|thumb|Main States]]<br />
typedef enum {<br />
IDLE = 0,<br />
FORWARD = 1,<br />
BRAKING = 2,<br />
START_NEUTRAL_FOR_REVERSE = 3,<br />
NEUTRAL_FOR_REVERSE = 4,<br />
REVERSE = 5,<br />
} CAR_MOTION_STATUS;<br />
<br />
Things to note:<br />
*Braking is the same as sending a reverse signal to the ESC. This is different from sending an idle signal that stops applying current to the motor and allows the car to coast to a halt.<br />
*The START_NEUTRAL_FOR_REVERSE, NEUTRAL_FOR_REVERSE, and REVERSE states are all necessary for the car to perform reverse motion if the car had been moving forward just prior.<br />
<br />
The state machine starts by checking the speed the Driver Controller wants to obtain. This can be one of three states: 0 speed, forward speed, or reverse speed<br />
if (target_motor__kph >= -0.1f && target_motor__kph <= 0.1f) {<br />
...<br />
} else if (target_motor__kph > 0.1f) {<br />
...<br />
} else if (target_motor__kph < -0.1f) {<br />
...<br />
}<br />
<br />
Within a speed value, the current state is checked and the next state is assigned based off of this. There's coverage for every case here, as the car should be able to go to any state from any state.<br />
<br />
if (target_motor__kph >= -0.1f && target_motor__kph <= 0.1f) {<br />
if (current_state == IDLE) {<br />
next_state = IDLE;<br />
} else if (current_state == FORWARD) {<br />
next_state = BRAKING;<br />
} else if (current_state == BRAKING) {<br />
if (current_speed >= -0.1f && current_speed <= 0.1f) {<br />
next_state = IDLE;<br />
} else {<br />
next_state = BRAKING;<br />
}<br />
}<br />
}<br />
<br />
=== Technical Challenges ===<br />
*RPM Sensor gave low voltage, improper signal (see: Hardware Design - RPM Sensor)<br />
*Interrupt handler generated interrupts on stable signal (see: Software Design - RPM Sensor)<br />
*ESC would require calibration on startup every time - Sending a neutral signal (15% Duty Cycle) to the ESC for the first three seconds gave the ESC a signal to lock on to and not require calibration<br />
<br />
<HR><br />
<BR/><br />
<br />
== Geographical Controller ==<br />
The geographical (geo) controller is used to provide the vehicle with a sense of location. To do this, the controller is interfaced to a compass which provides a heading, and a GPS module which provides a latitude, longitude, and GPS fix. GPS fix indicates that the GPS unit is connected to enough sattelites to provide accurate location data. The controller reads a destination off the CAN bus and calculates the distance from its current position. Additionally, it calculates a bearing, which is the degrees from north that the car must point to be facing the destination. If the car aligns its heading with the bearing and drives in a straight line for the number of meters described by the distance calculation, then the car will arrive at its destination.<br />
<br />
However, the vehicle will not be driving in a straight line because of obstacle avoidance. To deal with this, the distance and bearing are updated regularly at a rate of 10Hz. When an obstacle forces the vehicle to deviate from the desired course, it will recalculate the bearing and distance from its new location. This distance and location is then broadcast on the CAN bus, and digested by the driver controller.<br />
<br />
=== Hardware Design ===<br />
<br />
[[File:adafruit_gps.jpg]]<br />
<br />
An Adafruit Ultimate GPS breakout module using the MTK3339 chipset is interfaced over UART to the Geographical controller to provide latitude and longitude updates.<br />
<br />
<br />
[[File:wt901_compass.jpg]]<br />
<br />
A Witmotion WT901 IMU is connected over I2C to provide access to the vehicles heading.<br />
<br />
=== Software Design ===<br />
The general software flow is shown in the diagram below. This loop is run in a 10Hz periodic callback set up in FreeRTOS.<br />
<br />
[[File:geo_flow.jpg]]<br />
<br />
==== Initialization ====<br />
On startup the GPS module is configured. The GPS module sends data at 9600 bps after powering on but must be set to 115200 bps to support 10Hz updates. The controller must send a command to increase the GPS module's baud rate then change the baud rate on its own UART interface. Initially, the GPS sends out several different NMEA strings on every update. The vehicle only needs latitude , longitude and GPS fix data so the GPS is configured to only send GPGGA strings. This prevents the geo controller from wasting time to intake data that it is uninterested in. Finally, the GPS module is configured to send updated data at a rate of 10Hz. After this process is complete, the controller enters its main loop.<br />
<br />
==== Main Loop ====<br />
The geo controller runs at a frequency of 10Hz. A FreeRTOS task uses vTaskDelayUntil() to define a finite period of 100 milliseconds between invocations of the periodic callback.<br />
<br />
The GPS module is read by reading characters out of the UART into a line buffer. If a full line has been deposited into the buffer then the latitude, longitude and GPS Fix are updated. Additionally, a min and max time between GPS updates field is filled in as well as a count of updates. This debug information is published on the bus to analyze fidelity of the module.<br />
<br />
Next, the compass is read over an I2C interface to acquire the heading. The WT901 is an IMU which actually has a good deal more information available besides heading. Currently we are only reading the compass heading but can expand expand in the future to read acceleration and orientation. This module does need to be calibrated one time to ensure it is correctly reporting the heading. The module has a UART interface which can be used to interface between a TTL to USB converter to a software suite. This software can also be used for debugging and calibration.<br />
<br />
After reading the position the CAN interface checks if there are any changes to the destination being published by the bridge controller. After obtaining the most recent desired destination, the geographical module is invoked to calculate a distance and bearing. The section below goes into more detail on the geo calculation. After a distance and bearing are calculated, they are published onto the bis along with the current heading and dubug information. <br />
<br />
==== Geo process ====<br />
<br />
The desired and current position are used to calculate a distance and bearing using the haversine formula shown below.<br />
<br />
'''Distance'''<br />
<br />
[[File:haversine.PNG]]<br />
<br />
'''Bearing'''<br />
<br />
[[File:Bearing_calculations.PNG]]<br />
<br />
[https://www.movable-type.co.uk/scripts/latlong.html Moveable Type Scripts: Calculate distance, bearing and more between Latitude/Longitude points]<br />
<br />
<br />
<br />
=== Technical Challenges ===<br />
<br />
There were several challenges in developing a reliable geographical controller.<br />
<br />
Initially, connecting to the GPS was a challenge because the format of the ASCII lines were not well understood.<br />
<br />
'''Expected string'''<br />
<br />
$GPGGA,064951.000,2307.1256,N,12016.4438,E,1,8,0.95,39.9,M,17.8,M,,*65<br />
<br />
'''Actual string'''<br />
<br />
$GPGGA,,,,,,,5,,,,M,,*65<br />
<br />
There were also issues with verifying that the command strings being sent were achieving their desired results<br />
<br />
Both these problems were solved by attaching the tx line of the GPS to an oscilloscope and decoding the UART messages. This allowed us to fully characterize the output of the GPS and its response to command strings.<br />
<br />
<br />
<br />
<HR><br />
<BR/><br />
<br />
<HR><br />
<BR/><br />
<br />
== LCD & Communication Bridge Controller ==<br />
*Bridge '''''[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/tree/master/projects/lpc40xx_freertos_Bridge_Sensor_Controller Gitlab]'''''<br />
*LCD '''''[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/tree/master/projects/lpc40xx_freertos_LCD_I2C Gitlab]'''''<br />
<br />
=== LCD Hardware Design ===<br />
[[File:lcd_1.jpg |500px|middle]]<br />
<br />
LCD Circuit with 8-bit I/O expander for I2C-bus<br />
[[File:lcd_2.jpg |500px|middle]]<br />
[[File:lcd_3.jpg |500px|middle]]<br />
<br />
=== LCD Software Design ( SJ2- Driver Board) ===<br />
<br />
* '''Low level - peripheral driver'''<br />
** Peripheral Initialize function <br />
*** I2C Clock 400KHz<br />
*** I2C Pin: <br />
**** SCL: P0_10<br />
**** SDA: P0_11<br />
** I2C single byte write function <br />
*** Input parameter <br />
**** Slave address (7-bit + R\W bit) <br />
**** Register address (dummy byte - we always write directly into VRAM ) <br />
**** Written value (1 byte) <br />
*** Return true if success else return false<br />
<br />
** Toggle Enable Pin Function <br />
*** Input parameter<br />
**** byte value<br />
<br />
<br />
* '''Mid-level - LCD driver Command Byte vs Data Byte '''<br />
** Transfer command byte function <br />
*** Input parameter<br />
**** byte value<br />
<br />
** Transfer data byte function <br />
*** Input parameter<br />
**** byte value<br />
<br />
* '''High-level - LCD driver '''<br />
** LCD init function ( backlight ON )<br />
*** Input parameter<br />
**** Colum <br />
**** Row<br />
**** Character Size <br />
<br />
** LCD clear function <br />
<br />
** LCD clear particular location function <br />
*** Input parameter<br />
**** Start Colum <br />
**** Start Row<br />
**** Number of character need to clear <br />
<br />
** LCD set cursor location function <br />
*** Input parameter<br />
**** Start Colum <br />
**** Start Row<br />
<br />
** LCD print char function <br />
*** Input parameter <br />
**** Start Colum<br />
**** Start Row<br />
**** Pointer to first index of char array<br />
<br />
=== Bridge Controller ===<br />
The Bridge Controller is used to establish wireless communication between our vehicle and mobile app. This is a bi-directional communication where the bridge controller will send vehicle states (GPS location, heading, speed & sensor data) to the mobile app, and also receive command messages (gps destination) to broadcast back to the vehicle CAN bus. We decided to use an ESP8266 to connect the bridge controller to the local WIFI network. We picked ESP8266 because SJTwo board already provides an open slot to install this module. Instead of connecting the vehicle directly to the mobile app which may require managing low-level network sockets on mobile devices, we use a NodeJS server as a mediator to maintain a more reliable communication between these two end-points. This design decision also makes it possible to monitor the vehicle state and send commands from multiple devices at the same time.<br />
<br />
=== Bridge Hardware Design ===<br />
<br />
[[File:Sjtwo-esp8266.png]]<br />
ESP-8266 (ESP-01) slot on SJTwo board<br />
<br />
[[File:Esp8266-01.png]]<br />
ESP-8266 module pinouts<br />
<br />
The ESP-8266 is a low-cost WIFI with a built-in TCP/IP software stack. ESP-8266 is connected to the SJTwo board via UART3. SJ-Two board communicates with ESP8266 using AT Command Set Interface.<br />
<br />
=== Bridge Software Design ===<br />
<br />
There are two key components in our setup for the bridge controller:<br />
Local Bridge Node<br />
Remote Server<br />
Our local bridge node is a FreeRTOS task that runs continuously (with a 100ms sleep period). When being run, the task will start by performing an initialization sequence on ESP8266. When a WIFI connection is established, the bridge node will use new data collected from the CAN bus to compose a new message and send it to the server via a TCP/IP socket. Along with that, the task also monitors the current status of this TCP/IP connection and network status and attempts to reconnect whenever the connection dropped for any reason. <br />
The remote server is a NodeJS server running on an AWS EC2 instance. The server accepts raw TCP/IP communication with the local bridge node and broadcasts the data to any clients via topic channels (‘location’, ‘sensor’, ‘steering’, etc.) powered by socket.io. Since the local bridge node runs periodically at around 2Hz, we make use of the server response message as a way to send commands back to the bridge node. With this approach, we don’t have to configure ESP8266 as a server and create another TCP/IP socket just for sending commands from the server back to the local bridge node.<br />
<br />
=== Technical Challenges ===<br />
When implementing the bridge controller with the provided ESP-32 library, our board was reset occasionally due to the retry-and-timeout mechanism for sending TCP/IP packets more reliably. We were able to bypass this issue by running the bridge controller as an independent FreeRTOS task instead of running it inside the periodic scheduler.<br />
<br />
<HR><br />
<BR/><br />
<br />
== Master Module ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<br />
The main software design for the master controller comprises of taking in communication from all of the other controllers on the bus in order to figure out the status of the car and act accordingly. <br />
<br />
The purpose of the master controller’s branch of logic is for it to be used for responding to navigation sequences that are established by Bridge and Geo controller. From this, we can explain that there are two main branches of the car’s driver logic: Obstacle Avoidance Logic and Navigation to the Next Checkpoint logic.<br />
<br />
In Obstacle Avoidance mode, the main objective is for the car to avoid crashing into obstacles such as people, walls, etc throughout the course of the navigation sequence. This logic branch triggers only when there is a threshold of 0, 1, or 2 for any of the front sensors. <br />
<br />
In Navigation Towards next checkpoint mode, the car will navigate towards the next checkpoint until there are no checkpoints left. It will only do this if there are sensor readings above 150cm. If an object is detected at threshold 3, the car can still navigate towards the target, but it will do so at half of the speed so that it can apply breaks prematurely to help it avoid obstacles more smoothly.<br />
<br />
The way that we read the sensor thresholds is that we use 4 different values, 25cm for sensor threshold 0, 50cm for sensor threshold 1, 135cm for sensor threshold 2, and 149cm for sensor threshold 3.<br />
<br />
/// Check sensor values against defined constant thresholds and return bitfields for sensors corresponding to the convention below.<br />
<br />
/// Helper function called by all 4 function above to provide required output value using (0b0000BRML) bit convention<br />
obstacle_detected_on_sensors_e driver__helper_check_sensors_under_OBJECT_THRESHOLD_N(uint16_t left_sensor, uint16_t middle_sensor, uint16_t right_sensor, uint16_t back_sensor, uint16_t threshold) {<br />
obstacle_detected_on_sensors_e ret_sensors_trig = no_sensor_triggered; // Init to 0 for no obstacles detected<br />
// Sensor Bitmasks<br />
const uint8_t no_sensor_bitmask = 0b00000000;<br />
const uint8_t left_sensor_bitmask = 0b00000001;<br />
const uint8_t middle_sensor_bitmask = 0b00000010;<br />
const uint8_t right_sensor_bitmask = 0b00000100;<br />
const uint8_t back_sensor_bitmask = 0b00001000;<br />
// Bitwise OR each sensor below threshold passed in with it's respective bitmask<br />
ret_sensors_trig |= (left_sensor < threshold) ? left_sensor_bitmask : no_sensor_bitmask;<br />
ret_sensors_trig |= (middle_sensor < threshold) ? middle_sensor_bitmask : no_sensor_bitmask;<br />
ret_sensors_trig |= (right_sensor < threshold) ? right_sensor_bitmask : no_sensor_bitmask;<br />
ret_sensors_trig |= (back_sensor < threshold) ? back_sensor_bitmask : no_sensor_bitmask;<br />
return ret_sensors_trig;<br />
}<br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Mobile Application ==<br />
<br />
[[File: Testla-app-1.jpg |600px ]]<br />
[[File: App-2.jpg |600px ]]<br />
<br />
=== Software Design ===<br />
Our mobile app was developed using Flutter framework. We were able to release both Android and iOS version.<br />
The app is connected to our AWS server using Socket.IO and continue to listen to topics related to the vehicle. Whenever user select a new destination on the map, the app will send a new command message to server so that the new destination will be sent to the bridge controller.<br />
<br />
<BR/><br />
<HR><br />
<HR><br />
<BR/><br />
<br />
== Conclusion ==<br />
Testla, at its simplest, is a combination of four micro-controllers on an RC car chassis to accomplish autonomous driving. To drive autonomously there are several necessary components: local real-time awareness, big picture planning, actuation, and limited human input. <br />
<br />
Local real-time awareness in this project is handled by the sonar sensor array, geo controller and driver controller. This pathway takes in immediate, on the ground information to respond to a dynamic environment. <br />
<br />
Big picture planning is handled by our way point mapping scheme. By having a knowledge of the static elements of our environment we can constrain and scope out the behavior of the vehicle into a more reasonable subset of reactions. That sounds pretty vague, but the big picture aspect of the project is by definition vague. We use the known elements to set expectations and apply real-time on the ground sensing to deal with deviations from the expected environment.<br />
<br />
In order to move this vehicle from point-a to point-b we need a sophisticated drive train and driver. The motor controller provides effective execution of desired speed set-points regardless of terrain. Additionally, the driver reads in all of the static and dynamic environmental information to give actuator set-points.<br />
<br />
Finally, we have the human input. Our android application and wireless interface allows the user to select desired destinations and observe the vehicle's response. Our application provides a satellite map where way points can be applied and provides diagnostic information for the sonar, compass, and motors.<br />
<br />
==== what we learned ====<br />
We learned a great deal in this quick semester. <br />
<br />
We learned how the can bus is used to network several subsystems together. There are a lot of networking options available: Ethernet, CAN, LIN, and a host of wireless options. CAN is a predictable and reasonable standard that is proliferated throughout industry and is worth adding to your skill set.<br />
<br />
We learned how to break a complex project down into several smaller problems to utilize multiple parallel development tracks. By breaking the project down into several sub-systems we were able to delegate parts of the larger system to each of our team members.<br />
<br />
We also learned not to get comfortable with early successes. We had some early progress and relaxed but had problems later on and ended up falling behind for it. When you feel like things are going well, that is the time to double down and push harder, not the time to rest.<br />
<br />
"On the plains of hesitation bleach the bones of countless millions who, at the dawn of decision, sat down to wait, and waiting died." - George W. Cecil<br />
<br />
=== Project Video ===<br />
https://drive.google.com/file/d/1JcqAspXMEF0LxYeYpAiJtjhLEtfNJ3-H/view?usp=sharing<br />
<br />
=== Project Source Code ===<br />
<br />
https://gitlab.com/testla_sjsu/autonomous_vehicle<br />
<br />
=== Advise for Future Students ===<br />
===== General Message =====<br />
This is a car project, so the best way to phrase advice for future students is through a car metaphor. <br />
<br />
This project is a destination that you are a reasonable distance away from. You can race and drive recklessly towards your destination to try and get there on time but at the end of the day, leaving earlier is what puts you farther ahead on the road. Take the project seriously from day one and make realistic progress every week and you will have a great experience. Leave late and the journey will be a stressful catch-up game.<br />
<br />
===== Specific Tips =====<br />
*Attach a '''dog leash''' to your chassis when testing. This will probably be needed in every test session until the final week before the demo.<br />
*Put a massive amount of '''focus into the hardware setup at the beginning''' of the project. By the first prototype deadline we had a hardware setup that would’ve been acceptable as a final version. By focusing on the hardware, it was completely trustworthy while working on the software.<br />
*Set a '''consistent schedule for meeting up''' outside of class. What worked for us was Thursdays at 6pm and Sundays at about 1pm. Be prepared to spend '''one day of your weekend on a weekly basis''' focused on this project.<br />
*There will need to be at least a couple of '''meetings just to discern responsibilities and a schedule''' for the project everyone can agree on. This should be done before the class material fully shifts into project coverage.<br />
*Make sure '''everyone’s roles are clearly defined''' from the start, including controller assignments. The Geo, Sensor, and Bridge controllers can all be handled by one person per controller. The Motor controller is possible with one person, but ideally could use two people collaborating. The Driver controller needs two people. Note that someone should be leading the charge on wiring and physical packaging, but everyone should contribute to it where they can.<br />
*The people in charge of their controllers should '''be the master of their controller''' and able to answer any questions the group presents them. This will make collaboration between controllers smooth. Adding to this though, let each group member be in charge of their node. While communication and discussion is always encouraged, the final say of a decision of any controller should be left to the owner of that controller. They will be most familiar with their systems and know what they need to do.<br />
*Work on the wheel encoder / rpm sensor early and make it stable. Working speed readings are imperative for a smooth PID controller. Many groups including ours had trouble getting this part to work.<br />
<br />
=== Acknowledgement ===<br />
First and foremost we have to acknowledge all the teams who came before us. The largest source of information and inspiration came from them. There are an immense amount of well documented attempts at solving this problem. We truly in debt to the teams that came before us and hope we added something to the knowledge base here at Social Ledge.<br />
<br />
Next, we have to acknowledge Professor Preetpal Kang. CmpE 243 is the product of a lot of hard work on his part. Preet makes himself available for all the students and shares his many years of experience and expertise. This is one of the most valuable part of the SJSU computer engineering masters program.<br />
<br />
We also need to acknowledge the former students and others who work on the SJTwo repository and the Social Ledge website. This is another wealth of information and we could not have built this project without this resource.<br />
<br />
Finally, We should (and do) acknowledge all of the teams in our class this semester. We were lucky to have an engaged group of teams working together and sharing knowledge and experiences.<br />
<br />
=== References ===<br />
https://www.movable-type.co.uk/scripts/latlong.html <br><br />
https://www.youtube.com/watch?v=-26ZSgDqwQQ</div>Proj user2http://socialledge.com/sjsu/index.php?title=S22:_Testla&diff=68970S22: Testla2022-05-28T07:14:47Z<p>Proj user2: /* Software Design */</p>
<hr />
<div>== Testla ==<br />
[[File:Bunch of handsome young men.jpeg |800px|middle]]<br />
<br />
<br />
<HR><br />
<BR/><br />
<br />
== Abstract ==<br />
The Testla project is the culmination of our efforts to create an autonomously operated RC Car by pooling together our experience in software design, hardware design, power systems, and mobile application development. Project development started in February of 2022 and ended in May.<br />
<br />
=== Introduction ===<br />
<br />
The project was divided into 5 modules:<br />
<br />
* Sensor Information<br />
* Motor Operation<br />
* Geological Information<br />
* Driver & LCD Manager<br />
* Bridge & Android Application<br />
<br />
=== Team Members & Responsibilities ===<br />
<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle Gitlab Project Link]<br />
<BR/><br />
<br />
[[File:DevinAlexander.jpeg|200px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Co-Leader<br />
** Geographical Controller<br />
** Master Controller<br />
<br />
* Sinan Bayati '''''[https://gitlab.com/sinan.bayati Gitlab]'''''<br />
** PCB Design<br />
** Motor Controller<br />
<br />
[[File:MichaelHatzi.PNG|200px|middle]]<br />
* Michael Hatzikokolakis '''''[https://gitlab.com/mikehatzi8 Gitlab]'''''<br />
** Co-Leader<br />
** Motor Controller<br />
** Testing<br />
<br />
[[File:scott_locascio.jpeg|200px|middle]]<br />
* Scott LoCascio '''''[https://gitlab.com/scottlocascio Gitlab]'''''<br />
** Geographical Controller<br />
** Car Construction<br />
** Testing<br />
<br />
<br />
* Thinh Lu '''''[https://gitlab.com/lphucthinh40 Gitlab]'''''<br />
** Android Application<br />
** Sensor and Bridge Controller<br />
<br />
[[File:BangNguyen.jpg|200px|middle]]<br />
* Bang Nguyen '''''[https://gitlab.com/karosious Gitlab]'''''<br />
** Sensor and Bridge Controller<br />
** LCD Display<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<BR/><br />
<br />
== Schedule ==<br />
<br />
<br />
{| class="wikitable" <br />
|-<br />
! Week #<br />
! Start Date<br />
! End Date<br />
! Task<br />
! Status<br />
|-<br />
| 1<br />
| 2/15/2022<br />
| 2/21/2022<br />
| Read previous projects, gather information and discuss among the group members.<br />
| Complete<br />
|-<br />
| 2<br />
| 2/22/2022<br />
| 2/28/2022<br />
| style="background-color:#F9F9F9;" | Distribute modules to each team member.<br />
| Complete<br />
|-<br />
| 3<br />
| 3/1/2022<br />
| 3/7/2022<br />
| Purchase the RC Car<br />Purchase sensors<br />
| Complete<br />
|-<br />
| 4<br />
| 3/8/2022<br />
| 3/14/2022<br />
| style="background-color:#F9F9F9;" | Learning to use CAN BUSMASTER<br />
| Complete<br />
|-<br />
| 5<br />
| 3/15/2022<br />
| 3/21/2022<br />
| style="background-color:#F9F9F9;" | DBC file discussed and implemented<br />
| Complete<br />
|-<br />
| 6<br />
| 3/22/2022<br />
| 3/28/2022<br />
| style="background-color:#F9F9F9;" | Discuss modules needed for PCB, any feature requests<br />
| Complete<br />
|-<br />
| 7<br />
| 3/29/2022<br />
| 4/4/2022<br />
| Finalize preparations and research<br />
| Complete<br />
|-<br />
| 8<br />
| 4/5/2022<br />
| 4/11/2022<br />
| Interface with RC car and hack steering and motor<br />Integrate the GEO sensor with the GEO controller<br />Complete the Driver sensor using analog readings<br />Write a basic implementation of the sensor controller<br />Interface ESP8266 for bridge controller<br />Begin testing with single vs dual power supplies<br />
| Complete<br />
|-<br />
| 9<br />
| 4/12/2022<br />
| 4/18/2022<br />
| Install wheel encoder, implement, implement PID into velocity processing, and establish collaboration between the Motor and Sensor Controllers<br />Test alternate sonar sensor (I2C)<br />Configure GPS to run at 10Hz, 115200 baud and only parse $GPGGA strings on startup<br />Integrate compass<br />Setup NodeJS server to communicate with the Bridge controller via TCP/IP<br />Start Mobile Application development.<br />Finalize power supply choice<br />Finish PCB designs for each subsystem<br />
| Complete<br />
|-<br />
| 10<br />
| 4/19/2022<br />
| 4/25/2022<br />
| Finish 1st vehicle prototype - include PCBs if possible<br />Complete basic mobile application<br />Write various motor test routines to define in mobile application<br />Verify timing and correctness of GEO controller messages. Produce debug messages for Geo controller<br />Generate debug messages for all controllers.<br />Finalize sensor choice and complete integration of all three sensors.<br />
| Complete<br />
|-<br />
| 11<br />
| 4/26/2022<br />
| 5/2/2022<br />
| Identify first PCB design inefficiencies/failures and submit the second and final draft for production<br />Thoroughly test the motor's performance on sloped terrain and refine PID controller<br />Test message timing and propagation with Bus Master<br />Improve existing navigation algorithm with state estimation and localization<br />Integration testing Driver controller with Mobile App<br />
| Complete<br />
|-<br />
| 12<br />
| 5/3/2022<br />
| 5/9/2022<br />
| Finished mobile application<br />More testing, update schedule as needed<br />
| Complete<br />
|-<br />
| 13<br />
| 5/10/2022<br />
| 5/16/2022<br />
| Final prototype complete<br />
| Complete<br />
|-<br />
| 14<br />
| 5/17/2022<br />
| 5/25/2022<br />
| Last tests<br />
| Incomplete<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Parts List & Cost ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item#<br />
! scope="col"| Part Desciption<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost/Item<br />
|-<br />
! scope="row"| 1<br />
| Unassembled RC Car <br />
| Traxxas [https://traxxas.com/products/models/electric/stampede-4x4-assembly-kit]<br />
| 1<br />
| $279.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 4<br />
| $8.99<br />
|-<br />
! scope="row"| 3<br />
| PCB <br />
| JLCPCB [https://jlcpcb.com/]<br />
| 1<br />
| $40.00<br />
|-<br />
! scope="row"| 4<br />
| Sensors <br />
| DFRobot [https://www.dfrobot.com/product-1832.html]<br />
| 4<br />
| $12.90<br />
|-<br />
! scope="row"| 5<br />
| GPS<br />
| Amazon [https://www.amazon.com/Adafruit-Ultimate-GPS-Breakout-channel/dp/B01H1R8BK0]<br />
| 1<br />
| $29.92<br />
|-<br />
! scope="row"| 6<br />
| RPM Sensor <br />
| Traxxas [https://traxxas.com/sites/default/files/Rustler-Bandit-Stampede-Slash%20RPM%20Sensor%20Installation.pdf]<br />
| 1<br />
| $19.00<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Printed Circuit Board ==<br />
<br />
The preliminary design consisted of neatly routes wires on a breadboard connecting all the various components. It still looked confusing due to the sheer amount of connections that had to be made, this complexity was to be handled by a custom PCB designed in EasyEDA. <br />
<br />
<br />
[[File:Initial_wiring_testla.PNG|1000px|center|thumb|Breadboard Wiring]]<br />
<br />
<br />
=== Challenges ===<br />
We found that some wires we used were faulty and did not conduct electricity, this led to alot of debug time which could have been avoided by using another wire. To avoid this type of scenario, you can do a continuity check with a multimeter to ensure wire integrity. We chose to design a PCB to have a clean on the car and have higher pin connection strength, since bread board connections are too loose.<br />
<br />
<hr><br />
<br><br />
<br />
<br />
<br />
<br />
[[File:Master_diagram.PNG|1000px|center|thumb|PCB Schematic]]<br />
<br />
<br />
[[File:Pcb wiring testla.PNG|1000px|center|thumb|PCB Layout showing traces (red are front side, blue are back side)]]<br />
<br />
<br />
The design has many holes for mounting and pinouts for various peripherals (GPS, LCD, Buttons, etc.)<br />
<br />
Steps to design PCB:<br />
Following this general guideline will help you avoid any blockers.<br />
<br />
* Finish preliminary breadboard wiring and track changes along the way<br />
* Identify desired mounting topology and make measurements<br />
* Use pcb software to make schematic diagram (not PCB wiring)<br />
* Make holes in the pcb for desired mounting locations (The more the merrier)<br />
* Start positioning the components, then begin making traces<br />
<br />
<br />
[[File:Pcb_irl_testla_90.PNG|1000px|center|thumb|Pre-populated PCB]]<br />
<br />
== CAN Communication ==<br />
<Talk about your message IDs or communication strategy, such as periodic transmission, MIA management etc.><br />
<br />
=== Hardware Design ===<br />
<Show your CAN bus hardware design><br />
<br />
=== DBC File ===<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/blob/master/dbc/testla_proto1.dbc DBC Link]<br />
<br />
<pre><br />
VERSION ""<br />
<br />
NS_ :<br />
BA_<br />
BA_DEF_<br />
BA_DEF_DEF_<br />
BA_DEF_DEF_REL_<br />
BA_DEF_REL_<br />
BA_DEF_SGTYPE_<br />
BA_REL_<br />
BA_SGTYPE_<br />
BO_TX_BU_<br />
BU_BO_REL_<br />
BU_EV_REL_<br />
BU_SG_REL_<br />
CAT_<br />
CAT_DEF_<br />
CM_<br />
ENVVAR_DATA_<br />
EV_DATA_<br />
FILTER<br />
NS_DESC_<br />
SGTYPE_<br />
SGTYPE_VAL_<br />
SG_MUL_VAL_<br />
SIGTYPE_VALTYPE_<br />
SIG_GROUP_<br />
SIG_TYPE_REF_<br />
SIG_VALTYPE_<br />
VAL_<br />
VAL_TABLE_<br />
<br />
BS_:<br />
<br />
BU_: DRIVER MOTOR SENSOR GEO DEBUG<br />
<br />
<br />
BO_ 100 DRIVER_HEARTBEAT: 3 DRIVER<br />
SG_ DRIVER_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" DBG<br />
<br />
BO_ 110 DRIVER_STEERING: 3 DRIVER<br />
SG_ DRIVER_STEERING_yaw : 0|12@1+ (0.001,-2) [-10|10] "radians" MOTOR<br />
SG_ DRIVER_STEERING_velocity : 12|12@1+ (0.01,-20) [-20|20] "kph" MOTOR<br />
<br />
BO_ 120 MOTOR_HEARTBEAT: 5 MOTOR<br />
SG_ MOTOR_HEARTBEAT_speed_raw : 0|8@1+ (1,0) [0|0] "count" DEBUG<br />
SG_ MOTOR_HEARTBEAT_speed_rpm : 8|10@1+ (1,0) [0|0] "rpm" DEBUG<br />
SG_ MOTOR_HEARTBEAT_speed_kph : 18|10@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_HEARTBEAT_angle_duty : 28|10@1+ (0.001,-2) [-10|10] "duty" MOTOR<br />
<br />
<br />
BO_ 125 MOTOR_DEBUG: 8 MOTOR<br />
SG_ MOTOR_DEBUG_speed_target : 0|26@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_DEBUG_speed_kph : 26|10@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_DEBUG_speed_duty : 36|10@1+ (0.1,0) [0|0] "duty" DEBUG<br />
SG_ MOTOR_DEBUG_integral_error : 46|10@1+ (0.1,-10) [-10|10] "error" DEBUG<br />
SG_ MOTOR_DEBUG_current_state : 56|3@1+ (1,0) [0|5] "state" DEBUG<br />
SG_ MOTOR_DEBUG_next_state : 59|3@1+ (1,0) [0|5] "state" DEBUG<br />
<br />
<br />
<br />
<br />
BO_ 128 MOTOR_ESC_CALIBRATED: 1 MOTOR<br />
SG_ MOTOR_ESC_CALIBRATED_calibration_status : 0|4@1+ (1,0) [0|3] "esc_calibration_e" DRIVER<br />
SG_ MOTOR_ESC_CALIBRATED_start_calibration_ack_to_driver : 4|1@1+ (1,0) [0|1] "bool" DRIVER<br />
<br />
<br />
BO_ 129 DRIVER_START_ESC_CALIBRATION: 1 DRIVER<br />
SG_ MOTOR_ESC_CALIBRATED_begin_esc_calibration : 0|1@1+ (1,0) [0|3] "bool" MOTOR<br />
<br />
BO_ 130 MOTOR_ACK: 1 MOTOR<br />
SG_ MOTOR_ACK_cmd : 0|8@1+ (1,0) [0|0] "" DRIVER<br />
<br />
<br />
BO_ 200 SENSOR_SONARS: 8 SENSOR<br />
SG_ SENSOR_SONARS_left : 0|10@1+ (1,0) [0|800] "inch" DRIVER<br />
SG_ SENSOR_SONARS_right : 10|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_middle : 20|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_back : 30|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_frame_id : 42|16@1+ (1,0) [0|0] "" DRIVER<br />
<br />
BO_ 210 SENSOR_DESTINATION_LOCATION: 8 SENSOR<br />
SG_ SENSOR_DESTINATION_latitude : 0|28@1+ (0.000001,-90.000000) [-90|90] "Degrees" GEO<br />
SG_ SENSOR_DESTINATION_longitude : 28|28@1+ (0.000001,-180.000000) [-180|180] "Degrees" GEO<br />
<br />
BO_ 218 NAVIGATION_MESSAGE: 1 GEO<br />
SG_ NAVIGATION_STATUS_navigation_status : 0|8@1+ (1,0) [0|3] "navigation_status_e" DRIVER<br />
<br />
BO_ 219 CHECKPOINT_MESSAGE: 8 GEO<br />
SG_ CHECKPOINT_MESSAGE_compass_heading : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_destination_bearing : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_destination_distance : 24|16@1+ (0.1,0) [0|0] "Meters" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_curr_checkpoint_num : 40|8@1+ (1,0) [0|255] "Integer" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_total_checkpoint_num : 48|8@1+ (1,0) [0|255] "Integer" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_checkpoint_status : 56|8@1+ (1,0) [0|3] "checkpoint_status_e" DRIVER<br />
<br />
BO_ 220 GEO_STATUS: 8 GEO<br />
SG_ GEO_STATUS_compass_heading : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_destination_bearing : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_destination_distance : 24|16@1+ (0.1,0) [0|0] "Meters" DRIVER<br />
<br />
BO_ 520 DEBUG_GPS_CURRENT_LOCATION: 8 GEO<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_latitude : 0|28@1+ (0.000001,-90.000000) [-90|90] "Degrees" DEBUG<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_longitude : 28|28@1+ (0.000001,-180.000000) [-180|180] "Degrees" DEBUG<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_fix : 56|2@1+ (1,0) [0|2] "" DEBUG<br />
<br />
BO_ 521 DEBUG_GEO_GPS_UPDATE: 8 GEO<br />
SG_ DEBUG_GEO_GPS_UPDATE_count : 0|16@1+ (1,0) [0|0] "" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_max_period : 16|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_min_period : 32|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_average_period : 48|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
<br />
BO_ 522 DEBUG_GEO_COMPASS_UPDATE: 8 GEO<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_count : 0|16@1+ (1,0) [0|0] "" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_max_period : 16|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_min_period : 32|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_average_period : 48|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
<br />
CM_ BU_ DRIVER "The driver controller driving the car";<br />
CM_ BU_ MOTOR "The motor controller of the car";<br />
CM_ BU_ SENSOR "The sensor controller of the car";<br />
CM_ BU_ GEO "the geographical controller of the car";<br />
CM_ BU_ DEBUG "the debug topic that all controllers can publish to";<br />
CM_ BO_ 100 "Sync message used to synchronize the controllers";<br />
CM_ SG_ 100 DRIVER_HEARTBEAT_cmd "Heartbeat command from the driver";<br />
<br />
BA_DEF_ "BusType" STRING ;<br />
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 0;<br />
BA_DEF_ SG_ "FieldType" STRING ;<br />
<br />
BA_DEF_DEF_ "BusType" "CAN";<br />
BA_DEF_DEF_ "FieldType" "";<br />
BA_DEF_DEF_ "GenMsgCycleTime" 0;<br />
<br />
BA_ "GenMsgCycleTime" BO_ 100 1000;<br />
BA_ "GenMsgCycleTime" BO_ 200 50;<br />
BA_ "FieldType" SG_ 100 DRIVER_HEARTBEAT_cmd "DRIVER_HEARTBEAT_cmd";<br />
<br />
VAL_ 100 DRIVER_HEARTBEAT_cmd 2 "DRIVER_HEARTBEAT_cmd_REBOOT" 1 "DRIVER_HEARTBEAT_cmd_SYNC" 0 "DRIVER_HEARTBEAT_cmd_NOOP" ;<br />
<br />
<br />
</pre><br />
<HR><br />
<BR/><br />
<br />
== Sensor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
== Motor ECU ==<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/tree/master/projects/lpc40xx_freertos_Motor_Controller Motor Controller Link]<br />
<br />
=== Hardware Design ===<br />
<br />
[[File:Car_diagram.PNG|1000px|center|thumb|Car Diagram]]<br />
<br />
A single SJ2-C board was placed in charge of handling all interactions with the Traxxas parts. This included an ESC (Electronic Speed Control) connected to a brushed DC motor, a servo motor for steering control, and a wheel encoder installed adjacent to the gear shaft (CHECK).<br />
<br />
===== Defining Signals =====<br />
While Traxxas does provide support for hobby RC car enthusiasts, they do not provide clear documentation on signal inputs and outputs to all of their electrical components. To understand what signals would need to be generated by the SJ2-C, the output of the receiver was intercepted. Manipulating the Traxxas remote would generate PWM signals at the output of the receiver. By reading these signals on an oscilloscope, it was determined that both the ESC and servo motor both operated with a 100 Hz PWM signal on a range of duty cycles between 10 - 20%.<br />
<br />
*For the ESC: 10% DC = full reverse speed, 15% DC = idle/zero speed, 20% DC - full forward speed<br />
<br />
*For the servo motor: 10% DC = wheels fully turned to the left, 15% DC = wheels turned straight ahead, 20% DC = wheels turned fully to the right.<br />
<br />
===== Setting up the PWM channels =====<br />
The PWM channels on pins P2.0 and P2.1 were both enabled on single edge mode at a frequency of 100 Hz with a duty cycle of 15%. Initial tests were conducted by mapping the buttons of the SJ2-C to modifying the duty cycles on both PWM channels. These tests were successful in changing the motor speed and wheel direction.<br />
<br />
===== RPM Sensor =====<br />
In order to give real-time feedback on the speed the car is traveling at, an RPM sensor was installed. For ease of compatibility, the Traxxas 6520 RPM Sensor (long variant) was purchased for this task. It was installed with the Traxxas 6538 Telemetry Trigger Magnet Holder for Spur Gear by following this [https://youtu.be/-26ZSgDqwQQ?t=82 tutorial]. While this was expected to provide proper signal output with no extra components, initial testing of the sensor yielded an 0.4 Vpp signal comprised of an unstable, noisy signal. Doing further research led us to find that a 1kΩ pull-up resistor connecting the data pin to a 3.3V rail was required to pull the signal high instead of letting it float. This corrected the output signal to give the expected result.<br />
<br />
===== SJ2-C LED Breakdown =====<br />
Normal Operation:<br />
*LED 0: Toggle on CAN receive<br />
*LED 1: Toggle on CAN transmit<br />
*LED 2: Unused<br />
*LED 3: Driver signal Missing-in-Action<br />
<br />
ESC Calibration<br />
*LEDs 0-2: Used to detail current step in calibration process<br />
*LED 3: Unused<br />
<br />
===== SJ2-C Switch Breakdown =====<br />
*SW 0: Start ESC Calibration Sequence<br />
*SW 1: Disable Motor<br />
*SW 2: Disable Steering<br />
*SW 3: Enable both Motor and Steering<br />
(Note: Motor and Steering are disabled on startup by default)<br />
<br />
<br/><br />
<br />
=== Software Design ===<br />
===== CAN Bus Interactions =====<br />
The Motor Controller receives two different values from the Driver Controller: an angle to turn the wheels to (DRIVER_STEERING__yaw) and the speed at which to drive (DRIVER_STEERING__velocity).<br />
<br />
The Motor Controller sends a multitude of signals addressed to “Debug”, as well as one signal to the Driver pertaining to the status of ESC calibration. These debug signals include a variety of formats of the current speed given by the RPM sensor, the error calculation used in the PID logic, and the operations of the state machine within the motor logic handler.<br />
<br />
<br />
===== RPM Sensor =====<br />
With a proper data output from the sensor, the output was attached to pin CHECK for operation with Timer2. The initial plan was to measure the time between pulses and perform calculations to extrapolate the current speed, but another unexpected issue was experienced. When configuring the interrupt handler on the pin (CHECK) in either rising-edge or falling-edge detection, the interrupt handler would be triggered repeatedly on what appeared to be a steady low signal. This was observed by configuring Bus Master the interrupt count in combination with viewing a logic analyzer to see the signal state. This was especially concerning as it was noticed that if the car wheels stopped turning at a specific position, the sensor would permanently hold a low signal until further rotations, causing even further potential for inaccuracy in any given speed reading. After hours of trying different interrupt configuration settings, it was decided to work with the given conditions. A workaround was discovered by essentially disregarding any interrupts that were deemed to be physically too fast to have been caused by the actual rotation of the tires. This resulted in proper software operation of the interrupt handler, but it required a new method for ascertaining the speed. The final implementation revolved around counting the amount of sensor pulses within a 5 Hz window. This timing was specifically chosen as the proper middle ground for two choices (CHECK). A quicker window would allow for faster updates to the ESC, but a slower window would allow for more pulse data collection and higher accuracy.<br />
<br />
<br />
<br />
[[File:Sensorwire.PNG|1000px|center|thumb|Hall Effect Sensor for RPM]]<br />
<br />
<br />
[[File:Magnetholder.PNG|1000px|center|thumb|Magnet Holder for RPM]]<br />
<br />
[[File:Gear.PNG|1000px|center|thumb|Install location for Magnet Holder]]<br />
<br />
===== PID Controller =====<br />
While an objective of the car is to implement a “PID” controller, in reality a simple “P” controller is enough for an effective control system. This means that all that is needed is the target speed, the current speed, and a gain factor. If the current speed is far from the target speed, a higher error value is produced. When multiplied with the gain, this results in the car making larger changes to its speed to reach the target speed, while using smaller changes to modulate the speed as forces on the car change due to varying terrain or surface angle changes.<br />
// -------------Error Calculations-------------//<br />
if (next_state == FORWARD) {<br />
error = target_motor__kph - current_speed;<br />
} else if (next_state == REVERSE) {<br />
error = target_motor__kph + current_speed;<br />
}<br />
<br />
} else if (next_state == FORWARD) {<br />
speed_for_motor__kph += gain * error;<br />
}<br />
===== ESC Calibration =====<br />
When demoing the second prototype, the ESC fell out of calibration for the first time in operation. This created an undesirable situation where the Traxxas receiver had to be connected back to the motor so it could be calibrated with the Traxxas remote. This led to the need for the calibration sequence to be programmable from the board with no need to rewire components. It was observed that to calibrate the ESC, the remote trigger would need to follow a certain procedure:<br />
Neutral position<br />
Full forward speed<br />
Full reverse speed<br />
Neutral position<br />
This procedure was copied by the Motor Controller with a preparation delay inserted into the beginning of the sequence and can be activated by pressing switch 0 at any time. Note that the ESC should be placed in calibration mode just after pressing switch 0. Failure to do so could cause the car to attempt to reach its maximum speed and hold it for two seconds.<br />
<br />
===== State Machine =====<br />
The final version of the Motor Controller logic included a state machine. Each state is defined in the code below.<br />
<br />
typedef enum {<br />
IDLE = 0,<br />
FORWARD = 1,<br />
BRAKING = 2,<br />
START_NEUTRAL_FOR_REVERSE = 3,<br />
NEUTRAL_FOR_REVERSE = 4,<br />
REVERSE = 5,<br />
} CAR_MOTION_STATUS;<br />
<br />
Things to note:<br />
*Braking is the same as sending a reverse signal to the ESC. This is different from sending an idle signal that stops applying current to the motor and allows the car to coast to a halt.<br />
*The START_NEUTRAL_FOR_REVERSE, NEUTRAL_FOR_REVERSE, and REVERSE states are all necessary for the car to perform reverse motion if the car had been moving forward just prior.<br />
<br />
<br />
=== Technical Challenges ===<br />
*RPM Sensor gave low voltage, improper signal (see: Hardware Design - RPM Sensor)<br />
*Interrupt handler generated interrupts on stable signal (see: Software Design - RPM Sensor)<br />
*ESC would require calibration on startup every time - Sending a neutral signal (15% Duty Cycle) to the ESC for the first three seconds gave the ESC a signal to lock on to and not require calibration<br />
<br />
<HR><br />
<BR/><br />
<br />
== Geographical Controller ==<br />
The geographical (geo) controller is used to provide the vehicle with a sense of location. To do this, the controller is interfaced to a compass which provides a heading, and a GPS module which provides a latitude, longitude, and GPS fix. GPS fix indicates that the GPS unit is connected to enough sattelites to provide accurate location data. The controller reads a destination off the CAN bus and calculates the distance from its current position. Additionally, it calculates a bearing, which is the degrees from north that the car must point to be facing the destination. If the car aligns its heading with the bearing and drives in a straight line for the number of meters described by the distance calculation, then the car will arrive at its destination.<br />
<br />
However, the vehicle will not be driving in a straight line because of obstacle avoidance. To deal with this, the distance and bearing are updated regularly at a rate of 10Hz. When an obstacle forces the vehicle to deviate from the desired course, it will recalculate the bearing and distance from its new location. This distance and location is then broadcast on the CAN bus, and digested by the driver controller.<br />
<br />
=== Hardware Design ===<br />
<br />
[[File:adafruit_gps.jpg]]<br />
<br />
An Adafruit Ultimate GPS breakout module using the MTK3339 chipset is interfaced over UART to the Geographical controller to provide latitude and longitude updates.<br />
<br />
<br />
[[File:wt901_compass.jpg]]<br />
<br />
A Witmotion WT901 IMU is connected over I2C to provide access to the vehicles heading.<br />
<br />
=== Software Design ===<br />
The general software flow is shown in the diagram below. This loop is run in a 10Hz periodic callback set up in FreeRTOS.<br />
<br />
[[File:geo_flow.jpg]]<br />
<br />
==== Initialization ====<br />
On startup the GPS module is configured. The GPS module sends data at 9600 bps after powering on but must be set to 115200 bps to support 10Hz updates. The controller must send a command to increase the GPS module's baud rate then change the baud rate on its own UART interface. Initially, the GPS sends out several different NMEA strings on every update. The vehicle only needs latitude , longitude and GPS fix data so the GPS is configured to only send GPGGA strings. This prevents the geo controller from wasting time to intake data that it is uninterested in. Finally, the GPS module is configured to send updated data at a rate of 10Hz. After this process is complete, the controller enters its main loop.<br />
<br />
==== Main Loop ====<br />
The geo controller runs at a frequency of 10Hz. A FreeRTOS task uses vTaskDelayUntil() to define a finite period of 100 milliseconds between invocations of the periodic callback.<br />
<br />
The GPS module is read by reading characters out of the UART into a line buffer. If a full line has been deposited into the buffer then the latitude, longitude and GPS Fix are updated. Additionally, a min and max time between GPS updates field is filled in as well as a count of updates. This debug information is published on the bus to analyze fidelity of the module.<br />
<br />
Next, the compass is read over an I2C interface to acquire the heading. The WT901 is an IMU which actually has a good deal more information available besides heading. Currently we are only reading the compass heading but can expand expand in the future to read acceleration and orientation. This module does need to be calibrated one time to ensure it is correctly reporting the heading. The module has a UART interface which can be used to interface between a TTL to USB converter to a software suite. This software can also be used for debugging and calibration.<br />
<br />
After reading the position the CAN interface checks if there are any changes to the destination being published by the bridge controller. After obtaining the most recent desired destination, the geographical module is invoked to calculate a distance and bearing. The section below goes into more detail on the geo calculation. After a distance and bearing are calculated, they are published onto the bis along with the current heading and dubug information. <br />
<br />
==== Geo process ====<br />
<br />
The desired and current position are used to calculate a distance and bearing using the haversine formula shown below.<br />
<br />
'''Distance'''<br />
<br />
[[File:haversine.PNG]]<br />
<br />
'''Bearing'''<br />
<br />
[[File:Bearing_calculations.PNG]]<br />
<br />
[https://www.movable-type.co.uk/scripts/latlong.html Moveable Type Scripts: Calculate distance, bearing and more between Latitude/Longitude points]<br />
<br />
<br />
<br />
=== Technical Challenges ===<br />
<br />
There were several challenges in developing a reliable geographical controller.<br />
<br />
Initially, connecting to the GPS was a challenge because the format of the ASCII lines were not well understood.<br />
<br />
'''Expected string'''<br />
<br />
$GPGGA,064951.000,2307.1256,N,12016.4438,E,1,8,0.95,39.9,M,17.8,M,,*65<br />
<br />
'''Actual string'''<br />
<br />
$GPGGA,,,,,,,5,,,,M,,*65<br />
<br />
There were also issues with verifying that the command strings being sent were achieving their desired results<br />
<br />
Both these problems were solved by attaching the tx line of the GPS to an oscilloscope and decoding the UART messages. This allowed us to fully characterize the output of the GPS and its response to command strings.<br />
<br />
<br />
<br />
<HR><br />
<BR/><br />
<br />
<HR><br />
<BR/><br />
<br />
== LCD, Sonar Sensor & Communication Bridge Controller ==<br />
* Sensor '''''[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/tree/master/projects/lpc40xx_freertos_Bridge_Sensor_Controller Gitlab]'''''<br />
<br />
*LCD '''''[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/tree/master/projects/lpc40xx_freertos_LCD_I2C Gitlab]'''''<br />
<br />
=== Sensor Hardware Design ( SJ-2 Bridge Control Board) ===<br />
<br />
'''Block Diagram'''<br />
[[File:sensor_1.jpg |600px|middle]]<br />
<br />
'''Ultrasonic Sensor''' <br />
[[File:sensor_2.jpg |600px|middle]]<br />
<br />
* Ultra-Sonic Sensor URM09 (I2C Protocol)<br />
• '''Supply Voltage:''' 3.3~5.5V DC<br />
• '''Operating Current:''' 20mA<br />
• '''Operating Temperature Range:''' -10℃~+70℃<br />
• '''Measurement Range:''' 2cm~500cm (can be set)<br />
• '''Resolution:''' 1cm<br />
• '''Accuracy:''' 1%<br />
• '''Frequency:''' 50Hz Max<br />
• '''Dimension:''' 47mm × 22 mm/1.85” × 0.87”<br />
<br />
'''Sensor Mount''' <br />
[[File:sensor_3.jpg |600px|middle]]<br />
<br />
=== Sensor Software Design ===<br />
* '''Low level - peripheral driver'''<br />
** Peripheral Initialize function <br />
*** I2C Clock 100KHz<br />
*** I2C Pin: <br />
**** SCL: P0_10<br />
**** SDA: P0_11<br />
** I2C single byte read function <br />
*** Input parameter <br />
**** Slave address (7-bit + R/W-bit) <br />
**** Register address (1 byte) <br />
*** Output parameter <br />
**** Register value (1 byte)<br />
*** Return true if success else return false <br />
** I2C single byte write function <br />
*** Input parameter <br />
**** Slave address (7-bit + R\W bit) <br />
**** Register address (1 byte) <br />
**** Written value (1 byte) <br />
*** Return true if success else return false<br />
<br />
<br />
* ''' Mid-level -sensor ''' <br />
* Defined data struct <br />
** Sonar_sensor__sample_sum_s <br />
*** Left<br />
*** Middle <br />
*** Right <br />
*** Back <br />
** Sonar_sensor__sample_queue_s<br />
*** Left<br />
*** Middle <br />
*** Right <br />
*** Back <br />
** Sonar_sensor__address_e<br />
*** Left (7-bits - 0x26)<br />
*** Middle (7-bits – 0x22)<br />
*** Right (7-bits – 0x24)<br />
*** Back (7-bits – 0x20)<br />
** Sonar_sensor_measure_mode_e<br />
*** Automatic<br />
*** Passive <br />
** Sonar_sensor__measure_range_e<br />
*** 150 cm <br />
*** 300 cm <br />
*** 500 cm<br />
<br />
* Initialize sensor function <br />
** Init I2C peripheral<br />
** Init all the sensors with the following configurations: <br />
*** Passive measure mode <br />
*** 150 cm range <br />
* Sensor collects sample function <br />
** To avoid the sensor's crosstalk, we implement the following sequence<br />
*** Start the measurement left sensor <br />
*** Delay 25ms <br />
*** Collect data from the left sensor <br />
*** Start the measurement right sensor <br />
*** Delay 25ms <br />
*** Collect data from the right sensor <br />
*** Start the measurement back and middle <br />
*** Delay 25ms <br />
*** Collect data from the back and middle sensor<br />
<br />
<br />
<br />
=== Sensor Technical Challenges ===<br />
<br />
*'''Issue:''' we cannot read or write on the default address.<br />
*'''Reason:''' After using the logical analyzer, we realize the init clock at 400Khz was too fast for this sensor even though the datasheet did not mention it. <br />
*''' Solution:''' we reduce the I2C Clock speed to 100kHz <br />
<br />
<br />
*'''Issue:''' These nearby ultra-sonic sensors receive each other’s bounce-back signal. <br />
*'''Reason:''' We config the sensor in automatic mode, and it causes the sensors to crosstalk.<br />
*''' Solution:''' we config the sensor in passive mode and tested them with many test cases to come up with the best sequence, and the sensor must operate at 10hz frequency. <br />
<br />
<br />
*'''Issue:''' Sensor noise is getting worse with bad mounting <br />
*'''Reason:''' the sensors are mounted with the bean down to the ground.<br />
*''' Solution:''' we come to design a mechanical mount with the ability of 60 degrees horizontal and vertical adjustment<br />
<br />
=== LCD Hardware Design ===<br />
[[File:lcd_1.jpg |500px|middle]]<br />
<br />
LCD Circuit with 8-bit I/O expander for I2C-bus<br />
[[File:lcd_2.jpg |500px|middle]]<br />
[[File:lcd_3.jpg |500px|middle]]<br />
<br />
=== LCD Software Design ( SJ2- Driver Board) ===<br />
<br />
* '''Low level - peripheral driver'''<br />
** Peripheral Initialize function <br />
*** I2C Clock 400KHz<br />
*** I2C Pin: <br />
**** SCL: P0_10<br />
**** SDA: P0_11<br />
** I2C single byte write function <br />
*** Input parameter <br />
**** Slave address (7-bit + R\W bit) <br />
**** Register address (dummy byte - we always write directly into VRAM ) <br />
**** Written value (1 byte) <br />
*** Return true if success else return false<br />
<br />
** Toggle Enable Pin Function <br />
*** Input parameter<br />
**** byte value<br />
<br />
<br />
* '''Mid-level - LCD driver Command Byte vs Data Byte '''<br />
** Transfer command byte function <br />
*** Input parameter<br />
**** byte value<br />
<br />
** Transfer data byte function <br />
*** Input parameter<br />
**** byte value<br />
<br />
* '''High-level - LCD driver '''<br />
** LCD init function ( backlight ON )<br />
*** Input parameter<br />
**** Colum <br />
**** Row<br />
**** Character Size <br />
<br />
** LCD clear function <br />
<br />
** LCD clear particular location function <br />
*** Input parameter<br />
**** Start Colum <br />
**** Start Row<br />
**** Number of character need to clear <br />
<br />
** LCD set cursor location function <br />
*** Input parameter<br />
**** Start Colum <br />
**** Start Row<br />
<br />
** LCD print char function <br />
*** Input parameter <br />
**** Start Colum<br />
**** Start Row<br />
**** Pointer to first index of char array<br />
<br />
=== Bridge Controller ===<br />
The Bridge Controller is used to establish wireless communication between our vehicle and mobile app. This is a bi-directional communication where the bridge controller will send vehicle states (GPS location, heading, speed & sensor data) to the mobile app, and also receive command messages (gps destination) to broadcast back to the vehicle CAN bus. We decided to use an ESP8266 to connect the bridge controller to the local WIFI network. We picked ESP8266 because SJTwo board already provides an open slot to install this module. Instead of connecting the vehicle directly to the mobile app which may require managing low-level network sockets on mobile devices, we use a NodeJS server as a mediator to maintain a more reliable communication between these two end-points. This design decision also makes it possible to monitor the vehicle state and send commands from multiple devices at the same time.<br />
<br />
=== Bridge Hardware Design ===<br />
<br />
[[File:Sjtwo-esp8266.png]]<br />
ESP-8266 (ESP-01) slot on SJTwo board<br />
<br />
[[File:Esp8266-01.png]]<br />
ESP-8266 module pinouts<br />
<br />
The ESP-8266 is a low-cost WIFI with a built-in TCP/IP software stack. ESP-8266 is connected to the SJTwo board via UART3. SJ-Two board communicates with ESP8266 using AT Command Set Interface.<br />
<br />
=== Bridge Software Design ===<br />
<br />
There are two key components in our setup for the bridge controller:<br />
Local Bridge Node<br />
Remote Server<br />
Our local bridge node is a FreeRTOS task that runs continuously (with a 100ms sleep period). When being run, the task will start by performing an initialization sequence on ESP8266. When a WIFI connection is established, the bridge node will use new data collected from the CAN bus to compose a new message and send it to the server via a TCP/IP socket. Along with that, the task also monitors the current status of this TCP/IP connection and network status and attempts to reconnect whenever the connection dropped for any reason. <br />
The remote server is a NodeJS server running on an AWS EC2 instance. The server accepts raw TCP/IP communication with the local bridge node and broadcasts the data to any clients via topic channels (‘location’, ‘sensor’, ‘steering’, etc.) powered by socket.io. Since the local bridge node runs periodically at around 2Hz, we make use of the server response message as a way to send commands back to the bridge node. With this approach, we don’t have to configure ESP8266 as a server and create another TCP/IP socket just for sending commands from the server back to the local bridge node.<br />
<br />
<br />
=== Advice for future students === <br />
<br />
Using an ultrasonic sensor, which returns analog value might cause more trouble and require more work to analyze the analog signal. It could provide better resolution, but it might need extra work to improve the signal integrity such as using OP-AMP as a buffer or OP-AMP subtracting the offset voltage. You might run out time for other part <br />
<br />
<br />
<br />
<HR><br />
<BR/><br />
<br />
== Master Module ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<br />
The main software design for the master controller comprises of taking in communication from all of the other controllers on the bus in order to figure out the status of the car and act accordingly. <br />
<br />
The purpose of the master controller’s branch of logic is for it to be used for responding to navigation sequences that are established by Bridge and Geo controller. From this, we can explain that there are two main branches of the car’s driver logic: Obstacle Avoidance Logic and Navigation to the Next Checkpoint logic.<br />
<br />
In Obstacle Avoidance mode, the main objective is for the car to avoid crashing into obstacles such as people, walls, etc throughout the course of the navigation sequence. This logic branch triggers only when there is a threshold of 0, 1, or 2 for any of the front sensors. <br />
<br />
In Navigation Towards next checkpoint mode, the car will navigate towards the next checkpoint until there are no checkpoints left. It will only do this if there are sensor readings above 150cm. If an object is detected at threshold 3, the car can still navigate towards the target, but it will do so at half of the speed so that it can apply breaks prematurely to help it avoid obstacles more smoothly.<br />
<br />
The way that we read the sensor thresholds is that we use 4 different values, 25cm for sensor threshold 0, 50cm for sensor threshold 1, 135cm for sensor threshold 2, and 149cm for sensor threshold 3.<br />
<br />
/// Check sensor values against defined constant thresholds and return bitfields for sensors corresponding to the convention below.<br />
<br />
/// Helper function called by all 4 function above to provide required output value using (0b0000BRML) bit convention<br />
obstacle_detected_on_sensors_e driver__helper_check_sensors_under_OBJECT_THRESHOLD_N(uint16_t left_sensor, uint16_t middle_sensor, uint16_t right_sensor, uint16_t back_sensor, uint16_t threshold) {<br />
obstacle_detected_on_sensors_e ret_sensors_trig = no_sensor_triggered; // Init to 0 for no obstacles detected<br />
// Sensor Bitmasks<br />
const uint8_t no_sensor_bitmask = 0b00000000;<br />
const uint8_t left_sensor_bitmask = 0b00000001;<br />
const uint8_t middle_sensor_bitmask = 0b00000010;<br />
const uint8_t right_sensor_bitmask = 0b00000100;<br />
const uint8_t back_sensor_bitmask = 0b00001000;<br />
// Bitwise OR each sensor below threshold passed in with it's respective bitmask<br />
ret_sensors_trig |= (left_sensor < threshold) ? left_sensor_bitmask : no_sensor_bitmask;<br />
ret_sensors_trig |= (middle_sensor < threshold) ? middle_sensor_bitmask : no_sensor_bitmask;<br />
ret_sensors_trig |= (right_sensor < threshold) ? right_sensor_bitmask : no_sensor_bitmask;<br />
ret_sensors_trig |= (back_sensor < threshold) ? back_sensor_bitmask : no_sensor_bitmask;<br />
return ret_sensors_trig;<br />
}<br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Mobile Application ==<br />
<br />
[[File: Testla-app-1.jpg |600px ]]<br />
[[File: App-2.jpg |600px ]]<br />
<br />
=== Software Design ===<br />
Our mobile app was developed using Flutter framework. We were able to release both Android and iOS version.<br />
The app is connected to our AWS server using Socket.IO and continue to listen to topics related to the vehicle. Whenever user select a new destination on the map, the app will send a new command message to server so that the new destination will be sent to the bridge controller.<br />
<br />
<BR/><br />
<HR><br />
<HR><br />
<BR/><br />
<br />
== Conclusion ==<br />
Testla, at its simplest, is a combination of four micro-controllers on an RC car chassis to accomplish autonomous driving. To drive autonomously there are several necessary components: local real-time awareness, big picture planning, actuation, and limited human input. <br />
<br />
Local real-time awareness in this project is handled by the sonar sensor array, geo controller and driver controller. This pathway takes in immediate, on the ground information to respond to a dynamic environment. <br />
<br />
Big picture planning is handled by our way point mapping scheme. By having a knowledge of the static elements of our environment we can constrain and scope out the behavior of the vehicle into a more reasonable subset of reactions. That sounds pretty vague, but the big picture aspect of the project is by definition vague. We use the known elements to set expectations and apply real-time on the ground sensing to deal with deviations from the expected environment.<br />
<br />
In order to move this vehicle from point-a to point-b we need a sophisticated drive train and driver. The motor controller provides effective execution of desired speed set-points regardless of terrain. Additionally, the driver reads in all of the static and dynamic environmental information to give actuator set-points.<br />
<br />
Finally, we have the human input. Our android application and wireless interface allows the user to select desired destinations and observe the vehicle's response. Our application provides a satellite map where way points can be applied and provides diagnostic information for the sonar, compass, and motors.<br />
<br />
==== what we learned ====<br />
We learned a great deal in this quick semester. <br />
<br />
We learned how the can bus is used to network several subsystems together. There are a lot of networking options available: Ethernet, CAN, LIN, and a host of wireless options. CAN is a predictable and reasonable standard that is proliferated throughout industry and is worth adding to your skill set.<br />
<br />
We learned how to break a complex project down into several smaller problems to utilize multiple parallel development tracks. By breaking the project down into several sub-systems we were able to delegate parts of the larger system to each of our team members.<br />
<br />
We also learned not to get comfortable with early successes. We had some early progress and relaxed but had problems later on and ended up falling behind for it. When you feel like things are going well, that is the time to double down and push harder, not the time to rest.<br />
<br />
"On the plains of hesitation bleach the bones of countless millions who, at the dawn of decision, sat down to wait, and waiting died." - George W. Cecil<br />
<br />
=== Project Video ===<br />
https://drive.google.com/file/d/1JcqAspXMEF0LxYeYpAiJtjhLEtfNJ3-H/view?usp=sharing<br />
<br />
=== Project Source Code ===<br />
<br />
https://gitlab.com/testla_sjsu/autonomous_vehicle<br />
<br />
=== Advise for Future Students ===<br />
===== General Message =====<br />
This is a car project, so the best way to phrase advice for future students is through a car metaphor. <br />
<br />
This project is a destination that you are a reasonable distance away from. You can race and drive recklessly towards your destination to try and get there on time but at the end of the day, leaving earlier is what puts you farther ahead on the road. Take the project seriously from day one and make realistic progress every week and you will have a great experience. Leave late and the journey will be a stressful catch-up game.<br />
<br />
===== Specific Tips =====<br />
*Attach a '''dog leash''' to your chassis when testing. This will probably be needed in every test session until the final week before the demo.<br />
*Put a massive amount of '''focus into the hardware setup at the beginning''' of the project. By the first prototype deadline we had a hardware setup that would’ve been acceptable as a final version. By focusing on the hardware, it was completely trustworthy while working on the software.<br />
*Set a '''consistent schedule for meeting up''' outside of class. What worked for us was Thursdays at 6pm and Sundays at about 1pm. Be prepared to spend '''one day of your weekend on a weekly basis''' focused on this project.<br />
*There will need to be at least a couple of '''meetings just to discern responsibilities and a schedule''' for the project everyone can agree on. This should be done before the class material fully shifts into project coverage.<br />
*Make sure '''everyone’s roles are clearly defined''' from the start, including controller assignments. The Geo, Sensor, and Bridge controllers can all be handled by one person per controller. The Motor controller is possible with one person, but ideally could use two people collaborating. The Driver controller needs two people. Note that someone should be leading the charge on wiring and physical packaging, but everyone should contribute to it where they can.<br />
*The people in charge of their controllers should '''be the master of their controller''' and able to answer any questions the group presents them. This will make collaboration between controllers smooth. Adding to this though, let each group member be in charge of their node. While communication and discussion is always encouraged, the final say of a decision of any controller should be left to the owner of that controller. They will be most familiar with their systems and know what they need to do.<br />
*Work on the wheel encoder / rpm sensor early and make it stable. Working speed readings are imperative for a smooth PID controller. Many groups including ours had trouble getting this part to work.<br />
<br />
=== Acknowledgement ===<br />
First and foremost we have to acknowledge all the teams who came before us. The largest source of information and inspiration came from them. There are an immense amount of well documented attempts at solving this problem. We truly in debt to the teams that came before us and hope we added something to the knowledge base here at Social Ledge.<br />
<br />
Next, we have to acknowledge Professor Preetpal Kang. CmpE 243 is the product of a lot of hard work on his part. Preet makes himself available for all the students and shares his many years of experience and expertise. This is one of the most valuable part of the SJSU computer engineering masters program.<br />
<br />
We also need to acknowledge the former students and others who work on the SJTwo repository and the Social Ledge website. This is another wealth of information and we could not have built this project without this resource.<br />
<br />
Finally, We should (and do) acknowledge all of the teams in our class this semester. We were lucky to have an engaged group of teams working together and sharing knowledge and experiences.<br />
<br />
=== References ===<br />
https://www.movable-type.co.uk/scripts/latlong.html <br><br />
https://www.youtube.com/watch?v=-26ZSgDqwQQ</div>Proj user2http://socialledge.com/sjsu/index.php?title=S22:_Testla&diff=68771S22: Testla2022-05-28T04:29:26Z<p>Proj user2: /* Team Members & Responsibilities */</p>
<hr />
<div>== Testla ==<br />
[[File:Bunch of handsome young men.jpeg |800px|middle]]<br />
<br />
<br />
<HR><br />
<BR/><br />
<br />
== Abstract ==<br />
The Testla project is the culmination of our efforts to create an autonomously operated RC Car by pooling together our experience in software design, hardware design, power systems, and mobile application development. Project development started in February of 2022 and ended in May. (NOTE: One more sentence probably)<br />
<br />
=== Introduction ===<br />
<br />
The project was divided into 5 modules:<br />
<br />
* Bridge and Sensor Information<br />
* Motor Operation<br />
* Geological Information<br />
* Driver and LCD Manager<br />
* Android Application<br />
<br />
=== Team Members & Responsibilities ===<br />
<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle Gitlab Project Link]<br />
<BR/><br />
<br />
[[File:DevinAlexander.jpeg|200px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Leader<br />
** Geographical Controller<br />
** Master Controller<br />
<br />
<br />
[[File:scott_locascio.jpeg|200px|middle]]<br />
* Scott LoCascio '''''[https://gitlab.com/scottlocascio Gitlab]'''''<br />
** Geographical Controller<br />
** Car Construction<br />
** Testing<br />
<br />
<br />
* Thinh Lu '''''[https://gitlab.com/lphucthinh40 Gitlab]'''''<br />
** Android Application<br />
** Sensor and Bridge Controller<br />
<br />
<br />
* Bang Nguyen --couldn't find your gitlab <BR/><br />
** Sensor and Bridge Controller<br />
** LCD Display<br />
<br />
<br />
<br />
* Michael Hatzikokolakis '''''[https://gitlab.com/mikehatzi8 Gitlab]'''''<br />
** Motor Controller<br />
** Android Application<br />
<br />
<br />
* Sinan Bayati '''''[https://gitlab.com/sinan.bayati Gitlab]'''''<br />
** PCB Design<br />
** Motor Controller<br />
<br />
<BR/><br />
<br />
== Schedule ==<br />
<br />
<br />
{| class="wikitable" <br />
|-<br />
! Week #<br />
! Start Date<br />
! End Date<br />
! Task<br />
! Status<br />
|-<br />
| 1<br />
| 2/15/2022<br />
| 2/21/2022<br />
| Read previous projects, gather information and discuss among the group members.<br />
| Complete<br />
|-<br />
| 2<br />
| 2/22/2022<br />
| 2/28/2022<br />
| style="background-color:#F9F9F9;" | Distribute modules to each team member.<br />
| Complete<br />
|-<br />
| 3<br />
| 3/1/2022<br />
| 3/7/2022<br />
| Purchase the RC Car<br />Purchase sensors<br />
| Complete<br />
|-<br />
| 4<br />
| 3/8/2022<br />
| 3/14/2022<br />
| style="background-color:#F9F9F9;" | Learning to use CAN BUSMASTER<br />
| Complete<br />
|-<br />
| 5<br />
| 3/15/2022<br />
| 3/21/2022<br />
| style="background-color:#F9F9F9;" | DBC file discussed and implemented<br />
| Complete<br />
|-<br />
| 6<br />
| 3/22/2022<br />
| 3/28/2022<br />
| style="background-color:#F9F9F9;" | Discuss modules needed for PCB, any feature requests<br />
| Complete<br />
|-<br />
| 7<br />
| 3/29/2022<br />
| 4/4/2022<br />
| Finalize preparations and research<br />
| Complete<br />
|-<br />
| 8<br />
| 4/5/2022<br />
| 4/11/2022<br />
| Interface with RC car and hack steering and motor<br />Integrate the GEO sensor with the GEO controller<br />Complete the Driver sensor using analog readings<br />Write a basic implementation of the sensor controller<br />Interface ESP8266 for bridge controller<br />Begin testing with single vs dual power supplies<br />
| Complete<br />
|-<br />
| 9<br />
| 4/12/2022<br />
| 4/18/2022<br />
| Install wheel encoder, implement, implement PID into velocity processing, and establish collaboration between the Motor and Sensor Controllers<br />Test alternate sonar sensor (I2C)<br />Configure GPS to run at 10Hz, 115200 baud and only parse $GPGGA strings on startup<br />Integrate compass<br />Setup NodeJS server to communicate with the Bridge controller via TCP/IP<br />Start Mobile Application development.<br />Finalize power supply choice<br />Finish PCB designs for each subsystem<br />
| Complete<br />
|-<br />
| 10<br />
| 4/19/2022<br />
| 4/25/2022<br />
| Finish 1st vehicle prototype - include PCBs if possible<br />Complete basic mobile application<br />Write various motor test routines to define in mobile application<br />Verify timing and correctness of GEO controller messages. Produce debug messages for Geo controller<br />Generate debug messages for all controllers.<br />Finalize sensor choice and complete integration of all three sensors.<br />
| Complete<br />
|-<br />
| 11<br />
| 4/26/2022<br />
| 5/2/2022<br />
| Identify first PCB design inefficiencies/failures and submit the second and final draft for production<br />Thoroughly test the motor's performance on sloped terrain and refine PID controller<br />Test message timing and propagation with Bus Master<br />Improve existing navigation algorithm with state estimation and localization<br />Integration testing Driver controller with Mobile App<br />
| Complete<br />
|-<br />
| 12<br />
| 5/3/2022<br />
| 5/9/2022<br />
| Finished mobile application<br />More testing, update schedule as needed<br />
| Complete<br />
|-<br />
| 13<br />
| 5/10/2022<br />
| 5/16/2022<br />
| Final prototype complete<br />
| Complete<br />
|-<br />
| 14<br />
| 5/17/2022<br />
| 5/25/2022<br />
| Last tests<br />
| Incomplete<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Parts List & Cost ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item#<br />
! scope="col"| Part Desciption<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| Unassembled RC Car <br />
| Traxxas [https://traxxas.com/products/models/electric/stampede-4x4-assembly-kit]<br />
| 1<br />
| $279.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Printed Circuit Board ==<br />
<br />
The preliminary design consisted of neatly routes wires on a breadboard connecting all the various components. It still looked confusing due to the sheer amount of connections that had to be made, this complexity was to be handled by a custom PCB designed in EasyEDA. <br />
<br />
<br />
[[File:Initial_wiring_testla.PNG|1000px|center|thumb|Breadboard Wiring]]<br />
<br />
<br />
=== Challenges ===<br />
We found that some wires we used were faulty and did not conduct electricity, this led to alot of debug time which could have been avoided by using another wire. To avoid this type of scenario, you can do a continuity check with a multimeter to ensure wire integrity. We chose to design a PCB to have a clean on the car and have higher pin connection strength, since bread board connections are too loose.<br />
<br />
<hr><br />
<br><br />
<br />
<br />
<br />
<br />
[[File:Master_diagram.PNG|1000px|center|thumb|PCB Schematic]]<br />
<br />
<br />
[[File:Pcb wiring testla.PNG|1000px|center|thumb|PCB Layout showing traces (red are front side, blue are back side)]]<br />
<br />
<br />
The design has many holes for mounting and pinouts for various peripherals (GPS, LCD, Buttons, etc.)<br />
<br />
Steps to design PCB:<br />
Following this general guideline will help you avoid any blockers.<br />
<br />
* Finish preliminary breadboard wiring and track changes along the way<br />
* Identify desired mounting topology and make measurements<br />
* Use pcb software to make schematic diagram (not PCB wiring)<br />
* Make holes in the pcb for desired mounting locations (The more the merrier)<br />
* Start positioning the components, then begin making traces<br />
<br />
<br />
[[File:Pcb_irl_testla_90.PNG|1000px|center|thumb|Pre-populated PCB]]<br />
<br />
== CAN Communication ==<br />
<Talk about your message IDs or communication strategy, such as periodic transmission, MIA management etc.><br />
<br />
=== Hardware Design ===<br />
<Show your CAN bus hardware design><br />
<br />
=== DBC File ===<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/blob/master/dbc/testla_proto1.dbc DBC Link]<br />
<br />
<pre><br />
VERSION ""<br />
<br />
NS_ :<br />
BA_<br />
BA_DEF_<br />
BA_DEF_DEF_<br />
BA_DEF_DEF_REL_<br />
BA_DEF_REL_<br />
BA_DEF_SGTYPE_<br />
BA_REL_<br />
BA_SGTYPE_<br />
BO_TX_BU_<br />
BU_BO_REL_<br />
BU_EV_REL_<br />
BU_SG_REL_<br />
CAT_<br />
CAT_DEF_<br />
CM_<br />
ENVVAR_DATA_<br />
EV_DATA_<br />
FILTER<br />
NS_DESC_<br />
SGTYPE_<br />
SGTYPE_VAL_<br />
SG_MUL_VAL_<br />
SIGTYPE_VALTYPE_<br />
SIG_GROUP_<br />
SIG_TYPE_REF_<br />
SIG_VALTYPE_<br />
VAL_<br />
VAL_TABLE_<br />
<br />
BS_:<br />
<br />
BU_: DRIVER MOTOR SENSOR GEO DEBUG<br />
<br />
<br />
BO_ 100 DRIVER_HEARTBEAT: 3 DRIVER<br />
SG_ DRIVER_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" DBG<br />
<br />
BO_ 110 DRIVER_STEERING: 3 DRIVER<br />
SG_ DRIVER_STEERING_yaw : 0|12@1+ (0.001,-2) [-10|10] "radians" MOTOR<br />
SG_ DRIVER_STEERING_velocity : 12|12@1+ (0.01,-20) [-20|20] "kph" MOTOR<br />
<br />
BO_ 120 MOTOR_HEARTBEAT: 5 MOTOR<br />
SG_ MOTOR_HEARTBEAT_speed_raw : 0|8@1+ (1,0) [0|0] "count" DEBUG<br />
SG_ MOTOR_HEARTBEAT_speed_rpm : 8|10@1+ (1,0) [0|0] "rpm" DEBUG<br />
SG_ MOTOR_HEARTBEAT_speed_kph : 18|10@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_HEARTBEAT_angle_duty : 28|10@1+ (0.001,-2) [-10|10] "duty" MOTOR<br />
<br />
<br />
BO_ 125 MOTOR_DEBUG: 8 MOTOR<br />
SG_ MOTOR_DEBUG_speed_target : 0|26@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_DEBUG_speed_kph : 26|10@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_DEBUG_speed_duty : 36|10@1+ (0.1,0) [0|0] "duty" DEBUG<br />
SG_ MOTOR_DEBUG_integral_error : 46|10@1+ (0.1,-10) [-10|10] "error" DEBUG<br />
SG_ MOTOR_DEBUG_current_state : 56|3@1+ (1,0) [0|5] "state" DEBUG<br />
SG_ MOTOR_DEBUG_next_state : 59|3@1+ (1,0) [0|5] "state" DEBUG<br />
<br />
<br />
<br />
<br />
BO_ 128 MOTOR_ESC_CALIBRATED: 1 MOTOR<br />
SG_ MOTOR_ESC_CALIBRATED_calibration_status : 0|4@1+ (1,0) [0|3] "esc_calibration_e" DRIVER<br />
SG_ MOTOR_ESC_CALIBRATED_start_calibration_ack_to_driver : 4|1@1+ (1,0) [0|1] "bool" DRIVER<br />
<br />
<br />
BO_ 129 DRIVER_START_ESC_CALIBRATION: 1 DRIVER<br />
SG_ MOTOR_ESC_CALIBRATED_begin_esc_calibration : 0|1@1+ (1,0) [0|3] "bool" MOTOR<br />
<br />
BO_ 130 MOTOR_ACK: 1 MOTOR<br />
SG_ MOTOR_ACK_cmd : 0|8@1+ (1,0) [0|0] "" DRIVER<br />
<br />
<br />
BO_ 200 SENSOR_SONARS: 8 SENSOR<br />
SG_ SENSOR_SONARS_left : 0|10@1+ (1,0) [0|800] "inch" DRIVER<br />
SG_ SENSOR_SONARS_right : 10|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_middle : 20|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_back : 30|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_frame_id : 42|16@1+ (1,0) [0|0] "" DRIVER<br />
<br />
BO_ 210 SENSOR_DESTINATION_LOCATION: 8 SENSOR<br />
SG_ SENSOR_DESTINATION_latitude : 0|28@1+ (0.000001,-90.000000) [-90|90] "Degrees" GEO<br />
SG_ SENSOR_DESTINATION_longitude : 28|28@1+ (0.000001,-180.000000) [-180|180] "Degrees" GEO<br />
<br />
BO_ 218 NAVIGATION_MESSAGE: 1 GEO<br />
SG_ NAVIGATION_STATUS_navigation_status : 0|8@1+ (1,0) [0|3] "navigation_status_e" DRIVER<br />
<br />
BO_ 219 CHECKPOINT_MESSAGE: 8 GEO<br />
SG_ CHECKPOINT_MESSAGE_compass_heading : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_destination_bearing : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_destination_distance : 24|16@1+ (0.1,0) [0|0] "Meters" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_curr_checkpoint_num : 40|8@1+ (1,0) [0|255] "Integer" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_total_checkpoint_num : 48|8@1+ (1,0) [0|255] "Integer" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_checkpoint_status : 56|8@1+ (1,0) [0|3] "checkpoint_status_e" DRIVER<br />
<br />
BO_ 220 GEO_STATUS: 8 GEO<br />
SG_ GEO_STATUS_compass_heading : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_destination_bearing : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_destination_distance : 24|16@1+ (0.1,0) [0|0] "Meters" DRIVER<br />
<br />
BO_ 520 DEBUG_GPS_CURRENT_LOCATION: 8 GEO<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_latitude : 0|28@1+ (0.000001,-90.000000) [-90|90] "Degrees" DEBUG<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_longitude : 28|28@1+ (0.000001,-180.000000) [-180|180] "Degrees" DEBUG<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_fix : 56|2@1+ (1,0) [0|2] "" DEBUG<br />
<br />
BO_ 521 DEBUG_GEO_GPS_UPDATE: 8 GEO<br />
SG_ DEBUG_GEO_GPS_UPDATE_count : 0|16@1+ (1,0) [0|0] "" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_max_period : 16|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_min_period : 32|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_average_period : 48|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
<br />
BO_ 522 DEBUG_GEO_COMPASS_UPDATE: 8 GEO<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_count : 0|16@1+ (1,0) [0|0] "" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_max_period : 16|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_min_period : 32|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_average_period : 48|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
<br />
CM_ BU_ DRIVER "The driver controller driving the car";<br />
CM_ BU_ MOTOR "The motor controller of the car";<br />
CM_ BU_ SENSOR "The sensor controller of the car";<br />
CM_ BU_ GEO "the geographical controller of the car";<br />
CM_ BU_ DEBUG "the debug topic that all controllers can publish to";<br />
CM_ BO_ 100 "Sync message used to synchronize the controllers";<br />
CM_ SG_ 100 DRIVER_HEARTBEAT_cmd "Heartbeat command from the driver";<br />
<br />
BA_DEF_ "BusType" STRING ;<br />
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 0;<br />
BA_DEF_ SG_ "FieldType" STRING ;<br />
<br />
BA_DEF_DEF_ "BusType" "CAN";<br />
BA_DEF_DEF_ "FieldType" "";<br />
BA_DEF_DEF_ "GenMsgCycleTime" 0;<br />
<br />
BA_ "GenMsgCycleTime" BO_ 100 1000;<br />
BA_ "GenMsgCycleTime" BO_ 200 50;<br />
BA_ "FieldType" SG_ 100 DRIVER_HEARTBEAT_cmd "DRIVER_HEARTBEAT_cmd";<br />
<br />
VAL_ 100 DRIVER_HEARTBEAT_cmd 2 "DRIVER_HEARTBEAT_cmd_REBOOT" 1 "DRIVER_HEARTBEAT_cmd_SYNC" 0 "DRIVER_HEARTBEAT_cmd_NOOP" ;<br />
<br />
<br />
</pre><br />
<HR><br />
<BR/><br />
<br />
== Sensor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
== Motor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Geographical Controller ==<br />
The geographical (geo) controller is used to provide the vehicle with a sense of location. To do this, the controller is interfaced to a compass which provides a heading, and a GPS module which provides a latitude, longitude, and GPS fix. GPS fix indicates that the GPS unit is connected to enough sattelites to provide accurate location data. The controller reads a destination off the CAN bus and calculates the distance from its current position. Additionally, it calculates a bearing, which is the degrees from north that the car must point to be facing the destination. If the car aligns its heading with the bearing and drives in a straight line for the number of meters described by the distance calculation, then the car will arrive at its destination.<br />
<br />
However, the vehicle will not be driving in a straight line because of obstacle avoidance. To deal with this, the distance and bearing are updated regularly at a rate of 10Hz. When an obstacle forces the vehicle to deviate from the desired course, it will recalculate the bearing and distance from its new location. This distance and location is then broadcast on the CAN bus, and digested by the driver controller.<br />
<br />
=== Hardware Design ===<br />
<br />
[[File:adafruit_gps.jpg]]<br />
<br />
An Adafruit Ultimate GPS breakout module using the MTK3339 chipset is interfaced over UART to the Geographical controller to provide latitude and longitude updates.<br />
<br />
<br />
[[File:wt901_compass.jpg]]<br />
<br />
A Witmotion WT901 IMU is connected over I2C to provide access to the vehicles heading.<br />
<br />
=== Software Design ===<br />
The general software flow is shown in the diagram below. This loop is run in a 10Hz periodic callback set up in FreeRTOS.<br />
<br />
[[File:geo_flow.jpg]]<br />
<br />
==== Initialization ====<br />
On startup the GPS module is configured. The GPS module sends data at 9600 bps after powering on but must be set to 115200 bps to support 10Hz updates. The controller must send a command to increase the GPS module's baud rate then change the baud rate on its own UART interface. Initially, the GPS sends out several different NMEA strings on every update. The vehicle only needs latitude , longitude and GPS fix data so the GPS is configured to only send GPGGA strings. This prevents the geo controller from wasting time to intake data that it is uninterested in. Finally, the GPS module is configured to send updated data at a rate of 10Hz. After this process is complete, the controller enters its main loop.<br />
<br />
==== Main Loop ====<br />
The geo controller runs at a frequency of 10Hz. A FreeRTOS task uses vTaskDelayUntil() to define a finite period of 100 milliseconds between invocations of the periodic callback.<br />
<br />
The GPS module is read by reading characters out of the UART into a line buffer. If a full line has been deposited into the buffer then the latitude, longitude and GPS Fix are updated. Additionally, a min and max time between GPS updates field is filled in as well as a count of updates. This debug information is published on the bus to analyze fidelity of the module.<br />
<br />
Next, the compass is read over an I2C interface to acquire the heading. The WT901 is an IMU which actually has a good deal more information available besides heading. Currently we are only reading the compass heading but can expand expand in the future to read acceleration and orientation. This module does need to be calibrated one time to ensure it is correctly reporting the heading. The module has a UART interface which can be used to interface between a TTL to USB converter to a software suite. This software can also be used for debugging and calibration.<br />
<br />
After reading the position the CAN interface checks if there are any changes to the destination being published by the bridge controller. After obtaining the most recent desired destination, the geographical module is invoked to calculate a distance and bearing. The section below goes into more detail on the geo calculation. After a distance and bearing are calculated, they are published onto the bis along with the current heading and dubug information. <br />
<br />
==== Geo process ====<br />
<br />
The desired and current position are used to calculate a distance and bearing using the haversine formula shown below.<br />
<br />
'''Distance'''<br />
<br />
[[File:haversine.PNG]]<br />
<br />
'''Bearing'''<br />
<br />
[[File:Bearing_calculations.PNG]]<br />
<br />
[https://www.movable-type.co.uk/scripts/latlong.html Moveable Type Scripts: Calculate distance, bearing and more between Latitude/Longitude points]<br />
<br />
<br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
<HR><br />
<BR/><br />
<br />
== Communication Bridge Controller & LCD ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Master Module ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Mobile Application ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<br />
<BR/><br />
<HR><br />
<HR><br />
<BR/><br />
== Conclusion ==<br />
<Organized summary of the project><br />
<br />
<What did you learn?><br />
<br />
=== Project Video ===<br />
<br />
=== Project Source Code ===<br />
<br />
=== Advise for Future Students ===<br />
<Bullet points and discussion><br />
<br />
=== Acknowledgement ===<br />
<br />
=== References ===</div>Proj user2http://socialledge.com/sjsu/index.php?title=S22:_Testla&diff=68751S22: Testla2022-05-28T04:17:23Z<p>Proj user2: </p>
<hr />
<div>== Testla ==<br />
[[File:Bunch of handsome young men.jpeg |800px|middle]]<br />
<br />
<br />
<HR><br />
<BR/><br />
<br />
== Abstract ==<br />
The Testla project is the culmination of our efforts to create an autonomously operated RC Car by pooling together our experience in software design, hardware design, power systems, and mobile application development. Project development started in February of 2022 and ended in May. (NOTE: One more sentence probably)<br />
<br />
=== Introduction ===<br />
<br />
The project was divided into 5 modules:<br />
<br />
* Bridge and Sensor Information<br />
* Motor Operation<br />
* Geological Information<br />
* Driver and LCD Manager<br />
* Android Application<br />
<br />
=== Team Members & Responsibilities ===<br />
<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle Gitlab Project Link]<br />
<BR/><br />
<br />
[[File:DevinAlexander.jpeg|200px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Project Lead Meeting Organizer<br />
** Driver Controller<br />
** Geographical Controller<br />
<br />
<br />
<br />
[[File:scott_locascio.jpeg|200px|middle]]<br />
* Scott LoCascio '''''[https://gitlab.com/scottlocascio Gitlab]'''''<br />
** Geographical Controller<br />
** Car Construction<br />
** Testing?<br />
<br />
<br />
* Thinh Lu '''''[https://gitlab.com/lphucthinh40 Gitlab]'''''<br />
** Android Application<br />
** Sensor and Bridge Controller<br />
<br />
<br />
* Bang Nguyen --couldn't find your gitlab <BR/><br />
** Sensor and Bridge Controller<br />
** LCD Display<br />
<br />
<br />
<br />
* Michael Hatzikokolakis '''''[https://gitlab.com/mikehatzi8 Gitlab]'''''<br />
** Motor Controller<br />
** Android Application<br />
<br />
<br />
* Sinan Bayati '''''[https://gitlab.com/sinan.bayati Gitlab]'''''<br />
** PCB Design<br />
** Motor Controller<br />
<br />
<BR/><br />
<br />
== Schedule ==<br />
<br />
<br />
{| class="wikitable" <br />
|-<br />
! Week #<br />
! Start Date<br />
! End Date<br />
! Task<br />
! Status<br />
|-<br />
| 1<br />
| 2/15/2022<br />
| 2/21/2022<br />
| Read previous projects, gather information and discuss among the group members.<br />
| Complete<br />
|-<br />
| 2<br />
| 2/22/2022<br />
| 2/28/2022<br />
| style="background-color:#F9F9F9;" | Distribute modules to each team member.<br />
| Complete<br />
|-<br />
| 3<br />
| 3/1/2022<br />
| 3/7/2022<br />
| Purchase the RC Car<br />Purchase sensors<br />
| Complete<br />
|-<br />
| 4<br />
| 3/8/2022<br />
| 3/14/2022<br />
| style="background-color:#F9F9F9;" | Learning to use CAN BUSMASTER<br />
| Complete<br />
|-<br />
| 5<br />
| 3/15/2022<br />
| 3/21/2022<br />
| style="background-color:#F9F9F9;" | DBC file discussed and implemented<br />
| Complete<br />
|-<br />
| 6<br />
| 3/22/2022<br />
| 3/28/2022<br />
| style="background-color:#F9F9F9;" | Discuss modules needed for PCB, any feature requests<br />
| Complete<br />
|-<br />
| 7<br />
| 3/29/2022<br />
| 4/4/2022<br />
| Finalize preparations and research<br />
| Complete<br />
|-<br />
| 8<br />
| 4/5/2022<br />
| 4/11/2022<br />
| Interface with RC car and hack steering and motor<br />Integrate the GEO sensor with the GEO controller<br />Complete the Driver sensor using analog readings<br />Write a basic implementation of the sensor controller<br />Interface ESP8266 for bridge controller<br />Begin testing with single vs dual power supplies<br />
| Complete<br />
|-<br />
| 9<br />
| 4/12/2022<br />
| 4/18/2022<br />
| Install wheel encoder, implement, implement PID into velocity processing, and establish collaboration between the Motor and Sensor Controllers<br />Test alternate sonar sensor (I2C)<br />Configure GPS to run at 10Hz, 115200 baud and only parse $GPGGA strings on startup<br />Integrate compass<br />Setup NodeJS server to communicate with the Bridge controller via TCP/IP<br />Start Mobile Application development.<br />Finalize power supply choice<br />Finish PCB designs for each subsystem<br />
| Complete<br />
|-<br />
| 10<br />
| 4/19/2022<br />
| 4/25/2022<br />
| Finish 1st vehicle prototype - include PCBs if possible<br />Complete basic mobile application<br />Write various motor test routines to define in mobile application<br />Verify timing and correctness of GEO controller messages. Produce debug messages for Geo controller<br />Generate debug messages for all controllers.<br />Finalize sensor choice and complete integration of all three sensors.<br />
| Complete<br />
|-<br />
| 11<br />
| 4/26/2022<br />
| 5/2/2022<br />
| Identify first PCB design inefficiencies/failures and submit the second and final draft for production<br />Thoroughly test the motor's performance on sloped terrain and refine PID controller<br />Test message timing and propagation with Bus Master<br />Improve existing navigation algorithm with state estimation and localization<br />Integration testing Driver controller with Mobile App<br />
| Complete<br />
|-<br />
| 12<br />
| 5/3/2022<br />
| 5/9/2022<br />
| Finished mobile application<br />More testing, update schedule as needed<br />
| Complete<br />
|-<br />
| 13<br />
| 5/10/2022<br />
| 5/16/2022<br />
| Final prototype complete<br />
| Complete<br />
|-<br />
| 14<br />
| 5/17/2022<br />
| 5/25/2022<br />
| Last tests<br />
| Incomplete<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Parts List & Cost ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item#<br />
! scope="col"| Part Desciption<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| Unassembled RC Car <br />
| Traxxas [https://traxxas.com/products/models/electric/stampede-4x4-assembly-kit]<br />
| 1<br />
| $279.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Printed Circuit Board ==<br />
<br />
The preliminary design consisted of neatly routes wires on a breadboard connecting all the various components. It still looked confusing due to the sheer amount of connections that had to be made, this complexity was to be handled by a custom PCB designed in EasyEDA. <br />
<br />
<br />
[[File:Initial_wiring_testla.PNG|1000px|center|thumb|Breadboard Wiring]]<br />
<br />
<br />
=== Challenges ===<br />
We found that some wires we used were faulty and did not conduct electricity, this led to alot of debug time which could have been avoided by using another wire. To avoid this type of scenario, you can do a continuity check with a multimeter to ensure wire integrity. We chose to design a PCB to have a clean on the car and have higher pin connection strength, since bread board connections are too loose.<br />
<br />
<hr><br />
<br><br />
<br />
<br />
<br />
<br />
[[File:Master_diagram.PNG|1000px|center|thumb|PCB Schematic]]<br />
<br />
<br />
[[File:Pcb wiring testla.PNG|1000px|center|thumb|PCB Layout showing traces (red are front side, blue are back side)]]<br />
<br />
<br />
The design has many holes for mounting and pinouts for various peripherals (GPS, LCD, Buttons, etc.)<br />
<br />
Steps to design PCB:<br />
Following this general guideline will help you avoid any blockers.<br />
<br />
* Finish preliminary breadboard wiring and track changes along the way<br />
* Identify desired mounting topology and make measurements<br />
* Use pcb software to make schematic diagram (not PCB wiring)<br />
* Make holes in the pcb for desired mounting locations (The more the merrier)<br />
* Start positioning the components, then begin making traces<br />
<br />
<br />
[[File:Pcb_irl_testla_90.PNG|1000px|center|thumb|Pre-populated PCB]]<br />
<br />
== CAN Communication ==<br />
<Talk about your message IDs or communication strategy, such as periodic transmission, MIA management etc.><br />
<br />
=== Hardware Design ===<br />
<Show your CAN bus hardware design><br />
<br />
=== DBC File ===<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/blob/master/dbc/testla_proto1.dbc DBC Link]<br />
<br />
<pre><br />
VERSION ""<br />
<br />
NS_ :<br />
BA_<br />
BA_DEF_<br />
BA_DEF_DEF_<br />
BA_DEF_DEF_REL_<br />
BA_DEF_REL_<br />
BA_DEF_SGTYPE_<br />
BA_REL_<br />
BA_SGTYPE_<br />
BO_TX_BU_<br />
BU_BO_REL_<br />
BU_EV_REL_<br />
BU_SG_REL_<br />
CAT_<br />
CAT_DEF_<br />
CM_<br />
ENVVAR_DATA_<br />
EV_DATA_<br />
FILTER<br />
NS_DESC_<br />
SGTYPE_<br />
SGTYPE_VAL_<br />
SG_MUL_VAL_<br />
SIGTYPE_VALTYPE_<br />
SIG_GROUP_<br />
SIG_TYPE_REF_<br />
SIG_VALTYPE_<br />
VAL_<br />
VAL_TABLE_<br />
<br />
BS_:<br />
<br />
BU_: DRIVER MOTOR SENSOR GEO DEBUG<br />
<br />
<br />
BO_ 100 DRIVER_HEARTBEAT: 3 DRIVER<br />
SG_ DRIVER_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" DBG<br />
<br />
BO_ 110 DRIVER_STEERING: 3 DRIVER<br />
SG_ DRIVER_STEERING_yaw : 0|12@1+ (0.001,-2) [-10|10] "radians" MOTOR<br />
SG_ DRIVER_STEERING_velocity : 12|12@1+ (0.01,-20) [-20|20] "kph" MOTOR<br />
<br />
BO_ 120 MOTOR_HEARTBEAT: 5 MOTOR<br />
SG_ MOTOR_HEARTBEAT_speed_raw : 0|8@1+ (1,0) [0|0] "count" DEBUG<br />
SG_ MOTOR_HEARTBEAT_speed_rpm : 8|10@1+ (1,0) [0|0] "rpm" DEBUG<br />
SG_ MOTOR_HEARTBEAT_speed_kph : 18|10@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_HEARTBEAT_angle_duty : 28|10@1+ (0.001,-2) [-10|10] "duty" MOTOR<br />
<br />
<br />
BO_ 125 MOTOR_DEBUG: 8 MOTOR<br />
SG_ MOTOR_DEBUG_speed_target : 0|26@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_DEBUG_speed_kph : 26|10@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_DEBUG_speed_duty : 36|10@1+ (0.1,0) [0|0] "duty" DEBUG<br />
SG_ MOTOR_DEBUG_integral_error : 46|10@1+ (0.1,-10) [-10|10] "error" DEBUG<br />
SG_ MOTOR_DEBUG_current_state : 56|3@1+ (1,0) [0|5] "state" DEBUG<br />
SG_ MOTOR_DEBUG_next_state : 59|3@1+ (1,0) [0|5] "state" DEBUG<br />
<br />
<br />
<br />
<br />
BO_ 128 MOTOR_ESC_CALIBRATED: 1 MOTOR<br />
SG_ MOTOR_ESC_CALIBRATED_calibration_status : 0|4@1+ (1,0) [0|3] "esc_calibration_e" DRIVER<br />
SG_ MOTOR_ESC_CALIBRATED_start_calibration_ack_to_driver : 4|1@1+ (1,0) [0|1] "bool" DRIVER<br />
<br />
<br />
BO_ 129 DRIVER_START_ESC_CALIBRATION: 1 DRIVER<br />
SG_ MOTOR_ESC_CALIBRATED_begin_esc_calibration : 0|1@1+ (1,0) [0|3] "bool" MOTOR<br />
<br />
BO_ 130 MOTOR_ACK: 1 MOTOR<br />
SG_ MOTOR_ACK_cmd : 0|8@1+ (1,0) [0|0] "" DRIVER<br />
<br />
<br />
BO_ 200 SENSOR_SONARS: 8 SENSOR<br />
SG_ SENSOR_SONARS_left : 0|10@1+ (1,0) [0|800] "inch" DRIVER<br />
SG_ SENSOR_SONARS_right : 10|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_middle : 20|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_back : 30|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_frame_id : 42|16@1+ (1,0) [0|0] "" DRIVER<br />
<br />
BO_ 210 SENSOR_DESTINATION_LOCATION: 8 SENSOR<br />
SG_ SENSOR_DESTINATION_latitude : 0|28@1+ (0.000001,-90.000000) [-90|90] "Degrees" GEO<br />
SG_ SENSOR_DESTINATION_longitude : 28|28@1+ (0.000001,-180.000000) [-180|180] "Degrees" GEO<br />
<br />
BO_ 218 NAVIGATION_MESSAGE: 1 GEO<br />
SG_ NAVIGATION_STATUS_navigation_status : 0|8@1+ (1,0) [0|3] "navigation_status_e" DRIVER<br />
<br />
BO_ 219 CHECKPOINT_MESSAGE: 8 GEO<br />
SG_ CHECKPOINT_MESSAGE_compass_heading : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_destination_bearing : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_destination_distance : 24|16@1+ (0.1,0) [0|0] "Meters" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_curr_checkpoint_num : 40|8@1+ (1,0) [0|255] "Integer" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_total_checkpoint_num : 48|8@1+ (1,0) [0|255] "Integer" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_checkpoint_status : 56|8@1+ (1,0) [0|3] "checkpoint_status_e" DRIVER<br />
<br />
BO_ 220 GEO_STATUS: 8 GEO<br />
SG_ GEO_STATUS_compass_heading : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_destination_bearing : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_destination_distance : 24|16@1+ (0.1,0) [0|0] "Meters" DRIVER<br />
<br />
BO_ 520 DEBUG_GPS_CURRENT_LOCATION: 8 GEO<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_latitude : 0|28@1+ (0.000001,-90.000000) [-90|90] "Degrees" DEBUG<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_longitude : 28|28@1+ (0.000001,-180.000000) [-180|180] "Degrees" DEBUG<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_fix : 56|2@1+ (1,0) [0|2] "" DEBUG<br />
<br />
BO_ 521 DEBUG_GEO_GPS_UPDATE: 8 GEO<br />
SG_ DEBUG_GEO_GPS_UPDATE_count : 0|16@1+ (1,0) [0|0] "" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_max_period : 16|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_min_period : 32|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_average_period : 48|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
<br />
BO_ 522 DEBUG_GEO_COMPASS_UPDATE: 8 GEO<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_count : 0|16@1+ (1,0) [0|0] "" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_max_period : 16|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_min_period : 32|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_average_period : 48|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
<br />
CM_ BU_ DRIVER "The driver controller driving the car";<br />
CM_ BU_ MOTOR "The motor controller of the car";<br />
CM_ BU_ SENSOR "The sensor controller of the car";<br />
CM_ BU_ GEO "the geographical controller of the car";<br />
CM_ BU_ DEBUG "the debug topic that all controllers can publish to";<br />
CM_ BO_ 100 "Sync message used to synchronize the controllers";<br />
CM_ SG_ 100 DRIVER_HEARTBEAT_cmd "Heartbeat command from the driver";<br />
<br />
BA_DEF_ "BusType" STRING ;<br />
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 0;<br />
BA_DEF_ SG_ "FieldType" STRING ;<br />
<br />
BA_DEF_DEF_ "BusType" "CAN";<br />
BA_DEF_DEF_ "FieldType" "";<br />
BA_DEF_DEF_ "GenMsgCycleTime" 0;<br />
<br />
BA_ "GenMsgCycleTime" BO_ 100 1000;<br />
BA_ "GenMsgCycleTime" BO_ 200 50;<br />
BA_ "FieldType" SG_ 100 DRIVER_HEARTBEAT_cmd "DRIVER_HEARTBEAT_cmd";<br />
<br />
VAL_ 100 DRIVER_HEARTBEAT_cmd 2 "DRIVER_HEARTBEAT_cmd_REBOOT" 1 "DRIVER_HEARTBEAT_cmd_SYNC" 0 "DRIVER_HEARTBEAT_cmd_NOOP" ;<br />
<br />
<br />
</pre><br />
<HR><br />
<BR/><br />
<br />
== Sensor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
== Motor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Geographical Controller ==<br />
The geographical (geo) controller is used to provide the vehicle with a sense of location. To do this, the controller is interfaced to a compass which provides a heading, and a GPS module which provides a latitude and longitude. The controller reads a destination off the CAN bus and calculates the distance from its current position. Additionally, it calculates a bearing, which is the degrees from north that the car must point to be facing the destination. If the car aligns its heading with the bearing and drives in a straight line for the number of meters described by the distance calculation, then the car will arrive at its destination.<br />
<br />
However, the vehicle will not be driving in a straight line because of obstacle avoidance. To deal with this, the distance and bearing are updated regularly at a rate of 10Hz. When an obstacle forces the vehicle to deviate from the desired course, it will recalculate the bearing and distance from its new location. This distance and location is then broadcast on the CAN bus, and digested by the driver controller.<br />
<br />
=== Hardware Design ===<br />
<br />
[[File:adafruit_gps.jpg]]<br />
<br />
An Adafruit Ultimate GPS breakout module using the MTK3339 chipset is interfaced over UART to the Geographical controller to provide latitude and longitude updates.<br />
<br />
<br />
[[File:wt901_compass.jpg]]<br />
<br />
A Witmotion WT901 IMU is connected over I2C to provide access to the vehicles heading.<br />
<br />
=== Software Design ===<br />
The general software flow is shown in the diagram below. This loop is run in a 10Hz periodic callback set up in FreeRTOS.<br />
<br />
[[File:geo_flow.jpg]]<br />
<br />
==== Initialization ====<br />
<br />
On startup the GPS module is configured. The GPS module sends data at 9600 bps after powering on but must be set to 115200 bps to support 10Hz updates. The controller must send a command to increase the GPS module's baud rate then change the baud rate on its own UART interface. Initially, the GPS sends out several different NMEA strings on every update. The vehicle only needs latitude , longitude and GPS fix data so the GPS is configured to only send GPGGA strings. This prevents the geo controller from wasting time to intake data that it is uninterested in. Finally, the GPS module is configured to send updated data at a rate of 10Hz. After this process is complete, the controller enters its main loop.<br />
<br />
==== Main Loop ====<br />
<br />
==== Geo process ====<br />
<br />
The desired and current position are used to calculate a distance and bearing using the haversine formula shown below.<br />
<br />
[[File:haversine.PNG]]<br />
<br />
[https://www.movable-type.co.uk/scripts/latlong.html Moveable Type Scripts: Calculate distance, bearing and more between Latitude/Longitude points]<br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
<HR><br />
<BR/><br />
<br />
== Communication Bridge Controller & LCD ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Master Module ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Mobile Application ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<br />
<BR/><br />
<HR><br />
<HR><br />
<BR/><br />
== Conclusion ==<br />
<Organized summary of the project><br />
<br />
<What did you learn?><br />
<br />
=== Project Video ===<br />
<br />
=== Project Source Code ===<br />
<br />
=== Advise for Future Students ===<br />
<Bullet points and discussion><br />
<br />
=== Acknowledgement ===<br />
<br />
=== References ===</div>Proj user2http://socialledge.com/sjsu/index.php?title=S22:_Testla&diff=68704S22: Testla2022-05-28T03:45:47Z<p>Proj user2: Uploaded group photo</p>
<hr />
<div>== Testla ==<br />
<Group Pic><br />
<br />
[[File:Bunch of handsome young men.jpeg |800px|middle]]<br />
<br />
<br />
<HR><br />
<BR/><br />
<br />
== Abstract ==<br />
The Testla project is the culmination of our efforts to create an autonomously operated RC Car by pooling together our experience in software design, hardware design, power systems, and mobile application development. Project development started in February of 2022 and ended in May. (NOTE: One more sentence probably)<br />
<br />
=== Introduction ===<br />
<br />
The project was divided into 5 modules:<br />
<br />
* Bridge and Sensor Information<br />
* Motor Operation<br />
* Geological Information<br />
* Driver and LCD Manager<br />
* Android Application<br />
<br />
=== Team Members & Responsibilities ===<br />
<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle Gitlab Project Link]<br />
<BR/><br />
<br />
[[File:DevinAlexander.jpeg|200px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Project Lead Meeting Organizer<br />
** Driver Controller<br />
** Geographical Controller<br />
<br />
<br />
<br />
[[File:scott_locascio.jpeg|200px|middle]]<br />
* Scott LoCascio '''''[https://gitlab.com/scottlocascio Gitlab]'''''<br />
** Geographical Controller<br />
** Car Construction<br />
** Testing?<br />
<br />
<br />
* Thinh Lu '''''[https://gitlab.com/lphucthinh40 Gitlab]'''''<br />
** Android Application<br />
** Sensor and Bridge Controller<br />
<br />
<br />
* Bang Nguyen --couldn't find your gitlab <BR/><br />
** Sensor and Bridge Controller<br />
** LCD Display<br />
<br />
<br />
<br />
* Michael Hatzikokolakis '''''[https://gitlab.com/mikehatzi8 Gitlab]'''''<br />
** Motor Controller<br />
** Android Application<br />
<br />
<br />
* Sinan Bayati '''''[https://gitlab.com/sinan.bayati Gitlab]'''''<br />
** PCB Design<br />
** Motor Controller<br />
<br />
<BR/><br />
<br />
== Schedule ==<br />
<br />
<br />
{| class="wikitable" <br />
|-<br />
! Week #<br />
! Start Date<br />
! End Date<br />
! Task<br />
! Status<br />
|-<br />
| 1<br />
| 2/15/2022<br />
| 2/21/2022<br />
| Read previous projects, gather information and discuss among the group members.<br />
| Complete<br />
|-<br />
| 2<br />
| 2/22/2022<br />
| 2/28/2022<br />
| style="background-color:#F9F9F9;" | Distribute modules to each team member.<br />
| Complete<br />
|-<br />
| 3<br />
| 3/1/2022<br />
| 3/7/2022<br />
| Purchase the RC Car<br />Purchase sensors<br />
| Complete<br />
|-<br />
| 4<br />
| 3/8/2022<br />
| 3/14/2022<br />
| style="background-color:#F9F9F9;" | Learning to use CAN BUSMASTER<br />
| Complete<br />
|-<br />
| 5<br />
| 3/15/2022<br />
| 3/21/2022<br />
| style="background-color:#F9F9F9;" | DBC file discussed and implemented<br />
| Complete<br />
|-<br />
| 6<br />
| 3/22/2022<br />
| 3/28/2022<br />
| style="background-color:#F9F9F9;" | Discuss modules needed for PCB, any feature requests<br />
| Complete<br />
|-<br />
| 7<br />
| 3/29/2022<br />
| 4/4/2022<br />
| Finalize preparations and research<br />
| Complete<br />
|-<br />
| 8<br />
| 4/5/2022<br />
| 4/11/2022<br />
| Interface with RC car and hack steering and motor<br />Integrate the GEO sensor with the GEO controller<br />Complete the Driver sensor using analog readings<br />Write a basic implementation of the sensor controller<br />Interface ESP8266 for bridge controller<br />Begin testing with single vs dual power supplies<br />
| Complete<br />
|-<br />
| 9<br />
| 4/12/2022<br />
| 4/18/2022<br />
| Install wheel encoder, implement, implement PID into velocity processing, and establish collaboration between the Motor and Sensor Controllers<br />Test alternate sonar sensor (I2C)<br />Configure GPS to run at 10Hz, 115200 baud and only parse $GPGGA strings on startup<br />Integrate compass<br />Setup NodeJS server to communicate with the Bridge controller via TCP/IP<br />Start Mobile Application development.<br />Finalize power supply choice<br />Finish PCB designs for each subsystem<br />
| Complete<br />
|-<br />
| 10<br />
| 4/19/2022<br />
| 4/25/2022<br />
| Finish 1st vehicle prototype - include PCBs if possible<br />Complete basic mobile application<br />Write various motor test routines to define in mobile application<br />Verify timing and correctness of GEO controller messages. Produce debug messages for Geo controller<br />Generate debug messages for all controllers.<br />Finalize sensor choice and complete integration of all three sensors.<br />
| Complete<br />
|-<br />
| 11<br />
| 4/26/2022<br />
| 5/2/2022<br />
| Identify first PCB design inefficiencies/failures and submit the second and final draft for production<br />Thoroughly test the motor's performance on sloped terrain and refine PID controller<br />Test message timing and propagation with Bus Master<br />Improve existing navigation algorithm with state estimation and localization<br />Integration testing Driver controller with Mobile App<br />
| Complete<br />
|-<br />
| 12<br />
| 5/3/2022<br />
| 5/9/2022<br />
| Finished mobile application<br />More testing, update schedule as needed<br />
| Complete<br />
|-<br />
| 13<br />
| 5/10/2022<br />
| 5/16/2022<br />
| Final prototype complete<br />
| Complete<br />
|-<br />
| 14<br />
| 5/17/2022<br />
| 5/25/2022<br />
| Last tests<br />
| Incomplete<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Parts List & Cost ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item#<br />
! scope="col"| Part Desciption<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| Unassembled RC Car <br />
| Traxxas [https://traxxas.com/products/models/electric/stampede-4x4-assembly-kit]<br />
| 1<br />
| $279.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Printed Circuit Board ==<br />
<br />
The preliminary design consisted of neatly routes wires on a breadboard connecting all the various components. It still looked confusing due to the sheer amount of connections that had to be made, this complexity was to be handled by a custom PCB designed in EasyEDA. <br />
<br />
<br />
[[File:Initial_wiring_testla.PNG|1000px|center|thumb|Breadboard Wiring]]<br />
<br />
<br />
=== Challenges ===<br />
We found that some wires we used were faulty and did not conduct electricity, this led to alot of debug time which could have been avoided by using another wire. To avoid this type of scenario, you can do a continuity check with a multimeter to ensure wire integrity. We chose to design a PCB to have a clean on the car and have higher pin connection strength, since bread board connections are too loose.<br />
<br />
<hr><br />
<br><br />
<br />
<br />
<br />
<br />
[[File:Master_diagram.PNG|1000px|center|thumb|PCB Schematic]]<br />
<br />
<br />
[[File:Pcb wiring testla.PNG|1000px|center|thumb|PCB Layout showing traces (red are front side, blue are back side)]]<br />
<br />
<br />
The design has many holes for mounting and pinouts for various peripherals (GPS, LCD, Buttons, etc.)<br />
<br />
Steps to design PCB:<br />
Following this general guideline will help you avoid any blockers.<br />
<br />
* Finish preliminary breadboard wiring and track changes along the way<br />
* Identify desired mounting topology and make measurements<br />
* Use pcb software to make schematic diagram (not PCB wiring)<br />
* Make holes in the pcb for desired mounting locations (The more the merrier)<br />
* Start positioning the components, then begin making traces<br />
<br />
<br />
[[File:Pcb_irl_testla_90.PNG|1000px|center|thumb|Pre-populated PCB]]<br />
<br />
== CAN Communication ==<br />
<Talk about your message IDs or communication strategy, such as periodic transmission, MIA management etc.><br />
<br />
=== Hardware Design ===<br />
<Show your CAN bus hardware design><br />
<br />
=== DBC File ===<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/blob/master/dbc/testla_proto1.dbc DBC Link]<br />
<br />
<pre><br />
VERSION ""<br />
<br />
NS_ :<br />
BA_<br />
BA_DEF_<br />
BA_DEF_DEF_<br />
BA_DEF_DEF_REL_<br />
BA_DEF_REL_<br />
BA_DEF_SGTYPE_<br />
BA_REL_<br />
BA_SGTYPE_<br />
BO_TX_BU_<br />
BU_BO_REL_<br />
BU_EV_REL_<br />
BU_SG_REL_<br />
CAT_<br />
CAT_DEF_<br />
CM_<br />
ENVVAR_DATA_<br />
EV_DATA_<br />
FILTER<br />
NS_DESC_<br />
SGTYPE_<br />
SGTYPE_VAL_<br />
SG_MUL_VAL_<br />
SIGTYPE_VALTYPE_<br />
SIG_GROUP_<br />
SIG_TYPE_REF_<br />
SIG_VALTYPE_<br />
VAL_<br />
VAL_TABLE_<br />
<br />
BS_:<br />
<br />
BU_: DRIVER MOTOR SENSOR GEO DEBUG<br />
<br />
<br />
BO_ 100 DRIVER_HEARTBEAT: 3 DRIVER<br />
SG_ DRIVER_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" DBG<br />
<br />
BO_ 110 DRIVER_STEERING: 3 DRIVER<br />
SG_ DRIVER_STEERING_yaw : 0|12@1+ (0.001,-2) [-10|10] "radians" MOTOR<br />
SG_ DRIVER_STEERING_velocity : 12|12@1+ (0.01,-20) [-20|20] "kph" MOTOR<br />
<br />
BO_ 120 MOTOR_HEARTBEAT: 5 MOTOR<br />
SG_ MOTOR_HEARTBEAT_speed_raw : 0|8@1+ (1,0) [0|0] "count" DEBUG<br />
SG_ MOTOR_HEARTBEAT_speed_rpm : 8|10@1+ (1,0) [0|0] "rpm" DEBUG<br />
SG_ MOTOR_HEARTBEAT_speed_kph : 18|10@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_HEARTBEAT_angle_duty : 28|10@1+ (0.001,-2) [-10|10] "duty" MOTOR<br />
<br />
<br />
BO_ 125 MOTOR_DEBUG: 8 MOTOR<br />
SG_ MOTOR_DEBUG_speed_target : 0|26@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_DEBUG_speed_kph : 26|10@1+ (0.1,-10) [-10|10] "kph" DEBUG<br />
SG_ MOTOR_DEBUG_speed_duty : 36|10@1+ (0.1,0) [0|0] "duty" DEBUG<br />
SG_ MOTOR_DEBUG_integral_error : 46|10@1+ (0.1,-10) [-10|10] "error" DEBUG<br />
SG_ MOTOR_DEBUG_current_state : 56|3@1+ (1,0) [0|5] "state" DEBUG<br />
SG_ MOTOR_DEBUG_next_state : 59|3@1+ (1,0) [0|5] "state" DEBUG<br />
<br />
<br />
<br />
<br />
BO_ 128 MOTOR_ESC_CALIBRATED: 1 MOTOR<br />
SG_ MOTOR_ESC_CALIBRATED_calibration_status : 0|4@1+ (1,0) [0|3] "esc_calibration_e" DRIVER<br />
SG_ MOTOR_ESC_CALIBRATED_start_calibration_ack_to_driver : 4|1@1+ (1,0) [0|1] "bool" DRIVER<br />
<br />
<br />
BO_ 129 DRIVER_START_ESC_CALIBRATION: 1 DRIVER<br />
SG_ MOTOR_ESC_CALIBRATED_begin_esc_calibration : 0|1@1+ (1,0) [0|3] "bool" MOTOR<br />
<br />
BO_ 130 MOTOR_ACK: 1 MOTOR<br />
SG_ MOTOR_ACK_cmd : 0|8@1+ (1,0) [0|0] "" DRIVER<br />
<br />
<br />
BO_ 200 SENSOR_SONARS: 8 SENSOR<br />
SG_ SENSOR_SONARS_left : 0|10@1+ (1,0) [0|800] "inch" DRIVER<br />
SG_ SENSOR_SONARS_right : 10|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_middle : 20|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_back : 30|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_frame_id : 42|16@1+ (1,0) [0|0] "" DRIVER<br />
<br />
BO_ 210 SENSOR_DESTINATION_LOCATION: 8 SENSOR<br />
SG_ SENSOR_DESTINATION_latitude : 0|28@1+ (0.000001,-90.000000) [-90|90] "Degrees" GEO<br />
SG_ SENSOR_DESTINATION_longitude : 28|28@1+ (0.000001,-180.000000) [-180|180] "Degrees" GEO<br />
<br />
BO_ 218 NAVIGATION_MESSAGE: 1 GEO<br />
SG_ NAVIGATION_STATUS_navigation_status : 0|8@1+ (1,0) [0|3] "navigation_status_e" DRIVER<br />
<br />
BO_ 219 CHECKPOINT_MESSAGE: 8 GEO<br />
SG_ CHECKPOINT_MESSAGE_compass_heading : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_destination_bearing : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_destination_distance : 24|16@1+ (0.1,0) [0|0] "Meters" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_curr_checkpoint_num : 40|8@1+ (1,0) [0|255] "Integer" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_total_checkpoint_num : 48|8@1+ (1,0) [0|255] "Integer" DRIVER<br />
SG_ CHECKPOINT_MESSAGE_checkpoint_status : 56|8@1+ (1,0) [0|3] "checkpoint_status_e" DRIVER<br />
<br />
BO_ 220 GEO_STATUS: 8 GEO<br />
SG_ GEO_STATUS_compass_heading : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_destination_bearing : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_destination_distance : 24|16@1+ (0.1,0) [0|0] "Meters" DRIVER<br />
<br />
BO_ 520 DEBUG_GPS_CURRENT_LOCATION: 8 GEO<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_latitude : 0|28@1+ (0.000001,-90.000000) [-90|90] "Degrees" DEBUG<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_longitude : 28|28@1+ (0.000001,-180.000000) [-180|180] "Degrees" DEBUG<br />
SG_ DEBUG_GPS_CURRENT_LOCATION_fix : 56|2@1+ (1,0) [0|2] "" DEBUG<br />
<br />
BO_ 521 DEBUG_GEO_GPS_UPDATE: 8 GEO<br />
SG_ DEBUG_GEO_GPS_UPDATE_count : 0|16@1+ (1,0) [0|0] "" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_max_period : 16|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_min_period : 32|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_GPS_UPDATE_average_period : 48|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
<br />
BO_ 522 DEBUG_GEO_COMPASS_UPDATE: 8 GEO<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_count : 0|16@1+ (1,0) [0|0] "" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_max_period : 16|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_min_period : 32|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
SG_ DEBUG_GEO_COMPASS_UPDATE_average_period : 48|16@1+ (1,0) [0|0] "milliseconds" DEBUG<br />
<br />
CM_ BU_ DRIVER "The driver controller driving the car";<br />
CM_ BU_ MOTOR "The motor controller of the car";<br />
CM_ BU_ SENSOR "The sensor controller of the car";<br />
CM_ BU_ GEO "the geographical controller of the car";<br />
CM_ BU_ DEBUG "the debug topic that all controllers can publish to";<br />
CM_ BO_ 100 "Sync message used to synchronize the controllers";<br />
CM_ SG_ 100 DRIVER_HEARTBEAT_cmd "Heartbeat command from the driver";<br />
<br />
BA_DEF_ "BusType" STRING ;<br />
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 0;<br />
BA_DEF_ SG_ "FieldType" STRING ;<br />
<br />
BA_DEF_DEF_ "BusType" "CAN";<br />
BA_DEF_DEF_ "FieldType" "";<br />
BA_DEF_DEF_ "GenMsgCycleTime" 0;<br />
<br />
BA_ "GenMsgCycleTime" BO_ 100 1000;<br />
BA_ "GenMsgCycleTime" BO_ 200 50;<br />
BA_ "FieldType" SG_ 100 DRIVER_HEARTBEAT_cmd "DRIVER_HEARTBEAT_cmd";<br />
<br />
VAL_ 100 DRIVER_HEARTBEAT_cmd 2 "DRIVER_HEARTBEAT_cmd_REBOOT" 1 "DRIVER_HEARTBEAT_cmd_SYNC" 0 "DRIVER_HEARTBEAT_cmd_NOOP" ;<br />
<br />
<br />
</pre><br />
<HR><br />
<BR/><br />
<br />
== Sensor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
== Motor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Geographical Controller ==<br />
The geographical (geo) controller is used to provide the vehicle with a sense of location. To do this, the controller is interfaced to a compass which provides a heading, and a GPS module which provides a latitude and longitude. The controller reads a destination off the CAN bus and calculates the distance from its current position. Additionally, it calculates a bearing, which is the degrees from north that the car must point to be facing the destination. If the car aligns its heading with the bearing and drives in a straight line for the number of meters described by the distance calculation, then the car will arrive at its destination.<br />
<br />
However, the vehicle will not be driving in a straight line because of obstacle avoidance. To deal with this, the distance and bearing are updated regularly at a rate of 10Hz. When an obstacle forces the vehicle to deviate from the desired course, it will recalculate the bearing and distance from its new location. This distance and location is then broadcast on the CAN bus, and digested by the driver controller.<br />
<br />
=== Hardware Design ===<br />
<br />
[[File:adafruit_gps.jpg]]<br />
<br />
An Adafruit Ultimate GPS breakout module using the MTK3339 chipset is interfaced over UART to the Geographical controller to provide latitude and longitude updates.<br />
<br />
<br />
[[File:wt901_compass.jpg]]<br />
<br />
A Witmotion WT901 IMU is connected over I2C to provide access to the vehicles heading.<br />
<br />
=== Software Design ===<br />
The general software flow is shown in the diagram below. This loop is run in a 10Hz periodic callback set up in FreeRTOS.<br />
<br />
[[File:geo_flow.jpg]]<br />
<br />
==== Initialization ====<br />
<br />
On startup the GPS module is configured. The GPS module sends data at 9600 bps after powering on but must be set to 115200 bps to support 10Hz updates. The controller must send a command to increase the GPS module's baud rate then change the baud rate on its own UART interface. Initially, the GPS sends out several different NMEA strings on every update. The vehicle only needs latitude , longitude and GPS fix data so the GPS is configured to only send GPGGA strings. This prevents the geo controller from wasting time to intake data that it is uninterested in. Finally, the GPS module is configured to send updated data at a rate of 10Hz. After this process is complete, the controller enters its main loop.<br />
<br />
==== Main Loop ====<br />
<br />
==== Geo process ====<br />
<br />
The desired and current position are used to calculate a distance and bearing using the haversine formula shown below.<br />
<br />
[[File:haversine.PNG]]<br />
<br />
[https://www.movable-type.co.uk/scripts/latlong.html Moveable Type Scripts: Calculate distance, bearing and more between Latitude/Longitude points]<br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
<HR><br />
<BR/><br />
<br />
== Communication Bridge Controller & LCD ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Master Module ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Mobile Application ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<br />
<BR/><br />
<HR><br />
<HR><br />
<BR/><br />
== Conclusion ==<br />
<Organized summary of the project><br />
<br />
<What did you learn?><br />
<br />
=== Project Video ===<br />
<br />
=== Project Source Code ===<br />
<br />
=== Advise for Future Students ===<br />
<Bullet points and discussion><br />
<br />
=== Acknowledgement ===<br />
<br />
=== References ===</div>Proj user2http://socialledge.com/sjsu/index.php?title=File:Bunch_of_handsome_young_men.jpeg&diff=68700File:Bunch of handsome young men.jpeg2022-05-28T03:43:22Z<p>Proj user2: Group photo for the group testla</p>
<hr />
<div>Group photo for the group testla</div>Proj user2http://socialledge.com/sjsu/index.php?title=S22:_Testla&diff=67482S22: Testla2022-04-26T03:56:00Z<p>Proj user2: </p>
<hr />
<div>== Testla ==<br />
<Group Pic><br />
<br />
<HR><br />
<BR/><br />
<br />
== Abstract ==<br />
The Testla project is the culmination of our efforts to create an autonomously operated RC Car by pooling together our experience in software design, hardware design, power systems, and mobile application development. Project development started in February of 2022 and ended in May. (NOTE: One more sentence probably)<br />
<br />
=== Introduction ===<br />
<br />
The project was divided into 5 modules:<br />
<br />
* Bridge and Sensor Information<br />
* Motor Operation<br />
* Geological Information<br />
* Driver and LCD Manager<br />
* Android Application<br />
<br />
=== Team Members & Responsibilities ===<br />
<br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle Gitlab Project Link]<br />
<BR/><br />
<br />
[[File:DevinAlexander.jpeg|200px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Project Lead Meeting Organizer<br />
** Driver Controller<br />
** Geographical Controller<br />
<br />
<br />
<br />
* Scott LoCascio '''''[https://gitlab.com/scottlocascio Gitlab]'''''<br />
** Geographical Controller<br />
** Car Construction<br />
** Testing?<br />
<br />
<br />
* Thinh Lu '''''[https://gitlab.com/lphucthinh40 Gitlab]'''''<br />
** Android Application<br />
** Sensor and Bridge Controller<br />
<br />
<br />
* Bang Nguyen --couldn't find your gitlab <BR/><br />
** Sensor and Bridge Controller<br />
** LCD Display<br />
<br />
<br />
<br />
* Michael Hatzikokolakis '''''[https://gitlab.com/mikehatzi8 Gitlab]'''''<br />
** Motor Controller<br />
** Android Application<br />
<br />
<br />
* Sinan Bayati '''''[https://gitlab.com/sinan.bayati Gitlab]'''''<br />
** PCB Design<br />
** Motor Controller<br />
<br />
<BR/><br />
<br />
== Schedule ==<br />
<br />
<br />
{| class="wikitable" <br />
|-<br />
! Week #<br />
! Start Date<br />
! End Date<br />
! Task<br />
! Status<br />
|-<br />
| 1<br />
| 2/15/2022<br />
| 2/21/2022<br />
| Read previous projects, gather information and discuss among the group members.<br />
| Complete<br />
|-<br />
| 2<br />
| 2/22/2022<br />
| 2/28/2022<br />
| style="background-color:#F9F9F9;" | Distribute modules to each team member.<br />
| Complete<br />
|-<br />
| 3<br />
| 3/1/2022<br />
| 3/7/2022<br />
| Purchase the RC Car<br />Purchase sensors<br />
| Complete<br />
|-<br />
| 4<br />
| 3/8/2022<br />
| 3/14/2022<br />
| style="background-color:#F9F9F9;" | Learning to use CAN BUSMASTER<br />
| Complete<br />
|-<br />
| 5<br />
| 3/15/2022<br />
| 3/21/2022<br />
| style="background-color:#F9F9F9;" | DBC file discussed and implemented<br />
| Complete<br />
|-<br />
| 6<br />
| 3/22/2022<br />
| 3/28/2022<br />
| style="background-color:#F9F9F9;" | Discuss modules needed for PCB, any feature requests<br />
| Complete<br />
|-<br />
| 7<br />
| 3/29/2022<br />
| 4/4/2022<br />
| Finalize preparations and research<br />
| Complete<br />
|-<br />
| 8<br />
| 4/5/2022<br />
| 4/11/2022<br />
| Interface with RC car and hack steering and motor<br />Integrate the GEO sensor with the GEO controller<br />Complete the Driver sensor using analog readings<br />Write a basic implementation of the sensor controller<br />Interface ESP8266 for bridge controller<br />Begin testing with single vs dual power supplies<br />
| Complete<br />
|-<br />
| 9<br />
| 4/12/2022<br />
| 4/18/2022<br />
| Install wheel encoder, implement, implement PID into velocity processing, and establish collaboration between the Motor and Sensor Controllers<br />Test alternate sonar sensor (I2C)<br />Configure GPS to run at 10Hz, 115200 baud and only parse $GPGGA strings on startup<br />Integrate compass<br />Setup NodeJS server to communicate with the Bridge controller via TCP/IP<br />Start Mobile Application development.<br />Finalize power supply choice<br />Finish PCB designs for each subsystem<br />
| In Progress<br />
|-<br />
| 10<br />
| 4/19/2022<br />
| 4/25/2022<br />
| Finish 1st vehicle prototype - include PCBs if possible<br />Complete basic mobile application<br />Write various motor test routines to define in mobile application<br />Verify timing and correctness of GEO controller messages. Produce debug messages for Geo controller<br />Generate debug messages for all controllers.<br />Finalize sensor choice and complete integration of all three sensors.<br />
| Incomplete<br />
|-<br />
| 11<br />
| 4/26/2022<br />
| 5/2/2022<br />
| Identify first PCB design inefficiencies/failures and submit the second and final draft for production<br />Thoroughly test the motor's performance on sloped terrain and refine PID controller<br />Test message timing and propagation with Bus Master<br />Improve existing navigation algorithm with state estimation and localization<br />Integration testing Driver controller with Mobile App<br />
| Incomplete<br />
|-<br />
| 12<br />
| 5/3/2022<br />
| 5/9/2022<br />
| Finished mobile application<br />More testing, update schedule as needed<br />
| Incomplete<br />
|-<br />
| 13<br />
| 5/10/2022<br />
| 5/16/2022<br />
| Final prototype complete<br />
| Incomplete<br />
|-<br />
| 14<br />
| 5/17/2022<br />
| 5/25/2022<br />
| Last tests<br />
| Incomplete<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Parts List & Cost ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item#<br />
! scope="col"| Part Desciption<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| Unassembled RC Car <br />
| Traxxas [https://traxxas.com/products/models/electric/stampede-4x4-assembly-kit]<br />
| 1<br />
| $279.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Printed Circuit Board ==<br />
<Picture and information, including links to your PCB><br />
<br><br />
<br />
<HR><br />
<BR/><br />
== CAN Communication ==<br />
<Talk about your message IDs or communication strategy, such as periodic transmission, MIA management etc.><br />
<br />
=== Hardware Design ===<br />
<Show your CAN bus hardware design><br />
<br />
=== DBC File ===<br />
<Gitlab link to your DBC file><br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/blob/master/dbc/testla_proto1.dbc DBC Link]<br />
<br />
<pre><br />
VERSION ""<br />
<br />
NS_ :<br />
BA_<br />
BA_DEF_<br />
BA_DEF_DEF_<br />
BA_DEF_DEF_REL_<br />
BA_DEF_REL_<br />
BA_DEF_SGTYPE_<br />
BA_REL_<br />
BA_SGTYPE_<br />
BO_TX_BU_<br />
BU_BO_REL_<br />
BU_EV_REL_<br />
BU_SG_REL_<br />
CAT_<br />
CAT_DEF_<br />
CM_<br />
ENVVAR_DATA_<br />
EV_DATA_<br />
FILTER<br />
NS_DESC_<br />
SGTYPE_<br />
SGTYPE_VAL_<br />
SG_MUL_VAL_<br />
SIGTYPE_VALTYPE_<br />
SIG_GROUP_<br />
SIG_TYPE_REF_<br />
SIG_VALTYPE_<br />
VAL_<br />
VAL_TABLE_<br />
<br />
BS_:<br />
<br />
BU_: DBG DRIVER MOTOR SENSOR<br />
<br />
<br />
BO_ 100 DRIVER_HEARTBEAT: 3 DRIVER<br />
SG_ DRIVER_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" DBG<br />
<br />
BO_ 110 DRIVER_STEERING: 3 DRIVER<br />
SG_ DRIVER_STEERING_yaw : 0|12@1+ (0.001,-2) [-2|2] "radians" MOTOR<br />
SG_ DRIVER_STEERING_velocity : 12|12@1+ (0.01,0) [0|40] "kph" MOTOR<br />
<br />
BO_ 120 MOTOR_HEARTBEAT: 2 MOTOR<br />
SG_ MOTOR_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" DBG<br />
SG_ MOTOR_HEARTBEAT_encoder : 8|8@1+ (1,0) [0|0] "" DBG<br />
<br />
BO_ 130 MOTOR_ACK: 1 MOTOR<br />
SG_ MOTOR_ACK_cmd : 0|8@1+ (1,0) [0|0] "" DRIVER<br />
<br />
BO_ 200 SENSOR_SONARS: 8 SENSOR<br />
SG_ SENSOR_SONARS_left : 0|10@1+ (1,0) [0|800] "inch" DRIVER<br />
SG_ SENSOR_SONARS_right : 10|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_middle : 20|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_back : 30|10@1+ (1,0) [0|0] "inch" DRIVER<br />
SG_ SENSOR_SONARS_frame_id : 42|16@1+ (1,0) [0|0] "" DRIVER<br />
<br />
BO_ 210 GPS_DESTINATION_LOCATION: 8 SENSOR<br />
SG_ GPS_DEST_LATITUDE : 0|28@1+ (0.000001,-90.000000) [-90|90] "Degrees" GEO<br />
SG_ GPS_DEST_LONGITUDE : 28|28@1+ (0.000001,-180.000000) [-180|180] "Degrees" GEO<br />
<br />
BO_ 220 GEO_STATUS: 8 GEO<br />
SG_ GEO_STATUS_COMPASS_HEADING : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_COMPASS_BEARING : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER<br />
SG_ GEO_STATUS_DISTANCE_TO_DESTINATION : 24|16@1+ (0.1,0) [0|0] "Meters" DRIVER<br />
<br />
CM_ BU_ DRIVER "The driver controller driving the car";<br />
CM_ BU_ MOTOR "The motor controller of the car";<br />
CM_ BU_ SENSOR "The sensor controller of the car";<br />
CM_ BO_ 100 "Sync message used to synchronize the controllers";<br />
CM_ SG_ 100 DRIVER_HEARTBEAT_cmd "Heartbeat command from the driver";<br />
<br />
BA_DEF_ "BusType" STRING ;<br />
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 0;<br />
BA_DEF_ SG_ "FieldType" STRING ;<br />
<br />
BA_DEF_DEF_ "BusType" "CAN";<br />
BA_DEF_DEF_ "FieldType" "";<br />
BA_DEF_DEF_ "GenMsgCycleTime" 0;<br />
<br />
BA_ "GenMsgCycleTime" BO_ 100 1000;<br />
BA_ "GenMsgCycleTime" BO_ 200 50;<br />
BA_ "FieldType" SG_ 100 DRIVER_HEARTBEAT_cmd "DRIVER_HEARTBEAT_cmd";<br />
<br />
VAL_ 100 DRIVER_HEARTBEAT_cmd 2 "DRIVER_HEARTBEAT_cmd_REBOOT" 1 "DRIVER_HEARTBEAT_cmd_SYNC" 0 "DRIVER_HEARTBEAT_cmd_NOOP" ;<br />
</pre><br />
<HR><br />
<BR/><br />
<br />
== Sensor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
== Motor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Geographical Controller ==<br />
The Geographical controller is responsible for determining the position of the vehicle as well as the distance and bearing to desired destination.<br />
<br />
[[File:adafruit_gps.jpg]]<br />
<br />
=== Hardware Design ===<br />
<br />
An Adafruit Ultimate GPS breakout module using the MTK3339 chipset is interfaced over UART to the Geographical controller to provide latitude and longitude updates.<br />
<br />
TODO: interface and explain compass<br />
<br />
=== Software Design ===<br />
<br />
On startup the GPS module is initialized to provide updates at 10Hz with a 115200 baud rate. Additionally, the Bridge and Sensor controller sends a desired latitude and longitude to the Geo controller over the CAN bus. <br />
<br />
The desired and current position are used to calculate a distance and bearing using the haversine formula shown below.<br />
<br />
[[File:haversine.PNG]]<br />
<br />
[https://www.movable-type.co.uk/scripts/latlong.html Moveable Type Scripts: Calculate distance, bearing and more between Latitude/Longitude points]<br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
<HR><br />
<BR/><br />
<br />
== Communication Bridge Controller & LCD ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Master Module ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Mobile Application ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<br />
<BR/><br />
<HR><br />
<HR><br />
<BR/><br />
== Conclusion ==<br />
<Organized summary of the project><br />
<br />
<What did you learn?><br />
<br />
=== Project Video ===<br />
<br />
=== Project Source Code ===<br />
<br />
=== Advise for Future Students ===<br />
<Bullet points and discussion><br />
<br />
=== Acknowledgement ===<br />
<br />
=== References ===</div>Proj user2http://socialledge.com/sjsu/index.php?title=S22:_Testla&diff=67319S22: Testla2022-04-06T01:12:25Z<p>Proj user2: /* Schedule */</p>
<hr />
<div>== Project Title ==<br />
<Team Name><br />
<br />
<HR><br />
<BR/><br />
== Abstract ==<br />
<2-3 sentence abstract><br />
<br />
=== Introduction ===<br />
<br />
The project was divided into N modules:<br />
<br />
* Sensor ...<br />
* Motor..<br />
* ...<br />
* Android<br />
<br />
=== Team Members & Responsibilities ===<br />
<Team Picture><br />
<br />
Gitlab Project Link - [https://gitlab.com/...]<br />
<BR/><br />
<br />
<Provide ECU names and members responsible><br />
<One member may participate in more than one ECU><br />
<br />
* Sensor<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Motor<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Geographical<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Communication Bridge Controller & LCD<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Android Application<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Testing Team<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
<HR><br />
<BR/><br />
== Schedule ==<br />
<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| 02/15/2022<br />
| 02/21/2022<br />
|<br />
* Read previous projects, gather information and discuss among the group members.<br />
<br />
| style="background-color:#0F0;" | Completed<br />
|-<br />
! scope="row"| 2<br />
| 02/22/2022<br />
| 02/28/2022<br />
|<br />
* Distribute modules to each team member.<br />
<br />
| style="background-color:#0F0;" | Completed<br />
|-<br />
! scope="row"| 3<br />
| 03/01/2022<br />
| 03/07/2022<br />
|<br />
* Purchased the RC Car<br />
* Purchase sensors<br />
<br />
| style="background-color:#0F0;" | Completed<br />
|-<br />
! scope="row"| 4<br />
| 03/08/2022<br />
| 03/14/2022<br />
|<br />
* Learning to use CAN BUSMASTER<br />
| style="background-color:#0F0;" | Completed<br />
|-<br />
<br />
! scope="row"| 5<br />
| 03/15/2022<br />
| 03/21/2022<br />
|<br />
* DBC file discussed and implemented<br />
<br />
| style="background-color:#0F0;" | Completed<br />
|-<br />
<br />
! scope="row"| 6<br />
| 03/22/2022<br />
| 03/28/2022<br />
|<br />
* Discuss modules needed for PCB, any feature requests<br />
<br />
| style="background-color:#FFFF00;" | Incomplete<br />
|-<br />
<br />
! scope="row"| 7<br />
| 03/29/2022<br />
| 04/04/2022<br />
|<br />
* tbd<br />
<br />
| style="background-color:#FFFF00;" | Incomplete<br />
|-<br />
<br />
! scope="row"| 8<br />
| 04/05/2022<br />
| 04/11/2022<br />
|<br />
* tbd<br />
<br />
| style="background-color:#FFFF00;" | Incomplete<br />
|-<br />
<br />
! scope="row"| 9<br />
| 04/12/2022<br />
| 04/18/2022<br />
|<br />
* tbd<br />
<br />
| style="background-color:#FFFF00;" | Incomplete<br />
|-<br />
<br />
! scope="row"| 10<br />
| 04/19/2022<br />
| 04/25/2022<br />
|<br />
* tbd<br />
<br />
| style="background-color:#FFFF00;" | Incomplete<br />
|-<br />
<br />
! scope="row"| 11<br />
| 04/26/2022<br />
| 05/02/2022<br />
|<br />
* tbd<br />
<br />
| style="background-color:#FFFF00;" | Incomplete<br />
|-<br />
<br />
! scope="row"| 12<br />
| 05/03/2022<br />
| 05/09/2022<br />
|<br />
* tbd<br />
<br />
| style="background-color:#FFFF00;" | Incomplete<br />
|-<br />
<br />
! scope="row"| 13<br />
| 05/10/2022<br />
| 05/16/2022<br />
|<br />
* tbd<br />
<br />
| style="background-color:#FFFF00;" | Incomplete<br />
|-<br />
<br />
! scope="row"| 14<br />
| 05/17/2022<br />
| 05/25/2022<br />
|<br />
* Final working car<br />
<br />
| style="background-color:#FFFF00;" | Incomplete<br />
|-<br />
<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Parts List & Cost ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item#<br />
! scope="col"| Part Desciption<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| Unassembled RC Car <br />
| Traxxas [https://traxxas.com/products/models/electric/stampede-4x4-assembly-kit]<br />
| 1<br />
| $279.99<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers <br />
| Amazon [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_5?crid=24X3TRR0N6FAY&keywords=can+transceiver&qid=1647820367&sprefix=can+trasn%2Caps%2C344&sr=8-5]<br />
| 1<br />
| $8.99<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Printed Circuit Board ==<br />
<Picture and information, including links to your PCB><br />
<br><br />
<br />
<HR><br />
<BR/><br />
== CAN Communication ==<br />
<Talk about your message IDs or communication strategy, such as periodic transmission, MIA management etc.><br />
<br />
=== Hardware Design ===<br />
<Show your CAN bus hardware design><br />
<br />
=== DBC File ===<br />
<Gitlab link to your DBC file><br />
[https://gitlab.com/testla_sjsu/autonomous_vehicle/-/blob/master/dbc/projectLAB.dbc]<br />
<You can optionally use an inline image><br />
<br />
<br />
<HR><br />
<br />
<BR/><br />
<br />
== Sensor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
== Motor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Geographical Controller ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
<HR><br />
<BR/><br />
== Communication Bridge Controller & LCD ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Master Module ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Mobile Application ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<br />
<BR/><br />
<HR><br />
<HR><br />
<BR/><br />
== Conclusion ==<br />
<Organized summary of the project><br />
<br />
<What did you learn?><br />
<br />
=== Project Video ===<br />
<br />
=== Project Source Code ===<br />
<br />
=== Advise for Future Students ===<br />
<Bullet points and discussion><br />
<br />
=== Acknowledgement ===<br />
<br />
=== References ===</div>Proj user2http://socialledge.com/sjsu/index.php?title=S22:_Testla&diff=67136S22: Testla2022-03-18T02:29:56Z<p>Proj user2: /* Schedule */</p>
<hr />
<div>== Project Title ==<br />
<Team Name><br />
<br />
<HR><br />
<BR/><br />
== Abstract ==<br />
<2-3 sentence abstract><br />
<br />
=== Introduction ===<br />
<br />
The project was divided into N modules:<br />
<br />
* Sensor ...<br />
* Motor..<br />
* ...<br />
* Android<br />
<br />
=== Team Members & Responsibilities ===<br />
<Team Picture><br />
<br />
Gitlab Project Link - [https://gitlab.com/...]<br />
<BR/><br />
<br />
<Provide ECU names and members responsible><br />
<One member may participate in more than one ECU><br />
<br />
* Sensor<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Motor<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Geographical<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Communication Bridge Controller & LCD<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Android Application<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Testing Team<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
<HR><br />
<BR/><br />
== Schedule ==<br />
<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| 09/15/2017<br />
| 09/16/2017<br />
|<br />
* Read previous projects, gather information and discuss among the group members.<br />
* Distribute modules to each team member.<br />
* Purchased the RC Car<br />
* Pur<br />
<br />
| Completed<br />
|-<br />
! scope="row"| 2<br />
| 09/17/2017<br />
| 10/03/2017<br />
|<br />
|<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
|+ Legend<br />
|-<br />
! Description !! Color<br />
|-<br />
| Administrative || Black<br />
|-<br />
| Sensor || <span style="color:cyan">Cyan</span><br />
|-<br />
| Bluetooth & App || <span style="color:blue">Blue</span><br />
|-<br />
| GEO || <span style="color:red">Red</span><br />
|-<br />
| Motor || <span style="color:magenta">Magenta</span><br />
|-<br />
| Main || <span style="color:orange">Orange</span><br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date <br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
<div style="text-align:center">02/15/2021</div><br />
|<br />
<div style="text-align:center">02/21/2021</div><br />
|<br />
* Read previous projects to understand what is expected and have some meaningful knowledge by first meeting. Assign roles.<br />
| <br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
<div style="text-align:center">02/22/2021</div><br />
| <br />
<div style="text-align:center">02/28/2021</div><br />
|<br />
*Acquire parts: Canbus modules, GPS module, Ultrasonic module, Bluetooth module, Car frame, and LCD display<br />
*Conduct meeting: Discuss GitLab layout and expectation of each assigned role<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
<div style="text-align:center">03/01/2021</div><br />
|<br />
<div style="text-align:center">03/07/2021</div><br />
|<br />
*Purchased RC car and batteries.<br />
*<span style="color:cyan">Research and finalize which ultrasonic sensor the project will use.</span><br />
*<span style="color:blue">Purchased Bluetooth connector</span><br />
*<span style="color:red">Research math needed to determine distance between navigation points. Decide on distance algorithm</span><br />
*<span style="color:red">Research multiple navigation point algorithm(Djikstra's) to determine shortest path.</span><br />
*<span style="color:magenta">Create branch for motor controller driver. Create draft template API for motor controller.</span><br />
*<span style="color:orange">Using previous projects, determine what works needs to be completed for main board. Bring findings to weekly meeting</span><br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
<br />
|-<br />
! scope="row"| 4<br />
|<br />
<div style="text-align:center">03/08/2021</div><br />
|<br />
<div style="text-align:center">03/14/2021</div><br />
|<br />
*<span style="color:blue">Research connection with Bluetooth from board to application. Decide between bluetooth connection or wifi connection by this day</span><br />
*<span style="color:red">Work on implementation of multiple navigation point algorithm to determine shortest path </span><br />
*<span style="color:magenta">Plan motor controller API and create basic software flow of API</span><br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
<div style="text-align:center">03/15/2021</div><br />
|<br />
<div style="text-align:center">03/21/2021</div><br />
|<br />
*<span style="color:black">Begin laying out hardware requirements for PCB on excel document. Include voltage and pinout requirements in excel document</span><br />
*<span style="color:blue">Finish research on application building with android studio. Install android studio and necessary dependencies</span><br />
*<span style="color:blue">Implement a simple application with a button and text</span><br />
*<span style="color:magenta">Start researching on Wheel encoder according to the requirement</span><br />
*<span style="color:red">Unit Test Direction Distance Calculation Module. Manual calculation of data should match module output</span><br />
*<span style="color:red">Begin coding and digesting adafruit Compass data. Print Compass data.</span><br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
<div style="text-align:center">03/22/2021</div><br />
|<br />
<div style="text-align:center">03/28/2021</div><br />
|<br />
*<span style="color:cyan">Acquire sensor and interface sensors to SJ2 Board and receive raw data</span><br />
*<span style="color:blue">Implement basic communication between board and app</span><br />
*<span style="color:red">Update Wiki with proper software diagrams for GPS and Compass data flow</span><br />
*<span style="color:orange">Begin Mapping out pins used on all board</span><br />
*<span style="color:orange">Complete a block diagram and a control scheme</span><br />
<ol><br />
<li style="color:orange">Top Level Driver Logic diagram</li><br />
<li style="color:orange">Periodic Callback Functions Diagram</li><br />
</ol><br />
*<span style="color:orange">Create a basic Obstacle avoidance algorithm for Driver</span><br />
*<span style="color:magenta">Probe RC car to determine expected behavior of signals and install RPM sensor</span><br />
*<span style="color:magenta">Write motor controller modules and tests</span><br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
<div style="text-align:center">03/29/2021</div><br />
|<br />
<div style="text-align:center">04/04/2021</div><br />
|<br />
*<span style="color:black">Discuss and construct DBC file</span><br />
*<span style="color:cyan">Create sensor API to parse raw data and convert into inches</span><br />
*<span style="color:blue">Integrate google map features into app</span><br />
*<span style="color:magenta">Integration testing of motor controller logic</span><br />
*<span style="color:orange">Create a Checkpoint Navigation algorithm for Driver</span><br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
<div style="text-align:center">04/05/2021</div><br />
|<br />
<div style="text-align:center">04/11/2021</div><br />
|<br />
*<span style="color:black">Finish implementation of canbus between controllers and begin real world testing</span><br />
*<span style="color:cyan">3D print sensor mounts, sensor guards, and draft sensor offset timing to deter sensor cross talk</span><br />
*<span style="color:magenta">Finish integrating wheel encoder and display speed on SJTwo Telemetry</span><br />
*<span style="color:orange">Establish Communication between the LCD display and Master Board over I2C</span><br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
<div style="text-align:center">04/12/2021</div><br />
|<br />
<div style="text-align:center">04/18/2021</div><br />
|<br />
*<span style="color:black">Integrate Driver, Geo, Bridge sensor, and Motor nodes. Successful communication between all boards.</span><br />
*<span style="color:blue">Implement Kill button on app for emergency stop</span><br />
*<span style="color:cyan">Analyze noise in sensor values and design a filter to mitigate the noise</span><br />
*<span style="color:magenta">Complete "Self Test" for motor test(DC motor moves forward and backwards and servo moves right - left)</span><br />
*<span style="color:magenta">Start working on PID control algorithm. Design bare skeleton for workflow</span><br />
*<span style="color:orange">Create an algorithm to account for speed when the car is on an incline</span><br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
<br />
|-<br />
! scope="row"| 10<br />
| <br />
<div style="text-align:center">04/19/2021</div><br />
|<br />
<div style="text-align:center">05/25/2021</div><br />
|<br />
*<span style="color:black">Begin to analysis real world tests from previous weeks implementation and perform fixes for issues faced</span><br />
*<span style="color:black">Ensure Canbus nodes are communicating correctly by verifying PCON data. Verify that timing for data is correct</span><br />
*<span style="color:black">Added CAN debug messages</span><br />
*<span style="color:black">Start working on the PCB, order the PCB and also purchase the required components </span><br />
*<span style="color:cyan">Integration testing with obstacle avoidance.</span><br />
<ol><br />
<li style="color:cyan">Analyze possible blind spots and make adjustments to sensor placements. </li><br />
<li style="color:cyan">Analyze sensor response time and data while rc car is moving and make adjustments if needed.</li><br />
</ol><br />
*<span style="color:orange">Display relevant Motor and Checkpoint Information to the LCD.</span><br />
*<span style="color:magenta">Tuned and tested PID on RC Car (More refinement needed)</span><br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
*<span style="color:green">Completed</span><br />
*<span style="color:green">Completed</span><br />
*<span style="color:green">Completed</span><br />
*<span style="color:green">Completed</span><br />
*<span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
*<span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 11<br />
| <br />
<div style="text-align:center">04/26/2021</div><br />
|<br />
<div style="text-align:center">05/02/2021</div><br />
|<br />
*<span style="color:black">Perform more real world tests and isolate bugs. Update issues for bugs find during real world test</span><br />
*<span style="color:black">Perform final bug fixes, as listed under issues, for all Canbus nodes. </span><br />
*<span style="color:black">Integrate all the parts on the PCB. </span><br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:Green">Completed</span><br />
|-<br />
! scope="row"| 12<br />
| <br />
<div style="text-align:center">05/03/2021</div><br />
|<br />
<div style="text-align:center">05/09/2021</div><br />
|<br />
*<span style="color:black">Update Wiki Report to reflect all changes and include final testing video</span><br />
*<span style="color:black">Perform final code changes and commit to master branch</span><br />
*<span style="color:black">Received manufactured PCB, installed, and integration tested</span><br />
*<span style="color:magenta">Refactored motor controller code and wrote much needed unit tests</span><br />
*<span style="color:magenta">Finished tuning PID and tested RC Car driving on slope</span><br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 13<br />
| <br />
<div style="text-align:center">05/10/2021</div><br />
|<br />
<div style="text-align:center">05/16/2021</div><br />
|<br />
*<span style="color:black">Update Wiki schedule and begin draft for individual controller documentation</span><br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 14<br />
| <br />
<div style="text-align:center">05/17/2021</div><br />
|<br />
<div style="text-align:center">05/23/2021</div><br />
|<br />
*<span style="color:black">Update Wiki individual controller and general documentation</span><br />
*<span style="color:orange">Last minute bug fixes/refining</span><br />
*<span style="color:orange">Waypoint algorithm integration and test</span><br />
*<span style="color:magenta">Last minute bug fixes/refining & code cleanup</span><br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 15<br />
| <br />
<div style="text-align:center">05/24/2021</div><br />
|<br />
<div style="text-align:center">05/30/2021</div><br />
|<br />
*<span style="color:black">Demo Project</span><br />
*<span style="color:black">Finalize Wiki Documentation</span><br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Parts List & Cost ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item#<br />
! scope="col"| Part Desciption<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| RC Car <br />
| Traxxas<br />
| 1<br />
| $250.00<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers MCP2551-I/P<br />
| Microchip [http://www.microchip.com/wwwproducts/en/en010405]<br />
| 8<br />
| Free Samples<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
== Printed Circuit Board ==<br />
<Picture and information, including links to your PCB><br />
<br><br />
<br />
<HR><br />
<BR/><br />
== CAN Communication ==<br />
<Talk about your message IDs or communication strategy, such as periodic transmission, MIA management etc.><br />
<br />
=== Hardware Design ===<br />
<Show your CAN bus hardware design><br />
<br />
=== DBC File ===<br />
<Gitlab link to your DBC file><br />
<You can optionally use an inline image><br />
<br />
<br />
<HR><br />
<BR/><br />
== Sensor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
== Motor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Geographical Controller ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
<HR><br />
<BR/><br />
== Communication Bridge Controller & LCD ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Master Module ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Mobile Application ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<br />
<BR/><br />
<HR><br />
<HR><br />
<BR/><br />
== Conclusion ==<br />
<Organized summary of the project><br />
<br />
<What did you learn?><br />
<br />
=== Project Video ===<br />
<br />
=== Project Source Code ===<br />
<br />
=== Advise for Future Students ===<br />
<Bullet points and discussion><br />
<br />
=== Acknowledgement ===<br />
<br />
=== References ===</div>Proj user2http://socialledge.com/sjsu/index.php?title=S22:_Testla&diff=67135S22: Testla2022-03-18T02:15:02Z<p>Proj user2: /* Sensor ECU */</p>
<hr />
<div>== Project Title ==<br />
<Team Name><br />
<br />
<HR><br />
<BR/><br />
== Abstract ==<br />
<2-3 sentence abstract><br />
<br />
=== Introduction ===<br />
<br />
The project was divided into N modules:<br />
<br />
* Sensor ...<br />
* Motor..<br />
* ...<br />
* Android<br />
<br />
=== Team Members & Responsibilities ===<br />
<Team Picture><br />
<br />
Gitlab Project Link - [https://gitlab.com/...]<br />
<BR/><br />
<br />
<Provide ECU names and members responsible><br />
<One member may participate in more than one ECU><br />
<br />
* Sensor<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Motor<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Geographical<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Communication Bridge Controller & LCD<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Android Application<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Testing Team<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
<HR><br />
<BR/><br />
== Schedule ==<br />
<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| 09/15/2017<br />
| 09/16/2017<br />
|<br />
* Read previous projects, gather information and discuss among the group members.<br />
* Distribute modules to each team member.<br />
<br />
| Completed<br />
|-<br />
! scope="row"| 2<br />
| 09/17/2017<br />
| 10/03/2017<br />
|<br />
|<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
== Parts List & Cost ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item#<br />
! scope="col"| Part Desciption<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| RC Car <br />
| Traxxas<br />
| 1<br />
| $250.00<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers MCP2551-I/P<br />
| Microchip [http://www.microchip.com/wwwproducts/en/en010405]<br />
| 8<br />
| Free Samples<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
== Printed Circuit Board ==<br />
<Picture and information, including links to your PCB><br />
<br><br />
<br />
<HR><br />
<BR/><br />
== CAN Communication ==<br />
<Talk about your message IDs or communication strategy, such as periodic transmission, MIA management etc.><br />
<br />
=== Hardware Design ===<br />
<Show your CAN bus hardware design><br />
<br />
=== DBC File ===<br />
<Gitlab link to your DBC file><br />
<You can optionally use an inline image><br />
<br />
<br />
<HR><br />
<BR/><br />
== Sensor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
== Motor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Geographical Controller ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
<HR><br />
<BR/><br />
== Communication Bridge Controller & LCD ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Master Module ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Mobile Application ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<br />
<BR/><br />
<HR><br />
<HR><br />
<BR/><br />
== Conclusion ==<br />
<Organized summary of the project><br />
<br />
<What did you learn?><br />
<br />
=== Project Video ===<br />
<br />
=== Project Source Code ===<br />
<br />
=== Advise for Future Students ===<br />
<Bullet points and discussion><br />
<br />
=== Acknowledgement ===<br />
<br />
=== References ===</div>Proj user2http://socialledge.com/sjsu/index.php?title=S22:_Testla&diff=67134S22: Testla2022-03-18T02:12:26Z<p>Proj user2: Created page with "== Project Title == <Team Name> <HR> <BR/> == Abstract == <2-3 sentence abstract> === Introduction === The project was divided into N modules: * Sensor ... * Motor.. * ......"</p>
<hr />
<div>== Project Title ==<br />
<Team Name><br />
<br />
<HR><br />
<BR/><br />
== Abstract ==<br />
<2-3 sentence abstract><br />
<br />
=== Introduction ===<br />
<br />
The project was divided into N modules:<br />
<br />
* Sensor ...<br />
* Motor..<br />
* ...<br />
* Android<br />
<br />
=== Team Members & Responsibilities ===<br />
<Team Picture><br />
<br />
Gitlab Project Link - [https://gitlab.com/...]<br />
<BR/><br />
<br />
<Provide ECU names and members responsible><br />
<One member may participate in more than one ECU><br />
<br />
* Sensor<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Motor<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Geographical<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Communication Bridge Controller & LCD<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Android Application<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Testing Team<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
<HR><br />
<BR/><br />
== Schedule ==<br />
<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| 09/15/2017<br />
| 09/16/2017<br />
|<br />
* Read previous projects, gather information and discuss among the group members.<br />
* Distribute modules to each team member.<br />
<br />
| Completed<br />
|-<br />
! scope="row"| 2<br />
| 09/17/2017<br />
| 10/03/2017<br />
|<br />
|<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
== Parts List & Cost ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item#<br />
! scope="col"| Part Desciption<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| RC Car <br />
| Traxxas<br />
| 1<br />
| $250.00<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers MCP2551-I/P<br />
| Microchip [http://www.microchip.com/wwwproducts/en/en010405]<br />
| 8<br />
| Free Samples<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
== Printed Circuit Board ==<br />
<Picture and information, including links to your PCB><br />
<br><br />
<br />
<HR><br />
<BR/><br />
== CAN Communication ==<br />
<Talk about your message IDs or communication strategy, such as periodic transmission, MIA management etc.><br />
<br />
=== Hardware Design ===<br />
<Show your CAN bus hardware design><br />
<br />
=== DBC File ===<br />
<Gitlab link to your DBC file><br />
<You can optionally use an inline image><br />
<br />
<br />
<HR><br />
<BR/><br />
== Sensor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Motor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Geographical Controller ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
<HR><br />
<BR/><br />
== Communication Bridge Controller & LCD ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Master Module ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Mobile Application ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<br />
<BR/><br />
<HR><br />
<HR><br />
<BR/><br />
== Conclusion ==<br />
<Organized summary of the project><br />
<br />
<What did you learn?><br />
<br />
=== Project Video ===<br />
<br />
=== Project Source Code ===<br />
<br />
=== Advise for Future Students ===<br />
<Bullet points and discussion><br />
<br />
=== Acknowledgement ===<br />
<br />
=== References ===</div>Proj user2http://socialledge.com/sjsu/index.php?title=Industrial_Application_using_CAN_Bus&diff=67133Industrial Application using CAN Bus2022-03-18T02:10:37Z<p>Proj user2: /* Class Project Reports */</p>
<hr />
<div>= Class Information =<br />
==Presentation on Autonomous Vehicles==<br />
http://www.slideshare.net/ShantanuVashishtha1/autonomous-vehicles-70049669<br />
<br />
== Useful Topics ==<br />
<br />
=== Git ===<br />
[[Basic Git Tutorial]]<br />
<BR/ ><br />
<br />
=== CAN Bus ===<br />
[[CAN BUS Tutorial | CAN BUS]]<br />
<BR/ ><br />
<br />
=== [[DBC Format]] ===<br />
DBC format is a well known format to describe the format of a CAN message. This is essentially the schema of the data that is communicated over the CAN bus. Please view the linked [[DBC Format]] article for details before reading further.<br />
<br />
=== BusMaster Tutorial ===<br />
[[BusMaster | BusMaster Tutorial]]<br />
<br />
== Class Assignments ==<br />
=== [[Lab Assignments]] ===<br />
<br />
<BR/><br />
== Class Project ==<br />
=== [[Self-driving Car]] ===<br />
In this class project, students accomplish a self-drivable RC car with the following learning objectives:<br />
* Learn CAN Bus and how to communicate in an industrial or automotive environment.<br />
* Learn integration and testing across different controllers.<br />
* Learn how to work in teams.<br />
* Learn basics of an RTOS.<br />
<BR/><br />
<br />
[[Autonomous RC Car Project Report Template]]<br />
<br />
== Class Project Reports ==<br />
<br />
=== [[Spring 2022 | Spring 2022]] ===<br />
* [[S22: Testla]]<br />
* [[S22: TBD]]<br />
<br />
=== [[Spring 2021 | Spring 2021]] ===<br />
* [[S21: UTAH]]<br />
* [[S21: exFAT]]<br />
* [[S21: (RC)^2]]<br />
* [[S21: Roadster]]<br />
<br />
=== [[Spring 2020 | Spring 2020]] ===<br />
* [[S20: Nimble]]<br />
* [[S20: Bucephalus]]<br />
* [[S20: Canster Truck]]<br />
* [[S20: Tesla Model RC]]<br />
<br />
=== [[Spring 2019 | Spring 2019]] ===<br />
* [[S19: CANT Bus | S19: CANT Bus]]<br />
* [[S19: Tech Savy | S19: Tech Savy]]<br />
* [[S19: Mystery Machine | S19: Mystery Machine]]<br />
* [[S19: Run D.B.C | S19: Run D.B.C]]<br />
* [[S19: Hot Wheels | S19: Hot Wheels]]<br />
* [[S19: Zeus | S19: Zeus]]<br />
* [[S19: Automophiles | S19: Automophiles]]<br />
* [[S19: Lightfury | S19: Lightfury]]<br />
<br />
=== [[Fall 2017 | Fall 2017]] ===<br />
* [[F17: Alpha | F17: Alpha]]<br />
* [[F17: FoxP2 | F17 FoxP2]]<br />
* [[F17: Optimus | F17 Optimus]]<br />
* [[F17: Tata Nano | F17 Tata Nano]]<br />
* [[F17: Viserion | F17 Viserion]]<br />
* [[F17: Vindicators100 | F17 Vindicators100]]<br />
* [[F17: Rolling Thunder | F17: Rolling Thunder]]<br />
<br />
=== [[Fall 2016 | Fall 2016]] ===<br />
* [[F16: Spartan and Furious | F16: Spartan and Furious]]<br />
* [[F16: Titans | F16: Titans]]<br />
* [[F16: Kasper | F16: Kasper]]<br />
* [[F16: AutoNav | F16: AutoNav]]<br />
* [[F16: Thunderbolt| F16: Thunderbolt]]<br />
* [[F16: The-Nine| F16: The-Nine]]<br />
<br />
=== [[Fall 2015 | Fall 2015]] ===<br />
* [[F15: Quadcopter by Thomas]]<br />
* [[F15: Undergrads++]]<br />
* [[F15: TopGun]]<br />
* [[F15: Fury]]<br />
* [[F15: Minion]]<br />
* [[F15: ThunderBird]]<br />
<br />
=== [[CmpE243 Fall 2014 | Fall 2014]] ===<br />
<br />
* [[F14: Team2-Self Driving Car - AUG]]<br />
* [[F14: Team3-Self Driving Car - Optimus Prime]]<br />
* [[F14: Team4-Self Driving Car - AUG]]<br />
* [[F14: Team5-Self Driving Car - AUG]]<br />
* [[F14: Self Driving Undergrad Team]]</div>Proj user2http://socialledge.com/sjsu/index.php?title=S22:_TESTLA&diff=67132S22: TESTLA2022-03-18T02:09:13Z<p>Proj user2: Created page with "== Project Title == <Team Name> <HR> <BR/> == Abstract == <2-3 sentence abstract> === Introduction === The project was divided into N modules: * Sensor ... * Motor.. * ......"</p>
<hr />
<div>== Project Title ==<br />
<Team Name><br />
<br />
<HR><br />
<BR/><br />
== Abstract ==<br />
<2-3 sentence abstract><br />
<br />
=== Introduction ===<br />
<br />
The project was divided into N modules:<br />
<br />
* Sensor ...<br />
* Motor..<br />
* ...<br />
* Android<br />
<br />
=== Team Members & Responsibilities ===<br />
<Team Picture><br />
<br />
Gitlab Project Link - [https://gitlab.com/...]<br />
<BR/><br />
<br />
<Provide ECU names and members responsible><br />
<One member may participate in more than one ECU><br />
<br />
* Sensor<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Motor<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Geographical<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Communication Bridge Controller & LCD<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Android Application<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
* Testing Team<br />
** Link to Gitlab user1<br />
** Link to Gitlab user2<br />
<br />
<HR><br />
<BR/><br />
== Schedule ==<br />
<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| 09/15/2017<br />
| 09/16/2017<br />
|<br />
* Read previous projects, gather information and discuss among the group members.<br />
* Distribute modules to each team member.<br />
<br />
| Completed<br />
|-<br />
! scope="row"| 2<br />
| 09/17/2017<br />
| 10/03/2017<br />
|<br />
|<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
== Parts List & Cost ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item#<br />
! scope="col"| Part Desciption<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| RC Car <br />
| Traxxas<br />
| 1<br />
| $250.00<br />
|-<br />
! scope="row"| 2<br />
| CAN Transceivers MCP2551-I/P<br />
| Microchip [http://www.microchip.com/wwwproducts/en/en010405]<br />
| 8<br />
| Free Samples<br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
== Printed Circuit Board ==<br />
<Picture and information, including links to your PCB><br />
<br><br />
<br />
<HR><br />
<BR/><br />
== CAN Communication ==<br />
<Talk about your message IDs or communication strategy, such as periodic transmission, MIA management etc.><br />
<br />
=== Hardware Design ===<br />
<Show your CAN bus hardware design><br />
<br />
=== DBC File ===<br />
<Gitlab link to your DBC file><br />
<You can optionally use an inline image><br />
<br />
<br />
<HR><br />
<BR/><br />
== Sensor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Motor ECU ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Geographical Controller ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
<br />
<HR><br />
<BR/><br />
== Communication Bridge Controller & LCD ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Master Module ==<br />
<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<HR><br />
<BR/><br />
== Mobile Application ==<br />
<Picture and link to Gitlab><br />
<br />
=== Hardware Design ===<br />
<br />
=== Software Design ===<br />
<List the code modules that are being called periodically.><br />
<br />
=== Technical Challenges ===<br />
<br />
< List of problems and their detailed resolutions><br />
<br />
<br />
<BR/><br />
<HR><br />
<HR><br />
<BR/><br />
== Conclusion ==<br />
<Organized summary of the project><br />
<br />
<What did you learn?><br />
<br />
=== Project Video ===<br />
<br />
=== Project Source Code ===<br />
<br />
=== Advise for Future Students ===<br />
<Bullet points and discussion><br />
<br />
=== Acknowledgement ===<br />
<br />
=== References ===</div>Proj user2http://socialledge.com/sjsu/index.php?title=Industrial_Application_using_CAN_Bus&diff=67131Industrial Application using CAN Bus2022-03-18T02:08:33Z<p>Proj user2: /* Spring 2022 */</p>
<hr />
<div>= Class Information =<br />
==Presentation on Autonomous Vehicles==<br />
http://www.slideshare.net/ShantanuVashishtha1/autonomous-vehicles-70049669<br />
<br />
== Useful Topics ==<br />
<br />
=== Git ===<br />
[[Basic Git Tutorial]]<br />
<BR/ ><br />
<br />
=== CAN Bus ===<br />
[[CAN BUS Tutorial | CAN BUS]]<br />
<BR/ ><br />
<br />
=== [[DBC Format]] ===<br />
DBC format is a well known format to describe the format of a CAN message. This is essentially the schema of the data that is communicated over the CAN bus. Please view the linked [[DBC Format]] article for details before reading further.<br />
<br />
=== BusMaster Tutorial ===<br />
[[BusMaster | BusMaster Tutorial]]<br />
<br />
== Class Assignments ==<br />
=== [[Lab Assignments]] ===<br />
<br />
<BR/><br />
== Class Project ==<br />
=== [[Self-driving Car]] ===<br />
In this class project, students accomplish a self-drivable RC car with the following learning objectives:<br />
* Learn CAN Bus and how to communicate in an industrial or automotive environment.<br />
* Learn integration and testing across different controllers.<br />
* Learn how to work in teams.<br />
* Learn basics of an RTOS.<br />
<BR/><br />
<br />
[[Autonomous RC Car Project Report Template]]<br />
<br />
== Class Project Reports ==<br />
<br />
=== [[Spring 2022 | Spring 2022]] ===<br />
* [[S22: TESTLA]]<br />
* [[S22: TBD]]<br />
<br />
=== [[Spring 2021 | Spring 2021]] ===<br />
* [[S21: UTAH]]<br />
* [[S21: exFAT]]<br />
* [[S21: (RC)^2]]<br />
* [[S21: Roadster]]<br />
<br />
=== [[Spring 2020 | Spring 2020]] ===<br />
* [[S20: Nimble]]<br />
* [[S20: Bucephalus]]<br />
* [[S20: Canster Truck]]<br />
* [[S20: Tesla Model RC]]<br />
<br />
=== [[Spring 2019 | Spring 2019]] ===<br />
* [[S19: CANT Bus | S19: CANT Bus]]<br />
* [[S19: Tech Savy | S19: Tech Savy]]<br />
* [[S19: Mystery Machine | S19: Mystery Machine]]<br />
* [[S19: Run D.B.C | S19: Run D.B.C]]<br />
* [[S19: Hot Wheels | S19: Hot Wheels]]<br />
* [[S19: Zeus | S19: Zeus]]<br />
* [[S19: Automophiles | S19: Automophiles]]<br />
* [[S19: Lightfury | S19: Lightfury]]<br />
<br />
=== [[Fall 2017 | Fall 2017]] ===<br />
* [[F17: Alpha | F17: Alpha]]<br />
* [[F17: FoxP2 | F17 FoxP2]]<br />
* [[F17: Optimus | F17 Optimus]]<br />
* [[F17: Tata Nano | F17 Tata Nano]]<br />
* [[F17: Viserion | F17 Viserion]]<br />
* [[F17: Vindicators100 | F17 Vindicators100]]<br />
* [[F17: Rolling Thunder | F17: Rolling Thunder]]<br />
<br />
=== [[Fall 2016 | Fall 2016]] ===<br />
* [[F16: Spartan and Furious | F16: Spartan and Furious]]<br />
* [[F16: Titans | F16: Titans]]<br />
* [[F16: Kasper | F16: Kasper]]<br />
* [[F16: AutoNav | F16: AutoNav]]<br />
* [[F16: Thunderbolt| F16: Thunderbolt]]<br />
* [[F16: The-Nine| F16: The-Nine]]<br />
<br />
=== [[Fall 2015 | Fall 2015]] ===<br />
* [[F15: Quadcopter by Thomas]]<br />
* [[F15: Undergrads++]]<br />
* [[F15: TopGun]]<br />
* [[F15: Fury]]<br />
* [[F15: Minion]]<br />
* [[F15: ThunderBird]]<br />
<br />
=== [[CmpE243 Fall 2014 | Fall 2014]] ===<br />
<br />
* [[F14: Team2-Self Driving Car - AUG]]<br />
* [[F14: Team3-Self Driving Car - Optimus Prime]]<br />
* [[F14: Team4-Self Driving Car - AUG]]<br />
* [[F14: Team5-Self Driving Car - AUG]]<br />
* [[F14: Self Driving Undergrad Team]]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66814F21: Space Rage2021-12-18T04:57:36Z<p>Proj user2: /* Fast responsive controls */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
{|<br />
|[[File:Lives screen.gif |thumb|800px|'''Player Lives Screen''']]<br />
|[[File:Gameplay_countdown.gif |thumb|800px|'''Gameplay Countdown Sequence''']]<br />
|[[File:Title_screen.gif |thumb|800px|'''Gameover to Title Screen Sequence''']]<br />
|}<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly for up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Throughout the implementation project, we found that we had utilized many concepts that we had learned from this course. The concepts taught in the weeks leading up to the project allowed for us to be prepared to apply them into building Space Rage. The concept of multi-threaded code was newer to some of us, but we feel that it prepares us for our future careers as embedded software engineers. The use of prioritizing various blocks of code over others and how the impacts it has on the scheduling of tasks is an important concept to understand. The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block moving forward in our careers.<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reaching those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66813F21: Space Rage2021-12-18T04:55:47Z<p>Proj user2: /* Conclusion */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
{|<br />
|[[File:Lives screen.gif |thumb|800px|'''Player Lives Screen''']]<br />
|[[File:Gameplay_countdown.gif |thumb|800px|'''Gameplay Countdown Sequence''']]<br />
|[[File:Title_screen.gif |thumb|800px|'''Gameover to Title Screen Sequence''']]<br />
|}<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Throughout the implementation project, we found that we had utilized many concepts that we had learned from this course. The concepts taught in the weeks leading up to the project allowed for us to be prepared to apply them into building Space Rage. The concept of multi-threaded code was newer to some of us, but we feel that it prepares us for our future careers as embedded software engineers. The use of prioritizing various blocks of code over others and how the impacts it has on the scheduling of tasks is an important concept to understand. The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block moving forward in our careers.<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reaching those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66812F21: Space Rage2021-12-18T04:54:05Z<p>Proj user2: /* Conclusion */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
{|<br />
|[[File:Lives screen.gif |thumb|800px|'''Player Lives Screen''']]<br />
|[[File:Gameplay_countdown.gif |thumb|800px|'''Gameplay Countdown Sequence''']]<br />
|[[File:Title_screen.gif |thumb|800px|'''Gameover to Title Screen Sequence''']]<br />
|}<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Throughout the implementation project, we found that we had utilized many concepts that we had learned from this course. The concepts taught in the weeks leading up to the project allowed for us to be prepared to apply them into building Space Rage. The concept of multi-threaded code was newer to some of us, but we feel that it prepares us for our future careers as embedded software engineers. The use of prioritizing various blocks of code over others and how the impacts it has on the scheduling of tasks is an important concept to understand. The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward.<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reaching those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66811F21: Space Rage2021-12-18T04:52:30Z<p>Proj user2: /* Conclusion */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
{|<br />
|[[File:Lives screen.gif |thumb|800px|'''Player Lives Screen''']]<br />
|[[File:Gameplay_countdown.gif |thumb|800px|'''Gameplay Countdown Sequence''']]<br />
|[[File:Title_screen.gif |thumb|800px|'''Gameover to Title Screen Sequence''']]<br />
|}<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Throughout the implementation project, we found that we had utilized many concepts that we had learned from this course. The concepts taught in the weeks leading up to the project allowed for us to be prepared to apply them into building Space Rage. <br />
<br />
The concept of multi-threaded code was newer to some of us, but we feel that it prepares us for our future careers as embedded software engineers. The use of prioritizing various blocks of code over others and how the impacts it has on the scheduling of tasks is an important concept to understand.<br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward.<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reaching those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66804F21: Space Rage2021-12-18T04:45:23Z<p>Proj user2: /* Conclusion */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
{|<br />
|[[File:Lives screen.gif |thumb|800px|'''Player Lives Screen''']]<br />
|[[File:Gameplay_countdown.gif |thumb|800px|'''Gameplay Countdown Sequence''']]<br />
|[[File:Title_screen.gif |thumb|800px|'''Gameover to Title Screen Sequence''']]<br />
|}<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Throughout the implementation project, we found that we had utilized many concepts that we learned from this course. The concepts taught in the weeks leading up to the presentation allowed for us to be prepared to apply them into this project. <br />
<br />
The concept of multi-threaded code was newer to some of us, but we feel that it prepares us for our future careers as embedded software engineers. The use of prioritizing various blocks of code over others and how the impacts it has on the scheduling of tasks is an important concept to understand. <br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward.<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reaching those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66802F21: Space Rage2021-12-18T04:44:17Z<p>Proj user2: /* Acknowledgement */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
{|<br />
|[[File:Lives screen.gif |thumb|800px|'''Player Lives Screen''']]<br />
|[[File:Gameplay_countdown.gif |thumb|800px|'''Gameplay Countdown Sequence''']]<br />
|[[File:Title_screen.gif |thumb|800px|'''Gameover to Title Screen Sequence''']]<br />
|}<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Throughout the implementation project, we found that we had utilized many concepts that we learned from this course. The concepts taught in the weeks leading up to the presentation allowed for us to be prepared to apply them into this project. <br />
<br />
The concept of multi-threaded code was newer to some of us, but we feel that it prepares us for our future careers as embedded software engineers. The use of prioritizing various blocks of code over others and how the impacts it has on the scheduling of tasks is an important concept to understand. <br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward. The mindset you need to have in order to think critically about bugs <br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reaching those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66801F21: Space Rage2021-12-18T04:43:27Z<p>Proj user2: /* SPACE RAGE */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
{|<br />
|[[File:Lives screen.gif |thumb|800px|'''Player Lives Screen''']]<br />
|[[File:Gameplay_countdown.gif |thumb|800px|'''Gameplay Countdown Sequence''']]<br />
|[[File:Title_screen.gif |thumb|800px|'''Gameover to Title Screen Sequence''']]<br />
|}<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Throughout the implementation project, we found that we had utilized many concepts that we learned from this course. The concepts taught in the weeks leading up to the presentation allowed for us to be prepared to apply them into this project. <br />
<br />
The concept of multi-threaded code was newer to some of us, but we feel that it prepares us for our future careers as embedded software engineers. The use of prioritizing various blocks of code over others and how the impacts it has on the scheduling of tasks is an important concept to understand. <br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward. The mindset you need to have in order to think critically about bugs <br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reach those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66800F21: Space Rage2021-12-18T04:43:10Z<p>Proj user2: /* SPACE RAGE */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
{|<br />
|[[File:Lives screen.gif |thumb|500px|'''Player Lives Screen''']]<br />
|[[File:Gameplay_countdown.gif |thumb|500px|'''Gameplay Countdown Sequence''']]<br />
|[[File:Title_screen.gif |thumb|500px|'''Gameover to Title Screen Sequence''']]<br />
|}<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Throughout the implementation project, we found that we had utilized many concepts that we learned from this course. The concepts taught in the weeks leading up to the presentation allowed for us to be prepared to apply them into this project. <br />
<br />
The concept of multi-threaded code was newer to some of us, but we feel that it prepares us for our future careers as embedded software engineers. The use of prioritizing various blocks of code over others and how the impacts it has on the scheduling of tasks is an important concept to understand. <br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward. The mindset you need to have in order to think critically about bugs <br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reach those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66799F21: Space Rage2021-12-18T04:42:38Z<p>Proj user2: /* SPACE RAGE */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
{|<br />
|[[File:Lives screen.gif |thumb|400px|'''Player Lives Screen''']]<br />
|[[File:Gameplay_countdown.gif |thumb|400px|'''Gameplay Countdown Sequence''']]<br />
|[[File:Title_screen.gif |thumb|400px|'''Gameover to Title Screen Sequence''']]<br />
|}<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Throughout the implementation project, we found that we had utilized many concepts that we learned from this course. The concepts taught in the weeks leading up to the presentation allowed for us to be prepared to apply them into this project. <br />
<br />
The concept of multi-threaded code was newer to some of us, but we feel that it prepares us for our future careers as embedded software engineers. The use of prioritizing various blocks of code over others and how the impacts it has on the scheduling of tasks is an important concept to understand. <br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward. The mindset you need to have in order to think critically about bugs <br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reach those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=File:Title_screen.gif&diff=66796File:Title screen.gif2021-12-18T04:39:41Z<p>Proj user2: </p>
<hr />
<div></div>Proj user2http://socialledge.com/sjsu/index.php?title=File:Gameplay_countdown.gif&diff=66795File:Gameplay countdown.gif2021-12-18T04:39:27Z<p>Proj user2: </p>
<hr />
<div></div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66794F21: Space Rage2021-12-18T04:39:09Z<p>Proj user2: /* Conclusion */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Throughout the implementation project, we found that we had utilized many concepts that we learned from this course. The concepts taught in the weeks leading up to the presentation allowed for us to be prepared to apply them into this project. <br />
<br />
The concept of multi-threaded code was newer to some of us, but we feel that it prepares us for our future careers as embedded software engineers. The use of prioritizing various blocks of code over others and how the impacts it has on the scheduling of tasks is an important concept to understand. <br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward. The mindset you need to have in order to think critically about bugs <br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reach those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66793F21: Space Rage2021-12-18T04:38:57Z<p>Proj user2: /* Conclusion */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Throughout the implementation project, we found that we had utilized many concepts that we learned from this course. The concepts taught in the weeks leading up to the presentation allowed for us to be prepared to apply them into this project. <br />
<br />
The concept of multi-threaded code was newer to some of us, but we feel that it prepares us for our future careers as embedded software engineers. The use of prioritizing various blocks of code over others and how the impacts it has on the scheduling of tasks is an important concept to understand. <br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward. The mindset you need to have in order to think critically about bugs <br />
<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reach those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=File:Lives_screen.gif&diff=66792File:Lives screen.gif2021-12-18T04:38:01Z<p>Proj user2: </p>
<hr />
<div></div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66786F21: Space Rage2021-12-18T04:35:31Z<p>Proj user2: /* Conclusion */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
<br />
Throughout the implementation project, we found that we had utilized many concepts that we learned from this course. The concepts taught in the weeks leading up to the presentation allowed for us to be prepared to apply them into this project. <br />
<br />
The concept of multi threaded code was newer to some of us, but we feel that it prepares us for our future careers as embedded software engineers. The use of prioritizing various blocks of code over others and how the impacts it has on the scheduling of tasks is an important concept to understand. <br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward. The mindset you need to have in order to think critically about bugs <br />
<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reach those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66782F21: Space Rage2021-12-18T04:32:53Z<p>Proj user2: /* Conclusion */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
<br />
Throughout the implementation project, we found that we had utilized many concepts that we learned from this course. The concepts taught in the weeks leading up to the presentation allowed for us to be prepared to apply them into this project. <br />
<br />
The concept of multi threaded code was newer to some of us, but we feel that it prepares us as we make our way into <br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward. The mindset you need to have in order to think critically about bugs <br />
<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reach those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66781F21: Space Rage2021-12-18T04:32:21Z<p>Proj user2: /* Acknowledgement */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
<br />
Throughout the implementation project, we found that we had utilized many concepts that we learned from this course. <br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward. The mindset you need to have in order to think critically about bugs <br />
<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue careers in embedded systems and all of the knowledge we have gained from this course have been helpful in us reach those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66780F21: Space Rage2021-12-18T04:32:01Z<p>Proj user2: /* Acknowledgement */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
<br />
Throughout the implementation project, we found that we had utilized many concepts that we learned from this course. <br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward. The mindset you need to have in order to think critically about bugs <br />
<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue career in embedded systems and all of the knowledge we have gained from this course have been helpful in us reach those goals.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66777F21: Space Rage2021-12-18T04:30:14Z<p>Proj user2: /* References */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
<br />
Throughout the implementation project, we found that we had utilized many concepts that we learned from this course. <br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward. The mindset you need to have in order to think critically about bugs <br />
<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
We would like to thank Preet for making a wonderful course which encourages learning over pure memorization. All member of this group project are aiming to pursue career in embedded systems and of the knowledge we have gained from this course will without a doubt help us reach those goals.<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66774F21: Space Rage2021-12-18T04:29:20Z<p>Proj user2: /* Conclusion */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
<br />
Throughout the implementation project, we found that we had utilized many concepts that we learned from this course. <br />
<br />
The knowledge gained from going through the process of debugging the various issues we had experienced along the way will serve as a good building block going forward. The mindset you need to have in order to think critically about bugs <br />
<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66772F21: Space Rage2021-12-18T04:25:44Z<p>Proj user2: /* Appendix */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
#[https://www.sparkfun.com/news/2650 Everything You Didn't Want to Know About RGB Matrix Panels]</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66771F21: Space Rage2021-12-18T04:25:02Z<p>Proj user2: /* Team Members & Responsibilities */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/devin_alexander_sjsu Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
You can list the references you used.</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66763F21: Space Rage2021-12-18T04:20:26Z<p>Proj user2: /* Software Design */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
'''Changing volume'''<br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
You can list the references you used.</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66762F21: Space Rage2021-12-18T04:19:56Z<p>Proj user2: /* Software Design */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
'''Playing three MP3 files concurrently'''<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
You can list the references you used.</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66760F21: Space Rage2021-12-18T04:18:23Z<p>Proj user2: /* Testing & Technical Challenges */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
You can list the references you used.</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66759F21: Space Rage2021-12-18T04:18:07Z<p>Proj user2: /* Hardware Interface */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
The captive touch button that we used for controlling the volume was fond off of Amazon and is pictured below:<br />
{|<br />
|[[File:Capacitive touch button.jpg|250px|thumb|left|'''Capacitive Touch Button ]]<br />
|}<br />
<br />
==== Software Design ====<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
Describe the challenges of your project. What advise would you give yourself or someone else if your project can be started from scratch again?<br />
Make a smooth transition to testing section and described what it took to test your project.<br />
<br />
Include sub-sections that list out a problem and solution, such as:<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
You can list the references you used.</div>Proj user2http://socialledge.com/sjsu/index.php?title=File:Capacitive_touch_button.jpg&diff=66758File:Capacitive touch button.jpg2021-12-18T04:16:41Z<p>Proj user2: </p>
<hr />
<div></div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66756F21: Space Rage2021-12-18T04:13:33Z<p>Proj user2: /* Software Design */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
==== Software Design ====<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read. <br />
<br />
To change the volume on the MP3 decoder, we needed to write a value from 0-255 to register 0x0B using the SCI interface. A value of 0 corresponds to no volume attenuation, while a value of 255 corresponds to completely off. The value between each number is 0.5 decibels, so if you wrote a value of 6 for each left and right channel, it would lower the output of both channels by 3dB.<br />
<br />
We decided that for the sound effects, we wanted them to be louder than the background music, so we set the volumes of the Music MP3 decoder to a higher offset than the Sound_FX boards, which resulted in roughly a 9dB volume differential between the two devices.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
Describe the challenges of your project. What advise would you give yourself or someone else if your project can be started from scratch again?<br />
Make a smooth transition to testing section and described what it took to test your project.<br />
<br />
Include sub-sections that list out a problem and solution, such as:<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
You can list the references you used.</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66755F21: Space Rage2021-12-18T04:11:27Z<p>Proj user2: /* Hardware Interface */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
==== Software Design ====<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read and close out any other information <br />
<br />
<br />
To change<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
Describe the challenges of your project. What advise would you give yourself or someone else if your project can be started from scratch again?<br />
Make a smooth transition to testing section and described what it took to test your project.<br />
<br />
Include sub-sections that list out a problem and solution, such as:<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
You can list the references you used.</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66754F21: Space Rage2021-12-18T04:11:07Z<p>Proj user2: /* Hardware Interface */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
{|<br />
|[[File:VS1053b MP3 Decoder Board.jpg|thumb|left|250px|'''VS1053b MP3 Decoder]]<br />
|}<br />
<br />
''' Stereo Amplifier '''<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
{|<br />
|[[File:MAX98306 breakout board.jpg|250px|thumb|left|'''MAX98306 Stereo Amplifier ]]<br />
|}<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br />
==== Software Design ====<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read and close out any other information <br />
<br />
<br />
To change<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
Describe the challenges of your project. What advise would you give yourself or someone else if your project can be started from scratch again?<br />
Make a smooth transition to testing section and described what it took to test your project.<br />
<br />
Include sub-sections that list out a problem and solution, such as:<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
You can list the references you used.</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66750F21: Space Rage2021-12-18T04:03:13Z<p>Proj user2: /* Music, Sound, and Volume Control */</p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
==== Hardware Interface ====<br />
''' MP3 Decoder '''<br />
<br/><br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
[[File:VS1053b MP3 Decoder Board.jpg|250px]]<br />
<br />
''' Stereo Amplifier '''<br />
<br/><br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
[[File:MAX98306 breakout board.jpg|250px]]<br />
<br />
''' Touch Sensor and Volume Control '''<br />
<br/><br />
<br />
==== Software Design ====<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read and close out any other information <br />
<br />
<br />
To change<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
Describe the challenges of your project. What advise would you give yourself or someone else if your project can be started from scratch again?<br />
Make a smooth transition to testing section and described what it took to test your project.<br />
<br />
Include sub-sections that list out a problem and solution, such as:<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
You can list the references you used.</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66747F21: Space Rage2021-12-18T03:59:37Z<p>Proj user2: </p>
<hr />
<div>[[File:Space_rage_setup.jpg|800px|right]]<br />
== '''SPACE RAGE''' ==<br />
<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
<br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
[[File:VS1053b MP3 Decoder Board.jpg|250px]]<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
[[File:MAX98306 breakout board.jpg|250px]]<br />
<br />
==== Hardware Interface ====<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
==== Software Design ====<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read and close out any other information <br />
<br />
<br />
To change<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
Describe the challenges of your project. What advise would you give yourself or someone else if your project can be started from scratch again?<br />
Make a smooth transition to testing section and described what it took to test your project.<br />
<br />
Include sub-sections that list out a problem and solution, such as:<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
You can list the references you used.</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66744F21: Space Rage2021-12-18T03:55:31Z<p>Proj user2: /* Software Design */</p>
<hr />
<div><br />
== '''SPACE RAGE''' ==<br />
[[File:Space_rage_setup.jpg|800px|center]]<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
<br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
[[File:VS1053b MP3 Decoder Board.jpg|250px]]<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
[[File:MAX98306 breakout board.jpg|250px]]<br />
<br />
==== Hardware Interface ====<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
==== Software Design ====<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. Whenever an MP3 file was done playing, we would close out the file from being read and close out any other information <br />
<br />
<br />
To change<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
Describe the challenges of your project. What advise would you give yourself or someone else if your project can be started from scratch again?<br />
Make a smooth transition to testing section and described what it took to test your project.<br />
<br />
Include sub-sections that list out a problem and solution, such as:<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
You can list the references you used.</div>Proj user2http://socialledge.com/sjsu/index.php?title=F21:_Space_Rage&diff=66740F21: Space Rage2021-12-18T03:48:59Z<p>Proj user2: /* Music, Sound, and Volume Control */</p>
<hr />
<div><br />
== '''SPACE RAGE''' ==<br />
[[File:Space_rage_setup.jpg|800px|center]]<br />
== Abstract ==<br />
Space Rage was modeled off of the Tron Light Cycle game, in which two players, attempt to have the opponent run into their trail that is left behind as they move. It<br />
is similar to Snake, but the trail left behind is not dependent on any pickups and it is competitive.<br />
The players are able to move in the cardinal directions, North, East, South, and West, and are<br />
not able to steer directly behind them to prevent instant defeat.<br />
<br />
There are two levels of AI a player make compete against: Normal and Hard. The difficult of the AI is dependent on which controller the player is using: Player 1 faces the Normal computer while Player 2 faces the Hard computer. The selection of game type is done from the main screen that shows 1 Player or 2 Player. After the selection, the players are free to choose normal mode or turbo. Turbo mode allows for the pressing of the button on the controller to allow the player to move faster.<br />
<br />
The display is a 64 by 64 LED matrix. The player controls their ship by using the joystick and button in the controller. The<br />
button located on controller allows the user to select options from the main menu and go turbo mode while in that game mode. There are four speakers for the cabinet: two to play music on either side, one for sound effects related to player one, and one for sound effects related to player two. The volume of the speakers is controlled by a touch sensor that is attached to conductive tape which is attached to the side of the cabinet.<br />
<br />
== Objectives & Introduction ==<br />
<br />
Space Rage is a two player game that tests the players reaction times and strategy in a fast paced arena similar to the Tron Light Cycle game. The players only means of defense and offence is the wall that is left behind them as they move. There were a few key objectives and features we wanted to implement into our game to make it feel more like an arcade game:<br />
* Single Player and Two Player modes<br />
* Sound and Music<br />
* Fast responsive controls<br />
* High activity and quick rounds<br />
<br />
===== Player Modes =====<br />
The biggest highlight of the game is the two player aspect of the game, allowing you and a friend to play against each other in the game. Each player can use a one of the controllers attached by a CAT5e cable to the main cabinet.<br />
There is also a single player mode that allows a player to play an AI driven computer opponent. The difficulty of the computer depends on which player port the player is connected to. This is a nod to old Atari games that had different settings depending on which controller port the user plugged the controller into.<br />
<br />
===== Sound and Music =====<br />
When we think of arcade games, the thought of immersive visuals is almost just as important as the sound design. For this project, we wanted to set ourselves apart with the sound design section of this project and use 3 MP3 decoders to offer immersive sound on 4 speakers(2 dedicated to stereo background music and the other 2 for sound effects one left and right channel for player 1 and 2 respectively). We opted to do this instead of using a singular MP3 decoder because if we did this option, we could have only played a single MP3 file at a time (either music or a sound effect) but not both concurrently. With the music not taking any breaks to play sound effects, the result of this was a more immersive playing experience. With proper timing of the sound effects, this would only help amplify how immersive it is if the sounds would line up within +/- 20 milliseconds of an appropriate event happening.<br />
<br />
===== Fast responsive controls =====<br />
We have constructed two arcade joystick pads for each of the two players which are wired to the arcade box. Although the controllers are wired, they have been tested to function properly up to a 6ft cable. The controllers responsiveness are fast which is desired for a game such as Space Rage which is dependent on strategy and reaction time. The controllers are connected using a cat5e/cat6 cable and can be easily removed for easy transportation.<br />
<br />
===== High activity and quick rounds =====<br />
We tried to maximize the game space for the game with the limitation of having such a small screen, the 64 x 64 LED matrix. To accommodate this we elected to have small characters, just 2x3 pixels wide, which allowed for a much larger game space. The game does still run at a fast rate, leading to the short quick rounds we intended. We decided on a lives based system for the game, so players have 3 lives before they have truly lost a game. This information is shown between rounds and are represented by hearts, again maximizing the space and giving a brief reprieve from the action.<br />
<br />
=== Team Members & Responsibilities ===<br />
[[File:jbeardphoto.jpg|250px|middle]]<br />
*'''''[https://www.linkedin.com/in/jonathan-beard-155840205/ Jonathan Beard]''''' '''''[https://gitlab.com/jbeard79 Gitlab]'''''<br />
** Core game logic<br />
** Animation development<br />
** AI construction<br />
<br />
[[File:Jonathan tran self pic.jpeg|250px|middle]]<br />
*Jonathan Tran '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** LED Matrix Interface<br />
** Player Controllers Interface<br />
** Game Logic <br />
** MP3 Decoders <br />
<br />
[[File:DevinAlexander.jpeg|250px|middle]]<br />
*Devin Alexander '''''[https://gitlab.com/jtran1028 Gitlab]'''''<br />
** Lead construction and design<br />
** PCB designer<br />
** MP3 Decoders<br />
** Sound Engineer<br />
<br />
== Schedule ==<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Week#<br />
! scope="col"| Start Date<br />
! scope="col"| End Date<br />
! scope="col"| Task<br />
! scope="col"| Status<br />
|-<br />
! scope="row"| 1<br />
| <br />
* 10/12/2021<br />
* 10/13/2021<br />
|<br />
* 10/18/2021<br />
* 10/13/2021<br />
|<br />
* Read previous projects, gather information and discuss among the group members<br />
* Create GitLab repository for project<br />
| <br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 2<br />
| <br />
*10/19/2021<br />
*10/18/2021 <br />
| <br />
*10/20/2021<br />
*10/24/2021 <br />
|<br />
*Order LED Matrix<br />
*Order Joystick, buttons, mp3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 3<br />
|<br />
*10/24/2021<br />
|<br />
*10/30/2021<br />
|<br />
*Read and familiarize with LED Matrix Datasheet<br />
**Light a few pixels<br />
*Read and familiarize with Joystick and Buttons<br />
*Read and familiarize with MP3 decoder<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 4<br />
|<br />
* 10/31/2021<br />
|<br />
* 11/06/2021<br />
|<br />
* Develop graphics driver for LED matrix<br />
* Implement initial game objects and decide on logic<br />
* Decide on and draw Player Models<br />
* Finalize wiki schedule<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 5<br />
|<br />
*11/07/2021<br />
|<br />
*11/13/2021<br />
|<br />
* Order PCB components and complete the design for printing<br />
* Order additional accessories if required and finalize hardware specifications (touch sensor)<br />
* Figure out logic required for second player<br />
* Finalize controller design<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 6<br />
|<br />
*11/14/2021 <br />
| <br />
*11/20/2021<br />
|<br />
* PCB and component assembly<br />
* Integration of PCB and microcontroller<br />
* Game logic finalization <br />
* Testing and debugging of game logic<br />
* Figure out AI settings and algorithms<br />
* Construct both controllers<br />
* Circuit board testing, ensuring proper trace runs and connectivity<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 7<br />
| <br />
* 11/21/2021<br />
<br />
| <br />
* 11/27/2021<br />
|<br />
* Integrate game logic code with LED matrix<br />
* Get soundtrack and game sounds set<br />
* MP3 decoder driver construction<br />
* Develop and add method for animations<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 8<br />
| <br />
* 11/28/2021<br />
| <br />
* 12/04/2021<br />
|<br />
<br />
* Finalizing the video game<br />
* Construct enclosure for LED matrix and microcontroller<br />
* Finalize and test menu select screen<br />
* Update the wiki page<br />
* Integrate game sounds with game logic <br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 9<br />
| <br />
* 12/05/2021<br />
| <br />
* 12/11/2021<br />
|<br />
* Address bugs during testing of integrated system<br />
|<br />
* <span style="color:green">Completed</span><br />
|-<br />
! scope="row"| 10<br />
| <br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
*12/12/2021<br />
| <br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
*12/14/2021<br />
|<br />
<br />
*Final Demo<br />
*Update Gitlab repo with final code<br />
*Update test video<br />
*Update the wiki page<br />
|<br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
* <span style="color:green">Completed</span><br />
|-<br />
|}<br />
<br />
<HR><br />
<BR/><br />
<br />
== Bill of Materials ==<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Item #<br />
! scope="col"| Part<br />
! scope="col"| Vendor<br />
! scope="col"| Qty<br />
! scope="col"| Cost<br />
|-<br />
! scope="row"| 1<br />
| 64x64 RGB LED Matrix<br />
| [https://www.sparkfun.com/products/14824 Sparkfun] <br />
| 1<br />
| $87.15<br />
|-<br />
! scope="row"| 2<br />
| SJTwo Boards<br />
| [https://www.amazon.com/Generic-SJTwo-SJ2-SJSU/dp/B08G9LRPZ8 Amazon/SJSU] <br />
| 2<br />
| $100.00<br />
|-<br />
! scope="row"| 3<br />
| Two Player Joystick Bundle<br />
| [https://www.amazon.com/dp/B07JF34XPB/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B07JF34XPB&pd_rd_w=SPglL&pf_rd_p=9fd3ea7c-b77c-42ac-b43b-c872d3f37c38&pd_rd_wg=mWr1X&pf_rd_r=DWYSE9PS01WDX06HY879&pd_rd_r=054069e8-ef7a-4290-a581-a6fe254b599e&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExUDUzUUlTSlpUSUFZJmVuY3J5cHRlZElkPUEwMjk5NjgwMzRRREJQMjk1TzFSNiZlbmNyeXB0ZWRBZElkPUEwNTQxMjExMUVCQ1dJQVlQVjQxTSZ3aWRnZXROYW1lPXNwX2RldGFpbCZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=n Amazon]<br />
| 1<br />
| $44.99<br />
|-<br />
! scope="row"| 4<br />
| MP3 Decoder (VS1053)<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 3<br />
| $75.00<br />
|-<br />
! scope="row"| 5<br />
| Audio Amplifier<br />
| [https://www.adafruit.com/product/1381 Adafruit]<br />
| 2<br />
| $18.00<br />
|-<br />
! scope="row"| 6<br />
| Cat5e Female Connectors<br />
| Home Depot<br />
| 2<br />
| $10.00<br />
|-<br />
! scope="row"| 7<br />
| Cat6 3ft Ethernet Cables<br />
| Home Depot<br />
| 2<br />
| $14.00<br />
|-<br />
! scope="row"| 8<br />
| Spray Paint<br />
| Home Depot<br />
| 2<br />
| $7.00<br />
|-<br />
! scope="row"| 9<br />
| 2' x 4' Plywood<br />
| Home Depot<br />
| 1<br />
| $28.00<br />
|-<br />
! scope="row"| 10<br />
| Speakers <br />
| [https://www.adafruit.com/product/1313 Adafruit]<br />
| 4<br />
| $10.00<br />
|-<br />
|}<br />
<br />
== Design & Implementation ==<br />
The design section can go over your hardware and software design. Organize this section using sub-sections that go over your design and implementation.<br />
<br />
=== PCB ===<br />
For the PCB that we designed, we were able to get by with using the first rev of the PCB in the final version of the arcade game. As we continued to grow the scope of the project with additional MP3 decoders and an extra SJ2 board and stereo amplifier board, there was quickly a growing concern with using the free license of Eagle to design the board. This is because with the free version, there is a size limitation of how much space you have to lay out your components. So by carefully placing all of the board's components to not waste too much space to allow all components to fit within the space of 65 x 140 mm.<br />
<br />
The board that we designed consisted mostly of a means to interconnect all of the different breakout boards(stereo audio amplifiers and MP3 decoders), LED matrix and the other custom breakouts for controllers to both SJ2 boards. It was designed in such a way that all of the modules could be fitted onto the board the SJ2 boards connecting to it from the underside and the other boards all on the top of the PCB. We figured that it would be best to have the traces for the connections to peripherals by correspond to the area of the PCB that was closest to the corresponding SJ2 board. We layed it out so that only one of the SJ2 boards would have it's micro USB been easily accessible, unless you staggered the height of the boards. Because we had this in mid when doing the layout, we were able to quickly flash, test, and debug any code we wrote without any needs to disassemble anything.<br />
<br />
<br />
[[File:Space Rage Schematic Main Board.jpg|thumb|center|1000px|'''Main SJ2 Board: This is the schematic for the connections of what we label the Master MCU. This schematic contains connections to the master MCU, the UART bus that we are using to talk to the slave SJ2 audio board, both Controllers that we are using, the LED Matrix Display, and capacitive touch sensor breakouts. Also pictured to the left is the two power connectors that we routed onto the board, one for providing a 4.5V power bus from a wall wart power supply and the other for distributing the 4.5V power bus to the LED Matrix''']]<br />
<br />
[[File:Space Rage Schematic Music.jpg|thumb|center|1000px|'''Audio SJ2 Board: This is the schematic for the connections of what we label the Slave MCU. This portion of the schematic contains connections to the master MCU, three VS1053 MP3 Decoder breakout boards, two MAX98306 stereo amplifier breakout boards, and the UART bus that we are using to talk to the main SJ2 board.''']]<br />
<br />
[[File:Space Rage PCB Layout 450 DPI.png|thumb|center|1000px|'''Here is the Layout. The areas where each breakout board is attached to is clearly marked in outlines with text that resides on the silk screen layer to help show where each of the boards go. Everything from both portions of the schematic fits within the boundaries of this board.''']]<br />
<br />
[[File:Space Rage PCB stack.JPG|thumb|center|1000px|'''Here is the PCB all assembled with the breakout boards that were used on the top and the two SJ2 boards mounted to the bottom. As discussed, the two boards are staggered in heigh from the PCB with the Audio board (left) being spaced 12mm from the PCB and the main SJ2 board (right) is mounted 24mm below the PCB. This allows for both serial programmers to be available to each board at the same time and eliminates the need to unplug and re-plugin the main SJ2 board each time we want to reflash the board.''']]<br />
<br />
==='''LED Matrix'''===<br />
<br />
The display for Space Rage is a SparkFun 64x64 RGB LED Matrix. It has a scan rate of 1/32, where 2 of 64 rows are displayed at a single time. The matrix is split into two display sections, a top half and a bottom half such that 1 row of each section is driven at a single time. Due to the speed at which the matrix displays each row, users see an image as a whole due to "persistence of vision".<br />
<br />
As the display is split into two sections, rows 0 to 31 are considered to be a part of the upper section and rows 32 to 63 are part of the bottom half of the display. To select a row, the matrix consists of a 5:32 decoder to select each row of the display. This decoder is controlled by the signals A,B,C,D,E. The decoder simultaneously selects the same row in each display, hence each half of the display has rows 0 to 31.<br />
<br />
To set each pixel color value for each column, the matrix has a shift register to store each 3-bit color value per pixel for 64 columns. As the display is split into two sections, the signals R1,G1,B1 control the upper half of the display and R2,G2,B2 control the bottom half of the display. Thus, each pixel values per display section must be clocked into the shift register using their respective R,G,B signals and are clocked in using the "CLK" signal. Therefore, 64 3-bit values must be clocked into the shift register to store the color value of each pixel of all 64 columns of the display.<br />
<br />
<br/><br />
{|<br />
|[[File:Spark_fun_64x64_rgb_led_matrix.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX FRONT''']] <br />
|<br />
|[[File:CmpE244_F19_T4_Matrix_picture_back.jpg | thumb|300px| left| '''64x64 RGB LED MATRIX BACK''']] <br />
|}<br />
<br />
<br />
{|<br />
|[[File:space_invaders_diagram_led_matrix.jpg|500px|thumb|left|''' LED MATRIX LAYOUT. (Source: [http://socialledge.com/sjsu/index.php/F20:_Space_Invaders SPACE INVADERS])]]<br />
|}<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| Matrix PIN Name<br />
! scope="col"| PIN Description<br />
! scope="col"| SJ2 Pin Connection<br />
|-<br />
! scope="row"| A<br />
| Decoder Row Select <br />
| P1.20<br />
|-<br />
! scope="row"| B<br />
| Decoder Row Select <br />
| P1.30<br />
|-<br />
! scope="row"| C<br />
| Decoder Row Select <br />
| P1.28<br />
|-<br />
! scope="row"| D<br />
| Decoder Row Select <br />
| P1.23<br />
|-<br />
! scope="row"| E<br />
| Decoder Row Select <br />
| P0.25<br />
|-<br />
! scope="row"| R1<br />
| Upper display red for shift register<br />
| P0.6<br />
|-<br />
! scope="row"| G1<br />
| Upper display green for shift register<br />
| P0.7<br />
|-<br />
! scope="row"| B1<br />
| Upper display blue for shift register<br />
| P0.8<br />
|-<br />
! scope="row"| R2<br />
| Lower half display red for shift register<br />
| P0.26<br />
|-<br />
! scope="row"| G2<br />
| Lower half display green for shift register<br />
| P0.9<br />
|-<br />
! scope="row"| B2<br />
| Lower half display blue for shift register<br />
| P1.31<br />
|- <br />
! scope="row"| CLK<br />
| Signal to clock in 3-bit color values per pixel into shift register<br />
| P2.0<br />
|-<br />
! scope="row"| LAT<br />
| Signal to latch shift register pixel values to output driver<br />
| P1.29<br />
|-<br />
! scope="row"| OE<br />
| Active low signal to output a row's pixels onto display<br />
| P2.2<br />
|-<br />
|}<br />
<br />
==== Led Display Matrix Software Design ====<br />
''' How to display a frame '''<br />
<br />
Now given a brief description of the display, we will discuss how to display images. A [https://www.sparkfun.com/news/2650 sparkfun] article goes into how RGB Panels work, but here are the following steps that must take place to display a whole frame:<br />
# Set the R1,G1,B1 and R2,G2,B2 signals to set the desired pixel color for both the upper and bottom display sections<br />
# Set "CLK" high to clock in the pixel color for the columns for both display sections simultaneously<br />
# Set latch high to allow the data to the output driver (Output enable should be disable. (i.e. set high))<br />
# Set A,B,C,D,E to select the row to display all pixel values of the 64 columns. (Recall we are selecting rows simultaneously in each display section)<br />
# Disable latch (to clock in the next data). Enable output enable (set low as it is active low) to output the pixels onto the display<br />
# Disable output enable after a given delay<br />
# Repeat above steps until allows rows have been display to display a single frame <br />
<br />
'''Initializing GPIO Pins'''<br />
<br/><br />
As the 64x64 matrix is controlled by GPIO pins, a function was created to initialize gpio pins for all 14 pins of the matrix. A struct called "led_display_gpio_pins" was created to store multiple port and pin mappings (gpio_s structs) of each pin corresponding to the LED matrix. This allows easier readability on what pins correspond to each LED matrix pin. For instance, led_display_pins.r1 is a struct which has a member 'r1' which is a gpio_s struct which holds the port and pin which is connected to R1 on the LED matrix.<br />
<br />
'''Matrix Representation in a 64x64 Array'''<br />
<br/><br />
A static 64x64 uint8_t array is used to store the pixel color values of each row and column. Given that colors are controlled by R,G,and B pins, the array can store a value from 0-to-7 to represent a color. A function called led_display__draw_pixel(uint8_t row, uint8_t column, pixel_color_e pixel_color) was given to allow different functions to set certain pixels in the frame. Thus an image can be created by setting multiple pixel colors in the array.<br />
<br />
{| class="wikitable"<br />
|-<br />
! scope="col"| RGB Binary Representation<br />
! scope="col"| Pixel Color<br />
|-<br />
! scope="row"| 000<br />
| Black<br />
|-<br />
! scope="row"| 001<br />
| Blue <br />
|-<br />
! scope="row"| 010<br />
|Green<br />
|-<br />
! scope="row"| 011<br />
| Cyan<br />
|-<br />
! scope="row"| 100<br />
| Red<br />
|-<br />
! scope="row"| 101<br />
| Purple<br />
|-<br />
! scope="row"| 110<br />
| Yellow<br />
|-<br />
! scope="row"| 111<br />
| White<br />
|-<br />
|}<br />
<br />
'''Display Driver Task'''<br />
<br/><br />
To drive the display, a task with the highest priority was created to set the corresponding pins on the RGB LED matrix. Whenever the task is running, it loops through all indices of the multi-dimensional array and sets the corresponding R,G,B pins given the value in each index of the array. This is done by following the steps above under '''"How to display a frame"'''. The less time the display driver spends sleeping, the brighter the RGB panel display is. Thus, we had settled for a high frame rate by having the display driver run every 2ms.<br />
<br />
=== Music, Sound, and Volume Control ===<br />
<br />
The MP3 decoder boards that we used for this project is a breakout board that can be found on Adafruit.com and utilizes the VS1053b which can decode MP3, playback WAV files, and work with other popular audio formats. for our purposes, we used this for decoding MP3 files.<br />
<br />
[[File:VS1053b MP3 Decoder Board.jpg|250px]]<br />
<br />
The stereo amplifier breakout boards that we used can also be found on Adafruit.com and utilize the MAX98306, which is a stereo 37w class d audio amplifier IC from Maxim Integrated. <br />
<br />
[[File:MAX98306 breakout board.jpg|250px]]<br />
<br />
==== Hardware Interface ====<br />
<br />
To both be able to play music and sound effects, we had decided to use more than one MP3 Decoder. In addition, we also wanted each player to have their own sound effects and speaker. Thus, we had opted to use three MP3 Decoders. two MP3 decoders were used for each player and one dedicated to music. As a result of having three MP3 decoders and limited pins on the SJ2 board, we had opted to use a second SJ2 board to serve as the dedicated music board. Thus, we have the SJ2 board which drives the game called "SJ2 Main" and the music board called "SJ2 Music".<br />
<br />
To play music and sound effects, the SJ2 Main board sends a command to SJ2 Music over UART. Depending on the command, SJ2 Music will play music or a sound effect through one of the three MP3 decoders. The player one mp3 decoder is denoted as "SOUND_FX1", player two mp3 decoder is denoted as "SOUND_FX2", and finally the music decoder is denoted as "MUSIC". SJ2 Music receives all UART commands using the uart__get() function given by Preet's uart driver and the same same driver is used by SJ2 Main for uart__put() to send a command.<br />
<br />
==== Software Design ====<br />
<br />
To play up to 3 different MP3 files at the same time using the three separate MP3 decoders, we had to read 3 separate files from SD cards. The route we ended using was to use a singular SD card on the SSP2 bus and all three MP3 decoders were connected on the SSP0 bus. We implemented the SPI drivers for the SD card side using the SSP2 drivers that were provided to us and commands for the FAT file system. For the MP3 decoder side of the drivers, we modified the provided SSP2 driver and made it work with SSP0 by changing a few lines of code. <br />
<br />
To read three mp3 files at the same time on an SD card, we set up three separate tasks that would take the file descriptor that was requested to play and we would use a semaphore to block access to the SSP2 bus whenever there was another buffer that needed to be loaded into program memory. After each buffer would be read, we would relinquish the semaphore to the SSP2 line so that any other MP3 decoder that was requesting new buffers to be loaded into it would be able to take the semaphore and have a chance to load its next buffer. After the buffer was loaded into memory, there would be a request to take another semaphore for the SSP0 bus which was used for communications between MP3 boards. After the semaphore was in possession, we then could transfer over the buffer of 32 bytes of data to the MP3 board that was requesting more data. <br />
<br />
We would know that an MP3 decoder was in need of more information because we set up polling of the DREQ pins on the VS1053b from the MP3 decoder breakout boards. The pin DREQ is responsible for informing the host MCU that there needs to be more data sent over whenever the internal FIFO is no longer full. <br />
<br />
<br />
<br />
read 3 MP3 files concurrently <br />
<br />
each one of the 3 different SPI buses that are available to us on the SJ2 board.<br />
<br />
=== Player Joysticks and Buttons ===<br />
==== Hardware Interface ====<br />
For our game, we had decided to have two players. Each player has their own arcade joystick and a button to select a game mode and to use in-game. The arcade controllers have 4 directions, although there is an 8 direction mode, we had opted for only 4 directions.<br />
<br />
The joystick has 5-pinout connections. One for each direction and a single GND pin. The button has a 3-pin connection: signal, VCC, and GND. We had connected the Vcc connections to a gpio pin which would allow us to control when the button LED is on and to show that the game is ready for input. However, we had not implemented this logic, and simply left the gpio pins high to have the LEDs always active.<br />
<br />
{|<br />
|[[File:Sj2_player_controllers.jpg | thumb|950px| '''SJ2 Board interface to Player Controllers''']] <br />
|}<br />
<br />
''' Cat5e Cable and Player Controllers Interface '''<br />
<br/> <br />
<br />
Given the fact that we were dealing with 8 pins in total for each arcade controller and button, we had decided to wire each controller to our PCB using a Cat5e female connector and a Cat5e/Cat6 ethernet cable. This was possible as Cat5e ethernet cables have 8 wires. Our arcade box has two female Cat5e connectors, one for each player. Within the arcade box, wires are connected from the PCB to the female connectors. The same is done for our casing for the arcade controllers and buttons for each player. Therefore, each controller is able to connect to the arcade box by connecting a Cat5e/Cat6 cable to the respective female connectors. However, there is an issue with input delay given the Cat5e/Cat6 ethernet cable length. We have found that 3 to 6ft cables function properly whereas a 15ft cable had noticeable delays and issues.<br />
<br />
{|<br />
|[[File:Cat5e_female_connectors.jpg | thumb|200px| '''Cat5e Female Connector''']] <br />
|}<br />
<br />
==== Software Design ====<br />
The player controllers are handled by 10 ISRs, 8 for each of the players direction inputs from the controllers, and 2 for each player button. Two queues were created for each player that receives enum values corresponding to a direction. The queues were given a size of 1 to handle the event of switch debounce. Two binary semaphores were also created to handle button input for each player. We had also designed functions to empty the queues and semaphores as the game transitions to different game states in which stale queue values and semaphores are removed.<br />
<br />
Although two ISRs were created for each player button, we had also polled the player buttons during in-game mode. The reason behind this is due to the fact that "Turbo Mode" in our game relies on the user constantly holding the button.<br />
<br />
''' Interrupt Service Routines, FreeRTOS Queues, and User Controller Input Logic: '''<br />
# Player moves analog controller<br />
# ISR runs and calls xQueueSendsFromISR() a value corresponding to the direction<br />
# Game logic calls function receive_user_input() which calls xQueueReceives() with a 0 timeout to get the direction<br />
# Game logic uses the direction value to make a movement <br />
<br />
''' Interrupt Service Routines, FreeRTOS Binary Semaphore, and User Button Input Logic: '''<br />
# Player pushes button during menu select<br />
# ISR runs and calls xSemaphoreGiveFromISR()<br />
# Game logic calls function receive_user_button_input() which calls xSemaphoreTake() with a 0 timeout<br />
# If xSemaphoreTake() returns true, an action such as selecting game mode is done to change the state of the game state machine<br />
<br />
{|<br />
|[[File:Joystick_interrupt_processing.jpg | thumb|400px| '''Player's Joystick Input Processing''']] <br />
|[[File:Button_interrupt_processing.jpg | thumb|400px| '''Player's Button Input Processing''']] <br />
|}<br />
<br />
=== Game Software Design ===<br />
Show your software design. For example, if you are designing an MP3 Player, show the tasks that you are using, and what they are doing at a high level. Do not show the details of the code. For example, do not show exact code, but you may show psuedocode and fragments of code. Keep in mind that you are showing DESIGN of your software, not the inner workings of it.<br />
<br />
====== Core Game Design ======<br />
The game logic runs on a tick system, updating the players location after a certain amount of ticks has passed.<br />
A few key attributes are required for the logic of the game to work:<br />
*Each player has a speed (either 2 ticks for slow or 1 tick for fast)<br />
**This speed denotes how many game ticks must occur before the player is moved.<br />
**This tick count is stored in each players' game object.<br />
*Drawn Direction and New Direction<br />
**Drawn direction represents the way the player was facing, used to keep track of what pixels need to be cleared when movement occurs.<br />
**New direction represents the input from the player to change directions after their tick count has reached zero. As a rule, the input will be ignored if the player attempts to go backwards directly onto their drawn trail.<br />
<br />
====== Game Controller State Machine ======<br />
<br />
[[file:SpaceRageGameControllerStateMachine.jpg | thumb|450px| center| ''' Game State Machine''']]<br />
The Game Controller is the state machine that makes the game operate as a whole, with menus, sounds, and input.<br />
Each state is simplified in the diagram to its core functionality.<br />
<br />
The title screen is the background for both the player select screen and mode select screen, as visible in the main menu screenshots. <br />
The user is able to move the joystick up or down in these menus to the choices they want to select, then they hit the button on the controller to accept that choice.<br />
Once selections has been made for both menus, the round will begin.<br />
The lives screen shows up between rounds and displays how many lives each player has, represented as hearts. When a player crashes the heart is either faded out or faded out then exploded to represent the loss of a life. <br />
Once either one or both of the players has lost all 3 lives, the game over screen will display who won or a draw (in the case of both players losing all three lives).<br />
Each of these screens, the selections, and the winning player is played out of both of the sound effect speakers, with a slight delay on one to give it the arcade sound effect feel.<br />
<br />
<br />
[[file:SpaceRagePlayRound.jpg | thumb|450px| center| ''' Play Round Logic''']]<br />
The logic presented here is slightly simplified, but the main components are displayed.<br />
At the start of the round the 3,2,1,Go! animation plays to warn the character when the round is about to start.<br />
The controls for the player are interrupt driven, putting the direction moved on the joystick into a queue of size 1 for the game controller to interpret. The input is ignored if the player did attempt to go backwards.<br />
When the player is ticked twice (while not holding the button in turbo mode and all the time in classic mode) the game controller will set the new direction for the player. If this new direction would send the player into a wall, the player is considered to have crashed. Once this happens the game state will change to the Lives Screen, where the remaining lives of the player are presented.<br />
<br />
====== AI logic ======<br />
There are three main functions utilized as shown:<br />
<br />
<br />
[[File:SpaceRageAiLogic.jpg | thumb|900px| center| ''' AI core functions''']]<br />
<br />
The normal computer uses simple survival and educated turning to survive. To make the bot slightly less predictable, the bot has a 3% chance to turn either left or right, based off the educated turning model. This will still likely result in human being able to easily defeat the bot. The major intention on with this difficulty is to allow the player to practice the game without fear of the other player being too aggressive.<br />
<br />
The hard computer uses a state machine to commence it's attack. It starts by cutting directly down from the top left corner to the bottom right corner, making near impossible turns to cut the board perfectly in half. Once the opponent is either 25 pixels above (or greater) or 25 pixels to the left (or greater) of the player, the computer will either head directly east or directly south, respectively, to cut down the size of the arena. The original intention was to then have the bot simply go to the larger area and survive, since it can play nearly perfectly. This still does happen occasionally, but in certain circumstances the bot will turn into the area where the other player is. This results in rather intense competition. The adjustments were going to be made to ensure just the perfect play would take place, but after testing with the current state, it was found to be more fun to have the bot take either path, as it was much more unpredictable.<br />
<br />
== Testing & Technical Challenges ==<br />
Describe the challenges of your project. What advise would you give yourself or someone else if your project can be started from scratch again?<br />
Make a smooth transition to testing section and described what it took to test your project.<br />
<br />
Include sub-sections that list out a problem and solution, such as:<br />
=== Main Suggestions ===<br />
Make sure you write modular code. Keep functions short and simple to start. The most used function in our project was the function to write to the 64x64 array that represented our display: led_display__draw_pixel. With this simple interface between the LED matrix and the rest of the code allowed for other functions to be written to take care of drawing images of different sizes easily. <br />
<br />
Keeping code simple and using a naming convention that called for a description of what the function was doing allowed for rapid development with little to no debugging required. <br />
<br />
=== AI ===<br />
Figuring out the logic for a computer opponent in a game such as ours is a difficult task. To figure out how to optimize a bot, you must figure out various strategies the computer should employ and allow the bot to have as much or more knowledge of the game state as a human would have while playing. <br />
For our purposes, the simplest of computer difficulties basically plays without knowledge of the opponent's actions. This results in a very easy to trap opponent. <br />
Once we added in more knowledge for the AI, a viscous attack strategy was able to be formulated and the bot then took on the elements of a state machine. The initial part of the attack involved getting to the opposite bottom corner as fast as possible, going right down the middle of the screen making humanly impossible turns. Once the bot reached a close enough location to the other player, it would then decide (almost randomly, the algorithm is a bit complex) to either:<br />
*Go to the section of the screen the other player was not in and play a survival game, one a human is likely to lose.<br />
*Or join the player in the section and attempt to survive.<br />
The original intention was to force the bot to take the first option every time, but due the suggestion algorithm not responding exactly as intended, the bot can do either option listed previously. This bug actually made the experience more enjoyable and gave some variance to the bot's play style. The main take away from this section should be that not every not every bug is a fatal error when programming a game. The code was sufficiently tested to reasonably assert than no other crash happens because of the AI decisions.<br />
<br />
== Conclusion ==<br />
Conclude your project here. You can recap your testing and problems. You should address the "so what" part here to indicate what you ultimately learnt from this project. How has this project increased your knowledge?<br />
<br />
=== Project Video ===<br />
* [https://drive.google.com/file/d/1308neMjvFrtu6W8VKIW4RWXwvWXKZ73Y/view?usp=sharing Video Demo]<br />
<br />
=== Project Source Code ===<br />
* [https://gitlab.com/cmpe244spacerage/sjtwo-space-rage Space Rage Main Board Link]<br />
<br />
== References ==<br />
=== Acknowledgement ===<br />
Any acknowledgement that you may wish to provide can be included here.<br />
<br />
=== References Used ===<br />
List any references used in project.<br />
<br />
=== Appendix ===<br />
You can list the references you used.</div>Proj user2