Difference between revisions of "S22: Firebolt"

From Embedded Systems Learning Academy
Jump to: navigation, search
(Software Design)
Line 58: Line 58:
 
! scope="col"| Week#
 
! scope="col"| Week#
 
! scope="col"| Start Date
 
! scope="col"| Start Date
! scope="col"| End Date  
+
! scope="col"| End Date
 
! scope="col"| Task
 
! scope="col"| Task
 +
! scope=:col"| Actual Completion
 
! scope="col"| Status
 
! scope="col"| Status
 
|-
 
|-
! scope="row"| 1
+
! scope="row"| 1  
|
+
03/01 to 03/07
  <div style="text-align:center">02/15/2021</div>
+
<font color = "sienna"> ''Start of Phase 1''</font color>
 +
|
 +
* 03/01
 +
* 03/04
 +
* 03/05
 +
|
 +
* 03/04
 +
* 03/07
 +
* 03/07
 
|
 
|
  <div style="text-align:center">02/21/2021</div>
+
* Study and discuss previous project reports
 +
* Brainstorm on the requirements for the project
 +
* Identify and order/purchase the required components
 
|
 
|
* Read previous projects to understand what is expected and have some meaningful knowledge by first meeting. Assign roles.
+
* 03/04
 +
* 03/07
 +
*<font color = "maroon"> 03/09
 
|  
 
|  
* <span style="color:green">Completed</span>
+
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 
|-
 
|-
 
! scope="row"| 2
 
! scope="row"| 2
|  
+
03/08 to 03/14
  <div style="text-align:center">02/22/2021</div>
+
|
|  
+
* 03/08
  <div style="text-align:center">02/28/2021</div>
+
* 03/08
 +
* 03/11
 +
* 03/12
 +
|
 +
* 03/08
 +
* 03/08
 +
* 03/14
 +
* 03/14
 
|
 
|
*Acquire parts: Canbus modules, GPS module, Ultrasonic module, Bluetooth module, Car frame, and LCD display
+
* Create and setup Gitlab Repository
*Conduct meeting: Discuss GitLab layout and expectation of each assigned role
+
* Create and setup Confluence for document collaboration
 +
* Study the datasheets and manual of acquired components
 +
* Distribute initial roles among the team members
 
|
 
|
* <span style="color:green">Completed</span>
+
* 03/04
* <span style="color:green">Completed</span>
+
* 03/07
 +
* 03/17
 +
* 03/15
 +
|
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 
|-
 
|-
 
! scope="row"| 3
 
! scope="row"| 3
 +
03/15 to 03/21
 
|
 
|
  <div style="text-align:center">03/01/2021</div>
+
* 03/15
 +
* 03/15
 +
* 03/19
 +
* 03/18
 +
* 03/15
 
|
 
|
  <div style="text-align:center">03/07/2021</div>
+
* 03/18
 +
* 03/18
 +
* 03/21
 +
* 03/21
 +
* 03/27
 
|
 
|
*Purchased RC car and batteries.
+
* Interface ultrasonic sensors and test the functionality
*<span style="color:black">Acquired Bluetooth connector from Preet</span>
+
* Interface GPS and Compass and test the functionality
*<span style="color:black">Acquired PCAN dongle from Preet</span>
+
* Analyze and decide the hardware placement of the RC Car
*<span style="color:black">Get familiar with CAN tools</span>
+
* Create SENSOR and DRIVER nodes to transmit and receive data
*<span style="color:black">Using previous projects, determine what works needs to be completed for main board. Bring findings to weekly meeting</span>
+
* Identify the Android app requirements and start studying the Android framework
 
|
 
|
* <span style="color:Red">Not Completed</span>
+
* 03/18
* <span style="color:Red">Not Completed</span>
+
* <font color = 'maroon'> 03/22 </font>
* <span style="color:Red">Not Completed</span>
+
* 03/20
* <span style="color:Red">Not Completed</span>
+
* 03/21
* <span style="color:Red">Not Completed</span>
+
* 03/25
 +
|
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 
|-
 
|-
 
! scope="row"| 4
 
! scope="row"| 4
 +
03/22 to 03/28
 
|
 
|
  <div style="text-align:center">03/08/2021</div>
+
* 03/22
 +
* 03/22
 +
* 03/25
 +
* 03/27
 +
* 03/22
 
|
 
|
  <div style="text-align:center">03/14/2021</div>
+
* 03/25
 +
* 03/24
 +
* 03/28
 +
* 03/31
 +
* 03/28
 
|
 
|
*<span style="color:black">Decide roles and responsibilities for each team member</span>
+
* Create the GEO node to get coordinates and cardinal directions from GPS and Compass
*<span style="color:black">Discuss DBC file for the project and start working on DBC file </span>
+
* Interface the Bluetooth module to communicate with SJ-two board
*<span style="color:black">Begin laying out hardware requirements for PCB on excel document</span>
+
* Create the MOTOR node to drive the RC Car
 +
* Start designing the DBC file
 +
* Develop an initial version of the Android app
 
|
 
|
* <span style="color:Red">Not Completed</span>
+
* <font color = 'maroon'>03/24</font>  
* <span style="color:Red">Not Completed</span>
+
* 03/24
* <span style="color:Red">Not Completed</span>
+
* 03/28
 +
* 03/30
 +
* 03/28
 +
|
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 
|-
 
|-
 
! scope="row"| 5
 
! scope="row"| 5
 +
03/29 to 04/04
 +
<font color = "sienna"> ''End of Phase 1''</font color>
 
|
 
|
  <div style="text-align:center">03/15/2021</div>
+
* 04/02
 +
* 03/29
 +
* 03/29
 +
* 03/29
 +
* 03/31
 +
* 04/03
 
|
 
|
  <div style="text-align:center">03/21/2021</div>
+
* 04/03
 +
* 04/01
 +
* 04/01
 +
* 04/01
 +
* 04/03
 +
* 04/04
 
|
 
|
*<span style="color:black">Start working on Motor control API</span>
+
* Finalize the DBC file
*<span style="color:black">Finish research on application building with android studio. Install android studio and necessary dependencies</span>
+
* Design obstacle avoidance and steering logic on the DRIVER node
*<span style="color:black">Implement a simple application with a button and text</span>
+
* Design motor driving logic on the MOTOR node with the encoder
*<span style="color:black">Start researching on Wheel encoder according to the requirement</span>
+
* Interface the LCD module with the DRIVER node to display messages
*<span style="color:black">Unit Test Direction Distance Calculation Module. Manual calculation of data should match module output</span>
+
* Integrate sensor data on the SENSOR node
*<span style="color:black">Begin coding and digesting adafruit Compass data. Print Compass data.</span>
+
* '''Collective Test 1:'''<font color = "DarkGreen"> '''Integrate all the completed modules and test on BusMaster''' </font color>
 
|
 
|
* <span style="color:Red">Not Completed</span>
+
* <font color = 'maroon>04/05</font>
* <span style="color:Red">Not Completed</span>
+
* 04/01
* <span style="color:Red">Not Completed</span>
+
* 04/01
* <span style="color:Red">Not Completed</span>
+
* 04/01
* <span style="color:Red">Not Completed</span>
+
* <font color = 'maroon'>04/04</font>
* <span style="color:Red">Not Completed</span>
+
* 04/04
 +
|
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 
|-
 
|-
 
! scope="row"| 6
 
! scope="row"| 6
 +
04/05 to 04/11
 +
<font color = "magenta">''Start of Phase 2''</font color>
 
|
 
|
  <div style="text-align:center">03/22/2021</div>
+
* 04/05
 +
* 04/05
 +
* 04/08
 +
* 04/10
 
|
 
|
  <div style="text-align:center">03/28/2021</div>
+
* 04/08
 +
* 04/08
 +
* 04/10
 +
* 04/11
 
|
 
|
*<span style="color:black">Acquire sensor and interface sensors to SJ2 Board and receive raw data</span>
+
* Tune the SENSOR and DRIVER nodes to drive the RC car
*<span style="color:black">Implement basic communication between board and app</span>
+
* Communicate to the DRIVER node over Bluetooth via Android app
*<span style="color:black">Update Wiki with proper software diagrams for GPS and Compass data flow</span>
+
* Debug and revise the integrated modules with necessary improvements
*<span style="color:black">Begin Mapping out pins used on all board</span>
+
* '''Collective Test 2''':<font color = "DarkGreen">''' Drive the car to a hardcoded GPS destination'''</font color>  
*<span style="color:black">Complete a block diagram and a control scheme</span>
 
<ol>
 
<li style="color:black">Top Level Driver Logic diagram</li>
 
<li style="color:black">Periodic Callback Functions Diagram</li>
 
</ol>
 
*<span style="color:black">Create a basic Obstacle avoidance algorithm for Driver</span>
 
*<span style="color:black">Probe RC car to determine expected behavior of signals and install RPM sensor</span>
 
*<span style="color:black">Write motor controller modules and tests</span>
 
 
|
 
|
* <span style="color:Red">Not Completed</span>
+
* 04/08
* <span style="color:Red">Not Completed</span>
+
* 04/08
* <span style="color:Red">Not Completed</span>
+
* 04/08
* <span style="color:Red">Not Completed</span>
+
* 04/08
* <span style="color:Red">Not Completed</span>
+
|
* <span style="color:Red">Not Completed</span>
+
*<font color = "green"> Completed
* <span style="color:Red">Not Completed</span>
+
*<font color = "green"> Completed
* <span style="color:Red">Not Completed</span>
+
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 
|-
 
|-
 
! scope="row"| 7
 
! scope="row"| 7
|  
+
04/12 to 04/18
  <div style="text-align:center">03/29/2021</div>
+
|
 +
* 04/12
 +
* 04/15
 +
* 04/12
 +
* 04/17
 
|
 
|
  <div style="text-align:center">04/04/2021</div>
+
* 04/15
 +
* 04/18
 +
* 04/16
 +
* 04/18
 
|
 
|
*<span style="color:black">Discuss and construct DBC file</span>
+
* Integrate GEO node to DRIVER node for navigation
*<span style="color:black">Create sensor API to parse raw data and convert into inches</span>
+
* Design driving decision logic based on the navigation data
*<span style="color:black">Integrate google map features into app</span>
+
* Design a dashboard on the LCD to display the values
*<span style="color:black">Integration testing of motor controller logic</span>
+
* '''Collective Test 3''':<font color = "DarkGreen">''' Test the car driving with navigation data from the Android app'''</font color>
*<span style="color:black">Create a Checkpoint Navigation algorithm for Driver</span>
 
 
|
 
|
* <span style="color:Red">Not Completed</span>
+
* 04/15
* <span style="color:Red">Not Completed</span>
+
* 04/18
* <span style="color:Red">Not Completed</span>
+
* 04/16
* <span style="color:Red">Not Completed</span>
+
* 04/18
* <span style="color:Red">Not Completed</span>
+
|
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 
|-
 
|-
 
! scope="row"| 8
 
! scope="row"| 8
|
+
04/19 to 04/25
  <div style="text-align:center">04/05/2021</div>
+
<font color = "magenta">''End of Phase 2''</font color>
 +
|
 +
* 04/19
 +
* 04/19
 +
* 04/19
 +
* 04/19
 
|
 
|
  <div style="text-align:center">04/11/2021</div>
+
* 04/25
 +
* 04/25
 +
* 04/25
 +
* 04/25
 
|
 
|
*<span style="color:black">Finish implementation of canbus between controllers and begin real world testing</span>
+
* Add functionalities to display various sensor data on the Android app
*<span style="color:black">3D print sensor mounts, sensor guards, and draft sensor offset timing to deter sensor cross talk</span>
+
* Design and 3D print the required components
*<span style="color:black">Finish integrating wheel encoder and display speed on SJTwo Telemetry</span>
+
* Design and order PCB
*<span style="color:black">Establish Communication between the LCD display and Master Board over I2C</span>
+
* Test and improve the RC car performance based on the changes
 
|
 
|
* <span style="color:Red">Not Completed</span>
+
* 04/25
* <span style="color:Red">Not Completed</span>
+
*
* <span style="color:Red">Not Completed</span>
+
* 04/25
* <span style="color:Red">Not Completed</span>
+
* 04/25
 +
|
 +
*<font color = "green"> Completed
 +
*<font color = "red"> Incomplete
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 
|-
 
|-
 
! scope="row"| 9
 
! scope="row"| 9
|
+
04/26 to 05/02
  <div style="text-align:center">04/12/2021</div>
+
<font color = "Tomato">''Start of Phase 3''</font color>
 
|
 
|
  <div style="text-align:center">04/18/2021</div>
+
* 04/26
 +
* 04/26
 +
* 04/26
 +
* 05/01
 
|
 
|
*<span style="color:black">Integrate Driver, Geo, Bridge sensor, and Motor nodes. Successful communication between all boards.</span>
+
* 04/30
*<span style="color:black">Implement Kill button on app for emergency stop</span>
+
* 04/30
*<span style="color:black">Analyze noise in sensor values and design a filter to mitigate the noise</span>
+
* 04/30
*<span style="color:black">Complete "Self Test" for motor test(DC motor moves forward and backwards and servo moves right - left)</span>
+
* 05/02
*<span style="color:black">Start working on PID control algorithm. Design bare skeleton for workflow</span>
 
*<span style="color:black">Create an algorithm to account for speed when the car is on an incline</span>
 
 
|
 
|
* <span style="color:Red">Not Completed</span>
+
* Design individual architecture diagrams and algorithms for documentation
* <span style="color:Red">Not Completed</span>
+
* Make any necessary improvements based on previous test results
* <span style="color:Red">Not Completed</span>
+
* Complete the final version of the Android app
* <span style="color:Red">Not Completed</span>
+
* '''Collective Test 4:'''<font color = "DarkGreen">''' Test car on various terrains and slopes'''</font color>
* <span style="color:Red">Not Completed</span>
 
* <span style="color:Red">Not Completed</span>
 
 
 
|-
 
! scope="row"| 10
 
|
 
  <div style="text-align:center">04/19/2021</div>
 
 
|
 
|
  <div style="text-align:center">05/25/2021</div>
+
* 04/30
|
+
* 04/30
*<span style="color:black">Begin to analysis real world tests from previous weeks implementation and perform fixes for issues faced</span>
+
* 04/30
*<span style="color:black">Ensure Canbus nodes are communicating correctly by verifying PCON data. Verify that timing for data is correct</span>
+
* 05/02
*<span style="color:black">Added CAN debug messages</span>
 
*<span style="color:black">Start working on the PCB, order the PCB and also purchase the required components </span>
 
*<span style="color:black">Integration testing with obstacle avoidance.</span>
 
<ol>
 
<li style="color:black">Analyze possible blind spots and make adjustments to sensor placements. </li>
 
<li style="color:black">Analyze sensor response time and data while rc car is moving and make adjustments if needed.</li>
 
</ol>
 
*<span style="color:black">Display relevant Motor and Checkpoint Information to the LCD.</span>
 
*<span style="color:black">Tuned and tested PID on RC Car (More refinement needed)</span>
 
|
 
* <span style="color:Red">Not Completed</span>
 
* <span style="color:Red">Not Completed</span>
 
*<span style="color:Red">Not Completed</span>
 
*<span style="color:Red">Not Completed</span>
 
*<span style="color:Red">Not Completed</span>
 
*<span style="color:Red">Not Completed</span>
 
*<span style="color:Red">Not Completed</span>
 
* <span style="color:Red">Not Completed</span>
 
*<span style="color:Red">Not Completed</span>
 
|-
 
! scope="row"| 11
 
 
|  
 
|  
  <div style="text-align:center">04/26/2021</div>
+
*<font color = "green"> Completed
|
+
*<font color = "green"> Completed
  <div style="text-align:center">05/02/2021</div>
+
*<font color = "green"> Completed
|
+
*<font color = "green"> Completed
*<span style="color:black">Perform more real world tests and isolate bugs. Update issues for bugs find during real world test</span>
 
*<span style="color:black">Perform final bug fixes, as listed under issues, for all Canbus nodes. </span>
 
*<span style="color:black">Integrate all the parts on the PCB. </span>
 
|
 
* <span style="color:Red">Not Completed</span>
 
* <span style="color:Red">Not Completed</span>
 
* <span style="color:Red">Not Completed</span>
 
 
|-
 
|-
! scope="row"| 12
+
! scope="row"| 10
|
+
05/03 to 05/09
  <div style="text-align:center">05/03/2021</div>
 
|
 
  <div style="text-align:center">05/09/2021</div>
 
 
|
 
|
*<span style="color:black">Update Wiki Report to reflect all changes and include final testing video</span>
+
* 05/03
*<span style="color:black">Perform final code changes and commit to master branch</span>
+
* 05/03
*<span style="color:black">Received manufactured PCB, installed, and integration tested</span>
+
* 05/03
*<span style="color:black">Refactored motor controller code and wrote much needed unit tests</span>
+
* 05/08
*<span style="color:black">Finished tuning PID and tested RC Car driving on slope</span>
 
 
|
 
|
* <span style="color:Red">Not Completed</span>
+
* 05/07
* <span style="color:Red">Not Completed</span>
+
* 05/07
* <span style="color:Red">Not Completed</span>
+
* 05/07
* <span style="color:Red">Not Completed</span>
+
* 05/09
* <span style="color:Red">Not Completed</span>
 
|-
 
! scope="row"| 13
 
|
 
  <div style="text-align:center">05/10/2021</div>
 
 
|
 
|
  <div style="text-align:center">05/16/2021</div>
+
* Replace the circuits with their corresponding PCBs and assemble
 +
* Complete the RC Car structure and assembly with the 3D printed parts - Prototype 1
 +
* Refactor the code modules with necessary improvements
 +
* '''Collective Test 5:'''<font color = "DarkGreen">''' Test the Prototype 1 with the aim of sending the car to return Preet's PCAN Dongle'''</font color>
 
|
 
|
*<span style="color:black">Update Wiki schedule and begin draft for individual controller documentation</span>
+
* 05/07
 +
* 05/07
 +
* 05/07
 +
* 05/09
 
|
 
|
* <span style="color:Red">Not Completed</span>
+
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 +
*<font color = "brown"> Deferred
 
|-
 
|-
! scope="row"| 14
+
! scope="row"| 11
|
+
05/10 to 05/16
  <div style="text-align:center">05/17/2021</div>
+
<font color = "Tomato">''End of Phase 3''</font color>
|
 
  <div style="text-align:center">05/23/2021</div>
 
 
|
 
|
*<span style="color:black">Update Wiki individual controller and general documentation</span>
+
* 05/10
*<span style="color:black">Last minute bug fixes/refining</span>
+
* 05/10
*<span style="color:black">Waypoint algorithm integration and test</span>
+
* 05/10
*<span style="color:black">Last minute bug fixes/refining & code cleanup</span>
+
* 05/15
 
|
 
|
* <span style="color:Red">Not Completed</span>
+
* 05/16
* <span style="color:Red">Not Completed</span>
+
* 05/16
* <span style="color:Red">Not Completed</span>
+
* 05/16
* <span style="color:Red">Not Completed</span>
+
* 05/16
* <span style="color:Red">Not Completed</span>
 
|-
 
! scope="row"| 15
 
|
 
  <div style="text-align:center">05/27/2021</div>
 
 
|
 
|
  <div style="text-align:center">05/30/2021</div>
+
* Revise and improve the wiki report to cover all the aspects of design and implementation
 +
* Fix all the errors and make improvements
 +
* Final testing of all the modules and car
 +
* '''Collective Test 6:'''<font color = "DarkGreen">''' Have the final version of the project tested with all the functionalities'''</font color>
 
|
 
|
*<span style="color:black">Demo Project</span>
+
* 05/16
*<span style="color:black">Finalize Wiki Documentation</span>
+
* 05/16
 +
* 05/16
 +
* 05/16
 
|
 
|
* <span style="color:Red">Not Completed</span>
+
*<font color = "green"> Completed
* <span style="color:Red">Not Completed</span>
+
*<font color = "green"> Completed
|-
+
*<font color = "green"> Completed
 +
*<font color = "green"> Completed
 
|}
 
|}
  
Line 327: Line 400:
 
|-
 
|-
 
! scope="col"| Item#
 
! scope="col"| Item#
! scope="col"| Part Description
+
! scope="col"| Part Desciption
 
! scope="col"| Vendor
 
! scope="col"| Vendor
 
! scope="col"| Qty
 
! scope="col"| Qty
Line 333: Line 406:
 
|-
 
|-
 
! scope="row"| 1
 
! scope="row"| 1
| Traxxas 1/10 Scale RC Short Truck
+
| RC Car
| Traxxas [https://traxxas.com/products/models/electric/58034-1slash]
+
| Traxxas [https://www.amazon.com/gp/product/B07DFXN118/ref=ppx_yo_dt_b_asin_title_o06_s00?ie=UTF8&psc=1]
 
| 1
 
| 1
| $239.99 + Tax
+
| $250.00
 
|-
 
|-
 
! scope="row"| 2
 
! scope="row"| 2
| RPM Sensor & Mount
+
| CAN Transceivers MCP2551-I/P
| Traxxas [https://traxxas.com/sites/default/files/Rustler-Bandit-Stampede-Slash%20RPM%20Sensor%20Installation.pdf]
+
| Comimark [https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/ref=sr_1_4?crid=L6PXVWD9BFTN&dchild=1&keywords=can+transceiver&qid=1621786818&sprefix=can+trans%2Caps%2C566&sr=8-4]
| 1
+
| 5
| $19.00 + Tax
+
| $7.00
 
|-
 
|-
 
! scope="row"| 3
 
! scope="row"| 3
| 2S 7.4V 5000mAh LiPo Battery Pack
+
| Ultrasonic Sensors
| Amazon [https://www.amazon.com/gp/product/B00WOAWHUK]
+
| Max Botix[https://www.amazon.com/gp/product/B07Q588SBP/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1]
| 2
+
| 5
| $40.69 + Tax
+
| $150.00
 
|-
 
|-
 
! scope="row"| 4
 
! scope="row"| 4
| Bluetooth Adapter
+
| GPS and Antenna
| Amazon [https://www.amazon.com/DSD-TECH-HC-05-Pass-through-Communication/dp/B01G9KSAF6]
+
| Adafruit[https://www.amazon.com/Adafruit-Ultimate-GPS-Breakout-External/dp/B00I6LZW4O/ref=sr_1_7?dchild=1&keywords=adafruit+gps&qid=1622071143&sr=8-7]
 
| 1
 
| 1
| $8.99 + Tax
+
| $60.00
 
|-
 
|-
 
! scope="row"| 5
 
! scope="row"| 5
| Adafruit Ultimate GPS Breakout
+
| HC05 bluetooth RF Transreceiver
| Adafruit [https://www.adafruit.com/product/746]
+
| HiLetgo[https://www.amazon.com/HiLetgo-Bluetooth-Transceiver-Integrated-Communication/dp/B07VL725T8/]
 
| 1
 
| 1
| $39.95
+
| $12.59
 
|-
 
|-
 
! scope="row"| 6
 
! scope="row"| 6
| Adafruit Triple-axis Accelerometer+Magnetometer
+
| Triple-axis Accelerometer
| Adafruit [https://www.adafruit.com/product/1120]
+
| Adafruit[https://www.adafruit.com/product/1120]
 
| 1
 
| 1
| $14.95
+
| $21.40
 
|-
 
|-
! scope="row"|7
+
! scope="row"| 7
| Deans Connector
+
| Traxxas RPM Sensor
| Amazon [https://www.amazon.com/gp/product/B07QM1WS2J/ref=ox_sc_act_title_1?smid=A1JTH8JAMM4IYJ&psc=1]
+
| Traxxas[https://www.amazon.com/Traxxas-6520-RPM-Sensor-long/dp/B006IRXEZM]
 
| 1
 
| 1
| $8.99 + Tax
+
| $12
 
|-
 
|-
! scope="row"|8
+
! scope="row"| 8
| Pololu 5V Voltage Regulator
+
| Discrete Electronic Components
| Pololu [https://www.pololu.com/product/2836]
+
| Generic[http://www.excesssolutions.com/]
 
| 1
 
| 1
| $10.83
+
| $28.75
 
|-
 
|-
! scope="row"|9
+
! scope="row"| 9
| PCB
+
| Buck-Boost Voltage Regulator
| JLCPCB [https://jlcpcb.com/]
+
| Generic[https://www.amazon.com/Adjustable-Converter-Automatic-Voltage-Regulator/dp/B07NTXSJHB/]
 
| 1
 
| 1
| $40.00 
+
| $11.99
 
|-
 
|-
! scope="row"|10
+
! scope="row"| 10
| CAN transceiver
+
| Traxxas Telemetry Trigger magnet & holder
| Amazon [https://www.amazon.com/SN65HVD230-CAN-Board-Communication-Development/dp/B00KM6XMXO/ref=sr_1_1?dchild=1&keywords=can+waveshare&qid=1622233988&sr=8-1]
+
| Traxxas[https://www.amazon.com/Traxxas-Telemetry-Trigger-Magnet-Holder/dp/B00864A3T0/]
| 4
+
| 1
| $40.00 
+
| $6.35
 +
|-
 +
! scope="row"| 11
 +
| Acrylic Sheet
 +
| Tap Plastic
 +
| 1
 +
| $12
 +
|-
 +
! scope="row"| 12
 +
| Battery
 +
| Amazon[https://www.amazon.com/dp/B07LGZGG7T?ref=ppx_pop_mob_ap_share]
 +
| 1
 +
| $26.99
 +
|-
 +
! scope="row"| 13
 +
| Traxxas Battery and Charger
 +
| Amazon[https://www.amazon.com/dp/B074FXXP5J/ref=cm_sw_r_wa_api_glt_fabc_TQCR9J50NFX7VYE33PWB?_encoding=UTF8&psc=1]
 +
| 1
 +
| $55.94
 
|-
 
|-
! scope="row"|11
 
| Maxbotix MB1010 LV-MaxSonar-EZ1 Ultra Sonic Sensors
 
| Maxbotix [https://www.maxbotix.com/Ultrasonic_Sensors/MB1010.htm]
 
| 5
 
| $121.50 
 
 
|}
 
|}
  
Line 403: Line 489:
  
 
== Printed Circuit Board  ==
 
== Printed Circuit Board  ==
 +
<h4>PCB Schematic</h4>
 +
[[File:RoadsterSchematic.png|center|thumb|800px| Roadster Schematic]]
 +
<h4>PCB Design</h4>
 +
[[File:RoadsterPCB.png|center | 1200px| Roadster PCB]]
 +
 +
== CAN Communication ==
 +
We use controller area network to broadcast data between the 4 nodes. All nodes are connected to each other through a physically conventional two wire bus. The wires are a twisted pair with 120 Ω resistors at each ends of the bus. 1s and 0s are transmitted as CAN High(0V difference) and Can Low(2v difference).
 +
A CAN frame has the following contents:
 +
* Data Length Code (4bits)
 +
* Remote Transmission Request.
 +
* ID extend bit.
 +
* Message ID (11 bit or 29 bit)
 +
* Data bytes( depends on DLC)
 +
* CRC
  
  
 +
'''Arbitration''': No two nodes will transmit at the same time because if arbitration. A lower Message-ID has a Higher priority on the CAN bus since 0 is the dominant bit.
  
 +
'''Bit Stuffing''': CAN bus stuffs extra bits when a long chain of multiple 1's or 0's occur to improve CAN integrity.
  
 +
{| class="wikitable"
 +
|-
 +
! scope="col"| Sr. No
 +
! scope="col"| Message ID
 +
! scope="col"| Message function
 +
! scope="col"| Receivers
 +
|-
 +
|-
 +
|-
 +
|-
 +
! colspan="4"| Driver Controller
 +
|-
 +
|-
 +
|1
 +
|300
 +
|speed and steering direction for the motor.
 +
|Motor
 +
|-
 +
|2
 +
|310
 +
|Destination reached
 +
|Sensor
 +
|-
 +
|-
 +
! colspan="4"| Sensor Controller
 +
|-
 +
|-
 +
|1
 +
|200
 +
|Sensor sonars from front, back, left ,right sensor
 +
|Driver
 +
|-
 +
|-
 +
! colspan="4"| Motor Controller
 +
|-
 +
|-
 +
|8
 +
|700
 +
|motor speed, motor direction
 +
|Driver
 +
|-
 +
|-
 +
! colspan="4"| Geo and Bridge Controller
 +
|-
 +
|-
 +
|1
 +
|400
 +
|Bearing, Heading and Distance
 +
|Driver
 +
|-
 +
|-
 +
! colspan="4"| Debug messages
 +
|-
 +
|-
 +
|1
 +
|851
 +
|Driver Debug
 +
|SENSOR,MOTOR,GEO_AND_BRIDGE
 +
|-
 +
|-
 +
|1
 +
|811
 +
|Motor Debug
 +
|SENSOR,MOTOR,GEO_AND_BRIDGE
 +
|-
 +
|-
 +
|1
 +
|801
 +
|Sensor Debug
 +
|SENSOR,MOTOR,GEO_AND_BRIDGE
 +
|-
 +
|-
 +
|}
  
  
=== Challenges ===
+
=== Hardware Design ===
  
<hr>
+
[[File:roadstercan.png|center|500px|thumb|CAN Bus Design]]
<br>
 
  
==Fabrication==
+
<br/>
  
 +
=== DBC File ===
  
 +
<syntaxhighlight lang=c>
 +
VERSION ""
  
'''PCB Properties:''' <br/>
+
NS_ :
 +
BA_
 +
BA_DEF_
 +
BA_DEF_DEF_
 +
BA_DEF_DEF_REL_
 +
BA_DEF_REL_
 +
BA_DEF_SGTYPE_
 +
BA_REL_
 +
BA_SGTYPE_
 +
BO_TX_BU_
 +
BU_BO_REL_
 +
BU_EV_REL_
 +
BU_SG_REL_
 +
CAT_
 +
CAT_DEF_
 +
CM_
 +
ENVVAR_DATA_
 +
EV_DATA_
 +
FILTER
 +
NS_DESC_
 +
SGTYPE_
 +
SGTYPE_VAL_
 +
SG_MUL_VAL_
 +
SIGTYPE_VALTYPE_
 +
SIG_GROUP_
 +
SIG_TYPE_REF_
 +
SIG_VALTYPE_
 +
VAL_
 +
VAL_TABLE_
  
==Power Management==
+
BS_:
  
==Challenges==
+
BU_: DRIVER MOTOR SENSOR GEO_AND_BRIDGE DEBUG
  
 +
BO_ 200 SENSOR_SONARS: 5 SENSOR
 +
SG_ SENSOR_SONARS_left : 0|10@1+ (1,0) [0|800] "cm" DRIVER
 +
SG_ SENSOR_SONARS_right : 10|10@1+ (1,0) [0|0] "cm" DRIVER
 +
SG_ SENSOR_SONARS_middle : 20|10@1+ (1,0) [0|0] "cm" DRIVER
 +
SG_ SENSOR_SONARS_rear : 30|10@1+ (1,0) [0|0] "cm" DRIVER
  
<HR>
+
BO_ 300 DRIVER_TO_MOTOR: 2 DRIVER
<BR/>
+
SG_ MOTOR_speed : 0|8@1+ (0.1,-12.5) [-12.5|12.5] "m/s" MOTOR
 +
SG_ MOTOR_direction : 8|7@1+ (1,-45) [-45|45] "degree" MOTOR
  
== CAN Communication ==
+
BO_ 310 DRIVER_BROADCAST: 1 DRIVER
 +
SG_ DEST_reached : 0|8@1+ (1,0) [0|0] "flag" SENSOR
  
 +
BO_ 400 GEO_CONTROLLER_COMPASS: 6 GEO_AND_BRIDGE
 +
  SG_ HEADING : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER
 +
  SG_ BEARING : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER
 +
  SG_ DISTANCE : 24|17@1+ (0.01,0) [0|0] "Meters" DRIVER
  
=== Hardware Design ===
+
BO_ 401 GEO_CONTROLLER_COMPASS_DEBUG: 9 GEO_AND_BRIDGE
<Show your CAN bus hardware design>
+
  SG_ WAYPOINT_COUNT : 0|8@1+ (1,0) [0|16] "" DEBUG
<br>
+
  SG_ STATUS : 8|8@1+ (1,0) [0|359] "Degrees" DEBUG
 +
  SG_ DISTANCE_TO_WAYPOINT : 16|12@1+ (0.01,0) [0|0] "Meters" DEBUG
 +
  SG_ HEADING_TO_WAYPOINT : 28|12@1+ (1,0) [0|359] "Degrees" DEBUG
 +
  SG_ BEARING_TO_WAYPOINT : 40|12@1+ (1,0) [0|359] "Degrees" DEBUG
 +
  SG_ HEADING_RAW : 52|12@1+ (1,0) [0|359] "Degrees" DEBUG
 +
  SG_ WAYPOINT_CURRENT : 64|8@1+ (1,0) [0|16] "" DEBUG
  
=== DBC File ===
+
BO_ 700 MOTOR_TO_DRIVER: 8 MOTOR
 +
SG_ MOTOR_speed:0|8@1+ (0.1,-12.5) [-12.5|12.5] "m/s" DRIVER
 +
SG_ MOTOR_direction : 8|7@1+ (1,-45) [-45|45] "degree" DRIVER
  
 +
BO_ 851 DRIVER_DEBUG_DATA: 1 DEBUG
 +
SG_ forwardDrivingState:0|2@1+ (1,0) [0|0] "" SENSOR,MOTOR,GEO_AND_BRIDGE
 +
SG_ reverseDrivingState: 2|2@1+ (1,0) [0|0] "" SENSOR,MOTOR,GEO_AND_BRIDGE
 +
SG_ isRightSteeringPossible:4|2@1+ (1,0) [0|0] "" SENSOR,MOTOR,GEO_AND_BRIDGE
 +
SG_ isLeftSteeringPossible:6|2@1+ (1,0) [0|0] "" SENSOR,MOTOR,GEO_AND_BRIDGE
 +
 +
BO_ 801 SENSOR_DEBUG_DATA: 8 DEBUG
 +
SG_ LEFT_sensor_raw:0|16@1+ (1,0) [0|0] "cm" SENSOR,MOTOR,GEO_AND_BRIDGE
 +
SG_ RIGHT_sensor_raw: 16|16@1+ (1,0) [0|0] "cm" SENSOR,MOTOR,GEO_AND_BRIDGE
 +
SG_ FRONT_sensor_raw: 32|16@1+ (1,0) [0|0] "cm" SENSOR,MOTOR,GEO_AND_BRIDGE
 +
SG_ REAR_sensor_raw: 48|16@1+ (1,0) [0|0] "cm" SENSOR,MOTOR,GEO_AND_BRIDGE
  
 +
BO_ 811 MOTOR_DEBUG_DATA: 8 DEBUG
 +
SG_ MOTOR_rps_value:0|32@1+ (1,0) [0|0] "rps value" SENSOR,DRIVER,GEO_AND_BRIDGE
 +
SG_ MOTOR_pwm_value:32|8@1+ (0.01,0) [0|0] "dc motor pwm value" SENSOR,DRIVER,GEO_AND_BRIDGE
  
 +
BO_ 1000 DRIVER_HEARTBEAT: 1 DRIVER
 +
SG_ DRIVER_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" SENSOR,MOTOR,GEO_AND_BRIDGE
  
<HR>
+
BO_ 1100 MOTOR_HEARTBEAT: 1 DRIVER
<BR/>
+
SG_ MOTOR_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" SENSOR,DRIVER,GEO_AND_BRIDGE
  
== Sensor ECU ==
+
BO_ 1200 SENSOR_HEARTBEAT: 1 DRIVER
 +
SG_ SENSOR_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" MOTOR,DRIVER,GEO_AND_BRIDGE
  
 +
BO_ 1300 GEO_HEARTBEAT: 1 DRIVER
 +
SG_ GEO_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" SENSOR,MOTOR,DRIVER
  
=== Hardware Design ===
+
CM_ BU_ DRIVER "The driver controller driving the car";
 +
CM_ BU_ MOTOR "The motor controller of the car";
 +
CM_ BU_ SENSOR "The sensor controller of the car";
 +
CM_ BO_ 100 "Sync message used to synchronize the controllers";
 +
CM_ SG_ 100 DRIVER_HEARTBEAT_cmd "Heartbeat command from the driver";
  
+
BA_DEF_ "BusType" STRING ;
 +
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 0;
 +
BA_DEF_ SG_ "FieldType" STRING ;
  
<h5>Sensor Mounts and Placement</h5>
+
BA_DEF_DEF_ "BusType" "CAN";
 +
BA_DEF_DEF_ "FieldType" "";
 +
BA_DEF_DEF_ "GenMsgCycleTime" 0;
  
 +
BA_ "GenMsgCycleTime" BO_ 100 1000;
 +
BA_ "GenMsgCycleTime" BO_ 200 50;
 +
BA_ "FieldType" SG_ 100 DRIVER_HEARTBEAT_cmd "DRIVER_HEARTBEAT_cmd";
  
 +
VAL_ 100 DRIVER_HEARTBEAT_cmd 2 "DRIVER_HEARTBEAT_cmd_REBOOT" 1 "DRIVER_HEARTBEAT_cmd_SYNC" 0 "DRIVER_HEARTBEAT_cmd_NOOP" ;
 +
</syntaxhighlight>
  
  
 +
<HR>
 +
<BR/>
  
<h5>Sensor Range Readings Extraction</h5>
+
== Sensor ECU ==
 +
<Picture and link to Gitlab>
 +
Gitlab link to Sensor Node Firmware: https://gitlab.com/nimit.patel/roadster/-/tree/Main/Sensor_Node
  
=== Software Design ===
+
The sensor controller node is responsible for interfacing with Ultrasonic sensors to know obstacles’ distance from the vehicle. We have used MaxBotix 1010 LV-EZ1 sensors for the right and left positions and MaxBotix 1000 LV-EZ0 sensor in the middle front position (To have a wider beam range of obstacle detection in blind spots).
  
=== Technical Challenges ===
+
[[File:Sensor_Node.png|center|800px|thumb|Sensor Controller Diagram]]
  
<HR>
+
Below is the beam pattern for both sensors.
<BR/>
 
  
== Motor ECU ==
+
[[File:Beam_Pattern_MB1000_EZ0.gif|left|500px|thumb|Beam Pattern MaxBotix MB1000 EZ0]]
 +
[[File:Beam_Pattern_MB1010_EZ1.gif|center|500px|thumb|Beam Pattern MaxBotix MB1010 EZ1]]
  
[https://gitlab.com/infallibleprogrammer/utah/-/tree/user/amritpal_sidhu/%2310/Motor_Controller_Refine_PID Motor Source Code]
 
  
 
=== Hardware Design ===
 
=== Hardware Design ===
  
 +
==== Sensor Controller Schematic ====
  
  
 +
[[File:SensorSch.png|center|800px|thumb|Sensor Controller Node Schematic]]
  
  
 +
==== Board Pin Connections ====
  
 +
Sensors are interfaced with combination of GPIO, ADC Pins on SJTWo board. Below is the descriptive pin layout:
  
{| class="wikitable" style="margin-center: auto; margin-center: auto; text-align:center;"
+
{| class="wikitable" style="text-align: center; width: 400px; height: 200px;"
|+ Motor Board Pinout
+
|+ Sensors pin layout
 
|-
 
|-
! SJ2 Board Pin !! Description
+
! Sr. No.
 +
! SJTwo board Pin
 +
! Maxbotix sensor Pin
 +
! Function
 
|-
 
|-
| 5V || Input power
+
! 1
 +
| ADC2-P0.25 || AN(Front sensor) || ADC input from front sensor
 
|-
 
|-
| 3.3V || CAN transceiver power
+
! 2
 +
| ADC3-P0.26 || AN(Rear Sensor) || ADC input from rear sensor
 
|-
 
|-
| PWM2 P2.1 || DC Motor Speed Control
+
! 3
 +
| ADC4-P1.30 || AN(Left Sensor) || ADC input from left sensor
 
|-
 
|-
| PWM5 P2.4 || Servo Motor Control
+
! 4
 +
| ADC5-P1.31 || AN(Right Sensor) || ADC input from right sensor
 
|-
 
|-
| CAP0 P2.6 || Input Capture for RPM Sensor
+
! 5
 +
| GPIO-P0.6 || RX(Left Sensor) || Trigger for left sensor
 
|-
 
|-
| CAN1 TX || CAN Module Tx
+
! 6
 +
| GPIO-P0.7 || RX(Front Sensor) || Trigger for front sensor
 
|-
 
|-
| CAN1 RX || CAN Module Rx
+
! 7
 +
| GPIO-P0.8 || RX(Right Sensor) || Trigger for right sensor
 
|-
 
|-
| GND || Grounding
+
! 8
 +
| GPIO-P0.9 || RX(Rear Sensor) || Trigger for rear sensor
 
|}
 
|}
 
 
  
==== DC Motor and ESC  ====
+
=== <font color="0000FF">Software Design </font>===
  
The DC motor and ESC were provided with RC car. The DC motor is controlled by the ESC using PWM signals which were provided by the motor controller board for forward, neutral, and reverse movements. The ESC is powered ON using a 7.4 LiPo battery. The ESC converts this 7.4V to 6V and provides input to DC Motor.
+
The sensor node mainly does two activity viz. 1) Read sensor values, 2) Transmit obstacle distance over CAN bus. Both of these activities happen in a 20Hz periodic callback.  
  
 +
1. Read Sensor Values
  
[[File:DC motor.jpg|350px|center|thumb|DC Motor]]
+
*  Sensors are mounted at four locations as mentioned below diagram. To read these sensor values, we initialized and configured 4 sensors using 4 ADCs viz ADC2, ADC3, ADC4, and ADC5. Considering the front 3 sensors' close proximity and possible beam interference, we decided to range extreme front sensors at a time and the middle front next in sequence while in a 20 Hz loop. And the rear sensor is triggered regularly. All the sensor values are digitally converted in the range of 0 to 4096 (12 bit ADC). These values are converted to distance format in centimeter unit using formula '''conv_val = (raw_val * 0.3182) - 0.3959'''.
 +
[[File:Sensor_placement.png|center|400px|thumb|Sensors Placement location]]
  
 +
*  Now, to avoid frequent noise pulses, we used a median filter. We created an array of 10 elements for each sensor and maintained a write index to track the current update position. Thus, all read values have been updated in the buffer which acts as a circular buffer as we start overwriting from the start index.
  
{| class="wikitable" style="text-align: center;"
+
2.  Transmit obstacle distance over CAN bus:
|-
 
! scope="col"| ESC wires
 
! scope="col"| Description
 
! scope="col"| Wire Color                                                                   
 
|-
 
! scope="row"| Vout
 
| Output Power (6V)
 
| RED
 
|-
 
! scope="row"| GND
 
| Ground
 
| BLACK
 
|-
 
! scope="row"| PWM
 
| PWM input from SJ2-Board (P2.1)
 
| WHITE
 
|-
 
|}
 
  
The car can be operated at 100Hz in the following 3 modes :
+
* Sensor node is responsible for broadcasting all four sensor values in terms of distance in centimeter over CAN bus. To broadcast filtered values, it first sorts the existing values in the respective allocated sensor buffer. Then it takes the mean of five median values. It does the same thing for all four sensors. Finally, it transmits those values over CAN bus. Below flow chart gives the detailed flow of code at a high level.
<br/>
 
Sport Mode (100% Forward, 100% Brakes, 100% Reverse)
 
<br/>
 
Racing Mode (100% Forward, 100% Brakes, No Reverse)
 
<br/>
 
Training Mode (50% Forward, 100% Brakes, 50% Reverse)
 
<br><br>
 
The PWM frequency for our Traxxas ESC needed to be 100Hz. An idle (motor stopped) duty cycle is 15%. The full duty cycle range is [10%, 20%], where [10%, 15%) is the reverse range, and (15%, 20%] is the forward range. We ended up limiting the duty cycle range to [13%, 17%] since the RC car had more power than we needed.
 
<br>
 
  
==== Servo Motor ====
+
[[File:Sensor_Node_flow_chart.png|center|600px|thumb|Sensor Node Controller Flow Chart]]
  
[[File:Servo motor.jpg|350px|center|thumb|Servo Motor]]
+
=== <font color="0000FF">Technical Challenges </font>===
  
 +
==== Neighboring Sensor Interference: ====
 +
*  As explained above, we have mounted three ultrasonic sensors in the front, and those were configured to range in continuous mode, in which sensors were continuously measuring distance by transmitting beam. Out of 3, the middle sensor is of type with wider beam to detect blind spots ahead.
 +
*  Most of the time, we observed that the obstacle in the middle sensor range used also gets detected by the left/right sensor, which disturbs driving logic. This used to happen due to sensor beam interference among three sensors.
 +
*  To solve this problem, we decided to trigger sensor beams in such time intervals that they won’t interfere with neighboring ones. We used the Rx pin of the sensor to trigger ranging and scheduled to trigger left and right sensor at one time and middle sensor next time. This sequence helped us avoid interference altogether.
  
{| class="wikitable" style="text-align: center;"
+
==== Frequent noisy measurements: ====
|-
+
*  While reading the obstacle distance, it used to change suddenly to some random value, and that used to disturb driving logic. To get noise-free readings from sensors, we implemented a median filter. All the read values from sensors have been collected in the respective buffer of 10 elements. While sending obstacle distance on CAN bus, the median filter sort the buffer and takes an average of 5 median values. This way, it helped us to remove almost all noisy values.
! scope="col"| Servo Wires
 
! scope="col"| Description
 
! scope="col"| Wire Color
 
|-
 
! scope="row"| Vin
 
| Input Voltage (6V)
 
| RED
 
|-
 
! scope="row"| GND
 
| Ground
 
| BLACK
 
|-
 
! scope="row"| PWM
 
| PWM input from SJ2-Board (P2.4)
 
| WHITE
 
|-
 
|}
 
  
The PWM frequency for our Traxxas Servo motor also needed to be 100Hz.  An idle (wheel's pointing forward) duty cycle is 15%.  The full duty cycle range is [10%, 20%], where [10%, 15%) is the steer left range, and (15%, 20%] is the steer right.
 
<br>
 
  
==== Wheel Encoder ====
+
<HR>
 +
<BR/>
  
For speed sensing we purchased a Traxxas RPM sensor as it mounted nicely in the gearbox. The RPM sensor works by mounting a magnet to the spur gear and a hall effect sensor fixed to the gearbox.  To get the revolutions per second we used Timer2 as an input capture. <br>
+
== Motor ECU ==
 +
[[File:MotorSch.png|center|800px|thumb| Motor Node Schematic]]
  
 +
=== Hardware Design ===
 +
[[File:XL5esc.png|300px|thumb|left|Traxass ESC XL5]]
 +
[[File:Servotrx.jpg|300px|right|thumb|Traxass Servo Motor]]
 +
[[File:Rpmsens.jpg|300px|center|thumb|Traxass RPM Sensor]]
 +
<BR/>
  
[[File:RPM.jpg|350px|center|thumb|Servo Motor]]
+
The motor node(SJ-2) interfaces primarily interfaces with:
 +
* Traxass Motor ESC over PWM
 +
* Traxass RPM Sensor over GPIO Interrupt
 +
* Traxass Servo Motor over PWM
  
 +
All these three components have 3 pins each. The functionalities of these pins are mentioned in the table below.
  
{| class="wikitable" style="text-align: center;"
+
{| class="wikitable"
 
|-
 
|-
! scope="col"| RPM Sensor Wires
+
! scope="col"| Module
! scope="col"| Description
+
! scope="col"| Black
! scope="col"| Wire Color
+
! scope="col"| Red
 +
! scope="col"| White
 
|-
 
|-
! scope="row"| Vin
+
! scope="row"| ESC
| Input Voltage (6V)
+
| Ground
| RED
+
| Vout : 6 V
 +
| PWM Input
 
|-
 
|-
! scope="row"| GND
+
! scope="row"| Servo
 
| Ground
 
| Ground
| BLACK
+
| Vin : 6 V
|-
+
| PWM Input
! scope="row"| Sensor Output
 
| Input Capture to SJ2-Board (P2.6)
 
| WHITE
 
 
|-
 
|-
 +
! scope="row"| RPM Sensor
 +
| Ground
 +
| Vin : 6 V
 +
| Pulse Output
 
|}
 
|}
  
 
=== Software Design ===
 
=== Software Design ===
The motor controller code modules consisted of 3 main parts, which are: 1. PWM drivers and motor logic, 2. RPM/speed sensor, 3. PID controller.
 
 
<h6>1. PWM drivers and motor logic</h6>
 
The PWM drivers were fairly easy to write since the SJ2 project provided an API for the low level function calls.  Converting speed and angle values to duty cycle values was done by simply linearly mapping one onto the other.  This worked fine for steering control, but due to varying grades the car needs to drive on, the PID is needed.  The Traxxas ESC, as other students have discovered in the past, has safeguards to prevent damage to the motor by not allowing duty cycle to abruptly change from a forward signal to a reverse.  The Traxxas transmitter uses a trigger for this, but as other students suggested, we used a state machine to transition into opposite directions.  We found that going from reverse to forward simply requires stopping (15% duty cycle) the car first, while going from forward to reverse required sending the following signals: STOP, REVERSE, STOP, REVERSE.  Since we did not consult with Traxxas, this logic was created through trial and error.  Transitioning into the opposite direction might simply just require stopping first, and then delay until a speed is reached, then change directions.  We had access to an oscilloscope, however we did not capture what actually happens to the DC motor duty cycle when the transmitter does the same transition.
 
 
We created a separate module that encapsulated the motor's drive logic, such as getting speed feedback to compute PID value, updating the DC motor and servo motor's PWM in a state machine, and doing the start up self test.  Another feature we incorporated was to have the motor controller listen for a message from the Bridge/App, so we could easily start and stop the car remotely.  This feature was very helpful in testing.
 
 
Later on we also added the feature to run the Traxxas ESC setup by pushing a push button at start up.  You need to hold the ESC button when you turn on the car until the green light turns red, then push SW3 on the motor board to run the ESC setup.  The setup is fairly simple, it puts the DC motor PWM in full forward (20%) for 3 seconds, full reverse (10%) for 3 seconds, then neutral (15%) for 3 seconds before returning a true for finishing.  The function is called in a periodic and the counts are kept track of internally by the function.  The 3 seconds was a guess, but it seemed to work fine.
 
 
<h6>2. RPM/speed sensor</h6>
 
To count the time interval between pulses the RPM sensor makes, we used one of the LPC's peripheral timers that allowed for an input capture feature.  We configured the hardware registers such that a capture register is written the value of the timer count register when the input capture (pulse from RPM sensor) occurs.  This required writing a low level API so that we could unit test the hardware reading and writing.  An interrupt also triggers on a capture event to reset the timer counter, to make the value in the capture register easy to convert to revolutions per second.  The circumference of the car's tire and spur gear ratio are needed to determine a scalar value to convert the revolutions per second to conventional speed units.  Many students said the RPM sensor from Traxxas was inconsistent and unreliable for speed feedback.  We thought that this might be because of how the sensor is measuring the speed of the spur gear and that the differential of the car might cause variation, however when the car goes in a straight line that should not be a problem.  When we integration tested the software design with the PID using the above approach, the speed readings seemed stable enough for use with the PID.
 
 
<h6>3. PID controller</h6>
 
For situations where the DC motor needs to do more or less work (e.g. driving uphill or downhill) the linear mapping will not work.  The proportional, integral, derivative (PID) controller is a widely used control mechanism to ensure a machine maintains a set point, and responds quickly and smoothly upon disturbances.  In discrete time the integration becomes a summation and the derivative becomes a difference.  The controller is based on an error from the set point, which is why the RPM sensor is needed to get feedback.  The PID algorithm is fairly simple, as is tuning the gains.  We found that the proportional and integral gains were enough to get the car to maintain speed.
 
 
The way we tuned the PID was to start off by only using the proportional controller at a unity gain.  We had the car drive on level ground and tested at 3kph and 5kph drive speeds.  We varied the proportional gain until we saw the car have a "stop and go" motion.  Then we dropped the proportional gain in half and tested again with a low integral gain.  We now started testing on ground with a grade to see if speed could be maintained.  We varied the integral gain until we were satisfied with the DC motor's response to varying terrain.
 
 
 
Below is our design for the motor controller's periodic callbacks.
 
 
<div style="margin-left:1.5%;">
 
<h6>Periodic Callbacks Initialize:</h6>
 
* Initialize:
 
** CAN bus
 
** DC motor PWM
 
** Servo motor PWM
 
** RPM sensor input capture
 
** PID
 
** Motor logic
 
 
 
<h6>Periodic Callbacks 1Hz</h6>
 
* Reset CAN bus if bus goes off
 
** Have LED indicate CAN bus running status
 
* Transmit motor debug message
 
* Transmit motor CAN status
 
 
 
<h6>Periodic Callbacks 10Hz</h6>
 
* At 2Hz transmit motor speed
 
* Update steering angle and drive speed
 
** Run ESC setup once user pushes button (Optional, can be bypassed)
 
** At board power up a self test routine is ran (Also optional, but usually ran)
 
** After the self test, Driver & Bridge/App controller commands are followed
 
  
 +
The motor node acts based on the speed and direction received over CAN bus from the Driver Node. The positive speed values are treated as forward motion and the negative speed values are considered to be the reverse motion of the RC car.
  
<h6>Periodic Callbacks 100Hz</h6>
+
The steering angles are divided into 5-degree segments and the motor node sends the pre-defined pwm duty cycle of the particular segment to the servo motor depending on the angle value received from the driver node.
* At 20Hz receive all messages from CAN bus and update local motor data structure
 
</div>
 
  
[[File:motor_logic__run_once__picture.jpg|350px|left|thumb|motor_logic__run_once() flowchart]]
+
[[File:Flowchartmotor.png|800px|thumb|center|Motor Node - Software Flowchart]]
[[File:motor_logic__update_motor_state_once_picture.jpg|350px|center|thumb|motor_logic__update_motor_state_once() flowchart (see code, or description above, for more details on state machine)]]
 
  
 
=== Technical Challenges ===
 
=== Technical Challenges ===
  
* Getting the state machine right for the DC motor to transition between forward and reverse, and vice versa, took some experimentation. Luckily other student's reports were available for us to get hints on what we needed to do.
+
* Firstly, the Traxxas motor ESC and other Traxass parts are members of the Traxxas Hobby Parts family, and they are not intended for development purposes. This is why there are no technical specification documents or any program/development guides available. One needs to test the motor ESC by feeding the PWM duty cycles in various sequences at various duty cycle percentages. We used the Remote control to reproduce some scenarios where the ESC was behaving unexpectedly.  
* When first tuning the PID our boards were attached via jumper wires and breadboard on a piece of plexiglass.  The plexiglass was not rigidly secured to the car either, which resulted in collisions with walls and wires becoming undone. All this led to more hardware issues and had us backtrack to get the PID tuned.  Making sure the hardware is sound before doing full integration tests will save you time.  This requires planning out the hardware early on, and preferably just getting a PCB manufactured.
+
* The ESC configuration changes to the Lipo battery state if the Lipo battery is used. If one switches back to the NiMH battery, then the ESC starts flashing the led in a green-red repeated sequence, and the ESC power button stops working. In this scenario, there is a calibration process that can save your boat and can make the ESC function normally again. Follow this procedure : [https://www.youtube.com/watch?v=1br9_h1OsV8 ESC Calibration]
* We were having problems during integration testing where the motors would not run. It's hard to say what the solution was for certain, but slowing down the rate we updated the PWMs (from 20Hz to 10Hz) seemed to be it.
+
*Another challenge with the motor node program development is that you cannot rely on unit testing. Whoever works on the motor node, should make sure that the sequence of the duty cycles being fed to the ESC produces the expected results on the motor as well. The forward-reverse transitioning and the speed controlling both can be a bit tricky. Also, the hard brake logic can take a while to get working properly.
* We damaged the ESC somehow and needed to purchase another. This cost us time and money. Make sure you don't accidentally short the ESC!
+
* Some useful reference values for the ESC are : 15% -> Neutral; 15.8%-> Minimum forward speed, 10%->Full reverse speed.
* Some unit tests were not written until after integration testing. This goes against test driven development, but due to deadlines we had to make a choice.  Had we thought out the use cases of our modules and wrote unit tests sooner, I'm sure we would have avoided some in the field debugging.
 
* The code had to be redesigned for modularity and readability later on. Make sure to avoid software anti-patterns, like "blob," and use dependency injection to prevent tightly coupled code modules.
 
* We damaged one of the LiPo batteries we purchased because we drained the voltage below 3V per cell. Luckily we had another LiPo for testing, but having a voltage sensor to indicate to the app the battery level could be a good idea.
 
 
 
 
<HR>
 
<HR>
 
<BR/>
 
<BR/>
  
== Geographical Controller ==
+
== Geographical And Bridge Controller ==
https://gitlab.com/infallibleprogrammer/utah/-/tree/master/projects/GEO_Controller
+
 
<Picture and link to Gitlab>
+
''[https://gitlab.com/nimit.patel/roadster/-/merge_requests/5 Repository link for Geo Controller]''
  
 
=== Hardware Design ===
 
=== Hardware Design ===
The geographical controller runs all the processing for compass data as well as GPS data. The purpose of the controller is to interface with the Adafruit Ultimate GPS Breakout using UART which provides accurate GPS data formatted in GPGGA. The controller utilizes I2C protocol to interface with the Adafruit Magnetometer with tilt compensation for the purpose of finding our heading and where the car needs to point in order to get closer to its destination. The Adafruit magnetometer was able to give us accurate data with a possible deviation of up to 3 degrees in any direction. This was possible by using a software filter to normalize our data and create a standard.  
+
[[File:GeoSch.png|650px|thumb|center|Geo Node Schematic]]
 +
<BR/>
 +
[[File:Hc05.jpeg|400px|thumb|left|Bluetooth Trans-receiver]]
 +
[[File:GPS.jpg|400px|thumb|right|GPS Module]]
 +
[[File:compass_roadster.jpg|400px|thumb|center|3 Axis Magnetometer (eCompass)]]
 +
<BR/>
 +
[[File:Votlage Divider.jpg|400px|thumb|right|Battery Monitoring]]
  
[[File:Geo Akash.png|750px|center|thumb|Geo Hardware Design]]
+
<BR/>
{| class="wikitable" width="auto" style="text-align: center; margin-left: auto; margin-right: auto; border: none;"
 
|+Table 5. Geographical Node Pinout
 
|-
 
! scope="col"| SJTwo Board
 
! scope="col"| GPS/Compass Module
 
! scope="col"| Description
 
! scope="col"| Protocol/Bus
 
|-
 
| P4.28 (TX3)
 
| RX
 
| Adafruit GPS Breakout
 
| UART 3
 
|-
 
| P4.29 (RX3)
 
| TX
 
| Adafruit GPS Breakout
 
| UART 3
 
|-
 
| P0.10 (SDA2)
 
| SDA
 
| Adafruit Magnetometer
 
| I2C 2
 
|-
 
| P0.10 (SCL2)
 
| SCL
 
| Adafruit Magnetometer
 
| I2C 2
 
|-
 
| P0.1 (SCL1)
 
| CAN transceiver (Tx)
 
| CAN transmit
 
| CAN
 
|-
 
| P0.0 (SDA1)
 
| CAN transceiver (Rx)
 
| CAN  receive
 
| CAN
 
|-
 
| Vcc 3.3V
 
| Vcc
 
| Vcc
 
|
 
|-
 
| GND
 
| GND
 
| Ground
 
|
 
|-
 
|}
 
  
=== Software Design ===
 
The GEO controller consisted of 4 main parts which are: 1. GPS Driver and Processing, 2. Compass Processing, 3.Waypoints Algorithm, and 4. Geo Logic. The geo logic takes data from parts 1 to 3 and determines where the car should be moving. This data is sent to the driver controller via the canbus.
 
  
<h5>1. GPS Driver and Processing</h5>
+
The SJ2 board communicates with:
The GPS module uses UART3 to communicate with our SJ2 board. The API call for the GPS driver requires setting up the gps registers to only allow GPGGA data as well as refresh data every 10hz(100ms) instead of 1hz(1 second). This solve a lot of initial issues with getting stale data as the car moved. The main API function is called gps__run_once() which digests data from the physical GPS hardware. Inside gps__run_once(), we call two functions that help with parsing the gps coordinates. The first is taking using a line buffer for the UART characters that are digested during operation and checking if they are in fact a full GPGGA string. The second function parses those coordinates from the line buffer and converts them from GPGGA minutes data to polar coordinates. Once the function is called, global static variables located in gps.c are used while a gps__get_coorindate() function is called whenever the API's data wants to be used outside of the gps.c file. In order to check if there is a gps fix, we created a function that checks if certain GPGGA bits are set or not. If the are set, than we have a fix. This was more accurate than the FIX pin located on the GPS module because of that pin toggles every 150ms even when their is a fix.
+
* Bluettoth transreceiver over UART
 +
* LSM303DLHC over I2C
 +
* GPS model over UART
 +
* Battery monitoring
  
<h5>2.Compass Processing</h5>
+
Considering the orientation of the car changes as it travel along the land, tilt compensation logic for heading calculation using the magnetometer is a must for accurate measurement. Without the tilt compensation algorithm which uses the onboard accelorometer, the heading computation can have error up to 60 degrees, which has the potential to send the car off course.
The compass module was one of the trickiest parts of the GEO controller due to the necessary calibrations that came with the code. The compass is initialized to use I2C as a method for communicating with the SJ2 board. The API is primarily one function to get the latest, compass__run_once_get_heading(). This float function is split into three parts: get magnetometer data, get accelerometer data, and use both of those datasets to figure out the heading. The accelerometer was not used in the initial stages of development but was required to accommodate for tilt when the car was moving at high speeds. The compass required a lot of calculations to determine heading, and accommodate for tilt.  
+
<BR/>
 +
<BR/>
 +
For battery monitoring, the values for the voltage divider should be chosen such that the full range of the onboard ADC can be efficiently used. Depending one the cell type of the battery, the discharge curve can be use to map the charge state corresponding to voltage level. This method has its flaws and sophisticated techniques involving Coulomb count yields far better results, however, the technique discussed above suffices the needs of our project. Charge state of battery transmitted over Mobile app, greatly facilitates the charging schedule while testing and final demo day.
  
<h6>Heading Computation:</h6>
+
<BR/>
The lsm303DLHC magnetometer and acceletometer require tilt compensation to ensure accurate readings. If there is not tilt compensation, the compass heading can be up to 60 degrees off making it widely inaccurate. Once proper software based calculations were made, the compass was at most 3 degrees off. A software model was used to normalize the data and reduced noise related to bad readings.
+
<BR/>
[https://www.pololu.com/file/0J434/LSM303DLH-compass-app-note.pdf#page=6 Compass Tilt Calculation]
 
[https://www.instructables.com/Tilt-Compensated-Compass-With-LSM303DHLC/ Software Model for Compass]
 
  
<h6>Normalize Data: </h6>
+
=== Software Design ===
  float alpha = 0.25; // alpha to create base for software optimizations
+
The periodic scheduler for Geo Controller Node does the following functionalities:
  static float Mxcnf;
+
* In 10Hz periodic callback:
  static float Mycnf;
+
** gps__update() : Fetch GPS data from GPS controller.
  static float Mzcnf;
+
** geo_compass__periodic_send() : Reads the Magnetometer and accelerometer values from Compass controller and convert those to current heading data.
  static float Axcnf;
+
* In 100Hz periodic callback:
  static float Aycnf;
+
** bluetooth__run_once() : Send specified data to android application via Bluetooth.
  static float Azcnf;
 
 
 
  float norm_m =
 
      sqrtf(magnetometer_processed.x * magnetometer_processed.x + magnetometer_processed.y * magnetometer_processed.y +
 
            magnetometer_processed.z * magnetometer_processed.z); // normalize data between all 3 axis
 
  float Mxz = magnetometer_processed.z / norm_m;
 
  float Mxy = magnetometer_processed.y / norm_m;
 
  float Mxx = magnetometer_processed.x / norm_m;
 
  float norm_a = sqrtf(accel_raw_data.x * accel_raw_data.x + accel_raw_data.y * accel_raw_data.y +
 
                      accel_raw_data.z * accel_raw_data.z);
 
  float Axz = accel_raw_data.z / norm_a;
 
  float Axy = accel_raw_data.y / norm_a;
 
  float Axx = accel_raw_data.x / norm_a;
 
 
 
  Mxcnf = Mxx * alpha + (Mxcnf * (1.0 - alpha));
 
  Mycnf = Mxy * alpha + (Mycnf * (1.0 - alpha));
 
  Mzcnf = Mxz * alpha + (Mzcnf * (1.0 - alpha));
 
 
 
  // Low-Pass filter accelerometer
 
  Axcnf = Axx * alpha + (Axcnf * (1.0 - alpha));
 
  Aycnf = Axy * alpha + (Aycnf * (1.0 - alpha));
 
  Azcnf = Axz * alpha + (Azcnf * (1.0 - alpha));
 
*Notes:
 
** Mxcnf: Normalized Magnetometer X Data
 
** Mycnf: Normalized Magnetometer Y Data
 
** Mzcnf: Normalized Magnetometer Z Data
 
** Axcnf: Normalized Accelerometer X Data
 
** Aycnf: Normalized Accelerometer Y Data
 
** Azcnf: Normalized Accelerometer Z Data
 
 
 
The normalize data model shown above takes the magnetometer and accelerometer data that has been bit shifted and saved to a static function located in compass.c. The data is divided by the normalized data set for all 3 axis. This occurs for both the accelerometer and magnetometer. Once this data is taken, a low-pass filter is applied where the previous value of the data is used to check for deviation and offsets. An alpha of .25 is used to accommodate for a 75% threshold for deviations in the data during a given time frame. This data is later fed into the tilt compensation algorithm.
 
 
 
  <h6>Tilt Calculations: </h6>
 
  float pitch = asin(-Axcnf);
 
  float roll = asin(Aycnf / cos(pitch));
 
  float Xh = Mxcnf * cos(pitch) + Mzcnf * sin(pitch);
 
  float Yh = Mxcnf * sin(roll) * sin(pitch) + Mycnf * cos(roll) -
 
            Mzcnf * sin()roll) * cos(pitch);
 
  current_compass_heading = (atan2(Yh, Xh)) * 180 / PI;
 
  current_compass_heading += 13;
 
  if (current_compass_heading < 0) {
 
    current_compass_heading = 360 + current_compass_heading;
 
  }
 
  
Pitch and roll are a fundamental part of calculating the tilt. Pitch accounts for deviations in terms of the Y axis while roll is around the X axis. In the calculation seen above, pitch takes the asin of the negation of Axcnf(normalized x axis data for the accelerometer). Roll on the other hand is the ration of normalized y axis data over the cosine of pitch. These are used for the formula seen directly below it. The compass heading is adjusted 13 degrees due to our offset from true north. We need to use the true north value because the data sent to us by google maps compensates for true north. If we encounter an angle below 360, than we get its complement by adding 360 to ensure the rest of our calculations are correct.
+
The GEO controller is divided into 5 parts.
  
<h5>3.Waypoints</h5>
+
*The current location of the car is determined using the GPS.
The waypoints algorithm worked in a very simple way but was proven to be affective. The usage of waypoints are used as a way to 3D map obstacles related to the terrain of the SJSU 10th street garage.  As shown in the map below, we had 11 overall waypoints and a majority of them are located around the ramp located on the left side of the map. As shown in the map, we utilized waypoints in such a way to ensure that they went around the ramp, rather than through it. This was to avoid the hazard of the RC car believing it can go straight when in fact it can not due to the circular ramp. The points were also created in a line so that the RC car did not unnecessarily go towards the ramp because it was the closest waypoint. If we had a line of points, than it would calculate the point closest to itself and go towards the one. We also wanted to avoid redundant waypoints so we reduced the original 20 waypoints to 11. The checkpoint API looked flow is shown below.  
 
  
[[File:Waypoint algorithm.png|200px|middle|Figure #. Waypoint API Flow]]
+
*The current magnetic heading of car is determined using the on board compass.
[[File:UTAH Waypoints map.png|500px|middle|Figure #. Waypoint Map]]
 
  
<h6>Distance Calculations: </h6>
+
*The way point calculation determines the nearest way point continuously by computing the distance using Haversine formula and current location using GPS.
  // a = sin²(Δlatitude/2) + cos(destination_lat) * cos(origin_lat) * sin²(Δlongitude/2)
 
  // c = 2 * atan2(sqrt(a), sqrt(1−a))
 
  // d = (6371 *1000) * c
 
  const int Earth_Radius_in_km = 6371;
 
  const float delta_lat = (origin.latitude - destination.latitude) * (PI / 180);
 
  const float delta_long = (origin.longitude - destination.longitude) * (PI / 180);
 
  float a = pow(sinf(delta_lat / 2), 2) +
 
            cosf(destination.latitude * (PI / 180)) * cosf(origin.latitude * (PI / 180)) * pow(sin(delta_long / 2), 2);
 
  float c = 2 * atan2f(sqrt(a), sqrt(1 - a));
 
  return (float)(Earth_Radius_in_km * c * 1000);
 
  
In order to get the calculation for distance, we must accommodate for the curvature of the Earth as well as the radius. In the equation above, we see haversine translated into C code which allows us the compute the distance in meter. This is done in the find_next_point() API call where we calculate the distance from origin to waypoint and waypoint to destination. We are looking for closest point that reduce the distance to the destination. If both of those statements are true, then we set that as our waypoint.
+
*The heading is also computed using the Haversine formula and the difference between the actual and required is sent over the CAN bus for heading correction.
  
<h5>4.Geo Logic</h5>
+
*Alternatively, once the car is within the threshold distance, next way point is selected and the car heads to the next way point.
The geo logic was the primary API that allows the GEO controller to function. It takes data from waypoints.c, gps.c, and compass.c. The data is used and processed such that it may be send on the canbus. The geo_logic.c file primarily outputs dbc structs that are utilized in the can_module.c. With the implementation of waypoints, a lot of the calculation in geo_logic.c is no longer needed and will be editted out in the near future. At its current state the main functions in the API are geo_controller_processs_GEO_current_location() which gets the current GPS location for the RC car, geo_controllerprocess_geo_dat() which takes in the gps_destination sent by the bridge controller, and determine_destination_location() which tells the car where to go.
 
  
[[File:GEO logic.jpg|250px|center|Figure #. GEO_Logic]]
 
  
The geo logic was kept simple on purpose. We get our current location, then find out if a destination was sent to our static array. If no, new destination was received than we continue to determine if a waypoint is required to the destination. If the waypoint is used, then those values will be used for get_bearing(). We continue to process the read repeatedly for the 200ms cycle of the periodic scheduler. The task is that simple. If a new destination is appended then we add it and compute if we should go to that new destination first. The maximum allowed destinations is 5 by user design.
+
[[File:Geo logic.png|800px|thumb|center|Heading computation from geographical (Geo) controller]]
 
 
Geo Controller Periodics:
 
<div style="margin-left:1.5%;">
 
<h6>Periodic Callbacks Initialize:</h6>
 
* Initialize:
 
** CAN bus
 
** gps__init
 
** compass__init
 
 
 
<h6>Periodic Callbacks 1Hz</h6>
 
* If not sent yet, send the GPS instructions to only receive GPGGA data and 10hz refresh rate
 
* Get compass update values
 
* Send debug messages every 1 second
 
 
 
<h6>Periodic Callbacks 10Hz</h6>
 
* Run the API gps__run_once() to fetch the latest data.
 
* Use data to determine bearing and heading of first waypoint/destination
 
** Send this information to the driver for processing
 
*Receive all messages on the canbus that are designated for us
 
 
 
</div>
 
  
 
=== Technical Challenges ===
 
=== Technical Challenges ===
  
== Communication Bridge Controller & LCD ==
+
* The GPS module sends data at 9600 baud rate, updating the data every one second. The data update rate needs to be updated to 10Hz for fast maneuvering and course correction of the car. If the update frequency is updated, the data sent over the UART is higher than it can handle in 10Hz periodic function. Hence, only GPGGA messages should be enabled to extract the required data and reduce the time spent in parsing the incoming string. NEMA (PMTK) messages should be correctly configured on the module for desired functioning.
 +
* Heading calculation without the tilt compensation logic using the onboard accelorometer of LSM303 is in accurate. Reading accelorometer values requires and offset of 0x80 to the byte addressing of the accelorometer read. Magnetometer need no such offset. This is weird, considering both the I2C devices reside on the same physical chip.
 +
*Using data type as float as opposed to double, utilizes the onboard FPU, which is faster. Double utilizes software implementation, which takes more clock cycle. Considering extensive use of math library in distance/heading measurement and tilt compensation algorithm, completing the task with the periodic is of at most importance.
 +
* GPS fix is best when when there are no obstruction above the module. Module requires clear wide view of sky for a fast fix and error free location detection.
 +
* LSM303DLHC is sensitive to even weak magnetic field interference. Place the chip devoid of such active/passive magnetic fields.
 +
* Calibrating LSM303 is a must to get accurate heading values. 2-point calibration worked just fine for our team. More sophisticated methods are available too.
 +
<HR>
  
 +
== Driver Node ==
 +
https://gitlab.com/nimit.patel/roadster/-/tree/Main/Driver_Node
  
 
=== Hardware Design ===
 
=== Hardware Design ===
 +
The Driver Node has one peripheral connected to it and that is the LCD screen.
  
 +
[[File:Driver_Node_HW_Design.png|thumb|700px|caption|left|Driver Node Schematic]]
 +
[[File:DriverSch.png|thumb|700px|caption|center|Driver Node Schematic]]
  
 
=== Software Design ===
 
=== Software Design ===
 +
The driver node controls the logic of steering the car in the right direction based on the data received from the Sensor and Geo Nodes. The following flowchart describes that process.
 +
*Driver Node Flow Chart
  
=== Bridge Controller ===
+
[[File:FlowChartDriverNode.png|thumb|1000px|caption|center|Driver Node Flow Chart]]
  
 +
In case there are obstacles in the path where the car wants to move to, the following obstacle avoid logic would kick in.
 +
*Driver Node Obstacle Avoidance Logic
 +
 +
[[File:ObstacleAvoidanceDriverNode.png|thumb|1200px|caption|center|Driver Node Obstacle Avoidance Logic]]
 +
The work in the Driver Node is done using two different periodic tasks. Here is a description of those periodic tasks and what they do.
 +
*1 Hz Loop:
 +
**Transmit debug messages over the CAN bus
 +
**Transmit messages on the LCD
 +
**Transmit destination reached flag over the CAN Bus
 +
*20 Hz Loop:
 +
**Receive Sensor Data
 +
**Receive Geo Data
 +
**Process and Transmit Data(Motor Direction and Speed) to Motor Node
 +
*LCD Interface
 +
The LCD interface on the Driver is used to print some important information about the car. This is what it prints.
 +
**Car Speed
 +
**Distance from the Destination
 +
**Car State (Car Stopped from the App, Car Moving, Destination Reached)
  
 
=== Technical Challenges ===
 
=== Technical Challenges ===
 
+
*The Driver Node did not have much hardware interfaced on it apart from LCD. So from the hardware side there were no technical challenges. On the software front as well there were not many challenges as unit tests helped debug most of the issues then and there.
 
+
*We initially used GLCD which was configured via GPIOs and it was working perfectly. Hence we created our PCB as per this LCD. But, while testing our car with various speeds and PID logic, it got toppled and damaged the LCD. So, we had to change to SJ Valley LCD, which was configured via the UART interface, at the last moment. So, we used the same location on the PCB to place the LCD and soldered wires below PCB. Hence, this correction was not visible on our end product.
 
 
 
<HR>
 
<HR>
 
<BR/>
 
<BR/>
  
== Master Module ==
+
== Mobile Application ==
 +
''[https://gitlab.com/srikarreddy.narapureddy/roadster-app  Gitlab]''
 +
We created a lightweight mobile app to navigate our car, It can communicate with the car via Bluetooth and is capable of sending Destination co-ordinates along with checkpoints. Receive and Update live location on Google Maps, send Start, Stop and Clear commands, Receive and Display Debug Data.
  
 +
<div><ul>
 +
<li style="display: inline-block;">[[File:Roadsterintro.jpeg|thumb|none|220px| Splash screen]] </li>
 +
<li style="display: inline-block;">[[File:roadsterapp1.jpg|thumb|none|220px| Data from roadster]] </li>
 +
<li style="display: inline-block;">[[File:roadsterapp2.jpg|thumb|none|220px| Checkpoints]] </li>
  
 +
</ul></div>
  
=== Hardware Design ===
+
===User Interface===
 +
The app has minimal buttons on the same screen as Google Maps View to confirm the cars current state and location before sending the commands.
  
{| style="margin-left: auto; margin-right: auto; border: none;"
+
        connect_Btn.setOnClickListener(new View.OnClickListener() {
|-
+
            @Override
|
+
            public void onClick(View v) {
{| class="wikitable"
+
                listPairedDevices(v);
|+ Table 6. Driver Node Pinout: CAN Transceiver
+
            }
|-
+
        });
! SJTwo Board
+
        clear.setOnClickListener(new View.OnClickListener() {
! CAN Board
+
            @Override
|-
+
            public void onClick(View v) {
| P0.0
+
                try {
| CAN RX
+
                    if(!state) {
|-
+
                        mConnectedThread.write("--,\n");
| P0.1
+
                        mMap.clear();
| CAN TX
+
                        checkpoints.clear();
|-
+
                        sending_status.setText("Waiting");
| Vin
+
                    }
| 3.3
+
                    else{
|-
+
                        Toast.makeText(getApplicationContext(),"Stop the car First",Toast.LENGTH_SHORT).show();
| GND
+
                    }
| GND
+
                }
|}
+
                catch (Exception e)
|
+
                {
|
+
                    Toast.makeText(getApplicationContext(),"Connect to Roadster First",Toast.LENGTH_SHORT).show();
|
+
                }
|
+
            }
{| class="wikitable"  
+
        });
|+ Table 7. Driver Node Pinout: RPIgear LCD Screen
+
        stop.setOnClickListener(new View.OnClickListener() {
|-
+
            @Override
! SJTwo Board
+
            public void onClick(View v) {
! CAN Board
+
                try {
|-
+
                    mConnectedThread.write("!!,\n");
| P4.28
+
                    state=false;
| UART - RX
+
                    move_camera=false;
|-
+
                    car_status.setText("  stopped");
| P4.29
+
                }
| UART - TX
+
                catch (Exception e)
|-
+
                {
| Vin
+
                    Toast.makeText(getApplicationContext(),"Connect to Roadster First",Toast.LENGTH_SHORT).show();
| 3.3
+
                }
|-
+
            }
| GND
+
        });
| GND
+
        start.setOnClickListener(new View.OnClickListener() {
|}
+
            @Override
|}
+
            public void onClick(View v) {
 +
                try {
 +
                    mConnectedThread.write("##,\n");
 +
                    state=true;
 +
                    move_camera=true;
 +
                    car_status.setText("  started");
 +
                }
 +
                catch (Exception e)
 +
                {
 +
                    Toast.makeText(getApplicationContext(),"Connect to Roadster First",Toast.LENGTH_SHORT).show();
 +
                }
 +
            }
 +
        });
 +
        send_cpts.setOnClickListener(new View.OnClickListener() {
 +
            @Override
 +
            public void onClick(View v) {
 +
                try {
 +
                    sending_status.setText("....");
 +
                for(int i=0;i<checkpoints.size();i++) {
 +
                    String cpt="GPS,"+checkpoints.get(i).latitude+","+checkpoints.get(i).longitude+"\n";
 +
                    mConnectedThread.write(cpt);
 +
                }
 +
                sending_status.setText("Sent");
 +
                }
 +
                catch (Exception e)
 +
                {
 +
                    Toast.makeText(getApplicationContext(),"Connect to Roadster First",Toast.LENGTH_SHORT).show();
 +
                }
 +
            }
 +
        });
  
 
=== Software Design ===
 
=== Software Design ===
 +
This app has mainly two activities, The main activity and maps activity.
  
=== Technical Challenges ===
+
===Maps Activity===
 
+
This is the only functional activity for the app and is responsible for the Google Maps and Bluetooth related Tasks. User can also dynamically select multiple checkpoints and send them to the bridge node. This is achieved using java vector and OnMapclickListener setup to read each marker placed by the user.
 
 
<HR>
 
<BR/>
 
 
 
== Mobile Application ==
 
  
 +
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
 +
            @Override
 +
            public void onMapClick(LatLng latLng) {
 +
                int precision = (int) Math.pow(10,6);
 +
                double new_latitude = (double)((int)(precision*latLng.latitude))/precision;
 +
                double new_longitude = (double)((int)(precision*latLng.longitude))/precision;
 +
                LatLng myloc = new LatLng(latLng.latitude, latLng.longitude);
 +
                mMap.addMarker(new MarkerOptions().position(myloc).title("Destination"));
 +
                mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(myloc,20));
 +
                checkpoints.add(new LatLng(new_latitude,new_longitude));
 +
                destination_coordinates = "GPS," + new_latitude + "," + new_longitude +"\n";
 +
            }
 +
        });
  
=== Hardware Design ===
+
===Bluetooth===
 +
The Bluetooth connection is initially set up by reading the id and MAC addresses of the selected device, The available devices are displayed on a listView under the connect button. Once the socket is established, Bluetooth module provides read() and write() API used to communicate.
  
  
=== Software Design ===
+
            if(!mBTAdapter.isEnabled()) {
 +
                Toast.makeText(getBaseContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show();
 +
                return;
 +
            }
 +
            mBluetoothStatus.setText("Connecting...");
 +
            // Get the device MAC address, which is the last 17 chars in the View
 +
            String info = ((TextView) v).getText().toString();
 +
            final String address = info.substring(info.length() - 17);
 +
            final String name = info.substring(0,info.length() - 17);
 +
            new Thread()
 +
            {
 +
                public void run() {
 +
                    boolean fail = false;
 +
                    BluetoothDevice device = mBTAdapter.getRemoteDevice(address);
 +
                    try {
 +
                        mBTSocket = createBluetoothSocket(device);
 +
                    } catch (IOException e) {
 +
                        fail = true;
 +
                        Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
 +
                    }
 +
                    // Establish the Bluetooth socket connection.
 +
                    try {
 +
                        mBTSocket.connect();
 +
                    } catch (IOException e) {
 +
                        try {
 +
                            fail = true;
 +
                            mBTSocket.close();
 +
                            mHandler.obtainMessage(CONNECTING_STATUS, -1, -1)
 +
                                    .sendToTarget();
 +
                        } catch (IOException e2) {
 +
                            Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
 +
                        }
 +
                    }
 +
                    if(fail == false) {
 +
                        mConnectedThread = new ConnectedThread(mBTSocket);
 +
                        mConnectedThread.start();
 +
                        mHandler.obtainMessage(CONNECTING_STATUS, 1, -1, name)
 +
                                .sendToTarget();
 +
                    }
  
  
 +
The Bridge node sends data in string format with end of line chars, The Bluetooth handler concatenates the received data and waits for the "end of line" before trying to parse it. Below is the code snippet that parses the incoming stream with location and debug data sent by the bridge node.
  
 +
                    if(readMessage.indexOf("\n")>0) {
 +
                        message = new StringTokenizer(readMessage, "\n");
 +
                        StringTokenizer st;
 +
                        while (message.hasMoreTokens()) {
 +
                            st = null;
 +
                            received_line = message.nextToken();
 +
                            st = new StringTokenizer(received_line, ",");
 +
                            try {
 +
                                read = st.nextToken();
 +
                            } catch (Exception e) {
 +
                                continue;
 +
                            }
 +
                            if (read.compareTo("GPS") == 0) {
 +
                                try {
 +
                                    LatLng current_location = new LatLng(Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken()));
 +
                                    waypoint.setText(st.nextToken("\n").replace(",", ""));
 +
                                    prev.remove();
 +
                                    prev = mMap.addMarker(new
 +
                                          MarkerOptions().position(current_location).anchor(0.5f,0.5f).rotation(compass_value).title("Roadster")
 +
                                          .icon(BitmapFromVector(getApplicationContext(), R.drawable.ic_baseline_directions_car_filled_24)));
 +
                            if (state || init) {
 +
                                        mMap.moveCamera(CameraUpdateFactory.newLatLng(current_location));
 +
                                        if (current_location.latitude != 0) init = false;
 +
                                    }
 +
                                } catch (Exception e) {
 +
                                }
 +
                            } else if (read.compareTo("speed") == 0) {
 +
                                try {
 +
                                    speed.setText(st.nextToken("\n").replace(",", "") + "m/s");
 +
                                } catch (Exception e) {
 +
                                }
 +
                            } else if (read.compareTo("sens") == 0) {
 +
                                try {
 +
                                    left.setText(st.nextToken() + "cm");
 +
                                    right.setText(st.nextToken() + "cm");
 +
                                    center.setText(st.nextToken() + "cm");
 +
                                    back.setText(st.nextToken("\n").replace(",", "") + "cm");
 +
                                } catch (Exception e) {
 +
                                }
 +
                            } else if (read.compareTo("comp") == 0) {
 +
                                try {
 +
                                    compass.setText(st.nextToken());
 +
                                    String compass_s=st.nextToken("\n").replace(",", "");
 +
                                    compass_raw.setText(compass_s);
 +
                                    compass_value =Integer.parseInt(compass_s);
 +
                                    prev.setAnchor(0.5f,0.5f);
 +
                                    prev.setRotation(compass_value);
 +
                                } catch (Exception e) {
 +
                                }
 +
                            } else if (read.compareTo("dist") == 0) {
 +
                                try {
 +
                                    String dis=st.nextToken("\n").replace(",", "");
 +
                                    distance.setText(dis+"m");
 +
                                    //int prog=(int)Float.parseFloat(dis)%200;
 +
                                    //progress.setProgress(prog);
 +
                                } catch (Exception e) {
 +
                                }
 +
                            } else if (read.compareTo("mot") == 0) {
 +
                                try {
 +
                                    rps.setText(st.nextToken());
 +
                                    pwm.setText(st.nextToken("\n").replace(",", ""));
 +
                                } catch (Exception e) {
 +
                                }
 +
                            }
 +
                            else if(read.compareTo("bat")==0){
 +
                                try{
 +
                                    battery.setText(st.nextToken("\n").replace(",", "")+"%");
 +
                                }catch (Exception e){
 +
                                }
 +
                            }
 +
                      }
 +
                        readMessage="";
  
 
=== Technical Challenges ===
 
=== Technical Challenges ===
 +
Given no experience in Android Development, we had to start from the basics about the activities, message passing etc. The initial challenge was to understand the google maps API and generate the API key to access google cloud to implement the map view and markers. Implementing Bluetooth communication required scanning the list of paired devices and acquire the MAC address required to open a socket using the provided API. Fortunately, there are many example implementations to go through. We decided to use a similar line buffer that is used in the Geo node to read the debug data sent from the app, this helped solve the challenge of parsing the group of variables sent by the bridge node by reading from the CAN bus.
  
  
 
+
<BR/>
 +
<HR>
 +
<HR>
 
<BR/>
 
<BR/>
  
 
== Conclusion ==
 
== Conclusion ==
  
 +
* Embedded project are generally single board projects. The mandatory use of CAN bus required a great deal of collaboration, where all board are interdependent and the system design should be robust to make it work every single time, the car is used for its intended purpose.
 +
*Unit testing helps in early phase of the  project, where the hardware setup is not ready yet, but one needs to start coding to get ahead of the curve and start building logic. This helps in troubleshooting the hardware as well.
  
 +
=== Project Video ===
  
 
+
https://youtu.be/Q24ghJRe9VM
 
 
 
 
 
 
  
 
=== Project Source Code ===
 
=== Project Source Code ===
 
+
''[https://gitlab.com/nimit.patel/roadster Repository link for Autonomous RC Car]''
 +
''[https://gitlab.com/srikarreddy.narapureddy/roadster-app  Repository for Android App]''
  
 
=== Advise for Future Students ===
 
=== Advise for Future Students ===
 
+
* Get the hardware modules and test the same with SJ2 (Before the Mid Semester exams). Once this is done, create a PCB and mount devices and then start the extensive software testing. Considering the car is  moving object, temporary connections over bread board and zero PCB might work, but reliability will remain a doubt at the back of the head. Eliminate the same by creating the PCB early. You might even want to iterate to a second PCB, once you are a few weeks into testing and want to change amend previous mistakes/improve existing layout and placements. The time and effort this will save is worth it.
 +
*Once the hardware is nearing its completion, the Mobile app should be ready in its rudimentary form. Having a hand held debug device is more useful, compared to using PCAN dongle which is great for static testing.
 +
* The software will take multiple iteration by testing your car in various field scenarios. This is not a project which can be completed a night before demo. Keep a healthy amount of time for testing.
 +
* The sole working power socket available in university outside of the university buildings is available on the top floor of the tenth street car garage. This is especially useful when testing in field.
  
 
=== Acknowledgement ===
 
=== Acknowledgement ===
 
+
* Building a hardware project without the availability of a electronics lab of the university which had been shut, due to COVID-19 pandemic tested our resourcefulness to our extremes.Considering the remote nature of course work, resource availability in any shape or form from university was sadly non existent. All the team members should be appreciated for their unwavering enthusiasm to make this a success story.
 +
* Preet's advice for buying quality hardware parts should be followed to the line.
  
 
=== References ===
 
=== References ===
 
+
http://socialledge.com/sjsu/index.php/Industrial_Application_using_CAN_Bus
'''Motor Controller'''
+
<Br>
 
 
* [https://traxxas.com/support/Programming-Your-Traxxas-Electronic-Speed-Control ESC]
 

Revision as of 14:53, 20 March 2022

FireBolt RC Car

Abstract

The Firebolt project is a path finding and obstacle avoiding RC car. The RC Car can interface with an Android application to get new coordinates to travel to, and will do so all while avoiding obstacles visible by ultrasonic sensors.

Objectives & Introduction

Objectives

  • RC car can communicate with an Android application to:
    • Receive new coordinates to travel to
    • Send diagnostic information to the application
    • Emergency stop and start driving
  • RC car can travel to received coordinates in an efficient path while avoiding obstacles
  • RC car can maintain speed when driving on sloped ground
  • Design printed circuit board (PCB) to neatly connect all SJ2 boards
  • Design and 3D print sensor mounts for the ultrasonic sensors
  • Design a simple and intuitive user interface for the Android application
  • Design a DBC file

Introduction

The Firebolt RC car uses 4 SJ2 boards as nodes on the CAN bus

  1. Driver and LCD
  2. GEO and path finding
  3. Sensors and bridge app
  4. Motor

Team Members & Responsibilities

Priyanka Rai

    • Geographical Controller
    • Master Controller

Ritu Patil

    • Android Application Developer
    • Communication Bridge Controller

Ritika Beniwal

    • Master Controller

Utsav Savaliya

    • Sensors Controller

Dhanush Babu

    • Hardware Integration
    • PCB Designing


Schedule

Week# Start Date End Date Task Actual Completion Status
1

03/01 to 03/07 Start of Phase 1

  • 03/01
  • 03/04
  • 03/05
  • 03/04
  • 03/07
  • 03/07
  • Study and discuss previous project reports
  • Brainstorm on the requirements for the project
  • Identify and order/purchase the required components
  • 03/04
  • 03/07
  • 03/09
  • Completed
  • Completed
  • Completed
2

03/08 to 03/14

  • 03/08
  • 03/08
  • 03/11
  • 03/12
  • 03/08
  • 03/08
  • 03/14
  • 03/14
  • Create and setup Gitlab Repository
  • Create and setup Confluence for document collaboration
  • Study the datasheets and manual of acquired components
  • Distribute initial roles among the team members
  • 03/04
  • 03/07
  • 03/17
  • 03/15
  • Completed
  • Completed
  • Completed
  • Completed
3

03/15 to 03/21

  • 03/15
  • 03/15
  • 03/19
  • 03/18
  • 03/15
  • 03/18
  • 03/18
  • 03/21
  • 03/21
  • 03/27
  • Interface ultrasonic sensors and test the functionality
  • Interface GPS and Compass and test the functionality
  • Analyze and decide the hardware placement of the RC Car
  • Create SENSOR and DRIVER nodes to transmit and receive data
  • Identify the Android app requirements and start studying the Android framework
  • 03/18
  • 03/22
  • 03/20
  • 03/21
  • 03/25
  • Completed
  • Completed
  • Completed
  • Completed
  • Completed
4

03/22 to 03/28

  • 03/22
  • 03/22
  • 03/25
  • 03/27
  • 03/22
  • 03/25
  • 03/24
  • 03/28
  • 03/31
  • 03/28
  • Create the GEO node to get coordinates and cardinal directions from GPS and Compass
  • Interface the Bluetooth module to communicate with SJ-two board
  • Create the MOTOR node to drive the RC Car
  • Start designing the DBC file
  • Develop an initial version of the Android app
  • 03/24
  • 03/24
  • 03/28
  • 03/30
  • 03/28
  • Completed
  • Completed
  • Completed
  • Completed
  • Completed
5

03/29 to 04/04 End of Phase 1

  • 04/02
  • 03/29
  • 03/29
  • 03/29
  • 03/31
  • 04/03
  • 04/03
  • 04/01
  • 04/01
  • 04/01
  • 04/03
  • 04/04
  • Finalize the DBC file
  • Design obstacle avoidance and steering logic on the DRIVER node
  • Design motor driving logic on the MOTOR node with the encoder
  • Interface the LCD module with the DRIVER node to display messages
  • Integrate sensor data on the SENSOR node
  • Collective Test 1: Integrate all the completed modules and test on BusMaster
  • 04/05
  • 04/01
  • 04/01
  • 04/01
  • 04/04
  • 04/04
  • Completed
  • Completed
  • Completed
  • Completed
  • Completed
  • Completed
6

04/05 to 04/11 Start of Phase 2

  • 04/05
  • 04/05
  • 04/08
  • 04/10
  • 04/08
  • 04/08
  • 04/10
  • 04/11
  • Tune the SENSOR and DRIVER nodes to drive the RC car
  • Communicate to the DRIVER node over Bluetooth via Android app
  • Debug and revise the integrated modules with necessary improvements
  • Collective Test 2: Drive the car to a hardcoded GPS destination
  • 04/08
  • 04/08
  • 04/08
  • 04/08
  • Completed
  • Completed
  • Completed
  • Completed
7

04/12 to 04/18

  • 04/12
  • 04/15
  • 04/12
  • 04/17
  • 04/15
  • 04/18
  • 04/16
  • 04/18
  • Integrate GEO node to DRIVER node for navigation
  • Design driving decision logic based on the navigation data
  • Design a dashboard on the LCD to display the values
  • Collective Test 3: Test the car driving with navigation data from the Android app
  • 04/15
  • 04/18
  • 04/16
  • 04/18
  • Completed
  • Completed
  • Completed
  • Completed
8

04/19 to 04/25 End of Phase 2

  • 04/19
  • 04/19
  • 04/19
  • 04/19
  • 04/25
  • 04/25
  • 04/25
  • 04/25
  • Add functionalities to display various sensor data on the Android app
  • Design and 3D print the required components
  • Design and order PCB
  • Test and improve the RC car performance based on the changes
  • 04/25
  • 04/25
  • 04/25
  • Completed
  • Incomplete
  • Completed
  • Completed
9

04/26 to 05/02 Start of Phase 3

  • 04/26
  • 04/26
  • 04/26
  • 05/01
  • 04/30
  • 04/30
  • 04/30
  • 05/02
  • Design individual architecture diagrams and algorithms for documentation
  • Make any necessary improvements based on previous test results
  • Complete the final version of the Android app
  • Collective Test 4: Test car on various terrains and slopes
  • 04/30
  • 04/30
  • 04/30
  • 05/02
  • Completed
  • Completed
  • Completed
  • Completed
10

05/03 to 05/09

  • 05/03
  • 05/03
  • 05/03
  • 05/08
  • 05/07
  • 05/07
  • 05/07
  • 05/09
  • Replace the circuits with their corresponding PCBs and assemble
  • Complete the RC Car structure and assembly with the 3D printed parts - Prototype 1
  • Refactor the code modules with necessary improvements
  • Collective Test 5: Test the Prototype 1 with the aim of sending the car to return Preet's PCAN Dongle
  • 05/07
  • 05/07
  • 05/07
  • 05/09
  • Completed
  • Completed
  • Completed
  • Deferred
11

05/10 to 05/16 End of Phase 3

  • 05/10
  • 05/10
  • 05/10
  • 05/15
  • 05/16
  • 05/16
  • 05/16
  • 05/16
  • Revise and improve the wiki report to cover all the aspects of design and implementation
  • Fix all the errors and make improvements
  • Final testing of all the modules and car
  • Collective Test 6: Have the final version of the project tested with all the functionalities
  • 05/16
  • 05/16
  • 05/16
  • 05/16
  • Completed
  • Completed
  • Completed
  • Completed


Parts List & Cost

Item# Part Desciption Vendor Qty Cost
1 RC Car Traxxas [1] 1 $250.00
2 CAN Transceivers MCP2551-I/P Comimark [2] 5 $7.00
3 Ultrasonic Sensors Max Botix[3] 5 $150.00
4 GPS and Antenna Adafruit[4] 1 $60.00
5 HC05 bluetooth RF Transreceiver HiLetgo[5] 1 $12.59
6 Triple-axis Accelerometer Adafruit[6] 1 $21.40
7 Traxxas RPM Sensor Traxxas[7] 1 $12
8 Discrete Electronic Components Generic[8] 1 $28.75
9 Buck-Boost Voltage Regulator Generic[9] 1 $11.99
10 Traxxas Telemetry Trigger magnet & holder Traxxas[10] 1 $6.35
11 Acrylic Sheet Tap Plastic 1 $12
12 Battery Amazon[11] 1 $26.99
13 Traxxas Battery and Charger Amazon[12] 1 $55.94


Printed Circuit Board

PCB Schematic

Roadster Schematic

PCB Design

Roadster PCB

CAN Communication

We use controller area network to broadcast data between the 4 nodes. All nodes are connected to each other through a physically conventional two wire bus. The wires are a twisted pair with 120 Ω resistors at each ends of the bus. 1s and 0s are transmitted as CAN High(0V difference) and Can Low(2v difference). A CAN frame has the following contents:

  • Data Length Code (4bits)
  • Remote Transmission Request.
  • ID extend bit.
  • Message ID (11 bit or 29 bit)
  • Data bytes( depends on DLC)
  • CRC


Arbitration: No two nodes will transmit at the same time because if arbitration. A lower Message-ID has a Higher priority on the CAN bus since 0 is the dominant bit.

Bit Stuffing: CAN bus stuffs extra bits when a long chain of multiple 1's or 0's occur to improve CAN integrity.

Sr. No Message ID Message function Receivers
Driver Controller
1 300 speed and steering direction for the motor. Motor
2 310 Destination reached Sensor
Sensor Controller
1 200 Sensor sonars from front, back, left ,right sensor Driver
Motor Controller
8 700 motor speed, motor direction Driver
Geo and Bridge Controller
1 400 Bearing, Heading and Distance Driver
Debug messages
1 851 Driver Debug SENSOR,MOTOR,GEO_AND_BRIDGE
1 811 Motor Debug SENSOR,MOTOR,GEO_AND_BRIDGE
1 801 Sensor Debug SENSOR,MOTOR,GEO_AND_BRIDGE


Hardware Design

CAN Bus Design


DBC File

VERSION ""

NS_ :
	BA_
	BA_DEF_
	BA_DEF_DEF_
	BA_DEF_DEF_REL_
	BA_DEF_REL_
	BA_DEF_SGTYPE_
	BA_REL_
	BA_SGTYPE_
	BO_TX_BU_
	BU_BO_REL_
	BU_EV_REL_
	BU_SG_REL_
	CAT_
	CAT_DEF_
	CM_
	ENVVAR_DATA_
	EV_DATA_
	FILTER
	NS_DESC_
	SGTYPE_
	SGTYPE_VAL_
	SG_MUL_VAL_
	SIGTYPE_VALTYPE_
	SIG_GROUP_
	SIG_TYPE_REF_
	SIG_VALTYPE_
	VAL_
	VAL_TABLE_

BS_:

BU_: DRIVER MOTOR SENSOR GEO_AND_BRIDGE DEBUG

BO_ 200 SENSOR_SONARS: 5 SENSOR
 SG_ SENSOR_SONARS_left : 0|10@1+ (1,0) [0|800] "cm" DRIVER
 SG_ SENSOR_SONARS_right : 10|10@1+ (1,0) [0|0] "cm" DRIVER
 SG_ SENSOR_SONARS_middle : 20|10@1+ (1,0) [0|0] "cm" DRIVER
 SG_ SENSOR_SONARS_rear : 30|10@1+ (1,0) [0|0] "cm" DRIVER

BO_ 300 DRIVER_TO_MOTOR: 2 DRIVER
 SG_ MOTOR_speed : 0|8@1+ (0.1,-12.5) [-12.5|12.5] "m/s" MOTOR
 SG_ MOTOR_direction : 8|7@1+ (1,-45) [-45|45] "degree" MOTOR

BO_ 310 DRIVER_BROADCAST: 1 DRIVER
 SG_ DEST_reached : 0|8@1+ (1,0) [0|0] "flag" SENSOR 

BO_ 400 GEO_CONTROLLER_COMPASS: 6 GEO_AND_BRIDGE
  SG_ HEADING : 0|12@1+ (1,0) [0|359] "Degrees" DRIVER
  SG_ BEARING : 12|12@1+ (1,0) [0|359] "Degrees" DRIVER
  SG_ DISTANCE : 24|17@1+ (0.01,0) [0|0] "Meters" DRIVER

BO_ 401 GEO_CONTROLLER_COMPASS_DEBUG: 9 GEO_AND_BRIDGE
  SG_ WAYPOINT_COUNT : 0|8@1+ (1,0) [0|16] "" DEBUG
  SG_ STATUS : 8|8@1+ (1,0) [0|359] "Degrees" DEBUG
  SG_ DISTANCE_TO_WAYPOINT : 16|12@1+ (0.01,0) [0|0] "Meters" DEBUG
  SG_ HEADING_TO_WAYPOINT : 28|12@1+ (1,0) [0|359] "Degrees" DEBUG
  SG_ BEARING_TO_WAYPOINT : 40|12@1+ (1,0) [0|359] "Degrees" DEBUG
  SG_ HEADING_RAW : 52|12@1+ (1,0) [0|359] "Degrees" DEBUG
  SG_ WAYPOINT_CURRENT : 64|8@1+ (1,0) [0|16] "" DEBUG

BO_ 700 MOTOR_TO_DRIVER: 8 MOTOR
 SG_ MOTOR_speed:0|8@1+ (0.1,-12.5) [-12.5|12.5] "m/s" DRIVER
 SG_ MOTOR_direction : 8|7@1+ (1,-45) [-45|45] "degree" DRIVER

BO_ 851 DRIVER_DEBUG_DATA: 1 DEBUG
 SG_ forwardDrivingState:0|2@1+ (1,0) [0|0] "" SENSOR,MOTOR,GEO_AND_BRIDGE
 SG_ reverseDrivingState: 2|2@1+ (1,0) [0|0] "" SENSOR,MOTOR,GEO_AND_BRIDGE
 SG_ isRightSteeringPossible:4|2@1+ (1,0) [0|0] "" SENSOR,MOTOR,GEO_AND_BRIDGE
 SG_ isLeftSteeringPossible:6|2@1+ (1,0) [0|0] "" SENSOR,MOTOR,GEO_AND_BRIDGE
 
BO_ 801 SENSOR_DEBUG_DATA: 8 DEBUG
 SG_ LEFT_sensor_raw:0|16@1+ (1,0) [0|0] "cm" SENSOR,MOTOR,GEO_AND_BRIDGE
 SG_ RIGHT_sensor_raw: 16|16@1+ (1,0) [0|0] "cm" SENSOR,MOTOR,GEO_AND_BRIDGE
 SG_ FRONT_sensor_raw: 32|16@1+ (1,0) [0|0] "cm" SENSOR,MOTOR,GEO_AND_BRIDGE
 SG_ REAR_sensor_raw: 48|16@1+ (1,0) [0|0] "cm" SENSOR,MOTOR,GEO_AND_BRIDGE

BO_ 811 MOTOR_DEBUG_DATA: 8 DEBUG
 SG_ MOTOR_rps_value:0|32@1+ (1,0) [0|0] "rps value" SENSOR,DRIVER,GEO_AND_BRIDGE
 SG_ MOTOR_pwm_value:32|8@1+ (0.01,0) [0|0] "dc motor pwm value" SENSOR,DRIVER,GEO_AND_BRIDGE

BO_ 1000 DRIVER_HEARTBEAT: 1 DRIVER
 SG_ DRIVER_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" SENSOR,MOTOR,GEO_AND_BRIDGE

BO_ 1100 MOTOR_HEARTBEAT: 1 DRIVER
 SG_ MOTOR_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" SENSOR,DRIVER,GEO_AND_BRIDGE

BO_ 1200 SENSOR_HEARTBEAT: 1 DRIVER
 SG_ SENSOR_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" MOTOR,DRIVER,GEO_AND_BRIDGE

BO_ 1300 GEO_HEARTBEAT: 1 DRIVER
 SG_ GEO_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" SENSOR,MOTOR,DRIVER

CM_ BU_ DRIVER "The driver controller driving the car";
CM_ BU_ MOTOR "The motor controller of the car";
CM_ BU_ SENSOR "The sensor controller of the car";
CM_ BO_ 100 "Sync message used to synchronize the controllers";
CM_ SG_ 100 DRIVER_HEARTBEAT_cmd "Heartbeat command from the driver";

BA_DEF_ "BusType" STRING ;
BA_DEF_ BO_ "GenMsgCycleTime" INT 0 0;
BA_DEF_ SG_ "FieldType" STRING ;

BA_DEF_DEF_ "BusType" "CAN";
BA_DEF_DEF_ "FieldType" "";
BA_DEF_DEF_ "GenMsgCycleTime" 0;

BA_ "GenMsgCycleTime" BO_ 100 1000;
BA_ "GenMsgCycleTime" BO_ 200 50;
BA_ "FieldType" SG_ 100 DRIVER_HEARTBEAT_cmd "DRIVER_HEARTBEAT_cmd";

VAL_ 100 DRIVER_HEARTBEAT_cmd 2 "DRIVER_HEARTBEAT_cmd_REBOOT" 1 "DRIVER_HEARTBEAT_cmd_SYNC" 0 "DRIVER_HEARTBEAT_cmd_NOOP" ;




Sensor ECU

<Picture and link to Gitlab> Gitlab link to Sensor Node Firmware: https://gitlab.com/nimit.patel/roadster/-/tree/Main/Sensor_Node

The sensor controller node is responsible for interfacing with Ultrasonic sensors to know obstacles’ distance from the vehicle. We have used MaxBotix 1010 LV-EZ1 sensors for the right and left positions and MaxBotix 1000 LV-EZ0 sensor in the middle front position (To have a wider beam range of obstacle detection in blind spots).

Sensor Controller Diagram

Below is the beam pattern for both sensors.

Beam Pattern MaxBotix MB1000 EZ0
Beam Pattern MaxBotix MB1010 EZ1


Hardware Design

Sensor Controller Schematic

Sensor Controller Node Schematic


Board Pin Connections

Sensors are interfaced with combination of GPIO, ADC Pins on SJTWo board. Below is the descriptive pin layout:

Sensors pin layout
Sr. No. SJTwo board Pin Maxbotix sensor Pin Function
1 ADC2-P0.25 AN(Front sensor) ADC input from front sensor
2 ADC3-P0.26 AN(Rear Sensor) ADC input from rear sensor
3 ADC4-P1.30 AN(Left Sensor) ADC input from left sensor
4 ADC5-P1.31 AN(Right Sensor) ADC input from right sensor
5 GPIO-P0.6 RX(Left Sensor) Trigger for left sensor
6 GPIO-P0.7 RX(Front Sensor) Trigger for front sensor
7 GPIO-P0.8 RX(Right Sensor) Trigger for right sensor
8 GPIO-P0.9 RX(Rear Sensor) Trigger for rear sensor

Software Design

The sensor node mainly does two activity viz. 1) Read sensor values, 2) Transmit obstacle distance over CAN bus. Both of these activities happen in a 20Hz periodic callback.

1. Read Sensor Values

  • Sensors are mounted at four locations as mentioned below diagram. To read these sensor values, we initialized and configured 4 sensors using 4 ADCs viz ADC2, ADC3, ADC4, and ADC5. Considering the front 3 sensors' close proximity and possible beam interference, we decided to range extreme front sensors at a time and the middle front next in sequence while in a 20 Hz loop. And the rear sensor is triggered regularly. All the sensor values are digitally converted in the range of 0 to 4096 (12 bit ADC). These values are converted to distance format in centimeter unit using formula conv_val = (raw_val * 0.3182) - 0.3959.
Sensors Placement location
  • Now, to avoid frequent noise pulses, we used a median filter. We created an array of 10 elements for each sensor and maintained a write index to track the current update position. Thus, all read values have been updated in the buffer which acts as a circular buffer as we start overwriting from the start index.

2. Transmit obstacle distance over CAN bus:

  • Sensor node is responsible for broadcasting all four sensor values in terms of distance in centimeter over CAN bus. To broadcast filtered values, it first sorts the existing values in the respective allocated sensor buffer. Then it takes the mean of five median values. It does the same thing for all four sensors. Finally, it transmits those values over CAN bus. Below flow chart gives the detailed flow of code at a high level.
Sensor Node Controller Flow Chart

Technical Challenges

Neighboring Sensor Interference:

  • As explained above, we have mounted three ultrasonic sensors in the front, and those were configured to range in continuous mode, in which sensors were continuously measuring distance by transmitting beam. Out of 3, the middle sensor is of type with wider beam to detect blind spots ahead.
  • Most of the time, we observed that the obstacle in the middle sensor range used also gets detected by the left/right sensor, which disturbs driving logic. This used to happen due to sensor beam interference among three sensors.
  • To solve this problem, we decided to trigger sensor beams in such time intervals that they won’t interfere with neighboring ones. We used the Rx pin of the sensor to trigger ranging and scheduled to trigger left and right sensor at one time and middle sensor next time. This sequence helped us avoid interference altogether.

Frequent noisy measurements:

  • While reading the obstacle distance, it used to change suddenly to some random value, and that used to disturb driving logic. To get noise-free readings from sensors, we implemented a median filter. All the read values from sensors have been collected in the respective buffer of 10 elements. While sending obstacle distance on CAN bus, the median filter sort the buffer and takes an average of 5 median values. This way, it helped us to remove almost all noisy values.




Motor ECU

Motor Node Schematic

Hardware Design

Traxass ESC XL5
Traxass Servo Motor
Traxass RPM Sensor


The motor node(SJ-2) interfaces primarily interfaces with:

  • Traxass Motor ESC over PWM
  • Traxass RPM Sensor over GPIO Interrupt
  • Traxass Servo Motor over PWM

All these three components have 3 pins each. The functionalities of these pins are mentioned in the table below.

Module Black Red White
ESC Ground Vout : 6 V PWM Input
Servo Ground Vin : 6 V PWM Input
RPM Sensor Ground Vin : 6 V Pulse Output

Software Design

The motor node acts based on the speed and direction received over CAN bus from the Driver Node. The positive speed values are treated as forward motion and the negative speed values are considered to be the reverse motion of the RC car.

The steering angles are divided into 5-degree segments and the motor node sends the pre-defined pwm duty cycle of the particular segment to the servo motor depending on the angle value received from the driver node.

Motor Node - Software Flowchart

Technical Challenges

  • Firstly, the Traxxas motor ESC and other Traxass parts are members of the Traxxas Hobby Parts family, and they are not intended for development purposes. This is why there are no technical specification documents or any program/development guides available. One needs to test the motor ESC by feeding the PWM duty cycles in various sequences at various duty cycle percentages. We used the Remote control to reproduce some scenarios where the ESC was behaving unexpectedly.
  • The ESC configuration changes to the Lipo battery state if the Lipo battery is used. If one switches back to the NiMH battery, then the ESC starts flashing the led in a green-red repeated sequence, and the ESC power button stops working. In this scenario, there is a calibration process that can save your boat and can make the ESC function normally again. Follow this procedure : ESC Calibration
  • Another challenge with the motor node program development is that you cannot rely on unit testing. Whoever works on the motor node, should make sure that the sequence of the duty cycles being fed to the ESC produces the expected results on the motor as well. The forward-reverse transitioning and the speed controlling both can be a bit tricky. Also, the hard brake logic can take a while to get working properly.
  • Some useful reference values for the ESC are : 15% -> Neutral; 15.8%-> Minimum forward speed, 10%->Full reverse speed.


Geographical And Bridge Controller

Repository link for Geo Controller

Hardware Design

Geo Node Schematic


Bluetooth Trans-receiver
GPS Module
3 Axis Magnetometer (eCompass)


Battery Monitoring



The SJ2 board communicates with:

  • Bluettoth transreceiver over UART
  • LSM303DLHC over I2C
  • GPS model over UART
  • Battery monitoring

Considering the orientation of the car changes as it travel along the land, tilt compensation logic for heading calculation using the magnetometer is a must for accurate measurement. Without the tilt compensation algorithm which uses the onboard accelorometer, the heading computation can have error up to 60 degrees, which has the potential to send the car off course.

For battery monitoring, the values for the voltage divider should be chosen such that the full range of the onboard ADC can be efficiently used. Depending one the cell type of the battery, the discharge curve can be use to map the charge state corresponding to voltage level. This method has its flaws and sophisticated techniques involving Coulomb count yields far better results, however, the technique discussed above suffices the needs of our project. Charge state of battery transmitted over Mobile app, greatly facilitates the charging schedule while testing and final demo day.



Software Design

The periodic scheduler for Geo Controller Node does the following functionalities:

  • In 10Hz periodic callback:
    • gps__update() : Fetch GPS data from GPS controller.
    • geo_compass__periodic_send() : Reads the Magnetometer and accelerometer values from Compass controller and convert those to current heading data.
  • In 100Hz periodic callback:
    • bluetooth__run_once() : Send specified data to android application via Bluetooth.

The GEO controller is divided into 5 parts.

  • The current location of the car is determined using the GPS.
  • The current magnetic heading of car is determined using the on board compass.
  • The way point calculation determines the nearest way point continuously by computing the distance using Haversine formula and current location using GPS.
  • The heading is also computed using the Haversine formula and the difference between the actual and required is sent over the CAN bus for heading correction.
  • Alternatively, once the car is within the threshold distance, next way point is selected and the car heads to the next way point.


Heading computation from geographical (Geo) controller

Technical Challenges

  • The GPS module sends data at 9600 baud rate, updating the data every one second. The data update rate needs to be updated to 10Hz for fast maneuvering and course correction of the car. If the update frequency is updated, the data sent over the UART is higher than it can handle in 10Hz periodic function. Hence, only GPGGA messages should be enabled to extract the required data and reduce the time spent in parsing the incoming string. NEMA (PMTK) messages should be correctly configured on the module for desired functioning.
  • Heading calculation without the tilt compensation logic using the onboard accelorometer of LSM303 is in accurate. Reading accelorometer values requires and offset of 0x80 to the byte addressing of the accelorometer read. Magnetometer need no such offset. This is weird, considering both the I2C devices reside on the same physical chip.
  • Using data type as float as opposed to double, utilizes the onboard FPU, which is faster. Double utilizes software implementation, which takes more clock cycle. Considering extensive use of math library in distance/heading measurement and tilt compensation algorithm, completing the task with the periodic is of at most importance.
  • GPS fix is best when when there are no obstruction above the module. Module requires clear wide view of sky for a fast fix and error free location detection.
  • LSM303DLHC is sensitive to even weak magnetic field interference. Place the chip devoid of such active/passive magnetic fields.
  • Calibrating LSM303 is a must to get accurate heading values. 2-point calibration worked just fine for our team. More sophisticated methods are available too.

Driver Node

https://gitlab.com/nimit.patel/roadster/-/tree/Main/Driver_Node

Hardware Design

The Driver Node has one peripheral connected to it and that is the LCD screen.

Driver Node Schematic
Driver Node Schematic

Software Design

The driver node controls the logic of steering the car in the right direction based on the data received from the Sensor and Geo Nodes. The following flowchart describes that process.

  • Driver Node Flow Chart
Driver Node Flow Chart

In case there are obstacles in the path where the car wants to move to, the following obstacle avoid logic would kick in.

  • Driver Node Obstacle Avoidance Logic
Driver Node Obstacle Avoidance Logic

The work in the Driver Node is done using two different periodic tasks. Here is a description of those periodic tasks and what they do.

  • 1 Hz Loop:
    • Transmit debug messages over the CAN bus
    • Transmit messages on the LCD
    • Transmit destination reached flag over the CAN Bus
  • 20 Hz Loop:
    • Receive Sensor Data
    • Receive Geo Data
    • Process and Transmit Data(Motor Direction and Speed) to Motor Node
  • LCD Interface

The LCD interface on the Driver is used to print some important information about the car. This is what it prints.

    • Car Speed
    • Distance from the Destination
    • Car State (Car Stopped from the App, Car Moving, Destination Reached)

Technical Challenges

  • The Driver Node did not have much hardware interfaced on it apart from LCD. So from the hardware side there were no technical challenges. On the software front as well there were not many challenges as unit tests helped debug most of the issues then and there.
  • We initially used GLCD which was configured via GPIOs and it was working perfectly. Hence we created our PCB as per this LCD. But, while testing our car with various speeds and PID logic, it got toppled and damaged the LCD. So, we had to change to SJ Valley LCD, which was configured via the UART interface, at the last moment. So, we used the same location on the PCB to place the LCD and soldered wires below PCB. Hence, this correction was not visible on our end product.


Mobile Application

Gitlab We created a lightweight mobile app to navigate our car, It can communicate with the car via Bluetooth and is capable of sending Destination co-ordinates along with checkpoints. Receive and Update live location on Google Maps, send Start, Stop and Clear commands, Receive and Display Debug Data.

  • Splash screen
  • Data from roadster
  • Checkpoints

User Interface

The app has minimal buttons on the same screen as Google Maps View to confirm the cars current state and location before sending the commands.

       connect_Btn.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               listPairedDevices(v);
           }
       });
       clear.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               try {
                   if(!state) {
                       mConnectedThread.write("--,\n");
                       mMap.clear();
                       checkpoints.clear();
                       sending_status.setText("Waiting");
                   }
                   else{
                       Toast.makeText(getApplicationContext(),"Stop the car First",Toast.LENGTH_SHORT).show();
                   }
               }
               catch (Exception e)
               {
                   Toast.makeText(getApplicationContext(),"Connect to Roadster First",Toast.LENGTH_SHORT).show();
               }
           }
       });
       stop.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               try {
                   mConnectedThread.write("!!,\n");
                   state=false;
                   move_camera=false;
                   car_status.setText("   stopped");
               }
               catch (Exception e)
               {
                   Toast.makeText(getApplicationContext(),"Connect to Roadster First",Toast.LENGTH_SHORT).show();
               }
           }
       });
       start.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               try {
                   mConnectedThread.write("##,\n");
                   state=true;
                   move_camera=true;
                   car_status.setText("   started");
               }
               catch (Exception e)
               {
                   Toast.makeText(getApplicationContext(),"Connect to Roadster First",Toast.LENGTH_SHORT).show();
               }
           }
       });
       send_cpts.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               try {
                   sending_status.setText("....");
               for(int i=0;i<checkpoints.size();i++) {
                   String cpt="GPS,"+checkpoints.get(i).latitude+","+checkpoints.get(i).longitude+"\n";
                   mConnectedThread.write(cpt);
               }
               sending_status.setText("Sent");
               }
               catch (Exception e)
               {
                   Toast.makeText(getApplicationContext(),"Connect to Roadster First",Toast.LENGTH_SHORT).show();
               }
           }
       });

Software Design

This app has mainly two activities, The main activity and maps activity.

Maps Activity

This is the only functional activity for the app and is responsible for the Google Maps and Bluetooth related Tasks. User can also dynamically select multiple checkpoints and send them to the bridge node. This is achieved using java vector and OnMapclickListener setup to read each marker placed by the user.

mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {

           @Override
           public void onMapClick(LatLng latLng) {
               int precision = (int) Math.pow(10,6);
               double new_latitude = (double)((int)(precision*latLng.latitude))/precision;
               double new_longitude = (double)((int)(precision*latLng.longitude))/precision;
               LatLng myloc = new LatLng(latLng.latitude, latLng.longitude);
               mMap.addMarker(new MarkerOptions().position(myloc).title("Destination"));
               mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(myloc,20));
               checkpoints.add(new LatLng(new_latitude,new_longitude));
               destination_coordinates = "GPS," + new_latitude + "," + new_longitude +"\n";
           }
       });

Bluetooth

The Bluetooth connection is initially set up by reading the id and MAC addresses of the selected device, The available devices are displayed on a listView under the connect button. Once the socket is established, Bluetooth module provides read() and write() API used to communicate.


           if(!mBTAdapter.isEnabled()) {
               Toast.makeText(getBaseContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show();
               return;
           }
           mBluetoothStatus.setText("Connecting...");
           // Get the device MAC address, which is the last 17 chars in the View
           String info = ((TextView) v).getText().toString();
           final String address = info.substring(info.length() - 17);
           final String name = info.substring(0,info.length() - 17);
           new Thread()
           {
               public void run() {
                   boolean fail = false;
                   BluetoothDevice device = mBTAdapter.getRemoteDevice(address);
                   try {
                       mBTSocket = createBluetoothSocket(device);
                   } catch (IOException e) {
                       fail = true;
                       Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
                   }
                   // Establish the Bluetooth socket connection.
                   try {
                       mBTSocket.connect();
                   } catch (IOException e) {
                       try {
                           fail = true;
                           mBTSocket.close();
                           mHandler.obtainMessage(CONNECTING_STATUS, -1, -1)
                                   .sendToTarget();
                       } catch (IOException e2) {
                           Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
                       }
                   }
                   if(fail == false) {
                       mConnectedThread = new ConnectedThread(mBTSocket);
                       mConnectedThread.start();
                       mHandler.obtainMessage(CONNECTING_STATUS, 1, -1, name)
                               .sendToTarget();
                   }


The Bridge node sends data in string format with end of line chars, The Bluetooth handler concatenates the received data and waits for the "end of line" before trying to parse it. Below is the code snippet that parses the incoming stream with location and debug data sent by the bridge node.

                   if(readMessage.indexOf("\n")>0) {
                       message = new StringTokenizer(readMessage, "\n");
                       StringTokenizer st;
                       while (message.hasMoreTokens()) {
                           st = null;
                           received_line = message.nextToken();
                           st = new StringTokenizer(received_line, ",");
                           try {
                               read = st.nextToken();
                           } catch (Exception e) {
                               continue;
                           }
                           if (read.compareTo("GPS") == 0) {
                               try {
                                   LatLng current_location = new LatLng(Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken()));
                                   waypoint.setText(st.nextToken("\n").replace(",", ""));
                                   prev.remove();
                                   prev = mMap.addMarker(new 
                                          MarkerOptions().position(current_location).anchor(0.5f,0.5f).rotation(compass_value).title("Roadster")
                                          .icon(BitmapFromVector(getApplicationContext(), R.drawable.ic_baseline_directions_car_filled_24)));
                            if (state || init) {
                                       mMap.moveCamera(CameraUpdateFactory.newLatLng(current_location));
                                       if (current_location.latitude != 0) init = false;
                                   }
                               } catch (Exception e) {
                               }
                           } else if (read.compareTo("speed") == 0) {
                               try {
                                   speed.setText(st.nextToken("\n").replace(",", "") + "m/s");
                               } catch (Exception e) {
                               }
                           } else if (read.compareTo("sens") == 0) {
                               try {
                                   left.setText(st.nextToken() + "cm");
                                   right.setText(st.nextToken() + "cm");
                                   center.setText(st.nextToken() + "cm");
                                   back.setText(st.nextToken("\n").replace(",", "") + "cm");
                               } catch (Exception e) {
                               }
                           } else if (read.compareTo("comp") == 0) {
                               try {
                                   compass.setText(st.nextToken());
                                   String compass_s=st.nextToken("\n").replace(",", "");
                                   compass_raw.setText(compass_s);
                                   compass_value =Integer.parseInt(compass_s);
                                   prev.setAnchor(0.5f,0.5f);
                                   prev.setRotation(compass_value);
                               } catch (Exception e) {
                               }
                           } else if (read.compareTo("dist") == 0) {
                               try {
                                   String dis=st.nextToken("\n").replace(",", "");
                                   distance.setText(dis+"m");
                                   //int prog=(int)Float.parseFloat(dis)%200;
                                   //progress.setProgress(prog);
                               } catch (Exception e) {
                               }
                           } else if (read.compareTo("mot") == 0) {
                               try {
                                   rps.setText(st.nextToken());
                                   pwm.setText(st.nextToken("\n").replace(",", ""));
                               } catch (Exception e) {
                               }
                           }
                           else if(read.compareTo("bat")==0){
                               try{
                                   battery.setText(st.nextToken("\n").replace(",", "")+"%");
                               }catch (Exception e){
                               }
                           }
                      }
                       readMessage="";

Technical Challenges

Given no experience in Android Development, we had to start from the basics about the activities, message passing etc. The initial challenge was to understand the google maps API and generate the API key to access google cloud to implement the map view and markers. Implementing Bluetooth communication required scanning the list of paired devices and acquire the MAC address required to open a socket using the provided API. Fortunately, there are many example implementations to go through. We decided to use a similar line buffer that is used in the Geo node to read the debug data sent from the app, this helped solve the challenge of parsing the group of variables sent by the bridge node by reading from the CAN bus.






Conclusion

  • Embedded project are generally single board projects. The mandatory use of CAN bus required a great deal of collaboration, where all board are interdependent and the system design should be robust to make it work every single time, the car is used for its intended purpose.
  • Unit testing helps in early phase of the project, where the hardware setup is not ready yet, but one needs to start coding to get ahead of the curve and start building logic. This helps in troubleshooting the hardware as well.

Project Video

https://youtu.be/Q24ghJRe9VM

Project Source Code

Repository link for Autonomous RC Car Repository for Android App

Advise for Future Students

  • Get the hardware modules and test the same with SJ2 (Before the Mid Semester exams). Once this is done, create a PCB and mount devices and then start the extensive software testing. Considering the car is moving object, temporary connections over bread board and zero PCB might work, but reliability will remain a doubt at the back of the head. Eliminate the same by creating the PCB early. You might even want to iterate to a second PCB, once you are a few weeks into testing and want to change amend previous mistakes/improve existing layout and placements. The time and effort this will save is worth it.
  • Once the hardware is nearing its completion, the Mobile app should be ready in its rudimentary form. Having a hand held debug device is more useful, compared to using PCAN dongle which is great for static testing.
  • The software will take multiple iteration by testing your car in various field scenarios. This is not a project which can be completed a night before demo. Keep a healthy amount of time for testing.
  • The sole working power socket available in university outside of the university buildings is available on the top floor of the tenth street car garage. This is especially useful when testing in field.

Acknowledgement

  • Building a hardware project without the availability of a electronics lab of the university which had been shut, due to COVID-19 pandemic tested our resourcefulness to our extremes.Considering the remote nature of course work, resource availability in any shape or form from university was sadly non existent. All the team members should be appreciated for their unwavering enthusiasm to make this a success story.
  • Preet's advice for buying quality hardware parts should be followed to the line.

References

http://socialledge.com/sjsu/index.php/Industrial_Application_using_CAN_Bus