F15: Smart Car

From Embedded Systems Learning Academy
Jump to: navigation, search

Smart Car


A smart car with three wheels will be designed to have the capability of following high contrast lines. Options for the lines include using black Sharpie, black duct tape, and white duct tape. Afterwards, it will send back an X and Y coordinate which will be used to plot a visual representation of where the car has traveled onto the LED matrix. The controller board is in charge of plotting the LED matrix while the car's board is in charge of sending X and Y coordinates.

Objectives & Introduction

Our objectives include the following:

  • Self-driving car that is able to follow a line
  • LED matrix that can draw out the path the car is taking

Team Members & Responsibilities

  • Steven Hwu
    • B.S. Computer Engineering
  • Helen Tsui
    • B.S. Computer Engineering


Week# Date Task Actual
1 10/23 Complete project abstract Complete
2 10/30 Gather parts Complete
3 11/06 Program compass Complete
4 11/13 Program LED matrix Complete
5 11/20 Program wireless functionality Complete
6 11/27 Build car Complete
7 12/04 Put all the pieces together Complete
8 12/11 Testing Incomplete

Parts List & Cost

Quantity Description Price
2 SJ-One board $80 ea
1 Cardboard $0 ea
1 White duct tape $4.52 ea
1 Electric tape $1.99 ea
1 Compass $14.95
2 Motors $0 (reused)
1 LED matrix $24.95 ea
2 Photoresistors $1.20 ea
3 Jumper cables $3.99 ea
1 Super glue $3.99 ea
1 Breadboard $6.49 ea
2 NPN transistors $3.29 ea
1 5k potentiometer $2.29 ea
1 Switch $2.99 ea
Estimated total $243.12

Design & Implementation

Cmpe146 F15 smartcar car.jpg

Hardware Design

Cmpe146 F15 smartcar system.png


The compass uses I2C as the communication protocol. The x, y, and z coordinates were able to be read from the compass depending on its orientation. After one of the SJSUOne boards reads the x, y, and z values from the compass, it wirelessly sends the values to the other board to determine which LEDs to light up. The compass' purpose was to determine the car's location so that the path the car was taking could be drawn on the LED matrix.

Cmpe146 F15 smartcar compassInterface.png
HMC5883L Compass

LED Matrix

The purpose of the LED matrix was to display the path that the car is traveling. It uses SPI as its communication protocol. The LED matrix consists of 2 x 3 blocks of 8x8 LEDs. It has a few ports that must be utilized for LED programming. The first port is the WR port which is listed as active low. This is actually the serial clock which captures data in its DATA port on rising edges. While the datasheet recommends using an idle LOW serial clock, this is not a must. With the LPC1758, changing the active level of the serial clock is not the solution to this and will cause problems for data transmission to the LED matrix as it will be transmitting data on the falling edge instead and data corruption will occur.

LED Matrix


NPN transistors were used to control the power source to the motors. There was very little documentation for the motors used so initial tests with varying input voltages yielded that these motors seemed to operate successfully at 5V. This method should not be used on documented motors. Instead make sure to adhere to the specifications provided. In addition, if the input voltage is negated, the motor had the ability to rotate in the opposite direction. For the application, only the positive voltage was utilized since the car did not need to go backwards. For turning purposes, one motor moved slower than the other.


Photoresistors are resistors that have a special characteristic of having different resistances when exposed to differing intensities of light. If high intensity light is absorbed, the photoresistor will have a low resistance. If low intensity light is absorbed, the photoresistor will have a high resistance.

Initial tests of the photoresistors yielded a magnitude of several hundred ohms when shone by a very bright phone LED and several mega-ohms in a very dark setting. A voltage divider circuit was used to read the intensity of light with a 10kOhm resistor.

By using a resistor that had a magnitude logarithmically near the center of the two values, a decent range of voltage readings was able to be provided in many different environments in the voltage divider circuit. This would prove useful for light-sensitive applications.

ADC channels were used to record the voltage across the 10kOhm resistor. There were only two configurations to record the voltage from: across photoresistor or across 10kOhm resistor. Measuring across the constant resistance was chosen because when the photoresistor became exposed to light, the resistance would drop, and the voltage drop across the photoresistor would decrease in the voltage divider circuit. Therefore, the voltage divider circuit provided an analog voltage between the two resistors with a positive correlation to brightness instead of darkness.

Cmpe146 F15 smartcar voltagedivider.png


The SJOne was the microprocessor used for this project. The USB port from the PC was used to power the board. The 3.3V output was used to power the compass and the LED matrix. The compass and LED matrix were interfaced with the SJOne board. The compass used I2C while the LED matrix used SPI. The wireless functionality of the board was also utilized to in order to send information from one board to another.

Hardware Interface

Communication protocols used:

  1. I2C - HMC5883L Compass
  2. SPI - LED matrix
  3. PWM - Motors

Software Design

The software design utilizes drivers such as SPI and I2C. In addition to the drivers, Nordic wireless functionality was programmed.

Reading Position

The X, Y, and Z coordinates were able to be read from the compass depending on its orientation. After one of the SJSUOne boards reads the X, Y, and Z values from the compass, it wirelessly sends the values to the other board to determine which LEDs to light up. The compass' purpose was to determine the car's direction. Once the direction is interpreted, it is combined with the speed of the car to calculate position.

Displaying position

The position of the car will be centered around the center point of the LED matrix which we will map to coordinates (1,1), (1,-1), (-1, -1) and (-1,1). The first digit is the position we are at West vs East while the second digit represents how far we went North or South. Positive corresponds to traveling East and North for the first and second digit respectively.

Handling Start/Stop and Compass readings

The wireless transceiver task for the controller (with the LED matrix) is in charge of sending start and stop commands to the vehicle. In addition, the car’s board will be sending map coordinates for its X and Y coordinates. The controller will be in charge of turning that X and Y mapping into a format such that the LED matrix can properly display the data.

The format for the wireless transmission will be:

Byte 0,,,,,,,Byte 1,,,,,,,,,,,,,,,,,Byte 2


0x01,,,,,,,,,X position,,,,,,,,,,,,,Y position


Obtaining Compass Readings

In order to do read values from the compass, the compass must be in continuous read mode. Continuous read mode is enabled by writing a 0 to register 2. After continuous read mode is enabled, the values could be read by writing a 0 to register 3 and register 4 for x, a 0 to register 5 and register 6 for z, and a 0 to register 7 and 8 for y.

Mapping Received Coordinates to LED Matrix

There were only a few SPI ports and SPI0 was used for the original LED driver. Unfortunately, this was the same SPI port used for our wireless transceiver. As a result, the SPI port is shared between the two tasks. Currently there is no thread-safe protection with the SPI port and therefore some wireless communication may be dropped as a result. In order to share the SPI driver, the clock speed of the driver must be changed before/after each transmission to the LED matrix.

The controller on the car is in charge of reading the compass heading and translating that into a x and y vector where the combined vector would always yield the same magnitude. This would give us a more accurate reading for the car’s position at all times. This would be multiplied with the speed at which the car is moving and generate an X and Y position. On startup, the car will be placed at location 0,0. Since the LED matrix’ center cannot be represented on an even-dimension display (no true center), we will be setting the mapping of row 0 and column 0 to 1’s instead. Therefore the starting point will actually be displayed as 1,1 offset from the true center of the LED display.

The software to generate the correct register address/data is provided in the mapping.h header file. The addressing is quite complicated so when providing the user interface, we decided to organize the user’s API to only have to worry about putting an X and Y coordinate. In one layer, the X and Y coordinate are converted into a format of row, block and data. There are 16 rows, and each block consists of 8 columns. Therefore there are 16 rows and 3 blocks with each data being 8 bits (8 LEDs) wide. In the next layer, we convert from the 2D array of rows and blocks of data into the actual register mapping on the LED matrix.


Since we decided to make our ADC channel have a positive correlation to the intensity of light, we can interpret the mV reading as a starting point for measuring the brightness of the environment of the photoresistor. This raw data can be used in more advanced ways such as passing it through a filter or for a calibration step but that is a possible option that we did not explore too deeply.

Motor Control

In order to control a DC motor without an analog high-power source coming from the SJ One Board, we utilize a PWM channel to control the gate to an npn transistor. By putting the motor in series with the transistor and the power source, we can use a lower voltage/power source from our microcontroller to control the source of the motor. At a high enough frequency, the circuit acts similarly to a high-powered analog source controlled by the microcontroller.

The software for the motor control is premature as it receives limited information from the photoresistors and converts that into an error term that is handled only by a proportional and integral control. There needs to be more thought involved in calibrating the movement code. The logic for the motor control is merely, if the left photoresistors is brighter than the right photoresistors , then that means we are veering off course too far to the right of the tape. Therefore, we increase the command to the right motor and decrease the command to the left motor, attempting to return the motor back on track. Since we did not have reversing capabilities on our motors, there was no way to stop in place and return back on track before continuing. This was an adaptation that was inadequately handled and required more thought.

Testing & Technical Challenges

Plotting coordinates on the LED

To test plotting the coordinates on the LED, we put the mapping code on the controller and transmitted X and Y coordinates through the terminal. This was before we had issues with our SPI drivers when the LED task was running in conjunction with the wireless task. This test would make sure that each step from X and Y position code to LED display work correctly. We tested the corners of each block of LEDs on our display to make sure the mapping software was setting the appropriate registers on the LED matrix.

Running the LED matrix mapping

For the LED matrix mapping, we wrote tests to print out the result of turning a 2D array mapping of bytes into messages over SPI. Each bit that is set in the 2D array represents an LED. To test that each LED was addressed properly, we light up each LED in order until the entire LED matrix is lit up. In fact, due to this test being useful for many applications. We kept this in the code base running parallel to our X and Y plotter. Since the memory used to store the LED mappings was not completely volatile (existed a few minutes after loss of power), we had code to erase the LED matrix using a preprocessor compilation variable called ERASE. If ERASE is set, then the LED matrix will be erased. Otherwise, the LED matrix will be filled up. By compiling with ERASE being set, we guarantee that each time we restart the processor, the LED matrix will be reinitialized.

Testing the Smart Car

We ran several tests for this design and went through several tuning methods but each method we attempted would force the car to go off track very often. We would place the car to go onto the center of the tape but detect that the phototransistor readings were actually quite different from each other due to the lighting and shadows made from the car. After each iteration, the correction algorithms would be changed but to no luck. At one point we managed to keep the robot on track by having very small error correction but the moment it hit a turn, it would not be capable of adjusting quickly enough.

Issues Faced

Wireless communication and LED Matrix

The LED matrix that was used was programmed using SPI0. However, it turns out that SPI0 is shared with the wireless communication API. To fix the issue, the LED matrix was reprogrammed on SPI1.

Varied lighting conditions

The car was tested in various conditions, which affected our ability to calibrate the photoresistors properly. Additionally, the lighting in the environment often cast a shadow on one of the photoresistors, giving them very different values even though the car was centered on the white line. This drastically affected the car's ability to successfully follow the line.

Voltage drops

A 9V battery was used to power the motors and the LED strip. However, the LED strip required a vast amount of current that the battery was not able to fully supply. As a result, the voltage of the batteries dropped drastically. This caused the LED strip to dim and the motors to move extremely slowly. Due to those two problems, consistent calibration of the car was not successful.


The goal of the project was to create a car that would be able to follow a line and to display the car's path on an LED matrix. The LED matrix mapped the car's path, but the car was not able to successfully follow a line. This is due to the lack of time that was spent testing. The light of the environment that the car is vital to proper calibration. Because of how varied the environment the car was tested in was, its ability to follow the line was compromised. In addition, the light also cast a shadow underneath the car which affected the photoresistors. Ultimately, the project reinforced the concepts learned in CMPE146, particularly through the use of SPI and I2C drivers for communication between external hardware modules and the microprocessor.

We learned that more time should be spent on the car's line-following capabilities as it was the largest functional requirement we promised. The compass to LED mapping was only a nice to have. Tracking a line is very difficult and we should have spent more time researching alternatives to phototransistors such as IR sensors. We also should have investigated more configurations of the sensor locations such that we can create better car movement controls.

Project Source Code



We would like to acknowledge Haluk Ozemek and Preetpal Kang for providing us with the knowledge for this project.

References Used

LED Matrix HT1632C datasheet: https://www.adafruit.com/datasheets/ht1632cv120.pdf

3-Axis Digital Compass IC HMC5883L datasheet: https://www.adafruit.com/datasheets/HMC5883L_3-Axis_Digital_Compass_IC.pdf


You can list the references you used.