S19: Mystery Machine
Contents
Abstract
This project demonstrates the learning involved in Embedded Systems class to design a self-driving car capable of navigating through terrain and avoiding obstacles in order to reach a destination. The car receives destination GPS coordinates from a custom Android Application and relays back statistics and progress in reaching the target.
Introduction
The objective of this project was to create an autonomous self-driving car which was able to reach the target destination while avoiding obstacles through the terrain. In order to accomplish this, five SJ One boards were used that handled separate functionality of the car:
- Master Controller
- Sensor Controller
- Geo Controller
- Bridge Controller
- Android Application
- Motor and Steering Controller
Team Members & Responsibilities
- Neeraj Dhavale
- Master Controller [SPOC]
- Geo Controller [SPOC]
- Sanket Patil
- Bridge Controller [SPOC]
- Hardware integration and PCB [SPOC]
- Tarun Chawla
- Motor and Steering Controller [SPOC]
- Geo Controller
- Rachit Mathur
- Motor and Steering Controller
- Documentation [SPOC]
- Adithya Baskaran
- Sensor Controller [SPOC]
- Hardware integration and PCB
- Sudarshan Aithal
- Sensor Controller
- Motor and Steering Controller
- Chithambaram Singaravelu Poonkodi
- Android Application [SPOC]
- Git Management [SPOC]
- Sai Kiran
- Testing
Schedule
Week# | Start Date | End Date | Task | Status |
---|---|---|---|---|
1 |
|
|
|
|
2 |
|
|
|
|
3 |
|
|
|
|
4 |
|
|
|
|
5 |
|
|
|
|
6 |
|
|
|
|
7 |
|
|
|
|
8 |
|
|
|
|
9 |
|
|
|
|
10 |
|
|
|
|
11 |
|
|
|
|
12 |
|
|
|
|
13 |
05/10/2019 |
05/14/2019 |
Design and implementation of exterior body |
Completed |
14 |
05/17/2019 |
05/18/2019 |
Resolve any issues before Final Demo |
Completed |
15 |
05/22/2019 |
05/22/2019 |
FINAL DEMO |
Completed |
Parts List & Cost
Item# | Part Desciption | Vendor | Qty | Cost |
---|---|---|---|---|
1 | RC Car | Amazon | 1 | $90.00 |
2 | CAN Transceivers MCP2551-I/P | AliExpress | 5 | $1.13/piece |
Design and Interface
CAN Communication
Hardware Design
System Nodes: SENSOR, MOTOR, GEO CONTROLLER, BRIDGE, MASTER
CAN(Controlled Area Network) is a Broadcast Bus which is heavily used in automotive industry. It defines protocol and hardware interface. It operates in standard baudrates like 100k, 125k, 250k, 500k or 1M bps. CAN uses half duplex communication over differential pair. The number of nodes affect the cable length because more CAN transeives add more capacitance to the bus.
An MCU can be interfaced to CAN bus using CAN transceiver and terminated on each end with 120 ohm resistors. Resisters are used to avoid signal reflexion. CAN is frame based communication where each frame contains ID, length(DLC), and up to 8 data bytes.Message ID field can be 11-bit or 29-bit. Only one transmitter can transmit at a time which has highest priority will go ahead first. Low priority message ID's will back-off.Lower message ID wins i.e zero is dominant.
Each node asserts an ACK if it receives a good frame. Software may or may not accept the frames. If no one ACKS, then the message is retransmitted. Depending on the CAN specifications retransmission error can be send and can eventually lead to "Bus off" state.
DBC File
BU_: DBG DRIVER MASTER IO MOTOR SENSOR LIGHT BRIDGE GEO GATEWAY BO_ 600 SONAR_SENSOR_VALUES: 4 SENSOR SG_ SONAR_SENSOR_VALUES_Left_Sensor : 0|9@1+ (1,0) [0|300] "cm" BRIDGE,MASTER SG_ SONAR_SENSOR_VALUES_Right_Sensor : 9|9@1+ (1,0) [0|300] "cm" BRIDGE,MASTER SG_ SONAR_SENSOR_VALUES_Front_Sensor : 18|9@1+ (1,0) [0|300] "cm" BRIDGE,MASTER BO_ 601 DEMO_IR_SENSOR: 6 SENSOR SG_ LEFT_SENSOR : 0|16@1+ (1,0) [0|0] "LEFT_VALUES" MASTER SG_ RIGHT_SENSOR : 16|16@1+ (1,0) [0|0] "RIGHT_VALUES" MASTER SG_ FRONT_SENSOR : 32|16@1+ (1,0) [0|0] "FRONT_VALUES" MASTER BO_ 602 SONAR_SENSOR_THRESHOLD: 3 BRIDGE SG_ UPDATE_THRESHOLD_VALUE_Left : 0|8@1+ (1,0) [0|0] "cm" MASTER SG_ UPDATE_THRESHOLD_VALUE_Right : 8|8@1+ (1,0) [0|0] "cm" MASTER SG_ UPDATE_THRESHOLD_VALUE_Front : 16|8@1+ (1,0) [0|0] "cm" MASTER BO_ 603 STEER_CMD: 1 SENSOR SG_ SENSOR_STEER_DIRECTION : 0|8@1+ (1,0) [0|0] "DIRECTION" MASTER,BRIDGE BO_ 604 SONAR_REVERSE_SENSOR: 2 SENSOR SG_ SONAR_REVERSE_SENSOR_value : 0|9@1+ (1,0) [0|300] "cm" BRIDGE,MASTER BO_ 700 MOTOR_SPEED: 1 MASTER SG_ MOTOR_SPEED_speed_in_mps : 0|8@1+ (0.01,0) [0|2] "mps" MOTOR,BRIDGE BO_ 701 STEER_DIRECTION: 2 MASTER SG_ STEER_DIRECTION_ANGLE : 0|16@1- (1,0) [0|0] "ANGLE" MOTOR,BRIDGE BO_ 702 DEMO_STEER_DIRECTION: 2 MASTER SG_ STEER_DUTY_CYCLE_VAL : 0|8@1+ (0.01,0) [0|0] "DUTY_CYCLE" MOTOR,BRIDGE BO_ 703 DEMO_MOTOR_SPEED: 2 MASTER SG_ MOTOR_SPEED_DUTY_CYCLE : 0|8@1- (1,0) [-127|127] "DUTY_CYCLE" MOTOR,BRIDGE BO_ 704 MOTOR_FLAG: 1 MOTOR SG_ REVERSE_FLAG : 0|8@1+ (1,0) [0|0] "MOTOR_FLAG" MASTER,BRIDGE BO_ 740 COMPASS_DATA: 2 GEO SG_ COMPASS_HEADING_ANGLE : 0|9@1+ (1,0) [0|0] "DEGREES" MASTER,BRIDGE BO_ 750 GPS_DATA: 8 GEO SG_ GPS_LOCK : 0|1@1- (1,0) [0|0] "" MASTER,BRIDGE SG_ CURRENT_GPS_COORDINATES_X : 8|28@1- (0.000001,0) [36.000000|38.000000] "" MASTER,BRIDGE SG_ CURRENT_GPS_COORDINATES_Y : 36|28@1- (0.000001,0) [-122.000000|-120.000000] "" MASTER,BRIDGE BO_ 751 TELEMETRY: 8 GEO SG_ DISTANCE_TO_DEST : 0|8@1+ (1,0) [0|0] "" MASTER,BRIDGE BO_ 790 MASTER_HEARTBEAT: 1 MASTER SG_ HEART_BEAT : 0|8@1+ (1,0) [0|0] "MASTER_HEARTBEAT" BRIDGE BO_ 800 APP_CMD: 2 BRIDGE SG_ START_COMMAND : 0|8@1+ (1,0) [0|0] "" MASTER SG_ ABORT_COMMAND : 8|8@1+ (1,0) [0|0] "" MASTER BO_ 805 WHEEL_ENCODER: 1 MOTOR SG_ WHEEL_ENCODER_data : 0|7@1+ (1,0) [0|0] "" MASTER,BRIDGE BO_ 810 APP_DESTINATION_GPS: 8 BRIDGE SG_ DEST_GPS_COORDINATES_X : 0|28@1+ (0.000001,0) [0|0] "" GEO SG_ DEST_GPS_COORDINATES_Y : 28|28@1+ (0.000001,0) [0|0] "" GEO BO_ 909 SENSOR_TRIGGER: 1 SENSOR SG_ SENSOR_TRIGGER_Trigger_status : 0|1@1+ (1,0) [0|1] "" BRIDGE BO_ 908 SENSOR_INIT: 1 SENSOR SG_ SENSOR_INIT_init_Status : 0|1@1+ (1,0) [0|1] "" BRIDGE BO_ 910 SENSOR_TIMEOUT: 1 SENSOR SG_ SENSOR_TIMEOUT_left : 0|1@1+ (1,0) [0|1] "" BRIDGE SG_ SENSOR_TIMEOUT_center : 2|1@1+ (1,0) [0|1] "" BRIDGE SG_ SENSOR_TIMEOUT_right : 3|1@1+ (1,0) [0|1] "" BRIDGE SG_ SENSOR_TIMEOUT_reverse : 4|1@1+ (1,0) [0|1] "" BRIDGE BO_ 911 LEFT_SENSOR_ECHO_TIME: 2 SENSOR SG_ LEFT_SENSOR_ECHO_TIME_left_calculation_time : 0|16@1+ (1,0) [0|0] "us" BRIDGE BO_ 912 RIGHT_SENSOR_ECHO_TIME: 2 SENSOR SG_ RIGHT_SENSOR_ECHO_TIME_right_calculation_time : 0|16@1+ (1,0) [0|0] "us" BRIDGE BO_ 913 CENTER_SENSOR_ECHO_TIME: 2 SENSOR SG_ CENTER_SENSOR_ECHO_TIME_center_calculation_time : 0|16@1+ (1,0) [0|0] "us" BRIDGE BO_ 917 REVERSE_SENSOR_ECHO_TIME: 2 SENSOR SG_ REVERSE_SENSOR_ECHO_TIME_reverse_calculation_time : 0|16@1+ (1,0) [0|0] "us" BRIDGE BO_ 914 TOTAL_SENSOR_CALCULATION_TIME: 4 SENSOR SG_ TOTAL_SENSOR_CALCULATION_TIME_total_time : 0|32@1+ (1,0) [0|0] "us" BRIDGE BO_ 915 PERIODIC_SCHEDULER_INIT: 1 SENSOR SG_ PERIODIC_SCHEDULER_INIT_scheduler_init_status : 0|1@1+ (1,0) [0|1] "" BRIDGE BO_ 916 DBG_SENSOR_THRESHOLD: 4 MASTER SG_ THRESHOLD_VALUE_Left : 0|8@1+ (1,0) [0|0] "SONAR_DBG" BRIDGE SG_ THRESHOLD_VALUE_Right : 8|8@1+ (1,0) [0|0] "SONAR_DBG" BRIDGE SG_ THRESHOLD_VALUE_Front : 16|8@1+ (1,0) [0|0] "SONAR_DBG" BRIDGE SG_ THRESHOLD_VALUE_Reverse : 24|8@1+ (1,0) [0|0] "SONAR_DBG" BRIDGE BO_ 921 SPEED_CMPS: 1 MOTOR SG_ SPEED_CMPS_car : 0|7@1+ (1,0) [0|0] "CAR SPEED IN CM/S" MASTER,BRIDGE BO_ 926 MOTOR_DUTY: 1 MOTOR SG_ MOTOR_DUTY_CYCLE : 0|7@1+ (1,0) [0|1] "" MASTER,BRIDGE BO_ 922 ROTATIONS_PER_SECOND: 1 MOTOR SG_ ROTATIONS_PER_SECOND_WHEELS : 0|7@1+ (1,0) [0|0] "CAR SPEED IN ROTATIONS/SECOND" MASTER,BRIDGE BO_ 923 STEER_DUTY_LEFT: 1 MOTOR SG_ DUTY_CYCLE_LEFT : 0|7@1+ (1,0) [0|1] "" MASTER,BRIDGE BO_ 924 STEER_DUTY_RIGHT: 1 MOTOR SG_ DUTY_CYCLE_RIGHT : 0|7@1+ (1,0) [0|1] "" MASTER,BRIDGE BO_ 925 STEER_DUTY_CENTRE: 1 MOTOR SG_ DUTY_CYCLE_CENTRE : 0|7@1+ (1,0) [0|1] "" MASTER,BRIDGE
Sensor ECU
Ultrasonic sensors are great tools to measure distance without actual contact. Basic principal of ultrasonic distance measurement is based on ECHO and Trigger pins. Trigger pin is used to send the sonar wave from ECHO. ECHO goes high as soon as it sends Sonar wave. Once it receives the wave the ECHO pin will go low. We will measure this ECHO HIGH period and use to calculate the distance.
Hardware Design
For object detection we are ultrasonic sensors , Three in the front (LEFT, RIGHT and CENTER) and one behind to measure the distance of each object if present in front of the sensors general direction. The sensor presented each have a specific threshold beyond which the car is supposed to react and avoid obstacles by altering the direction of travel.
Hardware Interface
The trigger pin is common since all the sensors are activated at the same time. Echo in are individual and processed in parallel.The CAN connections are same as every other module.
In order to raise the sensor at a height decent enough to detect obstacles directly ahead of the RC car, we designed custom 3D printed mounts for all the sensors. These stand provided a rigid support for these sensors as well as ensured that the sensors would survive an accidental head-on crash.
Screenshots of these custom mounts can be seen along side.
Software Design
Sensors are calculated over in 10hz periodic task and sent to master module by use of the CAN connections between them every 20hz or 50ms period. All sensors are triggered simultaneously and calculated sequentially. GPIO protocols are used to set pins high or low. 8ms timeout is implemented for each sensors to avoid task overrun.
Implementation
In 100 Hz, Through the GPIO pin TRIGGER signal is sent and waits fro the ECHO signal to be created . If the timeout function runs out before the Echo completes the minimum distance is said to be obstacle free. If not the time taken for the signal to go high and then low is calculated with respect to speed of sound.
In 20 Hz, the data is sent through the CAN messages from the sensor module to the master and Bridge module.
Pseudo Code:
void 10hz_task(int count){ initialize the sensors; Reset_flags; Trigger each sensors; calculate the distance; if( timeout){ capture current value; set flags; } send distance values over can; }
Technical Challenges
Initially we went with sharp 2yoa21 IR sensor to obtain better precision. But the range of the sensor was 48cm which was not reliable distance for obstacle detection. We upgraded to an Ultrasonic sensor which had trouble with echo reception due to faulty firmware code.
Unreliable sonor sensors
We upgraded to an Ultrasonic sensor HC-SR04 which had a better range of around 200cm with reliable precision. Also we faced another problem with Ultrasonic Sensor. There was some chinese firmware code in the ultrasonic sensor due to which echo pin did not receive the signal for a long duration of time. We had 3 Ultrasonic sensors working together and each received other's echo signals sometimes due to reflection.
Solution
To solve the reflection problem, We elevated the sensor position and changed the direction of the sensor. To solve the faulty firmware, we introduced a timeout of 8ms in the code, until the timeout, if we don't receive the echo pulse, it will give a default distance of 110cm.
Motor ECU
DC Motor
Our car arrived with an in-built Electronic Speed Controller(ESC) that was responsible for controlling the steering servo motor and running the DC motor attached to the rear wheels.Along with the motor control, the ESC was also embedded with a receiver for the remote control that shipped with the car.
We realized that the ESC could not be tapped into by providing an external signal to the pin-heads available on the exterior. This external signal from a function generator gave unsatisfactory results when passed through the ESC but we did conclude the optimal frequencies at which both the motors worked satisfactorily.
A motor controller module was used for driving the DC motor. We experimented with the frequency input to the motor driver to run the motor at and found that it operated best at a high frequency of 4KHz,
Servo Motor
The servo motor was connected directly to the GPIO ports of the SJ One board.
After applying an external PWM signal to the servo, we concluded that the servo motor was designed to work smoothly on 80Hz frequency. Accordingly, accurate values of the duty cycle were noted to get precise angles of the steering.
Encoder Sensor
As part of speed feedback, we designed a custom encoder wheel between an encoder sensor mounted on the rear wheel shaft.
The wheel had a finite number of spokes which when intercepted the encoder receiver, a value was read at the falling edge of interrupt signifying one wheel rotation.
These detected number of rotations were passed into a formula that calculated the wheel speed in cm/s.
As part of the feedback, if the calculated wheel speed was not equivalent to the constant speed the PWM duty cycle was either increased or decreased to match the target.
A special scenario was also taken into consideration. If the speed of the wheel continued to remain zero after increasing the PWM duty cycle to the Maximum defined limit, then a reverse logic was called.
This case helped us in overcoming obstacles that were underneath the car and were initially not detected by the sensors.
Hardware Design
Software Design
<List the code modules that are being called periodically.>
Technical Challenges
- The primary challenge in the motor module was tapping into the ESC of the car but that was soon replaced by a Motor Driver module.
- While trying to run the motor driver module at a lower frequency of around 500Hz, we faced an issue of 'heat lock' where after 10 minutes the motor driver module would cut off the supply to the DC motor due to excessive heating. To fix this, we concluded that the motor driver module that we ordered worked best at a higher frequency upwards of 1KHz.
- We also learned about the limitation of the SJ One board in providing two PWM signals at different frequencies. To solve this, we temporarily attached the steering control with the Master Controller.
Geographical Controller
The Geographical controller is responisable for navigating the car in the direction of destination selected in the android app. It uses GPS module which gives the current location of the car and compass module for getting the heading angle of the car. After a destination location is selected in the android app, using the shortest path algorithm, the app generates a pirticular number of check points. These check points are then send to bridge controller. Now Bridge controller sends one check point at a time to the Geographical controller. Geo controller uses its current location and the destination location(check point) to calculate the bearing angle and the distance to the destination. Subsequently, heading angle and bearing angle are used to determine the angle that the car should turn, and sent to the master module. On reaching destination, the car will stop.
Hardware Design
Two modules are used in Geograpgical controller: GPS and Compass
GPS
Ublox NEO-7M GPS Module is used for detecting the location of the car. This module returns NMEA string which need to be parsed to get lock, latitude and longitude values from the module. To use the GPS string first we need to get lock. Values read are valid only if we get GPS lock.
COMPASS
The MPU-9150 is first integrated 9-axis MotionTracking device that combines a 3-axis MEMS gyroscope, a 3-axis MEMS accelerometer, a 3-axis MEMS magnetometer and a Digital Motion Processor hardware accelerator engine. The MPU9150’s 9-axis MotionFusion combines acceleration and rotational motion plus heading information into a single data stream for the application.
The MPU-9150 features three 16-bit analog-to-digital converters (ADCs) for digitizing the gyroscope outputs, three 16-bit ADCs for digitizing the accelerometer outputs and three 13-bit ADCs for digitizing the magnetometer outputs. For precision tracking of both fast and slow motions, the parts feature a userprogrammable gyroscope full-scale range of ±250, ±500, ±1000, and ±2000°/sec (dps), a user programmable accelerometer full-scale range of ±2g, ±4g, ±8g, and ±16g, and a magnetometer full-scale range of ±1200µT.
Communication with all registers of the device is performed using I2C at 400 kHz.
Hardware Design
GPS module is interface over UART:
GPS pins | SJOne Board |
---|---|
TX | P0.0 |
RX | P0.0 |
GND | GND |
VCC | 3.3v |
Compass module is interface over I2C:
Compass pins | SJOne Board |
---|---|
SDA | P0.0 |
SCL | P0.0 |
Software Design
<List the code modules that are being called periodically.>
Flowchart
Algorithm
Implementation
Formulae:
Current latitude and longitude position can be obtained form GPS module and destination latitude and longitude position should be determined from CAN message sent by bridge module. In order to compute the angle the car need to turn to reach destination can be computed using bearing angle and heading angle.
Bearing Angle - is the angle between the direction towards destination from the current location with respect to north.
Heading Angle The angle given by the compass. This is the angle with respect to north. Which is used to know the heading direction of car with respect to north.
Angle to turn
We need to compute the angle that the car has to turn from its current direction towards the destination, from the obtained bearing angle(angle at which the car should go with respect to north to reach the destination) and heading angle (angle at which our car is going currently with respect to north).
we need to compute the angle that the car has to turn from its current direction towards destination, from the obtained bearing angle and heading angle.
Angle to turn = Heading angle - Bearing angle
Distance Calculation
Technical Challenges
<Bullet or Headings of a module>
Unreliable GPS lock
<Problem Summary> <Problem Resolution>
Communication Bridge Controller & LCD
MQTT Protocol
MQTT protocol was chosen as the communication protocol between the android application since it is very light weight and is designed ideally for IOT devices.
For establishing the connection via MQTT a MQTT server has to be created and run. The clients can connect to that server. Multiple clients can connect to the server and share data between them
Message Passing
The data transfer in MQTT is done via topic scheme, where when a client has to send a message it has to publish the message with a topic. The client can subscribe to topics (which is essentially string). Whenever someone publishes a message in a topic every client subscribed to that topic will receive the message. The clients are not directly connected but in turn connected via the MQTT server
Server Setup
The RC car is equipped with a wifi-module. The wifi modules run a MQTT server to which it connects itself to and the mobile application also connects to wifi module and establishes a connection to the MQTT server. The communication happens by a set of predefined topics which each of the clients listen to and publish their message.
Hardware Design
The message inside in each topic is again formatted as below: “<COMMAND:value1|value2|value3”>
Here the COMMAND can be the type of message like “GO”, “COMPASS”, “RPS”(Rotation per second), “SPEED” etc. Each of these messages can have n number of values in them depending upon the type. For example the “COMPASS” type has only one value while the “SENSOR” has 4 values - one for each sensor in the car.
Software Design
<List the code modules that are being called periodically.>
Technical Challenges
<Bullet or Headings of a module>
Insane Bug
<Problem Summary> <Problem Resolution>
Master Module
Master Controller
The master controller is responsible for the handling motion of the car. The master controller decides how the car will move based on inputs from all the other ECUs. The master first waits to receive the start command from the Android app via Bridge ECU. When the app sends “START Command” the master controller takes the values of ultrasonic sensors from the Sensor Controller, also the master takes the direction angles from the Geo controller. The master controller first calculates if there are any obstacles, it will avoid those obstacles by giving out motor speed values to the motor controller and steer accordingly. Then the master starts following the steer instructions provided by the Geo Controller. The obstacle avoidance algorithm preempts the GEO controller navigation directions.
Obstacle Avoidance
The obstacle avoidance algorithm implemented is simple. The master controller receives values of the ultrasonic sensors from the Sensor Controller. The values which are distances in centimeters are received from the front, left, right and back sensor. When the car is supposed to move forward the master checks the values of the front, left and right sensors and checks if all the values are above the threshold.
Hardware Design
Software Design
The pseudocode of steering is as below:
if(left sensor < threshold){ STEER RIGHT(); } if(right sensor < threshold){ STEER LEFT(); } else{ Follow GPS_directions(); }
The pseudocode for speed controlling as below:
if(front_sensor < threshold){ REVERSE(); } else if(left_sensor && right_sensor < threshold){ REVERSE(); }
Technical Challenges
<Bullet or Headings of a module>
Improper Unit Testing
<Problem Summary> <Problem Resolution>
Mobile Application
The Android application allows the user to interface with the RC car.
The connection between the car and the mobile is established via MQTT protocol. The app requires that the mobile is connected to the Mystery machine wifi that is hosted by the wifi modules mounted on the car. Then the app automatically connects to the car via the MQTT broker.
Once connected the app takes part in a two-way communication that allows it to send commands to the car and to receive information from the car.
Since the mqtt client does not provide the connection details of the other clients that is connected to it, we are using a heartbeat message from the wifi module to ensure that the Android application can know the connection status of the car.
Transmission
- App sends the GO and STOP commands that starts and stops the motor accordingly.
- The messages are <GO0> for stop and <GO1> for start
- Sends the destination coordinates can be set by the user in the Android application by placing the destination marker on the Google Maps in the app. The marker can be moved by clicking on the map where ever the user wishes to place the destination for the car and the destination can be send by use of the destination send button
- The message is <GPS:latitude|longitude>
Reception
- The current speed of the car
- The direction the car is heading
- The direction of the destination
- RPS of the motor
- Sensor values
- Current location of the car
Software Design
Technical Challenges and Solutions
- Integrating the map onto the app was an issue.
- Since the application was designed with fragments and the map view integration was tricky.
- Solved it by converting everything into fragment including the map and a common fragment container.
Improvements
The app now connects directly to the car via the wifi hosted by the car. It can be improved by connecting the car to the cloud and there by the app can connect to the car from any where by connecting to the cloud.
Conclusion
<Organized summary of the project>
<What did you learn?>
Project Video
Project Source Code
Advise for Future Students
1. Start as soon as possible.
2. Don't go with cheap modules and cheap sensors. They might work but you will spend a lot of time trying to get them work.
3. Follow the guidelines that Preet provides, it will save your time.
4. Unit testing was critical. Unit test helped a lot with debugging and modularizing the code.
5. Keep it simple and modular. Don't create "GOD OBJECTS". Use natural language for code. Don't make it too complex.
6. Code review sessions from Preet helped a lot. You will get a lot of insight about making your code better.