Difference between revisions of "F16: The-Nine"
Proj user8 (talk | contribs) m (→Parts List & Cost) |
Proj user8 (talk | contribs) (→Conclusion) |
||
(217 intermediate revisions by the same user not shown) | |||
Line 4: | Line 4: | ||
== Abstract == | == Abstract == | ||
− | + | Nearly every car manufacturer today is in the process of developing fully autonomous vehicles. There are some that are on the brink of winning the development race as their systems are safer than many human drivers. However currently no one has been able to fully implement autonomous navigation requiring nothing but a destination while having the full support and trust of the community to remove the driver from the equation. Autonomous vehicles are incredibly difficult to create as there are a huge number of difficulties of autonomy that must be taken into account. The purpose of this project is to introduce the basic technologies in application of the types of systems that can be used in autonomy. The overall project goal is to make an autonomous RC car that utilizes five SJSU-One-Boards that intercommunicate with each other through CANbus; each controlling a major functionality. The RC car must be able to be given a destination through an interfacing application and it must be able to travel to that location. | |
+ | |||
+ | [[File:CMPE243 S16 The Nine Top Right View.jpg|left|200px|thumb]] | ||
+ | [[File:CMPE243 S16 The Nine Top View.jpg|right|200px|thumb]] | ||
== Objectives & Introduction == | == Objectives & Introduction == | ||
− | + | This project aimed towards developing and building a RC car which has the self-driven capability. We communicated over CAN bus. The car is capable to find its current location through the GPS module. The car could get the destination and way points through the google map API which is connected to the android application, and bluetooth and through CAN messages is sent over to the GPS and it could find its path to the destination while avoiding any obstacles that might run into while driving to the destination. To achieve this objective, we used 5 controllers, which each is dedicated to a specific role such as master, sensors, bluetooth, motors and geographical location. These controller can pass messages over the common CAN bus. In addition, the final prototype of has android application which is useful for data monitoring and keep tracking of the car remotely. Through the android application, the user can feed the desired destination and the car is capable of finding its path to the destination. The car follows the direction based on the data that is provided by the sensors, GPS and compass values. | |
+ | |||
+ | |||
+ | |||
+ | ===Project Objectives=== | ||
+ | *Primary | ||
+ | Use CANbus to intercommunicate between the different controllers on the car. | ||
+ | |||
+ | * Master Controller | ||
+ | Take in data from all controllers to make a logical decision on how to control Speed and Steering to get to a location and avoid obstacles. | ||
+ | |||
+ | * Bluetooth Controller | ||
+ | Make a Bluetooth Connection to the user interfacing application to display telemetry information on the application and to receive target locations for the car to travel to. In charge of I/O such as headlights and physical switches. | ||
− | + | * Motor and Display Controller | |
+ | Get commands from the master controller and control the drive motor and steering servo. Collect Drive motor feedback and make sure the drive motor is running at its target speed. Display Useful through some type of LCD Display. | ||
+ | |||
+ | * GPS Controller | ||
+ | Gets waypoints from the bluetooth and find the target heading to the nearest waypoint, and calculate the distance. As the car gets closer to the waypoint, checks if it is in range, if so it will move one to the next waypoint. | ||
+ | |||
+ | * Sensor Controller | ||
+ | Collect ultrasonic sensor and magnetometer data, battery voltage and send back to master controller. | ||
== Project Schedule Overview == | == Project Schedule Overview == | ||
Line 117: | Line 139: | ||
| 12/09/2016 | | 12/09/2016 | ||
| colspan=6 style="text-align: center;" | Finalization, Preparing for Demonstration | | colspan=6 style="text-align: center;" | Finalization, Preparing for Demonstration | ||
− | | | + | | Completed |
− | | | + | | 12/08/2016 |
|} | |} | ||
</center> | </center> | ||
Line 152: | Line 174: | ||
! scope="row"| 1 | ! scope="row"| 1 | ||
| RC Car | | RC Car | ||
− | | | + | | Nor-Cal Hobbies |
| 1 | | 1 | ||
− | | | + | | $200 |
|- | |- | ||
! scope="row"| 2 | ! scope="row"| 2 | ||
Line 178: | Line 200: | ||
| [http://www.digikey.com/product-search/en?keywords=469-1012-ND Digikey] | | [http://www.digikey.com/product-search/en?keywords=469-1012-ND Digikey] | ||
| 10 | | 10 | ||
− | | $8.80 | + | | $8.80(Total) |
|- | |- | ||
! scope="row"| 6 | ! scope="row"| 6 | ||
− | | High Power Motor Driver | + | | Pololu 5V Step-Up/Step-Down Voltage Regulator |
+ | | [https://www.pololu.com/product/2574 Polulu] | ||
+ | | 1 | ||
+ | | $14.95 | ||
+ | |- | ||
+ | ! scope="row"| 7 | ||
+ | | Pololu 6V Step-Up/Step-Down Voltage Regulator | ||
+ | | [https://www.pololu.com/product/2575 Polulu] | ||
+ | | 1 | ||
+ | | $14.95 | ||
+ | |- | ||
+ | ! scope="row"| 8 | ||
+ | | 24V21 High Power Motor Driver | ||
| [https://www.pololu.com/product/2995 Polulu] | | [https://www.pololu.com/product/2995 Polulu] | ||
| 1 | | 1 | ||
| $39.95 | | $39.95 | ||
+ | |- | ||
+ | ! scope="row"| 9 | ||
+ | | 2000mAH 3 Cell Lipo Battery | ||
+ | | [https://hobbyking.com/en_us/batteries/lipoly-all-brands.html HobbyKing] | ||
+ | | 1 | ||
+ | | $25.00 | ||
+ | |- | ||
+ | ! scope="row"| 10 | ||
+ | | MB1010 Ultrasonic Sensors | ||
+ | | Jameco | ||
+ | | 3 | ||
+ | | $74.85 | ||
+ | |- | ||
+ | ! scope="row"| 11 | ||
+ | | Assorted components for PCB | ||
+ | | Mouser | ||
+ | | 1 | ||
+ | | $31.60 | ||
+ | |- | ||
+ | ! scope="row"| 12 | ||
+ | | PCB manufacturing service | ||
+ | | Bay Area Circuits | ||
+ | | 1 | ||
+ | | $32.64 | ||
+ | |- | ||
+ | ! scope="row"| 13 | ||
+ | | GPS sensor | ||
+ | | Adafruit | ||
+ | | 1 | ||
+ | | $50.00 | ||
+ | |- | ||
+ | ! scope="row"| 14 | ||
+ | | Weatherproof LED strip (60 LEDs/meter) | ||
+ | | Adafruit | ||
+ | | 1 | ||
+ | | $25.00 | ||
+ | |- | ||
+ | ! scope="row"| 15 | ||
+ | | Schmartboard Jumper Wires | ||
+ | | Fry's Electronics | ||
+ | | 2 | ||
+ | | $6.00 (green, 12") / $5.00 (blue, 7") | ||
+ | |- | ||
+ | ! scope="row"| 16 | ||
+ | | 160x128 LCD display | ||
+ | | Adafruit | ||
+ | | 1 | ||
+ | | $19.95 | ||
+ | |- | ||
+ | ! scope="row"| 17 | ||
+ | | CR1220 lithium battery | ||
+ | | Mouser | ||
+ | | 1 | ||
+ | | $0.85 | ||
+ | |- | ||
|}</center> | |}</center> | ||
Line 235: | Line 324: | ||
| 10/27/2016 | | 10/27/2016 | ||
| Develop Bluetooth serial receiver library & web application. | | Develop Bluetooth serial receiver library & web application. | ||
− | | | + | | Completed |
− | | | + | | 10/19/2016 |
|- | |- | ||
! scope="row"| 6 | ! scope="row"| 6 | ||
Line 242: | Line 331: | ||
| 11/18/2016 | | 11/18/2016 | ||
| Integrate web application, SJOne board and DBC messages | | Integrate web application, SJOne board and DBC messages | ||
− | | | + | | Completed |
− | | | + | | 11/12/2016 |
|- | |- | ||
! scope="row"| 7 | ! scope="row"| 7 | ||
Line 249: | Line 338: | ||
| 12/02/2016 | | 12/02/2016 | ||
| Fine-tuning of web application | | Fine-tuning of web application | ||
− | | | + | | CONTINUOUS TASK |
| | | | ||
|- | |- | ||
Line 256: | Line 345: | ||
| 12/09/2016 | | 12/09/2016 | ||
| Final integration | | Final integration | ||
− | | | + | | Completed |
− | | | + | | 12/08/2016 |
|} | |} | ||
</center> | </center> | ||
=== Design & Implementation === | === Design & Implementation === | ||
− | |||
=== Hardware Design === | === Hardware Design === | ||
Line 268: | Line 356: | ||
=== Hardware Interface === | === Hardware Interface === | ||
− | + | [[File:BluetoothModule-Hardware-Connections.png|right|thumb|500px|Bluetooth Module System Diagram.]] | |
+ | |||
+ | The HC-06 bluetooth Serial device can be interfaced via UART. Simply, connect the Bluetooth RX -> the SJOne TX and connect the Bluetooth TX -> the SJOne RX. Any serial Bluetooth data transmitted to the HC-06 from a master bluetooth device will propagate to the Bluetooth TX pin. Send bytes through UART via the SJOne TX pin in order to transmit to the master bluetooth device. | ||
+ | |||
+ | Two tactile buttons are connected to GPIs on the SJOne board. | ||
+ | |||
+ | One PWM output (P2.1) from the SJOne board is connected to a logic level mosfet to control the brightness of an white light led strip. | ||
=== Software Design === | === Software Design === | ||
− | |||
=== Implementation === | === Implementation === | ||
− | + | ||
+ | The following code is basically all that is required to control a Bluetooth module along with headlight. | ||
+ | |||
+ | <syntaxhighlight lang="cpp”> | ||
+ | void period_1000Hz(void) | ||
+ | { | ||
+ | if(led_btn_is_released) | ||
+ | { | ||
+ | manually_increment_headlights(); | ||
+ | } | ||
+ | if(gps_btn_is_release) | ||
+ | { | ||
+ | send_fixed_gps_location(); | ||
+ | } | ||
+ | automatic_headlights_control(); | ||
+ | } | ||
+ | void period_10Hz(void) | ||
+ | { | ||
+ | handle_can(); | ||
+ | send_master_control_signal(); | ||
+ | if(gps_queue_ready) | ||
+ | { | ||
+ | send_gps_queue(); | ||
+ | } | ||
+ | } | ||
+ | void period_100Hz(void) | ||
+ | { | ||
+ | handle_uart(); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
=== Testing & Technical Challenges === | === Testing & Technical Challenges === | ||
− | + | The challenge was finding an HC-06 module that works. Some of the modules came in dead-on-arrival. After you find a set of them that work, attempt to connect them to your phone and make sure it can connect. Finally, use any Bluetooth serial application from your phone's app store and send messages to the bluetooth device. Using either the UART on your SJOne board or a USB to UART device (FTDI dongle), verify that the messages can be received from the device from your phone. | |
− | + | ||
+ | Also, as the application developer, there are many features you will want to add to the application. So during the beginning phases of integration, the DBC file changed rapidly between the many modules. Keeping up with the module changes result in issues such as more features were added. Try to keep up with those changes along with the apps changes as well. | ||
+ | |||
+ | === Issue #1: CAN evaluation task Overrun === | ||
+ | The Bluetooth module listens for signals from all of the devices in the system, which can result in problems. If you attempt to process a large number of CAN message in a while loop, the task could run longer than the 10Hz task can allow for (100ms) which will cause the system to crash. To fix this issue, it should be noted that the animations on the app look smooth enough at 10Hz. To minimize the time taken in the task, a flag for each CAN message type is set to 1 which means they have not been decoded. The while loop will check if that message's flag has been set and attempt to decode it if it has not been set. If the flag has been cleared it is ignored. When all flags have been set, the while loop is broken and the task ends. All other message are ignored. This is fine since most humans would not be able to notice small changes to the app display from below 10Hz. | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
− | + | == Mobile Phone Application == | |
− | === | + | <center><b>Team Members: </b> |
− | + | Khalil Estell</center> | |
+ | |||
+ | === Design & Implementation === | ||
+ | |||
+ | === Hardware Design === | ||
+ | N/A | ||
+ | |||
+ | === Hardware Interface === | ||
+ | see <b>Bluetooth Module System Diagram.</b> above. | ||
+ | |||
+ | === Software Design === | ||
+ | The mobile application for the-nine autonomous RC car was not a native Android or iOS application but instead a web application. The <b>EvoThings</b> desktop tool and application viewer were used to deploy the web application to the phone. The EvoThings viewer gives the web application access to Bluetooth and other features that only native applications would have access to. The EvoThings viewer provides a global <b>cordorva.js</b> script file that can be added into any of the html pages in the application. | ||
+ | |||
+ | Cordorva, by default, has the capability to communicate over standard Bluetooth (NOT BLE). To begin using Bluetooth, simply, include the cordova script and begin using: | ||
+ | <syntaxhighlight> | ||
+ | bluetoothSerial.connect(param1, param2, ..., function success() | ||
+ | { | ||
+ | bluetoothSerial.write("message to send to bluetooth device") | ||
+ | }, function failure() | ||
+ | { | ||
+ | alert("bluetooth connect failed"); | ||
+ | }); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | The application also used the Google Maps HTML API for displaying the current position of the RC car on a map (denoted as a cyan closed arrow), the direction it is facing, the direction it should be heading towards (denoted as a red open arrow underneath the cyan arrow), the waypoints it needs to get to, and the destination and where the current user is standing. The Google Maps API was also used for calculating waypoints. | ||
+ | |||
+ | The Bootstrap CSS framework was used to give structure to the layout of the page as well as give style to the buttons and other elements. | ||
+ | |||
+ | === Implementation === | ||
+ | <gallery caption="" heights="400px" widths="300px" > | ||
+ | File:CMPE243_F16_The-Nine_google-maps-waypoint-anim_360.gif|Google Maps Calculating Waypoints. | ||
+ | File:CMPE243_F16_The-Nine_destination-interface_360.gif|Application Telemetry View Demo Animation. (CLICK TO SEE ANIMATION!) | ||
+ | </gallery> | ||
+ | |||
+ | ==== Quick Start Guide: Telling the RC car where to go ==== | ||
+ | |||
+ | # In the map view, press on the map, where you want the RC car to go. A red cross hair will appear at the point that you pressed with a light blue path behind it and a set of black cross hairs. The red one cross hair indicates the destination. The black cross hairs indicate the sequence of waypoints the RC car will navigate to in order to reach the destination. | ||
+ | # Press the button that says "Map". | ||
+ | # The view should have changed and the Map button should now say Telemetry. | ||
+ | # Press the button <b>Navigate to Target</b>. When the progress bar below the buttons changes from "Destination Reached" to "Approaching Destination", you are ready to start. | ||
+ | # To start, enable the car by pressing the enable button on the top right of the application. | ||
+ | |||
+ | ==== GPS Waypoint Calculation ==== | ||
+ | |||
+ | The GPS waypoints were calculated utilizes the Google Maps walking directions API. But note that the direct results from the Walking Directions API is not appropriate for this project. When using the Google Maps walking directions API to get the <b>Steps</b> to get to a destination, the interface assumes you can handle walking down a winding street or maneuver around between buildings, so the number of steps are quite sparse. For example, if you use the walking steps, you may get a set of waypoint points that directs the car to go through a building. To fix this, notice that the Google Maps directions lines follow straight line paths that, if followed, will bring you to exactly where you need to go whilst avoid large static obstacles and buildings. Thus, the GPS waypoints were taken from the straight line segments that draw a path to and from origin to destination. This information can be found in the <b>DirectionsDisplay.directions.routes[0].overview_path</b> after a <b>DirectionsService.route()</b> call has been made to generate a route from origin to destination. | ||
+ | |||
+ | ==== Stylizing the Application ==== | ||
+ | |||
+ | The button styles and progress bars came from Bootstrap. The tabs on the top are just buttons in a div that is fixed to the top of the screen. No <nav> tags were used in the application. | ||
+ | |||
+ | The gauges compass/heading indicators come from the plugin JQuery Knob (http://anthonyterrien.com/demo/knob/). The Ultrasound indicators were designed by myself using CSS3 by manipulating the boarders of <div> elements to create shapes like trapezoids and triangles (see https://css-tricks.com/examples/ShapesOfCSS/). Using the CSS3 rotation-transformation, I could angle them to look like they were pointing in the directions of the ultrasounds on the car. Then, to indicate how close or far away an object is from the ultrasound sensors, the border color attribute of the divs can be used to color them grey (nothing detected, or something too far away to matter), green (something detected, but not serious enough to dodge), yellow (close by object, should lightly steer away from obstacle), and then red (very close object, should steer hard away from it). | ||
+ | |||
+ | ==== Features of the Application ==== | ||
+ | |||
+ | ===== Connect/Disconnect Buttons ===== | ||
+ | The connect button will only attempt to connect. It will never attempt to disconnect. Connecting to the car is a safe operation, but disconnecting from it is not. So, to make it harder for the user to make unsafe actions, the connect button is limited to only connecting. To disconnect, the user must go to the telemetry view, scroll to the bottom, press it, get a warning vibration and confirm box and finally press the confirm action button. | ||
+ | |||
+ | ===== Map/Telemetry view button ===== | ||
+ | |||
+ | The Map/Telemetry view button in the middle of the interface will switch the application from Map view to the Telemetry view. The Map View contains (you guessed it) the google maps interface that the user can use to give a destination to the RC car. The telemetry view shows the control buttons and sensor feedback (telemetry) of the RC car. | ||
+ | |||
+ | ===== Enable/Disable Buttons ===== | ||
+ | |||
+ | The enable/disable button at the top of the navigation bar will vibrate when pressed to alert the user of the action. The button text and color will indicate the current state of the RC car. When the user intends to disable the RC car, the button can be tapped to disable the car. The button will then become disabled for 2.5 seconds to keep the user from double tapping the enable/disable button. This is useful since the button is typically used to stop the car from doing something dangerous. Without this delay it is typical for a user to tap the button to disable the car multiple times in an attempt to stop it but result in enabling it once again. | ||
+ | |||
+ | ===== Return to User Buttons ===== | ||
+ | |||
+ | Press this button to set the navigation point for the RC car to your current location. Press the <b>navigate to target</b> button and the car will navigate to you. | ||
+ | |||
+ | ===== Message Log ===== | ||
+ | |||
+ | The message log at the bottom logs events like ultrasound re-calibrations, connection events, disconnect events, invalid Bluetooth transmission and if the headlight signals have been sent. | ||
+ | |||
+ | ===== Heartbeat Signal ===== | ||
+ | |||
+ | The heartbeat signal is sent to the phone as an another indicator to the user that the Bluetooth module is connected and alive. | ||
+ | |||
+ | ===== Ultrasound Re-calibration Indication ===== | ||
+ | |||
+ | In the event of a ultrasound sensor lock up, the sensor board would send a CAN message to the Bluetooth module which will send a message to the application. The app will vibrate 3 times in quick succession to alert the user to an ultrasound re-calibration event. The ultrasound indicators will also turn green, yellow, and red with a value of -1cm for each sensor. The heartbeat indicator text will also show a <b>!!! RECALIBRATING ULTRASOUNDS !!!</b> message. Below the message log is the <b>Force Ultrasound Recalibrate </b> button which does nothing as of the demo on December 21st. | ||
+ | |||
+ | === Testing & Technical Challenges === | ||
+ | Even before I found EvoThings, I was certain to make the app for this project a web application. The issue was finding a way to rapidly develop the application with Bluetooth capability. There exists an experimental Bluetooth API for HTML5 but it is not supported by any browsers or phones. In the end, I found EvoThings which did exactly what was needed. | ||
== Obstacle Detection Systems (Sensor Controller) == | == Obstacle Detection Systems (Sensor Controller) == | ||
Line 379: | Line 592: | ||
| Develop IMU and ultrasonic sensor libraries. | | Develop IMU and ultrasonic sensor libraries. | ||
− | | | + | | Complete |
− | | | + | | 10/19/16 |
|- | |- | ||
Line 393: | Line 606: | ||
| Use implemented DBC to transmit sensor data over CAN. | | Use implemented DBC to transmit sensor data over CAN. | ||
− | | | + | | Complete |
− | | | + | | 10/19/16 |
|- | |- | ||
Line 407: | Line 620: | ||
| Debug sensor library and work on integration | | Debug sensor library and work on integration | ||
− | | | + | | Complete |
− | | | + | | 11/25/16 |
|- | |- | ||
Line 421: | Line 634: | ||
| Fine-tuning of sensor readings | | Fine-tuning of sensor readings | ||
− | | | + | | Complete |
− | | | + | | 12/1/16 |
|- | |- | ||
Line 435: | Line 648: | ||
| Final integration | | Final integration | ||
− | | | + | | Complete |
− | | | + | | 12/8/16 |
|} | |} | ||
Line 452: | Line 665: | ||
=== Hardware Design === | === Hardware Design === | ||
+ | ====Bumpers and Ultrasonic Mounts==== | ||
+ | The two bumpers, ultrasonic housings, and headlight mounts were designed using Onshape and 3D printed using PLA plastic. Each bumper was designed to house 3 ultrasonic sensors. The initial ultrasonic housings were designed for the Sparkfun HC-SR04 ultrasonic sensor. The housings were printed in black PLA plastic and modified to snugly fit the sensors. The front and rear bumpers were then designed to mount onto the existing bumpers on the RC car, and to fit the ultrasonic mounts using M3 screws. Both the front and rear bumper were printed in glow in the dark PLA plastic. After the bumpers were printed, we switched to the current MaxSonar sensors, so the new ultrasonic housings were designed to fit the existing bumpers. Each sensor is screwed into the housing using 2 small M3 screws, and each housing is screwed onto the bumper using M3 screws. There are 3 sensors in the front of the car, and one in the rear. | ||
+ | |||
+ | During testing it was determined that we need to tilt the sensors upwards at a 10 degree angle to avoid detecting the floor. The right and left sensors were also tilted 15 degrees outside to better detect obstacles on the side. | ||
+ | |||
+ | A mount to house the LED strip mounts onto the front bumper. The mount fits inside existing holes in the front bumper, but can be screwed in for additional stability. The headlight mount was printed in black PLA plastic. | ||
+ | |||
+ | During further testing it was determined that we need to raise the sensors off the ground to avoid small obstacles on the ground, such as gravel and leaves. New ultrasonic sensor housings were designed in such a way so that the height off the ground can be adjusted. The new adjustable ultrasonic housings were printed in blue PLA plastic. | ||
+ | |||
====Ultrasonic sensors==== | ====Ultrasonic sensors==== | ||
− | + | Our original design called for six ultrasonic sensors, with three forward-facing (sensors SFL, SFC, SFR at front-left, front-center, front-right) and three rear-facing (sensors SRL, SRC, SRR at rear-left, rear-center, rear-right). In practice only one center rear-facing sensor was needed, but the design still supports six. The sensors are arranged around the car as follows: | |
+ | |||
+ | {|style="margin: 0 auto;" | ||
+ | | [[File:CMPE243_F16_The_Nine_Car_Outline.png|400px]] | ||
+ | |} | ||
+ | |||
+ | The ultrasonic sensors don't have a specific bus (such as SPI or I2C) and instead are triggered asynchronously through GPIO, described later. | ||
− | ==== | + | ====Compass==== |
− | The | + | A magnetometer is used to calculate the heading of the car. The magnetometer being used is the HMC5883L. The magnetometer measures the magnetic field of The Earth in units of Tesla as scalars in the X, Y and Z axis. The SJOne board communicates with the magnetometer using I2C at address 0x3C. An accelerometer onboard the SJOne board is used for tilt compensation. The magnetometer is oriented such that X axis faces forward, Z axis faces up, and Y axis faces to the left. |
=== Hardware Interface === | === Hardware Interface === | ||
− | + | ||
+ | ===== I/O expander ===== | ||
+ | |||
+ | To utilize the limited number of available capture inputs across four to six ultrasonic sensors, an I/O expansion circuit was developed. | ||
+ | |||
+ | It consists of a 74HCT253 dual 4-to-1 multiplexer, and a 74HCT259 8-bit addressable latch. The multiplexer routes the sensor inputs to the two capture pins such that the front and rear sensors can be captured in parallel. To keep our final design compatible with the code developed for our prototype, the rear-center sensor was also mapped to the fourth input of the front-sensor multiplexer inputs such that iterating over four inputs would cover the front three sensors and rear single sensor on the same capture channel. | ||
+ | |||
+ | {|style="margin: 0 auto;" | ||
+ | | [[File:CMPE243_F16_The_Nine_US-253.png|400px]] | ||
+ | | [[File:CMPE243_F15_The_Nine_US-259.png|400px]] | ||
+ | |} | ||
+ | |||
+ | The following table shows the mapping between the two capture inputs and the sensor echo outputs, as well as the addressable register and the sensor trigger output. GPIOs are used for handshaking to load data into the register as needed. | ||
+ | |||
+ | |||
+ | {| class="wikitable" style="margin-left: auto; margin-right: auto; border: none;" | ||
+ | |- | ||
+ | ! Select | ||
+ | ! Input on CAP1.1 | ||
+ | ! Input on CAP1.0 | ||
+ | ! Addressed register | ||
+ | |- | ||
+ | | 0 | ||
+ | | SFL_ECHO | ||
+ | | SRL_ECHO | ||
+ | | SFL_TRG | ||
+ | |- | ||
+ | | 1 | ||
+ | | SFC_ECHO | ||
+ | | SRC_ECHO | ||
+ | | SFC_TRG | ||
+ | |- | ||
+ | | 2 | ||
+ | | SFR_ECHO | ||
+ | | SRR_ECHO | ||
+ | | SFR_TRG | ||
+ | |- | ||
+ | | 3 | ||
+ | | SRC_ECHO | ||
+ | | Always '0' | ||
+ | | SRC_TRG (see JP1) | ||
+ | |- | ||
+ | | 4 | ||
+ | | SFL_ECHO | ||
+ | | SRL_ECHO | ||
+ | | SRL_TRG | ||
+ | |- | ||
+ | | 5 | ||
+ | | SFC_ECHO | ||
+ | | SRC_ECHO | ||
+ | | SRC_TRG (see JP1) | ||
+ | |- | ||
+ | | 6 | ||
+ | | SFR_ECHO | ||
+ | | SRR_ECHO | ||
+ | | SRR_TRG | ||
+ | |- | ||
+ | | 7 | ||
+ | | Always '0' | ||
+ | | Always '0' | ||
+ | | Not used | ||
+ | |} | ||
+ | |||
+ | A logic analyzer was used to monitor the sensor outputs during development to find optimal timings and delays for polling them, as shown below: | ||
+ | |||
+ | [[File:CMPE243_F16_The-Nine_Analyzer_Cap.png|center|Logic analyzer output of sensor signals.]] | ||
+ | |||
+ | In this sample the trigger (TRG) pulse starts the sensor, which asserts the echo signal when ranging starts. When the negative edge of the echo signal is captured the next sensor is triggered shortly after. The select field shows which sensor is currently addressed. In this particular capture, all four sensors are being read in under under 50ms. | ||
+ | |||
+ | ====Battery voltage monitor==== | ||
+ | |||
+ | A 12.6V battery is used to power the entire vehicle. It has an operating range 9V to 12.6V, which spans approximately 3.6V. In order to determine the current battery voltage this operating range has to be brought down to a valid level for the SJOne board to read on an ADC input which is limited to 3.3V | ||
+ | |||
+ | [[File:CMPE243_F16_The_Nine_Battery_Monitor.png|center|500px|Compass I2C connections to the SJSUOne Board.]] | ||
+ | |||
+ | An LM341 adjustable zener diode is used to provide a 9V drop on the battery output. This is accomplished by using a voltage divider to set the reference voltage input on the LM341. At this point the maximum voltage output is 3.6V which is still out of range. A second voltage divider is used to scale it down to 3.3V, and a regular zener diode is used to clamp the output at 3.3V. This allows the SJOne board to read the battery voltage safely. | ||
+ | |||
+ | ====Compass==== | ||
+ | [[File:CMPE243_F16_The-Nine_compass_schematic_480.png|right|thumb|500px|Compass I2C connections to the SJSUOne Board.]] | ||
+ | The SJOne board communicates with the HMC5883L using I2C bus 2, using slave address 0x3C. The magnetometer is oriented such that the X axis faces forward, the Y axis faces left, and the Z axis faces up. SDA and SCL pins are connected to the SDA2 and SCL2 pins on the SJOne, GND is connected to GND, and VCC is connected to 3.3V. | ||
=== Software Design === | === Software Design === | ||
− | + | ||
+ | ==== Ultrasonic sensors ==== | ||
+ | |||
+ | ===== Overview ===== | ||
+ | |||
+ | A sensor polling loop starts every second (1 Hz). Within this loop all four sensors are read, the distances are calculated and output on the CAN bus, and the elapsed time is determined. If there is enough time remaining to do a worst-case read of all four sensors (approximately 200ms), the sensors are read again. If polling of all four sensors finishes before a 50ms interval has expired, polling can't continue as each sensor must be idle for 50ms before being triggered again. In this case the software idles for the remainder of the 50ms interval until polling can resume. | ||
+ | |||
+ | This dynamic polling approach yields an average sensor update rate of 16 Hz, which is faster (up to 20 Hz) as the car gets closer to objects, and is slow (as low as 5 Hz) when in free space with no obstructions in any direction. This is using the hardware configuration where the rear sensor isn't read in parallel with the front sensors. If that mode is used, the worst-case polling rate is 6.66 Hz. | ||
+ | |||
+ | ===== Polling internals ===== | ||
+ | |||
+ | Timer #1 is used for capturing echo pulses from the sensors. Some caution is needed as Timer #1 is normally allocated to the watchdog and infrared (IR) interface. | ||
+ | In "sys_config.h" you need to redefine "SYS_CFG_SYS_TIMER" from 1 to some other number (0,2,3) to map those functions to a different timer. | ||
+ | This frees up timer 1 for use in capturing signals. | ||
+ | |||
+ | The capture function of timer #1 is triggered on the rising edge and the falling edge, and an interrupt is generated on each capture event. | ||
+ | The ISR saves the captured value on each edge and computes the difference between them to determine the length of the sensor's pulse. | ||
+ | A state machine is used to keep track of events per sensor (ranging request, positive edge received, negative edge received) so the ISR knows what stage of processing the sensor being polled is in. | ||
+ | |||
+ | ==== Battery voltage monitor ==== | ||
+ | |||
+ | The battery voltage is read after the sensors are polled using the ADC. This data is sent to the rest of the system over the CAN bus. | ||
+ | |||
+ | ====Compass==== | ||
+ | The compass headings are calculated 10 times a second using the period_10Hz task in period callbacks. An exponential moving average is used to smooth out the raw magnetometer and accelerometer data. A weight of .5 was used to smooth out the magnetometer, and a weight of .1 was used to smooth out the accelerometer. The magnetic and acceleration vectors as measured from the magnetometer and accelerometer are then normalized such that the length of the vectors is 1.0. Because a gyroscope is not being used to assist in tilt compensation, a very low weight must be used to compensate for the car accelerating forward and backward. Tilt compensation is used to ensure an accurate compass reading when the car is titled. The tilt compensation algorithm uses the roll and pitch as calculated from the accelerometer and the X Y and Z components of the normalized magnetometer vector. The calculated heading is then converted from radians to degrees. The magnetic declination offset angle is then added to the heading to account for the differences between magnetic and true north. The heading will then be sent to Master, BlueTooth, and Debug over Can bus. | ||
=== Implementation === | === Implementation === | ||
This section includes implementation, but again, not the details, just the high level. For example, you can list the steps it takes to communicate over a sensor, or the steps needed to write a page of memory onto SPI Flash. You can include sub-sections for each of your component implementation. | This section includes implementation, but again, not the details, just the high level. For example, you can list the steps it takes to communicate over a sensor, or the steps needed to write a page of memory onto SPI Flash. You can include sub-sections for each of your component implementation. | ||
+ | |||
+ | ====Compass==== | ||
+ | To communicate with the magnetometer sensor, a singleton class named IMU_Sensor was created. The class stores sensor data in a local struct, and handles initialization of the sensor, and reading raw magnetometer sensor data. | ||
+ | =====Measuring the raw sensor data===== | ||
+ | The IMU_Sensor class communicates with the magnetometer using I2C at address 0x3C. The period_init function in periodic callbacks calls the init function, which sets the two configuration registers and the mode register using the I2C2 class. Ten times per second the periodic scheduler calls the getXYZ() function. Six registers are read, starting at 0x03, which store the high and low bites for the X, Z, and Y axis of the magnetometer. If the readRegisters function returns false, the getXYZ function returns false. A zero byte is then written to register 0x03 to reset the internal pointer and prepare for the next measurement. The table below lists the relevant registers. | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | !Address Location | ||
+ | !Name | ||
+ | |- | ||
+ | |0x00 | ||
+ | |Configuration Register A | ||
+ | |- | ||
+ | |0x01 | ||
+ | |Configuration Register B | ||
+ | |- | ||
+ | |0x02 | ||
+ | |Mode Register | ||
+ | |- | ||
+ | |0x03 | ||
+ | |Data Output X MSB Register | ||
+ | |- | ||
+ | |0x04 | ||
+ | |Data Output X LSB Register | ||
+ | |- | ||
+ | |0x05 | ||
+ | |Data Output Z MSB Register | ||
+ | |- | ||
+ | |0x06 | ||
+ | |Data Output Z LSB Register | ||
+ | |- | ||
+ | |0x07 | ||
+ | |Data Output Y MSB Register | ||
+ | |- | ||
+ | |0x08 | ||
+ | |Data Output Y LSB Register | ||
+ | |} | ||
+ | |||
+ | =====Calculating Heading===== | ||
+ | The period_10Hz reads the raw values from both the magnetometer using the IMU_Sensors class, and from the accelerometer using a built in class. The raw data is then filtered using an exponential moving average, with a weight of 0.5 for the magnetometer and 0.1 for the accelerometer. The magnetometer and accelerometer vectors are then normalized. Roll and pitch are then calculated using the normalized accelerometer vector. The roll is calculated by taking the arcsin of the negative X component, and the pitch is calculated by taking the arcsin of the Y component. The following formula is used to calculate the tilt compensated vector. | ||
+ | |||
+ | <code>hy = normHy * cos(roll) + normHx * sin(roll) * sin(pitch) - normHz * cos(pitch) * sin(roll) | ||
+ | |||
+ | hx = normHx * cos(pitch) + normHz * sin(pitch) | ||
+ | </code> | ||
+ | |||
+ | The heading in radians is then calculated by taking the arctan of the Y and X components of the tilt compensated vector. The declination angle (13 degrees for San Jose) is then added to the current heading. The heading in radians is then converted into degrees. The heading in degrees is then sent over Can Bus to be received by Master, Bluetooth, and Debug. | ||
=== Testing & Technical Challenges === | === Testing & Technical Challenges === | ||
− | + | ====Compass==== | |
− | + | =====Initial Testing===== | |
+ | [[File:CMPE243_F16_The-Nine_magnetic_declination_480.png|right|thumb|300px|Magnetic declination map for San Jose.]] | ||
+ | Initial testing was done by connecting the magnetometer to the SJOne board and printing out the calculated heading over serial. By rotating the magnetometer, the current heading can be verified by using a real compass. | ||
+ | =====Testing on the car===== | ||
+ | The magnetometer was then installed on the car. Using the bluetooth app, the current heading can be displayed. The car was then successfully tested indoors. During the outdoor test runs, it was discovered that the compass loses accuracy when the car is on a slope. This was due to the lack of tilt compensation, because only the X and Y axis of the magnetometer are used to calculate heading. | ||
− | + | ||
+ | A tilt compensation algorithm was then implemented using the accelerometer onboard the SJOne board. Again, the magnetometer was tested first off the car by using the serial console. The compass was tested by rotating and tilting and observing the calculated heading. After the tilt compensation was verified outside the car, it was again installed in the car. The car was tested by driving around campus. The tilt compensated compass worked as expected, although a small difference was noticed between calculated heading and actual heading. The observed difference is due to magnetic declination, the difference between magnetic and true north. The magnetic declination for San Jose, CA was determined to be 13 degrees. An offset of 13 degrees was added to the calculated heading. | ||
+ | |||
+ | After further testing with the car with the PCB installed, it was determined that the tilt compensation algorithm was not working correctly. The tilt compensation was disabled, and the car was tested without it. It was determined that the compass without tilt compensation works well enough, so the tilt compensation was disabled for the final build. | ||
==== Ultrasonic sensors ==== | ==== Ultrasonic sensors ==== | ||
− | ===== | + | ===== Calibration ===== |
+ | |||
+ | The MB1010 sensor calibrates itself when power is applied. To prevent improper calibration, it's important to have no objects blocking the sensors during power-up. | ||
+ | When testing we elevated the front of the car to point the sensors upwards and out into open air where there were no obstacles. A similar procedure was used when testing the rear sensors as well. | ||
+ | During outdoors testing we had to be mindful about turning on the car while not blocking sensors either. | ||
+ | |||
+ | ===== Recalibration ===== | ||
+ | |||
+ | According to the manufacturer the MB1010 requires recalibration when the operating voltage, temperature, or location changes. While these criteria are mostly constant during testing, they can fluctuate somewhat. | ||
+ | Specifically this need manifested itself as a condition where after normal operation for some duration of time, a sensor begins to report the minimum distance (~14cm) regardless of what is in front of the sensor. | ||
+ | This behavior persists until power is cycled, at which point recalibration occurs and normal operation resumes. | ||
+ | |||
+ | Our solution was to add a TPS2034 two-channel power switch to manually cycle the sensor power rails under software control. One channel was for the forward-facing sensors, another for the rear-facing sensors. | ||
+ | To determine when recalibration is needed, the past history of sensor readings are scanned to see if any are stuck and are consistently reporting the same minimum value. | ||
+ | If any are stuck the power is cycled using the TPS2034. This allowed the sensors to be recalibrated automatically during operation. | ||
+ | |||
+ | The 7-segment LED of the sensor board is used to keep track of the number of recalibration events that have occurred. During recalibration a status signal is sent to the Bluetooth board so that the application can report to the user that recalibration occurred. | ||
+ | |||
+ | In a future revision a better power switch would be the TPS2054 which has four independent outputs so each individual sensor could be recalibrated without disturbing the other ones. The sensor manufacturer also recommends a power filtering circuit for quadcopters which may be applicable to our autonomous vehicle, but testing would be needed to determine if that's the case. | ||
+ | |||
+ | === Printed Circuit Board === | ||
+ | |||
+ | A printed circuit board was designed in EAGLE to integrate all of the wiring and components that were previously implemented on protoboard and using point-to-point wiring. The board was designed to have several features fur redundancy such as sockets for external CAN transceivers in case the built-in ones failed and breaking out the SJOne board pins to extra headers to add additional peripherals or test signals. Each SJOne board interfaced to the car using a ribbon cable with crimped IDC headers. The silk screen layer was utilized to label all connectors and polarities for power connectors as well. | ||
− | The | + | The PCB encompasses the following components: |
− | + | * IDC ribbon cable connectors to each SJOne board. | |
− | + | * LCD screen | |
+ | * GPS module | ||
+ | * Motor controller module | ||
+ | * IMU module | ||
+ | * Bluetooth module | ||
+ | * I/O expander | ||
+ | * Battery voltage monitor | ||
+ | * CAN bus transceivers | ||
+ | * Power switch for ultrasound sensor recalibration | ||
+ | * Header for logic analyzer | ||
+ | * Pushbuttons for headlights and return to home | ||
+ | * Headlight driver circuit | ||
+ | |||
+ | EAGLE schematic: | ||
+ | |||
+ | [[File:CMPE243_F16_The_Nine_SCH.png|center|600px|thumb| Circuit Schematic]] | ||
+ | |||
+ | Printed circuit board from Bay Area Circuits (parts side): | ||
+ | |||
+ | [[File:CMPE243_F16_The-Nine_manufactured-pcb_720.jpg|center|600px|thumb|Printed Circuit Board Manufactured]] | ||
+ | |||
+ | Fully assembled PCB mounted on acrylic sheet with all components attached. | ||
+ | |||
+ | [[File:CMPE243_F16_The-Nine_populated-pcb_720.jpg|center|600px|thumb|Printed Circuit Board Populated]] | ||
== Localization and Positioning (GPS) == | == Localization and Positioning (GPS) == | ||
Line 502: | Line 933: | ||
|- | |- | ||
! scope="row"| 1 | ! scope="row"| 1 | ||
− | | | + | | 09/16/2016 |
− | | | + | | 09/22/2016 |
| Researched and decided upon the GPS module and Compass module. | | Researched and decided upon the GPS module and Compass module. | ||
| Completed | | Completed | ||
− | | | + | | 09/22/2016 |
|- | |- | ||
! scope="row"| 2 | ! scope="row"| 2 | ||
Line 513: | Line 944: | ||
| Ordered GPS module and compass module. | | Ordered GPS module and compass module. | ||
| Completed | | Completed | ||
− | | | + | | 09/30/2016 |
|- | |- | ||
! scope="row"| 3 | ! scope="row"| 3 | ||
Line 519: | Line 950: | ||
| 10/14/2016 | | 10/14/2016 | ||
| Parse GPS data and format the data to be transmitted<br>Test code to get compass reading information | | Parse GPS data and format the data to be transmitted<br>Test code to get compass reading information | ||
− | | | + | | Completed |
− | | | + | | 10/04/2016 |
|- | |- | ||
! scope="row"| 3 | ! scope="row"| 3 | ||
Line 526: | Line 957: | ||
| 10/25/2016 | | 10/25/2016 | ||
| Interface GPS module and compass module to SJOne board. | | Interface GPS module and compass module to SJOne board. | ||
− | | | + | | Completed |
− | | | + | | 10/19/2016 |
|- | |- | ||
! scope="row"| 4 | ! scope="row"| 4 | ||
Line 533: | Line 964: | ||
| 10/30/2016 | | 10/30/2016 | ||
| Calibrating the compass module.Integration of GPS and compass module. Interfacing of GPS and compass module to Android. | | Calibrating the compass module.Integration of GPS and compass module. Interfacing of GPS and compass module to Android. | ||
− | | | + | | Completed |
− | | | + | | 10/19/2016 |
|- | |- | ||
! scope="row"| 5 | ! scope="row"| 5 | ||
Line 540: | Line 971: | ||
| 11/13/2016 | | 11/13/2016 | ||
| Integration with Master through CAN bus. | | Integration with Master through CAN bus. | ||
− | | | + | | Completed |
− | | | + | | 10/19/2016 |
|- | |- | ||
! scope="row"| 6 | ! scope="row"| 6 | ||
Line 547: | Line 978: | ||
| 12/10/2016 | | 12/10/2016 | ||
| Testing and calibrating with other modules. | | Testing and calibrating with other modules. | ||
− | | | + | | Completed |
− | | | + | | 12/08/2016 |
|} | |} | ||
</center> | </center> | ||
=== Design & Implementation === | === Design & Implementation === | ||
− | The | + | The GEO Controller is responsible for calculating/ providing the location which the car is currently at and target direction to the master controller and bluetooth. The GEO controller will receives the way-points from the Bluetooth Controller and calculates the target heading to the closest waypoint an. The Master Controller is still responsible for controlling the logic of forward, backward, left, and right to reach the final destination. We were able to receive data from GPS module at 10Hz and communicate at 38400bps through UART. We sent specific data packets to receive the GPS module to be able to read the $GPGGA( Global Positioning System Fix Data) string over the UART from the module. |
=== Hardware Design === | === Hardware Design === | ||
− | + | GPS module used in our project is Adafruit Ultimate GPS Breakout - 66 channel w/10 Hz updates - Version 3 and GPS external active antenna. We were able to configure this module at 10Hz and communicate at 38400bps through UART. The GPS module had 10Hz update rate with low current draw which helped power usage very low. The GPS module GPS can also be configured to operate and communicate at various speed though the provided Graphical User Interface. This module has got an on-board flash to store these configuration which us a built in data-logging capability. | |
+ | |||
+ | [[File:Cmp243_F16_the_nine.png |center|300px|500px|thumb|SJone Board connection to GPS module and CAN transceiver]] | ||
+ | [[File:Cmpe243_F16_the_nine.png|center|300px|500px|thumb|GEO controller connection to GPS module ]] | ||
=== Hardware Interface === | === Hardware Interface === | ||
− | + | {| class="wikitable" | |
+ | |+ GEO Controller Pin Configurations | ||
+ | |- | ||
+ | ! scope="col"| '''Device''' | ||
+ | ! scope="col"| '''Port Source''' | ||
+ | ! scope="col"| '''Port Destination''' | ||
+ | ! scope="col"| '''Device''' | ||
+ | |- | ||
+ | | SJ One | ||
+ | | 3v3 | ||
+ | | Vin | ||
+ | | Adafruit GPS | ||
+ | |- | ||
+ | | SJ One | ||
+ | | GND | ||
+ | | GND | ||
+ | | Adafruit GPS | ||
+ | |- | ||
+ | | SJ One | ||
+ | | TXD3 | ||
+ | | RX | ||
+ | | Adafruit GPS | ||
+ | |- | ||
+ | | SJ One | ||
+ | | RXD3 | ||
+ | | TX | ||
+ | | Adafruit GPS | ||
+ | |- | ||
+ | |} | ||
=== Software Design === | === Software Design === | ||
− | + | The GEO Controller is responsible for retrieving the data from GPS and parsing this information and calculate the needed values. | |
+ | After parsing the NMEA string, the current location is known and we can calculate the target value to the closest way point which has been received from bluetooth controller must be calculated to help the car move in the correct direction. When the correct heading is calculated, which target has been calculated we sent out the data over CAN communication to master and bluetooth controllers. | ||
+ | |||
+ | ==== GPS Data Format==== | ||
+ | The Data that was retrieved from GPS is in NMEA 0183 format. NMEA is a combined electrical and data specification for communication between marine electronic devices such GPS receivers and many other types of instruments. The sting we received is in this format: $GPGGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh. Which each section describe an specific characteristic of the data. | ||
+ | The following table shows format description of each substring within the received string from GPS module. | ||
+ | {| class="wikitable" | ||
+ | |+ | ||
+ | $GPGGA- Global Positioning System Fix Data | ||
+ | |- | ||
+ | ! align="center"|Name | ||
+ | ! align="center"|Example Data | ||
+ | ! align="center"|Description | ||
+ | |- | ||
+ | | Sentence Identifier | ||
+ | | $GPGGA | ||
+ | | Global Positioning System Fix Data | ||
+ | |- | ||
+ | | Time | ||
+ | | 170834 | ||
+ | | 17:08:34 Z | ||
+ | |- | ||
+ | | Latitude | ||
+ | | 4124.8963, N | ||
+ | | 41d 24.8963' N or 41d 24' 54" N | ||
+ | |- | ||
+ | | Longitude | ||
+ | | 08151.6838, W | ||
+ | | 81d 51.6838' W or 81d 51' 41" W | ||
+ | |- | ||
+ | | Fix Quality | ||
+ | | 1 | ||
+ | | Data is from a GPS fix | ||
+ | |- | ||
+ | | # of Satellites | ||
+ | | 05 | ||
+ | | 5 Satellites are in view | ||
+ | |- | ||
+ | | Horizontal Dilution of Precision | ||
+ | | 1.5 | ||
+ | | Relative accuracy of horizontal position | ||
+ | |- | ||
+ | | Altitude | ||
+ | | 170834 | ||
+ | | 280.2 meters above mean sea level | ||
+ | |- | ||
+ | | Height of geoid above WGS84 ellipsoid | ||
+ | | -34.0, M | ||
+ | | -34.0 meters | ||
− | === | + | |- |
− | + | | Time since last DGPS update | |
+ | | blank | ||
+ | | No last update | ||
+ | |- | ||
+ | | GGPS reference station id | ||
+ | | blank | ||
+ | | No station id | ||
+ | |- | ||
+ | | Checksum | ||
+ | | *75 | ||
+ | | Used by program to check for transmission errors | ||
+ | |- | ||
+ | |} | ||
+ | |||
+ | ==== System Flow Table ==== | ||
+ | {| class="wikitable" | ||
+ | |+ GEO Controller Tasks | ||
+ | |- | ||
+ | ! scope="col" = "center"|Task Name | ||
+ | ! scope="col" = "center"|Purpose | ||
+ | |- | ||
+ | ! scope="row"| Periodic 10Hz Callback | ||
+ | | | ||
+ | *Data will flows between different states which includes states: RESET, CALCULATE_HEADING, CHANGE_WAYPOINT, and default. | ||
+ | *RESET: Reset the system and variables. | ||
+ | *CALCULATE_HEADING: Calculate the distance and target values of base on the current way point value and GPS current location value. | ||
+ | *CHANGE_WAYPOINT: Checks to see if we are within the RANGE from the waypoint and if so we move on to another way point till we get to destination. | ||
+ | *default: Reset the state | ||
+ | *At the end send a CAN message including target data and destination value to master and bluetooth controller. | ||
+ | |- | ||
+ | ! scope="row"| Periodic 100Hz Callback | ||
+ | | | ||
+ | *Receive checkpoints from bluetooth Controller and send decode the retrieved data from the CAN message and fill the array with all the received way points. The CAN message include the sequence which is index value of the way point in the array. Sequences are based on the nearest point to the current GPS location. | ||
+ | |- | ||
+ | |} | ||
+ | =====Algorithm===== | ||
+ | Finding the TARGET between two coordinates. | ||
+ | <syntaxhighlight lang="cpp”> | ||
+ | /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ | ||
+ | /*:: This function calculates heading based on the 2 coordinates :*/ | ||
+ | /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ | ||
+ | double gps_heading(double lat1, double lon1, double lat2, double lon2){ | ||
+ | |||
+ | double head = 0 , lon_difference = 0; | ||
+ | lat1 = (lat1 * PI)/ PI_DEGREES; | ||
+ | lon1 = (lon1 * PI)/ PI_DEGREES; | ||
+ | lat2 = (lat2 * PI)/ PI_DEGREES; | ||
+ | lon2 = (lon2 * PI)/ PI_DEGREES; | ||
+ | lon_difference = lon2 - lon1; | ||
+ | |||
+ | head = atan2((sin(lon_difference)*cos(lat2)), ((cos(lat1)*sin(lat2))-(sin(lat1)*cos(lat2)*cos(lon_difference)))) ; | ||
+ | head = (head * PI_DEGREES)/ PI; | ||
+ | |||
+ | if( head <= 0 ) | ||
+ | head += 360; | ||
+ | |||
+ | return head; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | <BR/> | ||
+ | Finding the distance between two coordinates. | ||
+ | <syntaxhighlight lang="cpp”> | ||
+ | /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ | ||
+ | /*:: This function calculates distance between the two coordinates in meters :*/ | ||
+ | /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ | ||
+ | double distance(double lat1, double lon1, double lat2, double lon2) { | ||
+ | double theta, dist; | ||
+ | theta = lon1 - lon2; | ||
+ | dist = sin(deg2rad(lat1)) * sin(deg2rad(lat2)) + cos(deg2rad(lat1)) * cos(deg2rad(lat2)) * cos(deg2rad(theta)); | ||
+ | dist = acos(dist); | ||
+ | dist = rad2deg(dist); | ||
+ | dist = dist * 60 * 1.1515; | ||
+ | dist = dist * 1609.344; | ||
+ | return (dist); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | <BR/> | ||
=== Testing & Technical Challenges === | === Testing & Technical Challenges === | ||
− | + | The GPS device should start transmitting NMEA sentences over the TX pin as soon as it is powered up, but the problem was that I wasn't able to retrieve data fast enough by sending out packages to the GPS module such as "$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28" to turn ON the GGA first, which helped us exploring our other options to make commands that are capable changing the update rate and also put the GPS module in the stand by command. Adding an external antenna was helpful to get the fixed data faster and definitely having an external antenna helped making the processes much faster. | |
− | |||
− | + | The most important part was that we tried writing a unit test for the GPS module and it took us awhile to actually write the test but the very nice part was that now the code and also the integration is much simpler and cleaner. Integrating with bluetooth and receiving data and also with the whole system in general became really easy after writing the unit test code which was able to go through the state machine and check the states and properly change and flow through the state machine. | |
− | |||
− | |||
− | |||
== Propulsion Systems and Speed Tracking (Motor Controller) == | == Propulsion Systems and Speed Tracking (Motor Controller) == | ||
Line 666: | Line 1,248: | ||
| 12/09/2016 | | 12/09/2016 | ||
| Test with the rest of the group, and fix any minor issues that come up.<br>* Finalize code and merge into master. | | Test with the rest of the group, and fix any minor issues that come up.<br>* Finalize code and merge into master. | ||
− | | | + | | Completed |
− | | | + | | 12/09/2016 |
|} | |} | ||
</center> | </center> | ||
=== Design & Implementation === | === Design & Implementation === | ||
− | |||
− | === Hardware Design === | + | ==== Hardware Design ==== |
− | + | ||
+ | [[File:CmpE243_F16_T6_MotorNetwork.png|right|thumb|500px|Motor connections to the SJSUOne Board.]] | ||
+ | [[File:CmpE243_F16_T6_ServoNetwork.png|right|thumb|500px|Servo connections to the SJSUOne Board and power.]] | ||
+ | [[File:CmpE243_F16_T6_MotorSoftwareTasks.png | thumb | 400px | Motor Tasks.]] | ||
+ | The motor controller board takes charge of two main systems: motoring and steering. | ||
+ | |||
+ | To accomplish motoring, a high power motor driver from Polulu is used to drive the RC car's motor. It takes a simple digital signal for direction and a PWM signal for speed. To help control speed accurately, a tachometer and a set of magnets in a wheel are used to feed back rotations per second (rps). For debugging, a TFT display was connected to the SJSUOne board and displayed tachometer readings versus commanded readings. | ||
+ | The figure on the right shows how the SJSUOne board is connected to the display and the motor driver. In addition, the block diagram also shows power connections from the battery. | ||
+ | |||
+ | Steering controlled as simply as the motor. A single wire is needed to feed a PWM signal to the servo. The figure below the motor connections image shows how the servo is connected. | ||
− | === Hardware Interface === | + | ==== Hardware Interface ==== |
− | + | ===== Motor ===== | |
+ | The interface to the motor consists of two sections: feedback and output. The feedback section involves connecting the SJSUOne board to the FAULT and Current sense pins. This allows the board to stop or slow down the motor if problems or overcurrent situations appear. Then the output section consists of a simple digital signal and a PWM signal. The simple digital output controls the direction of the motor: HIGH motors the car forward and LOW motors the car in reverse. To manipulate speed, the duty cycle of the PWM signal is changed according to a PI control algorithm in the SJSUOne board. In order to avoid overcurrent problems, the PWM signal is kept at a high frequency such as 20 kHz. | ||
+ | ===== Tachometer ===== | ||
+ | The tachometer provides information about wheel rotation speed by pulling the its output line low every time the tachometer passes over the south pole of a magnet. | ||
+ | ===== Servo ===== | ||
+ | Controlling the servo requires just one PWM signal. Instead of the duty cycle, the on-time of the signal determines how far the servo turns the car to the left or right. For the servo on this car, the range is 1.300 to 1.900 ms, where 1.5 ms means straight. With this time range, the best frequency for this signal would be 50 Hz. However, since the SJSUOne board provides only one PWM module, a software PWM module was implemented to produce the signal. | ||
+ | ===== TFT Display ===== | ||
+ | A board from Adafruit, the TFT display used for this project communicates with the SPI protocol. However, the board also provides a reset pin and an SD card, so there are a couple of extra pins to choose which device to connect to. The SD card port may be used to log debugging information. | ||
+ | For drawing the actual characters, a library from Adafruit was imported. | ||
− | === Software Design === | + | ==== Software Design ==== |
− | + | ======Created Libraries====== | |
+ | * Servo Driver (Uses a hardware timer attached to an interrupt to drives a servo at 50 HZ with 100 microseconds of resolution) | ||
+ | * Motor Controller (Runs the control loops that drive the main motor and steering) | ||
+ | * LCD Display Driver(Controls the LCD display. Most functions were imported from the Adafruit library for the device) | ||
+ | * Tachometer Driver (Sets-up/monitors an external interrupt and keeps track of the tachometer ticks) | ||
− | + | All code on this SJSU-Oneboard software was separated into two running tasks, the Periodic Scheduler and the LCD Display task. The LCD Display was put into its own task due to the need for specific timing requirements that are randomized and large. Typically a custom delay system should be created and put into the periodic scheduler but the LDC display is a low priority objective and a separate task handles its requirements adequately. The periodic scheduler runs every other task on the system. The two subsystems of the periodic scheduler that run on different timing requirements are both the interrupts for the tachometer and the servo hardware timer. Both of these Interrupts are set as lower priority than the periodic scheduler interrupts and RTOS interrupts. This does causes a gap in the hardware timer's control signal for the servo, however the gap is not often enough to cause the servo issues. Furthermore the gap is outside the range of input to the servo so whenever the gap happens, the servo completely ignores it. | |
− | |||
− | === | + | ==== Implementation ==== |
− | + | =====Motor Control System===== | |
− | + | Using the 10 Hz periodic scheduler task with a counter, the Motor Control system runs every half a second. This amount of time was selected from the low resolution of eight tachometer ticks per rotation of the car's wheel. In general, the greater the resolution of your feedback in a closed loop system, the faster your control loop can run. Within the Control loop, a system similar to a PI(Proportion, Integral) system was used. When a command from the master controller is sent, that value will get multiplied by a constant and added with an offset. The offset is simply an incremented or decremented value that gets changed according to how far the motors actual speed is from its targeted speed. The Final value is then fed to the motors as a percentage to the PWM I/O that controls the motor's speed. | |
− | + | =====Servo Hardware Timer===== | |
+ | The SJSU-One-Board's PWM controller can only be set to one frequency and with the Motor controller needing to be run at ultra-sonic frequencies, another method to control the servo was needed. To control a servo, a PWM signal running at 50 Hz is needed. Furthermore the positive portion of the PWM wave has to be timed to a specific microsecond value between 1000 microseconds and 2000 microseconds. The method to satisfy these requirements was to implement a hardware timer that triggers an interrupt every 100 microseconds. Inside of this interrupt, is a counter. At a count of zero, a GPIO is set to HIGH and then at a controlled count between 10 to 20, the value is set to LOW. Once the count hits 202, the count is reset. | ||
− | === | + | === Testing & Technical Challenges === |
− | + | ==== Motor Driver control ==== | |
+ | Several times during testing, the SJSUOne board was powered up or reprogrammed while still connected to the motor driver, causing the motor to rev at full speed and destroy the motor driver. The first solution to avoid full speed upon board power up was to add a tri-state buffer between the output of the SJSUOne board and the motor driver. Later on, the team discovered that a single pull-down resistor on the line was sufficient to solve the issue. | ||
+ | This taught the team that for future projects involving powered mechanical systems to always make sure the control line by default will keep the systems off, whether by pull-down resistors or tri-state buffers. | ||
+ | ==== PWM accuracy ==== | ||
+ | While testing servo control, the frequency of the generated PWM signal proved to be inaccurate. The generated signal would have a frequency 10 times greater than what is set in the program, leading to inaccurate on-times. The team soon found out that the problem was because of where the PWM object in the program was constructed. Initially, the PWM objects were created in the global scope, meaning the constructor would write to the registers before the main() function was entered. While this problem is not fully understood, it was solved by constructing the objects in init() functions, which were called after the main() function was entered. | ||
+ | This shows that, for future drivers written for microcontrollers, driver behaviour would be much more well defined if all register manipulation happened in an init() member function rather than in a constructor. This way, client users do not have to worry about accidentally constructing driver objects in the global scope. | ||
== Master Control Systems == | == Master Control Systems == | ||
Line 719: | Line 1,326: | ||
| 9/20/2016 | | 9/20/2016 | ||
− | | Assigned tasks to one another and | + | | Assigned tasks to one another and strategize approach. |
| Complete | | Complete | ||
Line 757: | Line 1,364: | ||
| 10/29/2016 | | 10/29/2016 | ||
| Program obstacle detection/autonomous car control algorithms | | Program obstacle detection/autonomous car control algorithms | ||
− | | | + | | Complete |
− | | | + | | 10/29/2016 |
|- | |- | ||
! scope="row"| 4 | ! scope="row"| 4 | ||
Line 764: | Line 1,371: | ||
| 11/06/2016 | | 11/06/2016 | ||
| Test RC car obstacle detection and autonomous control interfaced with Sensor Module over CAN | | Test RC car obstacle detection and autonomous control interfaced with Sensor Module over CAN | ||
− | | | + | | Complete |
− | | | + | | 11/06/2016 |
|- | |- | ||
! scope="row"| 5 | ! scope="row"| 5 | ||
Line 771: | Line 1,378: | ||
| 11/13/2016 | | 11/13/2016 | ||
| Interface GPS module with Master Controller | | Interface GPS module with Master Controller | ||
− | | | + | | Complete |
− | | | + | | 11/13/2016 |
|- | |- | ||
! scope="row"| 6 | ! scope="row"| 6 | ||
Line 778: | Line 1,385: | ||
| 11/20/2016 | | 11/20/2016 | ||
| Interface Android/Bluetooth module with Master Controller.Test Waypoint System | | Interface Android/Bluetooth module with Master Controller.Test Waypoint System | ||
− | | | + | | Complete |
− | | | + | | 11/20/2016 |
|- | |- | ||
! scope="row"| 7 | ! scope="row"| 7 | ||
Line 785: | Line 1,392: | ||
| 11/27/2016 | | 11/27/2016 | ||
| Debug any issues with Master controller and other modules | | Debug any issues with Master controller and other modules | ||
− | | | + | | Complete |
− | | | + | | 11/27/2016 |
|- | |- | ||
! scope="row"| 8 | ! scope="row"| 8 | ||
Line 792: | Line 1,399: | ||
| 12/12/2016 | | 12/12/2016 | ||
| Final debug/testing of RC CAR | | Final debug/testing of RC CAR | ||
− | | | + | | Complete |
− | | | + | | 12/12/2016 |
|} | |} | ||
</center> | </center> | ||
+ | === Hardware Design === | ||
+ | |||
+ | For Master Controller since we did not have to interface with any external peripherals the hardware was very simple and initially only consisted of a SJOne board along with a Waveshare SN65HVD230 CAN transceiver to communicate over the CAN bus. The CAN transceiver was already equipped with internal 120 ohm resistors but when the PCB board was created these transceivers were no longer needed. The RD1 (pin 0.0) and TD1 (pin 0.1) on the SJOne board are connected to the CAN Rx and CAN Tx pins on the CAN transceiver thus using CAN1 for our SJOne board. | ||
+ | |||
+ | === Software Design === | ||
− | === | + | === Modes of Operation === |
− | The | + | There are two modes of operation for the Master controller. One is the steering control and the other is obstacle avoidance mode. None of these modes are operational until a Master Enable message is received by the master. The steering control mode relies on target and heading messages from the GPS and Sensors nodes to successfully navigate the car to its destination. It is the default mode of operation for the Master Controller. The other mode of operation mentioned is obstacle avoidance mode. The obstacle avoidance mode is only triggered when the front sensors distance values are within a predefined threshold thus telling the car to get out of the way. |
+ | |||
+ | '''PI Controls on Steering''' | ||
+ | |||
+ | This "steering" mode is only run when there are no obstacles detected. This mode uses a PI controller to close the steering error between our target direction and our heading. The error is calculated as target - heading and the PI gains were scaled such that 180 degrees off target results in 100% steering in either the left or right direction. The steering errors would then be closed through an integral gain. | ||
+ | |||
+ | '''Obstacle Detection''' | ||
− | + | Obstacle avoidance is entirely dependent on the front sensor values and rendered inactive if nothing is being detected. The algorithm is shown below. | |
− | + | [[File:CmpE243 The-Nine Obstacle.JPG|600px|thumb|center|Obstacle Avoidance]] | |
− | + | Obstacle Avoidance mode is triggered when a front sensor value is within a predefined set of distance thresholds. The speed of the car is also reduced when in this mode to provide enough time to get out of the way. The degree of steering is proportional to how close an object is to the RC car, the closer an object is the harder the steering of left or right. If an obstacle is deemed too close to our RC car, giving us the idea that there's no way to get out of the obstacle's way, the RC car goes in reverse and will continue to do so until the there's enough space in front of it. | |
− | |||
− | === | + | {| class="wikitable" |
− | + | |+ Sensor Readings Triggering Obstacle Avoidance | |
+ | |- | ||
+ | ! scope="col"| Front Left Sensor Threshold | ||
+ | ! scope="col"| Front Center Sensor Threshold | ||
+ | ! scope="col"| Front Right Sensor Threshold | ||
+ | ! scope="col"| Threshold for RC car reversal | ||
+ | |- | ||
+ | | 80 cm | ||
+ | | 120 cm | ||
+ | | 80 cm | ||
+ | | 30 cm | ||
+ | |} | ||
=== Implementation === | === Implementation === | ||
− | + | Using FreeRTOS we had the two modes operating in the periodic scheduler at the 100Hz() task , and we decided to send motor commands at that same frequency. The 100Hz() task also managed the receiving of signals from the GPS and Sensor nodes. Transmitting debug signals caused the issue of overloading the CAN bus at 100Hz so it was designated to the 1Hz() task as these signals were less of a priority. | |
+ | |||
+ | [[File:CmpE243 The-Nine Tasks.JPG|600px|thumb|right|Periodic Scheduler]] | ||
+ | |||
+ | '''Software Libraries''' | ||
+ | |||
+ | To avoid an unnecessarily long 100Hz() task that would include our steering and obstacle avoidance code, we included header files for our code, header files Obstacle_Detect.hpp and vehicle_controls.hpp were included for obstacle avoidance mode and steering control respectfully. | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |+ Master Controller DBC Communication Table | ||
+ | |- | ||
+ | ! CAN Message ID Number | ||
+ | ! Purpose | ||
+ | ! Data layout | ||
+ | |- | ||
+ | | 0x64 | ||
+ | | Receive Enable or Disable Master from Debug Node | ||
+ | | 1 for Enable, 0 for Disable | ||
+ | |- | ||
+ | | 0x65 | ||
+ | | Send Debug Signals to Debug Node | ||
+ | | Current Mode of Operation, Current Speed Commanded, Which sensor triggered Obstacle Avoidance | ||
+ | |- | ||
+ | | 0x100 | ||
+ | | Send Speed and Steer Commands to Motor Controller | ||
+ | | Speed Commands from -100 to 100, Steer Commands from -100 to 100 | ||
+ | |- | ||
+ | | 0x200 | ||
+ | | Receive sensor values and compass heading direction via multiplexer | ||
+ | | Sensor values in centimeters, Compass heading in degrees | ||
+ | |- | ||
+ | | 0x300 | ||
+ | | Receive GPS IMU target heading and destination | ||
+ | | Target Heading in degrees, Destination Reached true/false | ||
+ | |} | ||
=== Testing & Technical Challenges === | === Testing & Technical Challenges === | ||
− | |||
− | |||
− | + | === Testing Code Functionality === | |
+ | Since the Master Controller is all but software driven and relies heavily on communication between other CAN nodes , testing the functionality of your code can be a bit tricky especially when outright testing the RC car isn't viable. To fix this we had to familiarize ourselves with the BUSMASTER software as it can easily replicate other nodes. This made debugging much easier and decreased the burden of having to rely on other parts of our RC car that were not ready. Another method we used to unit test our code is the C library <assert.h>. This allowed us to more rigorously test each function of our code by passing in specific parameters that corresponded to specific scenarios into our obstacle detection algorithm and then see if it returned the correct value. | ||
− | === | + | === Obstacle Detection Sensor Thresholds and Speed Control === |
− | + | Another issue we faced was on figuring out when Master should trigger obstacle avoidance mode. Alot of trial and error was gone through to properly assess a good speed for the RC car. With the car going faster we noticed that greater obstacle detection distance thresholds needed to be used thus improving the response time of the vehicle and avoiding collisions. We did not want our car to go too fast and destroy itself so we decided on a speed that was a slow and steady pace but not too slow. This provided the car with plenty of time to steer itself out of the way and allowed for smaller distance thresholds for obstacle avoidance to be triggered. | |
+ | |||
+ | === Steering Control for Obstacle Avoidance=== | ||
+ | There was also the issue of steering to slowly in case of an object is in the way, which often led to it crashing. We tried to incrementally increase the speed of steering by different factors but realized that this was not reliable and often led to crashes. To fix this we decided to adjust the steering so that the rate of steering would increase proportionately to how close it was to an object, this gave us a factor between 0 and +-100 for right(+) and left(-). | ||
== Conclusion == | == Conclusion == | ||
− | + | ||
+ | Overall we had a successful project and the car performed as intended. However achieving that goal was more difficult than expected, and we certainly felt the project was going to be more straightforward than it was. | ||
+ | Some of our learning experiences were: | ||
+ | |||
+ | * No last-minute changes. We had modified part of our motor handling before our second demo and it malfunctioned spectacularly by crashing into a wall at high speed. We had found that an unnecessary fail-safe circuit used to disconnect PWM from the motor had masked a bug in how the PWM object was instantiated, causing acceleration right after startup. More testing would have resolved this, but that needed to happen much earlier and not minutes before the demo. | ||
+ | |||
+ | * Don't trust good results. Our vehicle had navigated the campus several times flawlessly so all systems seemed to be good. Later we realized the magnetometer never really worked at all and wasn't calibrated either, merely by chance our previous runs had went well. What followed was a rush to characterize the problem and resolve it with time running out. Probably more comprehensive testing would have revealed this problem, as well as going through a checklist of common magnetometer issues to double-check we were addressing them as these issues are well documented on the internet. | ||
+ | |||
+ | * Communication is key. We used Slack and Trello to keep in touch at all times and could discuss the project even when not in a face-to-face meeting. This was instrumental to keeping the teams up to date about what was happening and what to expect, as we all had different schedules and could seldom all meet at once. But this required members to make a commitment to check their Slack messages and keep their Trello board updated. Productivity applications are only as good as the users that use them, and they can't solve problems if they aren't being utilized correctly. | ||
+ | |||
+ | * Every voice counts. We all had different ideas about how things should be done, but the best results came from learning when to listen and when to give constructive and helpful criticism. We didn't want to be isolated to our own tasks and had an open dialogue across each sub-team about how we were going to implement things. This increased as the project progressed, for example we had the headlight design coming from our GPS team, with a 3D-printed mount and hardware implemented by our sensor team, and application control, manual button control, and light-sensitive controls programmed by our Bluetooth team. Even for a simple feature like this we were very pleased with the results because it was a collaborative effort and each team could contribute. | ||
+ | |||
+ | It would be hard to pinpoint exactly how our knowledge has increased because we've been exposed to a huge array of topics as part of this project. You could say we learned a little bit of everything! | ||
== Project Video == | == Project Video == | ||
− | + | ||
+ | === Final Demonstration Video (December 21st, 2016) === | ||
+ | https://www.youtube.com/watch?v=45zn2YhpKiY | ||
+ | By: Derek Tran | ||
+ | |||
+ | === Final Demonstration Close up Video (December 21st, 2016) === | ||
+ | https://youtu.be/1Sts9X9gJdM | ||
+ | By: John Strube | ||
+ | |||
+ | === Full System Pre-Final Demonstration Testing (December 20st, 2016) === | ||
+ | https://www.youtube.com/watch?v=4u3rgHmo4yo | ||
+ | By: Charles MacDonald, David Cruz | ||
+ | |||
+ | === Obstacles Avoidance Testing (December 5st, 2016) === | ||
+ | https://www.youtube.com/watch?v=3b5x-d2T8aY | ||
+ | |||
+ | === MORE TESTING FOOTAGE TO COME!!! === | ||
== Project Source Code == | == Project Source Code == | ||
Line 836: | Line 1,528: | ||
== References == | == References == | ||
=== Acknowledgement === | === Acknowledgement === | ||
− | + | ||
+ | We would like to thank Preet for his help, our ISAs including Calvin, Shangming, Jon, and our classmates. | ||
=== References Used === | === References Used === |
Latest revision as of 20:14, 23 December 2016
Contents
- 1 Project Title
- 2 Abstract
- 3 Objectives & Introduction
- 4 Project Schedule Overview
- 5 Team Members & Responsibilities
- 6 Parts List & Cost
- 7 Bluetooth Communications (Communication Bridge)
- 8 Mobile Phone Application
- 9 Obstacle Detection Systems (Sensor Controller)
- 10 Localization and Positioning (GPS)
- 11 Propulsion Systems and Speed Tracking (Motor Controller)
- 12 Master Control Systems
- 13 Conclusion
- 14 Project Video
- 15 Project Source Code
- 16 References
Project Title
The-Nine: Self Driving Car
Abstract
Nearly every car manufacturer today is in the process of developing fully autonomous vehicles. There are some that are on the brink of winning the development race as their systems are safer than many human drivers. However currently no one has been able to fully implement autonomous navigation requiring nothing but a destination while having the full support and trust of the community to remove the driver from the equation. Autonomous vehicles are incredibly difficult to create as there are a huge number of difficulties of autonomy that must be taken into account. The purpose of this project is to introduce the basic technologies in application of the types of systems that can be used in autonomy. The overall project goal is to make an autonomous RC car that utilizes five SJSU-One-Boards that intercommunicate with each other through CANbus; each controlling a major functionality. The RC car must be able to be given a destination through an interfacing application and it must be able to travel to that location.
Objectives & Introduction
This project aimed towards developing and building a RC car which has the self-driven capability. We communicated over CAN bus. The car is capable to find its current location through the GPS module. The car could get the destination and way points through the google map API which is connected to the android application, and bluetooth and through CAN messages is sent over to the GPS and it could find its path to the destination while avoiding any obstacles that might run into while driving to the destination. To achieve this objective, we used 5 controllers, which each is dedicated to a specific role such as master, sensors, bluetooth, motors and geographical location. These controller can pass messages over the common CAN bus. In addition, the final prototype of has android application which is useful for data monitoring and keep tracking of the car remotely. Through the android application, the user can feed the desired destination and the car is capable of finding its path to the destination. The car follows the direction based on the data that is provided by the sensors, GPS and compass values.
Project Objectives
- Primary
Use CANbus to intercommunicate between the different controllers on the car.
- Master Controller
Take in data from all controllers to make a logical decision on how to control Speed and Steering to get to a location and avoid obstacles.
- Bluetooth Controller
Make a Bluetooth Connection to the user interfacing application to display telemetry information on the application and to receive target locations for the car to travel to. In charge of I/O such as headlights and physical switches.
- Motor and Display Controller
Get commands from the master controller and control the drive motor and steering servo. Collect Drive motor feedback and make sure the drive motor is running at its target speed. Display Useful through some type of LCD Display.
- GPS Controller
Gets waypoints from the bluetooth and find the target heading to the nearest waypoint, and calculate the distance. As the car gets closer to the waypoint, checks if it is in range, if so it will move one to the next waypoint.
- Sensor Controller
Collect ultrasonic sensor and magnetometer data, battery voltage and send back to master controller.
Project Schedule Overview
Task # | Start Date | End Date | Team Task Description | Bluetooth Communications | Obstacle Detection Systems | Localization and Positioning (GPS) | Propulsion Systems and Speed Tracking | Master Control Systems | Status | Actual End Date |
---|---|---|---|---|---|---|---|---|---|---|
1 | 9/14/2016 | 9/20/2016 | Assigned tasks to one another and strategized approach. Read Previous Reports | Completed | 9/20/2016 | |||||
2 | 9/21/2016 | 9/27/2016 | Set up Version Control System and Basic Project Documentation Research Project Components |
Research of web application frameworks for mobile. | Research of sensor systems and sensor types needed. | * Researched and decided upon the GPS module and Compass module. * Ordered GPS module and compass module. |
Work with team leader to devise version control strategy. | Research different RC cars for the project. | Completed | 9/27/2016 |
3 | 9/28/2016 | 10/04/2016 | Discuss controllers' responsibilities and communication | Started development of DBC and finalized hardware choices. | Completed | 10/04/2016 | ||||
4 | 10/05/2016 | 10/19/2016 | Order Project Components Individual Prototyping and Module Design |
Research Bluetooth device HC-06 for the RC car. | Interface IMU and ultrasonic sensors to board. | * Parse GPS data and format the data to be transmitted * Test code to get compass reading information |
Research what encoders and/or tachometers to use, help the team leader choose an RC car to purchase, and decide what motor driver to use | Implement Decision Tree for obstacle detection/autonomous car control. Decide on Message ID system over the CANBUS/Types of Data being Transmitted | Completed | 10/19/2016 |
5 | 10/20/2016 | 10/27/2016 | Status Update: Demoing first round of Prototyping to the group | Develop Bluetooth serial receiver library & web application. | Develop IMU and ultrasonic sensor libraries. | Interface GPS module and compass module to SJOne board. | Make the motors spin and the servo control the steering. Receive can signals and control the motor and steering servo. | * Implement Decision Tree for obstacle detection/autonomous car control. Decide on Message ID system over the CANBUS/Types of Data being Transmitted * Program obstacle detection/autonomous car control algorithms |
Completed | 10/27/2016 |
6 | 10/28/2016 | 11/18/2016 | Adding a level of complexity to designs: Interfacing Motor, Sensor, GPS, and Bluetooth Modules with the Master Controller over CAN bus | Integrate web application, SJOne board and DBC messages | Use implemented DBC to transmit sensor data over CAN. | * Calibrating the compass module.Integration of GPS and compass module. Interfacing of GPS and compass module to Android. * Integration with Master through CAN bus. |
* Validate and calibrate the motor controller and steering code. Receive the Tachometer and magnetic polarity strip. * Merge motor_test/tach with master. * Reorganize code for readability. * Finalize and test speed feedback system. |
* Program obstacle detection/autonomous car control algorithms * Test RC car obstacle detection and autonomous control interfaced with Sensor Module over CAN * Interface GPS module with Master Controller * Interface Android/Bluetooth module with Master Controller.Test Waypoint System |
Completed | 11/18/2016 |
7 | 11/19/2016 | 11/25/2016 | Integration Testing between Modules, System Validation | Fine-tuning of web application | Debug sensor library and work on integration | Testing and calibrating with other modules. | Test with the rest of the group * Fine tune nominal speed. Add LCD to display debug information. |
* Interface Android/Bluetooth module with Master Controller.Test Waypoint System * Debug any issues with Master controller and other modules |
Completed | 11/28/2016 |
8 | 11/26/2016 | 12/02/2016 | Overall System Optimization | Fine-tuning of sensor readings | Testing and calibrating with other modules. | * Replace motor driver with higher amperage driver. * Adjust steering offset to reduce error. |
* Debug any issues with Master controller and other modules * Final debug/testing of RC CAR |
Completed | 12/04/2016 | |
9 | 12/03/2016 | 12/09/2016 | Finalization, Preparing for Demonstration | Completed | 12/08/2016 |
Team Members & Responsibilities
Application & Control Interface
- Khalil Estell
Bluetooth Communications
- Khalil Estell
Obstacle Detection Systems
- Charles MacDonald
- John Strube
Localization and Positioning (GPS)
- Sara Sepasian
Propulsion Systems and Speed Tracking
- Derek Tran
- Matthew Boyd
Master Control Systems
- Steven Hwu
- Adam Iglesias
Parts List & Cost
Give a simple list of the cost of your project broken down by components. Do not write long stories here.
Item # | Part Description | Vendor | QTY | Cost |
---|---|---|---|---|
1 | RC Car | Nor-Cal Hobbies | 1 | $200 |
2 | SJSUOne Board | Preet Kang | 5 | $400.00 |
3 | HC-06 Bluetooth Module | Amazon | 1 | $8.99 |
4 | Magnetic Tachometer | Digikey | 1 | $8.53 |
5 | Radial Magnet cube magnets | Digikey | 10 | $8.80(Total) |
6 | Pololu 5V Step-Up/Step-Down Voltage Regulator | Polulu | 1 | $14.95 |
7 | Pololu 6V Step-Up/Step-Down Voltage Regulator | Polulu | 1 | $14.95 |
8 | 24V21 High Power Motor Driver | Polulu | 1 | $39.95 |
9 | 2000mAH 3 Cell Lipo Battery | HobbyKing | 1 | $25.00 |
10 | MB1010 Ultrasonic Sensors | Jameco | 3 | $74.85 |
11 | Assorted components for PCB | Mouser | 1 | $31.60 |
12 | PCB manufacturing service | Bay Area Circuits | 1 | $32.64 |
13 | GPS sensor | Adafruit | 1 | $50.00 |
14 | Weatherproof LED strip (60 LEDs/meter) | Adafruit | 1 | $25.00 |
15 | Schmartboard Jumper Wires | Fry's Electronics | 2 | $6.00 (green, 12") / $5.00 (blue, 7") |
16 | 160x128 LCD display | Adafruit | 1 | $19.95 |
17 | CR1220 lithium battery | Mouser | 1 | $0.85 |
Bluetooth Communications (Communication Bridge)
Schedule
Task # | Start Date | End Date | Task Description | Status | Actual End Date |
---|---|---|---|---|---|
1 | 9/14/2016 | 9/20/2016 | Assigned tasks to one another and strategize approach. | Completed | 9/20/2016 |
2 | 9/21/2016 | 9/27/2016 | Research of web application frameworks for mobile. | Completed | 9/27/16 |
3 | 9/28/2016 | 10/04/2016 | Started development of DBC and finalized hardware choices. | Completed | 10/04/2016 |
4 | 10/05/2016 | 10/19/2016 | Research Bluetooth device HC-06 for the RC car. | Completed | 10/19/2016 |
5 | 10/20/2016 | 10/27/2016 | Develop Bluetooth serial receiver library & web application. | Completed | 10/19/2016 |
6 | 10/20/2016 | 11/18/2016 | Integrate web application, SJOne board and DBC messages | Completed | 11/12/2016 |
7 | 11/19/2016 | 12/02/2016 | Fine-tuning of web application | CONTINUOUS TASK | |
8 | 12/03/2016 | 12/09/2016 | Final integration | Completed | 12/08/2016 |
Design & Implementation
Hardware Design
Discuss your hardware design here. Show detailed schematics, and the interface here.
Hardware Interface
The HC-06 bluetooth Serial device can be interfaced via UART. Simply, connect the Bluetooth RX -> the SJOne TX and connect the Bluetooth TX -> the SJOne RX. Any serial Bluetooth data transmitted to the HC-06 from a master bluetooth device will propagate to the Bluetooth TX pin. Send bytes through UART via the SJOne TX pin in order to transmit to the master bluetooth device.
Two tactile buttons are connected to GPIs on the SJOne board.
One PWM output (P2.1) from the SJOne board is connected to a logic level mosfet to control the brightness of an white light led strip.
Software Design
Implementation
The following code is basically all that is required to control a Bluetooth module along with headlight.
void period_1000Hz(void)
{
if(led_btn_is_released)
{
manually_increment_headlights();
}
if(gps_btn_is_release)
{
send_fixed_gps_location();
}
automatic_headlights_control();
}
void period_10Hz(void)
{
handle_can();
send_master_control_signal();
if(gps_queue_ready)
{
send_gps_queue();
}
}
void period_100Hz(void)
{
handle_uart();
}
Testing & Technical Challenges
The challenge was finding an HC-06 module that works. Some of the modules came in dead-on-arrival. After you find a set of them that work, attempt to connect them to your phone and make sure it can connect. Finally, use any Bluetooth serial application from your phone's app store and send messages to the bluetooth device. Using either the UART on your SJOne board or a USB to UART device (FTDI dongle), verify that the messages can be received from the device from your phone.
Also, as the application developer, there are many features you will want to add to the application. So during the beginning phases of integration, the DBC file changed rapidly between the many modules. Keeping up with the module changes result in issues such as more features were added. Try to keep up with those changes along with the apps changes as well.
Issue #1: CAN evaluation task Overrun
The Bluetooth module listens for signals from all of the devices in the system, which can result in problems. If you attempt to process a large number of CAN message in a while loop, the task could run longer than the 10Hz task can allow for (100ms) which will cause the system to crash. To fix this issue, it should be noted that the animations on the app look smooth enough at 10Hz. To minimize the time taken in the task, a flag for each CAN message type is set to 1 which means they have not been decoded. The while loop will check if that message's flag has been set and attempt to decode it if it has not been set. If the flag has been cleared it is ignored. When all flags have been set, the while loop is broken and the task ends. All other message are ignored. This is fine since most humans would not be able to notice small changes to the app display from below 10Hz.
Mobile Phone Application
Design & Implementation
Hardware Design
N/A
Hardware Interface
see Bluetooth Module System Diagram. above.
Software Design
The mobile application for the-nine autonomous RC car was not a native Android or iOS application but instead a web application. The EvoThings desktop tool and application viewer were used to deploy the web application to the phone. The EvoThings viewer gives the web application access to Bluetooth and other features that only native applications would have access to. The EvoThings viewer provides a global cordorva.js script file that can be added into any of the html pages in the application.
Cordorva, by default, has the capability to communicate over standard Bluetooth (NOT BLE). To begin using Bluetooth, simply, include the cordova script and begin using:
bluetoothSerial.connect(param1, param2, ..., function success()
{
bluetoothSerial.write("message to send to bluetooth device")
}, function failure()
{
alert("bluetooth connect failed");
});
The application also used the Google Maps HTML API for displaying the current position of the RC car on a map (denoted as a cyan closed arrow), the direction it is facing, the direction it should be heading towards (denoted as a red open arrow underneath the cyan arrow), the waypoints it needs to get to, and the destination and where the current user is standing. The Google Maps API was also used for calculating waypoints.
The Bootstrap CSS framework was used to give structure to the layout of the page as well as give style to the buttons and other elements.
Implementation
Quick Start Guide: Telling the RC car where to go
- In the map view, press on the map, where you want the RC car to go. A red cross hair will appear at the point that you pressed with a light blue path behind it and a set of black cross hairs. The red one cross hair indicates the destination. The black cross hairs indicate the sequence of waypoints the RC car will navigate to in order to reach the destination.
- Press the button that says "Map".
- The view should have changed and the Map button should now say Telemetry.
- Press the button Navigate to Target. When the progress bar below the buttons changes from "Destination Reached" to "Approaching Destination", you are ready to start.
- To start, enable the car by pressing the enable button on the top right of the application.
GPS Waypoint Calculation
The GPS waypoints were calculated utilizes the Google Maps walking directions API. But note that the direct results from the Walking Directions API is not appropriate for this project. When using the Google Maps walking directions API to get the Steps to get to a destination, the interface assumes you can handle walking down a winding street or maneuver around between buildings, so the number of steps are quite sparse. For example, if you use the walking steps, you may get a set of waypoint points that directs the car to go through a building. To fix this, notice that the Google Maps directions lines follow straight line paths that, if followed, will bring you to exactly where you need to go whilst avoid large static obstacles and buildings. Thus, the GPS waypoints were taken from the straight line segments that draw a path to and from origin to destination. This information can be found in the DirectionsDisplay.directions.routes[0].overview_path after a DirectionsService.route() call has been made to generate a route from origin to destination.
Stylizing the Application
The button styles and progress bars came from Bootstrap. The tabs on the top are just buttons in a div that is fixed to the top of the screen. No <nav> tags were used in the application.
The gauges compass/heading indicators come from the plugin JQuery Knob (http://anthonyterrien.com/demo/knob/). The Ultrasound indicators were designed by myself using CSS3 by manipulating the boarders ofFeatures of the Application
Connect/Disconnect Buttons
The connect button will only attempt to connect. It will never attempt to disconnect. Connecting to the car is a safe operation, but disconnecting from it is not. So, to make it harder for the user to make unsafe actions, the connect button is limited to only connecting. To disconnect, the user must go to the telemetry view, scroll to the bottom, press it, get a warning vibration and confirm box and finally press the confirm action button.
Map/Telemetry view button
The Map/Telemetry view button in the middle of the interface will switch the application from Map view to the Telemetry view. The Map View contains (you guessed it) the google maps interface that the user can use to give a destination to the RC car. The telemetry view shows the control buttons and sensor feedback (telemetry) of the RC car.
Enable/Disable Buttons
The enable/disable button at the top of the navigation bar will vibrate when pressed to alert the user of the action. The button text and color will indicate the current state of the RC car. When the user intends to disable the RC car, the button can be tapped to disable the car. The button will then become disabled for 2.5 seconds to keep the user from double tapping the enable/disable button. This is useful since the button is typically used to stop the car from doing something dangerous. Without this delay it is typical for a user to tap the button to disable the car multiple times in an attempt to stop it but result in enabling it once again.
Return to User Buttons
Press this button to set the navigation point for the RC car to your current location. Press the navigate to target button and the car will navigate to you.
Message Log
The message log at the bottom logs events like ultrasound re-calibrations, connection events, disconnect events, invalid Bluetooth transmission and if the headlight signals have been sent.
Heartbeat Signal
The heartbeat signal is sent to the phone as an another indicator to the user that the Bluetooth module is connected and alive.
Ultrasound Re-calibration Indication
In the event of a ultrasound sensor lock up, the sensor board would send a CAN message to the Bluetooth module which will send a message to the application. The app will vibrate 3 times in quick succession to alert the user to an ultrasound re-calibration event. The ultrasound indicators will also turn green, yellow, and red with a value of -1cm for each sensor. The heartbeat indicator text will also show a !!! RECALIBRATING ULTRASOUNDS !!! message. Below the message log is the Force Ultrasound Recalibrate button which does nothing as of the demo on December 21st.
Testing & Technical Challenges
Even before I found EvoThings, I was certain to make the app for this project a web application. The issue was finding a way to rapidly develop the application with Bluetooth capability. There exists an experimental Bluetooth API for HTML5 but it is not supported by any browsers or phones. In the end, I found EvoThings which did exactly what was needed.
Obstacle Detection Systems (Sensor Controller)
Schedule
Task # | Start Date | End Date | Task Description | Status | Actual End Date |
---|---|---|---|---|---|
1 | 9/14/2016 | 9/20/2016 | Assigned tasks to one another and strategized approach. | Complete | 9/20/2016 |
2 | 9/21/2016 | 9/27/2016 | Research of sensor systems and sensor types needed. | Complete | 9/27/2016 |
3 | 9/28/2016 | 10/04/2016 | Started development of DBC and finalized hardware choices. | Complete | 10/04/2016 |
4 | 10/05/2016 | 10/19/2016 | Interface IMU and ultrasonic sensors to board. | Complete | 10/19/2016 |
5 | 10/20/2016 | 10/27/2016 | Develop IMU and ultrasonic sensor libraries. | Complete | 10/19/16 |
6 | 10/20/2016 | 11/18/2016 | Use implemented DBC to transmit sensor data over CAN. | Complete | 10/19/16 |
7 | 11/19/2016 | 11/25/2016 | Debug sensor library and work on integration | Complete | 11/25/16 |
8 | 11/26/2016 | 12/02/2016 | Fine-tuning of sensor readings | Complete | 12/1/16 |
9 | 12/03/2016 | 12/09/2016 | Final integration | Complete | 12/8/16 |
Design & Implementation
The obstacle detection system covers two areas: detecting obstacles and determining vehicle orientation.
Obstacle detection is performed using ultrasonic sensors placed around the perimeter of the vehicle, concentrated at the front (three sensors) and less so in the back (one sensor) as the vehicle is primarily driven in the forward direction.
Vehicle orientation is accomplished using an inertial measurement unit, which is used to determine the speed and bearing of the vehicle.
Hardware Design
Bumpers and Ultrasonic Mounts
The two bumpers, ultrasonic housings, and headlight mounts were designed using Onshape and 3D printed using PLA plastic. Each bumper was designed to house 3 ultrasonic sensors. The initial ultrasonic housings were designed for the Sparkfun HC-SR04 ultrasonic sensor. The housings were printed in black PLA plastic and modified to snugly fit the sensors. The front and rear bumpers were then designed to mount onto the existing bumpers on the RC car, and to fit the ultrasonic mounts using M3 screws. Both the front and rear bumper were printed in glow in the dark PLA plastic. After the bumpers were printed, we switched to the current MaxSonar sensors, so the new ultrasonic housings were designed to fit the existing bumpers. Each sensor is screwed into the housing using 2 small M3 screws, and each housing is screwed onto the bumper using M3 screws. There are 3 sensors in the front of the car, and one in the rear.
During testing it was determined that we need to tilt the sensors upwards at a 10 degree angle to avoid detecting the floor. The right and left sensors were also tilted 15 degrees outside to better detect obstacles on the side.
A mount to house the LED strip mounts onto the front bumper. The mount fits inside existing holes in the front bumper, but can be screwed in for additional stability. The headlight mount was printed in black PLA plastic.
During further testing it was determined that we need to raise the sensors off the ground to avoid small obstacles on the ground, such as gravel and leaves. New ultrasonic sensor housings were designed in such a way so that the height off the ground can be adjusted. The new adjustable ultrasonic housings were printed in blue PLA plastic.
Ultrasonic sensors
Our original design called for six ultrasonic sensors, with three forward-facing (sensors SFL, SFC, SFR at front-left, front-center, front-right) and three rear-facing (sensors SRL, SRC, SRR at rear-left, rear-center, rear-right). In practice only one center rear-facing sensor was needed, but the design still supports six. The sensors are arranged around the car as follows:
The ultrasonic sensors don't have a specific bus (such as SPI or I2C) and instead are triggered asynchronously through GPIO, described later.
Compass
A magnetometer is used to calculate the heading of the car. The magnetometer being used is the HMC5883L. The magnetometer measures the magnetic field of The Earth in units of Tesla as scalars in the X, Y and Z axis. The SJOne board communicates with the magnetometer using I2C at address 0x3C. An accelerometer onboard the SJOne board is used for tilt compensation. The magnetometer is oriented such that X axis faces forward, Z axis faces up, and Y axis faces to the left.
Hardware Interface
I/O expander
To utilize the limited number of available capture inputs across four to six ultrasonic sensors, an I/O expansion circuit was developed.
It consists of a 74HCT253 dual 4-to-1 multiplexer, and a 74HCT259 8-bit addressable latch. The multiplexer routes the sensor inputs to the two capture pins such that the front and rear sensors can be captured in parallel. To keep our final design compatible with the code developed for our prototype, the rear-center sensor was also mapped to the fourth input of the front-sensor multiplexer inputs such that iterating over four inputs would cover the front three sensors and rear single sensor on the same capture channel.
The following table shows the mapping between the two capture inputs and the sensor echo outputs, as well as the addressable register and the sensor trigger output. GPIOs are used for handshaking to load data into the register as needed.
Select | Input on CAP1.1 | Input on CAP1.0 | Addressed register |
---|---|---|---|
0 | SFL_ECHO | SRL_ECHO | SFL_TRG |
1 | SFC_ECHO | SRC_ECHO | SFC_TRG |
2 | SFR_ECHO | SRR_ECHO | SFR_TRG |
3 | SRC_ECHO | Always '0' | SRC_TRG (see JP1) |
4 | SFL_ECHO | SRL_ECHO | SRL_TRG |
5 | SFC_ECHO | SRC_ECHO | SRC_TRG (see JP1) |
6 | SFR_ECHO | SRR_ECHO | SRR_TRG |
7 | Always '0' | Always '0' | Not used |
A logic analyzer was used to monitor the sensor outputs during development to find optimal timings and delays for polling them, as shown below:
In this sample the trigger (TRG) pulse starts the sensor, which asserts the echo signal when ranging starts. When the negative edge of the echo signal is captured the next sensor is triggered shortly after. The select field shows which sensor is currently addressed. In this particular capture, all four sensors are being read in under under 50ms.
Battery voltage monitor
A 12.6V battery is used to power the entire vehicle. It has an operating range 9V to 12.6V, which spans approximately 3.6V. In order to determine the current battery voltage this operating range has to be brought down to a valid level for the SJOne board to read on an ADC input which is limited to 3.3V
An LM341 adjustable zener diode is used to provide a 9V drop on the battery output. This is accomplished by using a voltage divider to set the reference voltage input on the LM341. At this point the maximum voltage output is 3.6V which is still out of range. A second voltage divider is used to scale it down to 3.3V, and a regular zener diode is used to clamp the output at 3.3V. This allows the SJOne board to read the battery voltage safely.
Compass
The SJOne board communicates with the HMC5883L using I2C bus 2, using slave address 0x3C. The magnetometer is oriented such that the X axis faces forward, the Y axis faces left, and the Z axis faces up. SDA and SCL pins are connected to the SDA2 and SCL2 pins on the SJOne, GND is connected to GND, and VCC is connected to 3.3V.
Software Design
Ultrasonic sensors
Overview
A sensor polling loop starts every second (1 Hz). Within this loop all four sensors are read, the distances are calculated and output on the CAN bus, and the elapsed time is determined. If there is enough time remaining to do a worst-case read of all four sensors (approximately 200ms), the sensors are read again. If polling of all four sensors finishes before a 50ms interval has expired, polling can't continue as each sensor must be idle for 50ms before being triggered again. In this case the software idles for the remainder of the 50ms interval until polling can resume.
This dynamic polling approach yields an average sensor update rate of 16 Hz, which is faster (up to 20 Hz) as the car gets closer to objects, and is slow (as low as 5 Hz) when in free space with no obstructions in any direction. This is using the hardware configuration where the rear sensor isn't read in parallel with the front sensors. If that mode is used, the worst-case polling rate is 6.66 Hz.
Polling internals
Timer #1 is used for capturing echo pulses from the sensors. Some caution is needed as Timer #1 is normally allocated to the watchdog and infrared (IR) interface. In "sys_config.h" you need to redefine "SYS_CFG_SYS_TIMER" from 1 to some other number (0,2,3) to map those functions to a different timer. This frees up timer 1 for use in capturing signals.
The capture function of timer #1 is triggered on the rising edge and the falling edge, and an interrupt is generated on each capture event. The ISR saves the captured value on each edge and computes the difference between them to determine the length of the sensor's pulse. A state machine is used to keep track of events per sensor (ranging request, positive edge received, negative edge received) so the ISR knows what stage of processing the sensor being polled is in.
Battery voltage monitor
The battery voltage is read after the sensors are polled using the ADC. This data is sent to the rest of the system over the CAN bus.
Compass
The compass headings are calculated 10 times a second using the period_10Hz task in period callbacks. An exponential moving average is used to smooth out the raw magnetometer and accelerometer data. A weight of .5 was used to smooth out the magnetometer, and a weight of .1 was used to smooth out the accelerometer. The magnetic and acceleration vectors as measured from the magnetometer and accelerometer are then normalized such that the length of the vectors is 1.0. Because a gyroscope is not being used to assist in tilt compensation, a very low weight must be used to compensate for the car accelerating forward and backward. Tilt compensation is used to ensure an accurate compass reading when the car is titled. The tilt compensation algorithm uses the roll and pitch as calculated from the accelerometer and the X Y and Z components of the normalized magnetometer vector. The calculated heading is then converted from radians to degrees. The magnetic declination offset angle is then added to the heading to account for the differences between magnetic and true north. The heading will then be sent to Master, BlueTooth, and Debug over Can bus.
Implementation
This section includes implementation, but again, not the details, just the high level. For example, you can list the steps it takes to communicate over a sensor, or the steps needed to write a page of memory onto SPI Flash. You can include sub-sections for each of your component implementation.
Compass
To communicate with the magnetometer sensor, a singleton class named IMU_Sensor was created. The class stores sensor data in a local struct, and handles initialization of the sensor, and reading raw magnetometer sensor data.
Measuring the raw sensor data
The IMU_Sensor class communicates with the magnetometer using I2C at address 0x3C. The period_init function in periodic callbacks calls the init function, which sets the two configuration registers and the mode register using the I2C2 class. Ten times per second the periodic scheduler calls the getXYZ() function. Six registers are read, starting at 0x03, which store the high and low bites for the X, Z, and Y axis of the magnetometer. If the readRegisters function returns false, the getXYZ function returns false. A zero byte is then written to register 0x03 to reset the internal pointer and prepare for the next measurement. The table below lists the relevant registers.
Address Location | Name |
---|---|
0x00 | Configuration Register A |
0x01 | Configuration Register B |
0x02 | Mode Register |
0x03 | Data Output X MSB Register |
0x04 | Data Output X LSB Register |
0x05 | Data Output Z MSB Register |
0x06 | Data Output Z LSB Register |
0x07 | Data Output Y MSB Register |
0x08 | Data Output Y LSB Register |
Calculating Heading
The period_10Hz reads the raw values from both the magnetometer using the IMU_Sensors class, and from the accelerometer using a built in class. The raw data is then filtered using an exponential moving average, with a weight of 0.5 for the magnetometer and 0.1 for the accelerometer. The magnetometer and accelerometer vectors are then normalized. Roll and pitch are then calculated using the normalized accelerometer vector. The roll is calculated by taking the arcsin of the negative X component, and the pitch is calculated by taking the arcsin of the Y component. The following formula is used to calculate the tilt compensated vector.
hy = normHy * cos(roll) + normHx * sin(roll) * sin(pitch) - normHz * cos(pitch) * sin(roll)
hx = normHx * cos(pitch) + normHz * sin(pitch)
The heading in radians is then calculated by taking the arctan of the Y and X components of the tilt compensated vector. The declination angle (13 degrees for San Jose) is then added to the current heading. The heading in radians is then converted into degrees. The heading in degrees is then sent over Can Bus to be received by Master, Bluetooth, and Debug.
Testing & Technical Challenges
Compass
Initial Testing
Initial testing was done by connecting the magnetometer to the SJOne board and printing out the calculated heading over serial. By rotating the magnetometer, the current heading can be verified by using a real compass.
Testing on the car
The magnetometer was then installed on the car. Using the bluetooth app, the current heading can be displayed. The car was then successfully tested indoors. During the outdoor test runs, it was discovered that the compass loses accuracy when the car is on a slope. This was due to the lack of tilt compensation, because only the X and Y axis of the magnetometer are used to calculate heading.
A tilt compensation algorithm was then implemented using the accelerometer onboard the SJOne board. Again, the magnetometer was tested first off the car by using the serial console. The compass was tested by rotating and tilting and observing the calculated heading. After the tilt compensation was verified outside the car, it was again installed in the car. The car was tested by driving around campus. The tilt compensated compass worked as expected, although a small difference was noticed between calculated heading and actual heading. The observed difference is due to magnetic declination, the difference between magnetic and true north. The magnetic declination for San Jose, CA was determined to be 13 degrees. An offset of 13 degrees was added to the calculated heading.
After further testing with the car with the PCB installed, it was determined that the tilt compensation algorithm was not working correctly. The tilt compensation was disabled, and the car was tested without it. It was determined that the compass without tilt compensation works well enough, so the tilt compensation was disabled for the final build.
Ultrasonic sensors
Calibration
The MB1010 sensor calibrates itself when power is applied. To prevent improper calibration, it's important to have no objects blocking the sensors during power-up. When testing we elevated the front of the car to point the sensors upwards and out into open air where there were no obstacles. A similar procedure was used when testing the rear sensors as well. During outdoors testing we had to be mindful about turning on the car while not blocking sensors either.
Recalibration
According to the manufacturer the MB1010 requires recalibration when the operating voltage, temperature, or location changes. While these criteria are mostly constant during testing, they can fluctuate somewhat. Specifically this need manifested itself as a condition where after normal operation for some duration of time, a sensor begins to report the minimum distance (~14cm) regardless of what is in front of the sensor. This behavior persists until power is cycled, at which point recalibration occurs and normal operation resumes.
Our solution was to add a TPS2034 two-channel power switch to manually cycle the sensor power rails under software control. One channel was for the forward-facing sensors, another for the rear-facing sensors. To determine when recalibration is needed, the past history of sensor readings are scanned to see if any are stuck and are consistently reporting the same minimum value. If any are stuck the power is cycled using the TPS2034. This allowed the sensors to be recalibrated automatically during operation.
The 7-segment LED of the sensor board is used to keep track of the number of recalibration events that have occurred. During recalibration a status signal is sent to the Bluetooth board so that the application can report to the user that recalibration occurred.
In a future revision a better power switch would be the TPS2054 which has four independent outputs so each individual sensor could be recalibrated without disturbing the other ones. The sensor manufacturer also recommends a power filtering circuit for quadcopters which may be applicable to our autonomous vehicle, but testing would be needed to determine if that's the case.
Printed Circuit Board
A printed circuit board was designed in EAGLE to integrate all of the wiring and components that were previously implemented on protoboard and using point-to-point wiring. The board was designed to have several features fur redundancy such as sockets for external CAN transceivers in case the built-in ones failed and breaking out the SJOne board pins to extra headers to add additional peripherals or test signals. Each SJOne board interfaced to the car using a ribbon cable with crimped IDC headers. The silk screen layer was utilized to label all connectors and polarities for power connectors as well.
The PCB encompasses the following components:
- IDC ribbon cable connectors to each SJOne board.
- LCD screen
- GPS module
- Motor controller module
- IMU module
- Bluetooth module
- I/O expander
- Battery voltage monitor
- CAN bus transceivers
- Power switch for ultrasound sensor recalibration
- Header for logic analyzer
- Pushbuttons for headlights and return to home
- Headlight driver circuit
EAGLE schematic:
Printed circuit board from Bay Area Circuits (parts side):
Fully assembled PCB mounted on acrylic sheet with all components attached.
Localization and Positioning (GPS)
Schedule
Task # | Start Date | End Date | Task Description | Status | Actual End Date |
---|---|---|---|---|---|
1 | 09/16/2016 | 09/22/2016 | Researched and decided upon the GPS module and Compass module. | Completed | 09/22/2016 |
2 | 9/23/2016 | 9/30/2016 | Ordered GPS module and compass module. | Completed | 09/30/2016 |
3 | 10/01/2016 | 10/14/2016 | Parse GPS data and format the data to be transmitted Test code to get compass reading information |
Completed | 10/04/2016 |
3 | 10/15/2016 | 10/25/2016 | Interface GPS module and compass module to SJOne board. | Completed | 10/19/2016 |
4 | 10/26/2016 | 10/30/2016 | Calibrating the compass module.Integration of GPS and compass module. Interfacing of GPS and compass module to Android. | Completed | 10/19/2016 |
5 | 11/01/2016 | 11/13/2016 | Integration with Master through CAN bus. | Completed | 10/19/2016 |
6 | 11/15/2016 | 12/10/2016 | Testing and calibrating with other modules. | Completed | 12/08/2016 |
Design & Implementation
The GEO Controller is responsible for calculating/ providing the location which the car is currently at and target direction to the master controller and bluetooth. The GEO controller will receives the way-points from the Bluetooth Controller and calculates the target heading to the closest waypoint an. The Master Controller is still responsible for controlling the logic of forward, backward, left, and right to reach the final destination. We were able to receive data from GPS module at 10Hz and communicate at 38400bps through UART. We sent specific data packets to receive the GPS module to be able to read the $GPGGA( Global Positioning System Fix Data) string over the UART from the module.
Hardware Design
GPS module used in our project is Adafruit Ultimate GPS Breakout - 66 channel w/10 Hz updates - Version 3 and GPS external active antenna. We were able to configure this module at 10Hz and communicate at 38400bps through UART. The GPS module had 10Hz update rate with low current draw which helped power usage very low. The GPS module GPS can also be configured to operate and communicate at various speed though the provided Graphical User Interface. This module has got an on-board flash to store these configuration which us a built in data-logging capability.
Hardware Interface
Device | Port Source | Port Destination | Device |
---|---|---|---|
SJ One | 3v3 | Vin | Adafruit GPS |
SJ One | GND | GND | Adafruit GPS |
SJ One | TXD3 | RX | Adafruit GPS |
SJ One | RXD3 | TX | Adafruit GPS |
Software Design
The GEO Controller is responsible for retrieving the data from GPS and parsing this information and calculate the needed values. After parsing the NMEA string, the current location is known and we can calculate the target value to the closest way point which has been received from bluetooth controller must be calculated to help the car move in the correct direction. When the correct heading is calculated, which target has been calculated we sent out the data over CAN communication to master and bluetooth controllers.
GPS Data Format
The Data that was retrieved from GPS is in NMEA 0183 format. NMEA is a combined electrical and data specification for communication between marine electronic devices such GPS receivers and many other types of instruments. The sting we received is in this format: $GPGGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh. Which each section describe an specific characteristic of the data. The following table shows format description of each substring within the received string from GPS module.
Name | Example Data | Description |
---|---|---|
Sentence Identifier | $GPGGA | Global Positioning System Fix Data |
Time | 170834 | 17:08:34 Z |
Latitude | 4124.8963, N | 41d 24.8963' N or 41d 24' 54" N |
Longitude | 08151.6838, W | 81d 51.6838' W or 81d 51' 41" W |
Fix Quality | 1 | Data is from a GPS fix |
# of Satellites | 05 | 5 Satellites are in view |
Horizontal Dilution of Precision | 1.5 | Relative accuracy of horizontal position |
Altitude | 170834 | 280.2 meters above mean sea level |
Height of geoid above WGS84 ellipsoid | -34.0, M | -34.0 meters |
Time since last DGPS update | blank | No last update |
GGPS reference station id | blank | No station id |
Checksum | *75 | Used by program to check for transmission errors |
System Flow Table
Task Name | Purpose |
---|---|
Periodic 10Hz Callback |
|
Periodic 100Hz Callback |
|
Algorithm
Finding the TARGET between two coordinates.
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:: This function calculates heading based on the 2 coordinates :*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
double gps_heading(double lat1, double lon1, double lat2, double lon2){
double head = 0 , lon_difference = 0;
lat1 = (lat1 * PI)/ PI_DEGREES;
lon1 = (lon1 * PI)/ PI_DEGREES;
lat2 = (lat2 * PI)/ PI_DEGREES;
lon2 = (lon2 * PI)/ PI_DEGREES;
lon_difference = lon2 - lon1;
head = atan2((sin(lon_difference)*cos(lat2)), ((cos(lat1)*sin(lat2))-(sin(lat1)*cos(lat2)*cos(lon_difference)))) ;
head = (head * PI_DEGREES)/ PI;
if( head <= 0 )
head += 360;
return head;
}
Finding the distance between two coordinates.
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:: This function calculates distance between the two coordinates in meters :*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
double distance(double lat1, double lon1, double lat2, double lon2) {
double theta, dist;
theta = lon1 - lon2;
dist = sin(deg2rad(lat1)) * sin(deg2rad(lat2)) + cos(deg2rad(lat1)) * cos(deg2rad(lat2)) * cos(deg2rad(theta));
dist = acos(dist);
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
dist = dist * 1609.344;
return (dist);
}
Testing & Technical Challenges
The GPS device should start transmitting NMEA sentences over the TX pin as soon as it is powered up, but the problem was that I wasn't able to retrieve data fast enough by sending out packages to the GPS module such as "$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28" to turn ON the GGA first, which helped us exploring our other options to make commands that are capable changing the update rate and also put the GPS module in the stand by command. Adding an external antenna was helpful to get the fixed data faster and definitely having an external antenna helped making the processes much faster.
The most important part was that we tried writing a unit test for the GPS module and it took us awhile to actually write the test but the very nice part was that now the code and also the integration is much simpler and cleaner. Integrating with bluetooth and receiving data and also with the whole system in general became really easy after writing the unit test code which was able to go through the state machine and check the states and properly change and flow through the state machine.
Propulsion Systems and Speed Tracking (Motor Controller)
Schedule
Task # | Start Date | End Date | Task Description | Status | Actual End Date |
---|---|---|---|---|---|
1 | 9/14/2016 | 9/20/2016 | Assigned tasks to one another and strategized approach. | Completed | 9/20/2016 |
1 | 9/21/2016 | 9/27/2016 | Work with team leader to devise version control strategy. | Completed | 9/27/2016 |
2 | 9/28/2016 | 10/04/2016 | Started development of DBC and finalized hardware choices. | Completed | 10/04/2016 |
3 | 10/05/2016 | 10/19/2016 | Research what encoders and/or tachometers to use, help the team leader choose an RC car to purchase, and decide what motor driver to use | Completed | 10/22/2016 |
4 | 10/23/2016 | 10/27/2016 | Make the motors spin and the servo control the steering. Receive can signals and control the motor and steering servo. | Completed | 10/25/2016 |
5 | 10/26/2016 | 11/04/2016 | Validate and calibrate the motor controller and steering code. Receive the Tachometer and magnetic polarity strip. | Completed | 11/05/16 |
5 | 11/06/2016 | 11/11/2016 | * Merge motor_test/tach with master. * Reorganize code for readability. * Finalize and test speed feedback system. |
Completed | 11/11/2016 |
5 | 11/12/2016 | 11/18/2016 | validate the wheel speed control system and calibrate. | Completed | 11/18/2016 |
6 | 11/19/2016 | 11/25/2016 | Test with the rest of the group * Fine tune nominal speed. Add LCD to display debug information. |
Completed | 11/28/2016 |
7 | 11/29/2016 | 12/02/2016 | * Replace motor driver with higher amperage driver. * Adjust steering offset to reduce error. |
Completed | 12/04/2016 |
8 | 12/06/2016 | 12/09/2016 | Test with the rest of the group, and fix any minor issues that come up. * Finalize code and merge into master. |
Completed | 12/09/2016 |
Design & Implementation
Hardware Design
The motor controller board takes charge of two main systems: motoring and steering.
To accomplish motoring, a high power motor driver from Polulu is used to drive the RC car's motor. It takes a simple digital signal for direction and a PWM signal for speed. To help control speed accurately, a tachometer and a set of magnets in a wheel are used to feed back rotations per second (rps). For debugging, a TFT display was connected to the SJSUOne board and displayed tachometer readings versus commanded readings. The figure on the right shows how the SJSUOne board is connected to the display and the motor driver. In addition, the block diagram also shows power connections from the battery.
Steering controlled as simply as the motor. A single wire is needed to feed a PWM signal to the servo. The figure below the motor connections image shows how the servo is connected.
Hardware Interface
Motor
The interface to the motor consists of two sections: feedback and output. The feedback section involves connecting the SJSUOne board to the FAULT and Current sense pins. This allows the board to stop or slow down the motor if problems or overcurrent situations appear. Then the output section consists of a simple digital signal and a PWM signal. The simple digital output controls the direction of the motor: HIGH motors the car forward and LOW motors the car in reverse. To manipulate speed, the duty cycle of the PWM signal is changed according to a PI control algorithm in the SJSUOne board. In order to avoid overcurrent problems, the PWM signal is kept at a high frequency such as 20 kHz.
Tachometer
The tachometer provides information about wheel rotation speed by pulling the its output line low every time the tachometer passes over the south pole of a magnet.
Servo
Controlling the servo requires just one PWM signal. Instead of the duty cycle, the on-time of the signal determines how far the servo turns the car to the left or right. For the servo on this car, the range is 1.300 to 1.900 ms, where 1.5 ms means straight. With this time range, the best frequency for this signal would be 50 Hz. However, since the SJSUOne board provides only one PWM module, a software PWM module was implemented to produce the signal.
TFT Display
A board from Adafruit, the TFT display used for this project communicates with the SPI protocol. However, the board also provides a reset pin and an SD card, so there are a couple of extra pins to choose which device to connect to. The SD card port may be used to log debugging information. For drawing the actual characters, a library from Adafruit was imported.
Software Design
Created Libraries
- Servo Driver (Uses a hardware timer attached to an interrupt to drives a servo at 50 HZ with 100 microseconds of resolution)
- Motor Controller (Runs the control loops that drive the main motor and steering)
- LCD Display Driver(Controls the LCD display. Most functions were imported from the Adafruit library for the device)
- Tachometer Driver (Sets-up/monitors an external interrupt and keeps track of the tachometer ticks)
All code on this SJSU-Oneboard software was separated into two running tasks, the Periodic Scheduler and the LCD Display task. The LCD Display was put into its own task due to the need for specific timing requirements that are randomized and large. Typically a custom delay system should be created and put into the periodic scheduler but the LDC display is a low priority objective and a separate task handles its requirements adequately. The periodic scheduler runs every other task on the system. The two subsystems of the periodic scheduler that run on different timing requirements are both the interrupts for the tachometer and the servo hardware timer. Both of these Interrupts are set as lower priority than the periodic scheduler interrupts and RTOS interrupts. This does causes a gap in the hardware timer's control signal for the servo, however the gap is not often enough to cause the servo issues. Furthermore the gap is outside the range of input to the servo so whenever the gap happens, the servo completely ignores it.
Implementation
Motor Control System
Using the 10 Hz periodic scheduler task with a counter, the Motor Control system runs every half a second. This amount of time was selected from the low resolution of eight tachometer ticks per rotation of the car's wheel. In general, the greater the resolution of your feedback in a closed loop system, the faster your control loop can run. Within the Control loop, a system similar to a PI(Proportion, Integral) system was used. When a command from the master controller is sent, that value will get multiplied by a constant and added with an offset. The offset is simply an incremented or decremented value that gets changed according to how far the motors actual speed is from its targeted speed. The Final value is then fed to the motors as a percentage to the PWM I/O that controls the motor's speed.
Servo Hardware Timer
The SJSU-One-Board's PWM controller can only be set to one frequency and with the Motor controller needing to be run at ultra-sonic frequencies, another method to control the servo was needed. To control a servo, a PWM signal running at 50 Hz is needed. Furthermore the positive portion of the PWM wave has to be timed to a specific microsecond value between 1000 microseconds and 2000 microseconds. The method to satisfy these requirements was to implement a hardware timer that triggers an interrupt every 100 microseconds. Inside of this interrupt, is a counter. At a count of zero, a GPIO is set to HIGH and then at a controlled count between 10 to 20, the value is set to LOW. Once the count hits 202, the count is reset.
Testing & Technical Challenges
Motor Driver control
Several times during testing, the SJSUOne board was powered up or reprogrammed while still connected to the motor driver, causing the motor to rev at full speed and destroy the motor driver. The first solution to avoid full speed upon board power up was to add a tri-state buffer between the output of the SJSUOne board and the motor driver. Later on, the team discovered that a single pull-down resistor on the line was sufficient to solve the issue. This taught the team that for future projects involving powered mechanical systems to always make sure the control line by default will keep the systems off, whether by pull-down resistors or tri-state buffers.
PWM accuracy
While testing servo control, the frequency of the generated PWM signal proved to be inaccurate. The generated signal would have a frequency 10 times greater than what is set in the program, leading to inaccurate on-times. The team soon found out that the problem was because of where the PWM object in the program was constructed. Initially, the PWM objects were created in the global scope, meaning the constructor would write to the registers before the main() function was entered. While this problem is not fully understood, it was solved by constructing the objects in init() functions, which were called after the main() function was entered. This shows that, for future drivers written for microcontrollers, driver behaviour would be much more well defined if all register manipulation happened in an init() member function rather than in a constructor. This way, client users do not have to worry about accidentally constructing driver objects in the global scope.
Master Control Systems
Schedule
Task # | Start Date | End Date | Task Description | Status | Actual End Date |
---|---|---|---|---|---|
1 | 9/14/2016 | 9/20/2016 | Assigned tasks to one another and strategize approach. | Complete | 9/20/2016 |
2 | 9/21/2016 | 9/27/2016 | Research different RC cars for the project. | Complete | 10/15/2016 |
3 | 10/16/2016 | 10/23/2016 | Implement Decision Tree for obstacle detection/autonomous car control. Decide on Message ID system over the CANBUS/Types of Data being Transmitted | Complete | 10/23/2016 |
3 | 10/24/2016 | 10/29/2016 | Program obstacle detection/autonomous car control algorithms | Complete | 10/29/2016 |
4 | 10/30/2016 | 11/06/2016 | Test RC car obstacle detection and autonomous control interfaced with Sensor Module over CAN | Complete | 11/06/2016 |
5 | 11/07/2016 | 11/13/2016 | Interface GPS module with Master Controller | Complete | 11/13/2016 |
6 | 11/14/2016 | 11/20/2016 | Interface Android/Bluetooth module with Master Controller.Test Waypoint System | Complete | 11/20/2016 |
7 | 11/21/2016 | 11/27/2016 | Debug any issues with Master controller and other modules | Complete | 11/27/2016 |
8 | 11/28/2016 | 12/12/2016 | Final debug/testing of RC CAR | Complete | 12/12/2016 |
Hardware Design
For Master Controller since we did not have to interface with any external peripherals the hardware was very simple and initially only consisted of a SJOne board along with a Waveshare SN65HVD230 CAN transceiver to communicate over the CAN bus. The CAN transceiver was already equipped with internal 120 ohm resistors but when the PCB board was created these transceivers were no longer needed. The RD1 (pin 0.0) and TD1 (pin 0.1) on the SJOne board are connected to the CAN Rx and CAN Tx pins on the CAN transceiver thus using CAN1 for our SJOne board.
Software Design
Modes of Operation
There are two modes of operation for the Master controller. One is the steering control and the other is obstacle avoidance mode. None of these modes are operational until a Master Enable message is received by the master. The steering control mode relies on target and heading messages from the GPS and Sensors nodes to successfully navigate the car to its destination. It is the default mode of operation for the Master Controller. The other mode of operation mentioned is obstacle avoidance mode. The obstacle avoidance mode is only triggered when the front sensors distance values are within a predefined threshold thus telling the car to get out of the way.
PI Controls on Steering
This "steering" mode is only run when there are no obstacles detected. This mode uses a PI controller to close the steering error between our target direction and our heading. The error is calculated as target - heading and the PI gains were scaled such that 180 degrees off target results in 100% steering in either the left or right direction. The steering errors would then be closed through an integral gain.
Obstacle Detection
Obstacle avoidance is entirely dependent on the front sensor values and rendered inactive if nothing is being detected. The algorithm is shown below.
Obstacle Avoidance mode is triggered when a front sensor value is within a predefined set of distance thresholds. The speed of the car is also reduced when in this mode to provide enough time to get out of the way. The degree of steering is proportional to how close an object is to the RC car, the closer an object is the harder the steering of left or right. If an obstacle is deemed too close to our RC car, giving us the idea that there's no way to get out of the obstacle's way, the RC car goes in reverse and will continue to do so until the there's enough space in front of it.
Front Left Sensor Threshold | Front Center Sensor Threshold | Front Right Sensor Threshold | Threshold for RC car reversal |
---|---|---|---|
80 cm | 120 cm | 80 cm | 30 cm |
Implementation
Using FreeRTOS we had the two modes operating in the periodic scheduler at the 100Hz() task , and we decided to send motor commands at that same frequency. The 100Hz() task also managed the receiving of signals from the GPS and Sensor nodes. Transmitting debug signals caused the issue of overloading the CAN bus at 100Hz so it was designated to the 1Hz() task as these signals were less of a priority.
Software Libraries
To avoid an unnecessarily long 100Hz() task that would include our steering and obstacle avoidance code, we included header files for our code, header files Obstacle_Detect.hpp and vehicle_controls.hpp were included for obstacle avoidance mode and steering control respectfully.
CAN Message ID Number | Purpose | Data layout |
---|---|---|
0x64 | Receive Enable or Disable Master from Debug Node | 1 for Enable, 0 for Disable |
0x65 | Send Debug Signals to Debug Node | Current Mode of Operation, Current Speed Commanded, Which sensor triggered Obstacle Avoidance |
0x100 | Send Speed and Steer Commands to Motor Controller | Speed Commands from -100 to 100, Steer Commands from -100 to 100 |
0x200 | Receive sensor values and compass heading direction via multiplexer | Sensor values in centimeters, Compass heading in degrees |
0x300 | Receive GPS IMU target heading and destination | Target Heading in degrees, Destination Reached true/false |
Testing & Technical Challenges
Testing Code Functionality
Since the Master Controller is all but software driven and relies heavily on communication between other CAN nodes , testing the functionality of your code can be a bit tricky especially when outright testing the RC car isn't viable. To fix this we had to familiarize ourselves with the BUSMASTER software as it can easily replicate other nodes. This made debugging much easier and decreased the burden of having to rely on other parts of our RC car that were not ready. Another method we used to unit test our code is the C library <assert.h>. This allowed us to more rigorously test each function of our code by passing in specific parameters that corresponded to specific scenarios into our obstacle detection algorithm and then see if it returned the correct value.
Obstacle Detection Sensor Thresholds and Speed Control
Another issue we faced was on figuring out when Master should trigger obstacle avoidance mode. Alot of trial and error was gone through to properly assess a good speed for the RC car. With the car going faster we noticed that greater obstacle detection distance thresholds needed to be used thus improving the response time of the vehicle and avoiding collisions. We did not want our car to go too fast and destroy itself so we decided on a speed that was a slow and steady pace but not too slow. This provided the car with plenty of time to steer itself out of the way and allowed for smaller distance thresholds for obstacle avoidance to be triggered.
Steering Control for Obstacle Avoidance
There was also the issue of steering to slowly in case of an object is in the way, which often led to it crashing. We tried to incrementally increase the speed of steering by different factors but realized that this was not reliable and often led to crashes. To fix this we decided to adjust the steering so that the rate of steering would increase proportionately to how close it was to an object, this gave us a factor between 0 and +-100 for right(+) and left(-).
Conclusion
Overall we had a successful project and the car performed as intended. However achieving that goal was more difficult than expected, and we certainly felt the project was going to be more straightforward than it was. Some of our learning experiences were:
- No last-minute changes. We had modified part of our motor handling before our second demo and it malfunctioned spectacularly by crashing into a wall at high speed. We had found that an unnecessary fail-safe circuit used to disconnect PWM from the motor had masked a bug in how the PWM object was instantiated, causing acceleration right after startup. More testing would have resolved this, but that needed to happen much earlier and not minutes before the demo.
- Don't trust good results. Our vehicle had navigated the campus several times flawlessly so all systems seemed to be good. Later we realized the magnetometer never really worked at all and wasn't calibrated either, merely by chance our previous runs had went well. What followed was a rush to characterize the problem and resolve it with time running out. Probably more comprehensive testing would have revealed this problem, as well as going through a checklist of common magnetometer issues to double-check we were addressing them as these issues are well documented on the internet.
- Communication is key. We used Slack and Trello to keep in touch at all times and could discuss the project even when not in a face-to-face meeting. This was instrumental to keeping the teams up to date about what was happening and what to expect, as we all had different schedules and could seldom all meet at once. But this required members to make a commitment to check their Slack messages and keep their Trello board updated. Productivity applications are only as good as the users that use them, and they can't solve problems if they aren't being utilized correctly.
- Every voice counts. We all had different ideas about how things should be done, but the best results came from learning when to listen and when to give constructive and helpful criticism. We didn't want to be isolated to our own tasks and had an open dialogue across each sub-team about how we were going to implement things. This increased as the project progressed, for example we had the headlight design coming from our GPS team, with a 3D-printed mount and hardware implemented by our sensor team, and application control, manual button control, and light-sensitive controls programmed by our Bluetooth team. Even for a simple feature like this we were very pleased with the results because it was a collaborative effort and each team could contribute.
It would be hard to pinpoint exactly how our knowledge has increased because we've been exposed to a huge array of topics as part of this project. You could say we learned a little bit of everything!
Project Video
Final Demonstration Video (December 21st, 2016)
https://www.youtube.com/watch?v=45zn2YhpKiY By: Derek Tran
Final Demonstration Close up Video (December 21st, 2016)
https://youtu.be/1Sts9X9gJdM By: John Strube
Full System Pre-Final Demonstration Testing (December 20st, 2016)
https://www.youtube.com/watch?v=4u3rgHmo4yo By: Charles MacDonald, David Cruz
Obstacles Avoidance Testing (December 5st, 2016)
https://www.youtube.com/watch?v=3b5x-d2T8aY
MORE TESTING FOOTAGE TO COME!!!
Project Source Code
GitLab
References
Acknowledgement
We would like to thank Preet for his help, our ISAs including Calvin, Shangming, Jon, and our classmates.
References Used
List any references used in project.