Purpose/ What our robot does:

The purpose of the assignment was to create a robot that could follow a line of black electrical tape on a white dry erase board.

Design Process:

The first step of the assignment was to research the hardware and software of line following robots.

The hardware includes a breadboard, an Arduino, a 9V battery, and a motor rechargeable battery. Note how there are two batteries needed, one for motors and one for the Arduino. We soldered the motor controller and connected to the servo motors. Information about the correct connections was found online and specified in the bibliography section. We tested each wheel at different speed and direction. 

Next, we started developing the sensor module. The module consists of three photoresistor and three yellow LEDs. The original design evolved over time since we realized that exposing the photoresistor we natural light will alter the sensor reading greatly, and eventually the robot can’t distinguish between white and black. With this in mind, we made an enclosure for the sensor module in the front of the robot. The sensors  and LEDs were soldered on to longer wires and connected to the Arduino. 


Next, found variables for the photoresistors for black and white “thresholds”. We coded four different scenarios that the robot could be in: if the left sensor is on black then the right wheel turns, left wheel off;  if the right sensor is on black then the right wheel turns, right wheel off; if the middle sensor is on black then go forward. However, errors appeared in our reading method since we did not know the exact lighting conditions for the actual test.

We concluded that we would need to find the difference in the white in black with an initial reading to calibrate the photocells before the course began. We also tried to solve this problem by adding an ambient light reading, which would consist of another photocell coming out of the breadboard, above the wires, and using that data as a baseline saying that anything below that reading is black. However, we found that the ambient light reading wasn’t consistent because all three sensors are often lower than ambient light, therefore, all of them were reading black color all the time. So, we deprecated the ambient light sensor and code. We changed the code to make the robot gather an initial reading of the black tap. With this method, sensors know before the robot started moving what is black and what is white in this lighting condition. With the current reading, we tested thresholds of +- 20, +- 30, +- 40, and realized that +- 40 gave us the best result. The robot did a terrific job of following the line. We even added additional code for 90-degree turns. 

Difficulties arise once again after several tests in dim hallways. Initial reading will be distracted by the lighting condition if the difference between and white is less than desired  value – 40. What if we eliminate that variable. In another word, put an enclosure around the photoresistors so ambient light will never effect the reading of the photocells. The enclosure is made out of duct tape and reinforced by electrical tape.

Next, we added yellow LEDs above each sensor to control lighting all the time. We also changed the approach to the programming; instead of having an initial reading, we changed it so that there is constant updating for the lowest possible white value which we labeled as the black threshold. 

We kept testing on the track but the robot kept going off the line at a certain point. We slowed down the robot and looked at the exact readings at this point and saw that both the left and the middle sensor sensed black and then went directly to white. We also added in delays to better analyze the readings. We then changed the range of the thresholds from plus or minus three to zero to distinguish white and black but we later determined to have the threshold was causing too much error when sensors were in between lines and constantly updating was causing the robot to jerk back and forth. We switched back to the initial reading with a range of plus or minus 30 to control the robot more.

With these new changes, we also found that we were missing the screws for the wheels of our robot which made our wheels loose and made the robot unable to go in a straight line. So we borrowed old screws from another group.


  • 1 Arduino Uno
  • 1 breadboard
  • 3 photocells
  • 1 red LED
  • 3 yellow LEDs
  • 3 330 Ohm resistor
  • 3 100K resistors
  • 1 motor control
  • 1 9V battery
  • 1 motor battery
  • About 30 wires
  • 1 DC motor in Micro Servo Body
  • Anodized Aluminum Metal Chassis
  • 2 Wheels for FS90R Servo
  • Duct tape
  • Electrical tape
  • Soldering materials

Procedures/ How our robot works/ How to build our robot:


The first step is to construct the base of your robot and we will need the anodized aluminum metal chassis, the two wheels, the DC motors, and a screwdriver for this task. Once you have these at hand, we begin to assemble the pieces of the robot together; there should be screws in the bags. We screwed in a second floor to the base and installed the motors and the wheels in slots that are on either side of the wider end of the base and then the wheels are screwed into the motors. You can build the second floor by inserting screws in the horizontal line in the back of the robot’s structure.   


The next step is to solder the motor driver component to the breadboard. We connected the motor component to either side of the breadboard so it was easier to organize the wires to the Arduino and distinguish between power and ground. Once we soldered the motor driver on, we wired the motors and the battery on the breadboard. At this point, the wheels should be able to move if programmed to do so. Below the steps to making this robot, we wrote out the functions of each part of the motor driver and attached a link to youtube as an introduction to soldering. This is the completed connections for the motor driver.    


Build the sensor module for the robot. This part’s purpose is the send information back to the Arduino to ultimately tell the Arduino if it senses black or white which is then categorized by the “if” statements in the code. We started making this by soldering the photocells with longer wires and having them hang in front of the robot’s structure facing the ground. We installed three photocells; one in the middle and then one on each side. They should be far enough apart so that the only sensor reading black in the beginning is the middle sensor and the other two are on the white. Next, we connected the soldered photocells with the breadboard and Arduino.


After the sensor module and motors are connected, you will notice that your robot can’t detect what is black or white because the lighting is constantly changing due to shadows, time of day, or lights in the room. To completely control the scenario the robot is in, it is essential to building a barrier for the photocells that block the surrounding world. We did this by circling gray duct tape around the robot’s base 360 degrees around all three photocells.


After building a cage for the photocells, we added constant lighting to the scenario by soldering three yellow LEDs, attaching them to the breadboard, and hanging them in the duct tape. It is important to have all three LEDs suspended at the same height so that there is consistent lighting for the three photocells.


Once the photocells’ surroundings were contained, we had to tell the robot what is black or white. So, we wrote code to have it take an initial reading and then made a range define black or white below the photocells (this code is described later). To find this range, we collected sensor data of black and white color throughout the track by having the robot move slowly and delay many times and watched the serial monitor see when the readings were low, detecting black, and high, detecting white.

Understanding the Motor Control:

After some research, we figured out the basics of the motor controller that we are using and make some improvements to the robot.

The motor controller is TB6612. On the right (in figure_1) there are four outlets for the motors and two GNDs. Based on the research, I connected the grounds with two grounds on the Arduino and also hooked up the motors. On the right, there are:

PWMA: speed control for motor A

AIN2: Direction control for motor A

AIN1: Direction control for motor A

STBY: Standby.

BIN1: Direction control for motor B

BIN2: Direction control for motor B

PWMB: Speed control for motor B

GND: Ground for external motor power.

VMOT: external motor power.

Soldering Link: https://www.youtube.com/watch?v=oqV2xU1fee8


Photoresistors (or photocells) are critical to this robot. They tell the robot that’s white, that’s black. Photoresistors are resistors, you can tell from their names. Therefore, we can read their readings with Arduino and control the sensitivity of the reading with resistors as well. We initially implemented 10K resistor without the sensor enclosure. We ran multiple sensor tests for accurcy and consistency.

From http://www.instructables.com/id/Photocell-tutorial/

Read the data from the photoresistor is straightforward. Simply connect one of the legs to a 100k resistor and to the Arduino analogIn pin, you see the reading for that sensor. The average reading for black with the sensor enclosure is 870 and white is around 920.

Principles of the Program:

First, we declared local variables, mainly integers, to define different pin numbers.

your code here<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>
int leftSensor = 1;
int midSensor = 2;
int rightSensor = 3;
int ambLight = 4;

int LEDPin = 2;

int leftReading;
int rightReading;
int midReading;
int initialReading;

int STBY = 8; //standby
//Motor A
int PWMA = 3; //Speed control
int AIN1 = 6; //Direction
int AIN2 = 5; //Direction
//Motor B
int PWMB = 10; //Speed control
int BIN1 = 11; //Direction
int BIN2 = 12; //Direction

In the setup() method:

  pinMode(STBY, OUTPUT);
  pinMode(PWMA, OUTPUT);
  pinMode(AIN1, OUTPUT);

  pinMode(AIN2, OUTPUT);
  pinMode(PWMB, OUTPUT);
  pinMode(BIN1, OUTPUT);
  pinMode(BIN2, OUTPUT);

  pinMode(LEDPin, OUTPUT);


We configure the motor pins and the LED pin

Specifically, we used a method found in one of the sources below. The method allows the motors to move clockwise, or counterclockwise at a given speed.

void move(int motor, int speed, int direction){
//Move specific motor at speed and direction
//motor: 0 for B 1 for A
//speed: 0 is off, and 255 is full speed
//direction: 0 clockwise, 1 counter-clockwise

  digitalWrite(STBY, HIGH); //disable standby

  boolean inPin1 = LOW;
  boolean inPin2 = HIGH;
  if(direction == 1){
    inPin1 = HIGH;
    inPin2 = LOW;
  if(motor == 1){
    digitalWrite(AIN1, inPin1);
    digitalWrite(AIN2, inPin2);
    analogWrite(PWMA, speed);
    digitalWrite(BIN1, inPin1);
    digitalWrite(BIN2, inPin2);
    analogWrite(PWMB, speed);

void stop(){
//enable standby
  digitalWrite(STBY, LOW);

In the loop() method, first, the robot will read data from three sensors. We then set up four different cases which is the main logic of this robot. First, if MidSensor is black, motors move forward. If LeftSensor is black when move left. If RightSensor is black when moving right. Lastly, if all three sensors read black then stop and turn on LED. This method is executed continuously in the program, therefore, the robot will check all these cases every millisecond or so. This logic let the robot perform the desired task.

void loop() {

 if (midIsBlack() == true && leftIsBlack() == false && rightIsBlack() == false){
    move(1, 100, 1); //motor 1, half speed, right
    move(2, 100, 0); //motor 2, half speed, right

  }else if (leftIsBlack() == true && midIsBlack() == false && rightIsBlack() == false){
    //move left, turn on right motor;
    move(2, 00, 1);
    move(1, 100, 1);

  }else if(rightIsBlack() == true && midIsBlack() == false && leftIsBlack() == false){
    //move right, turn on left motor;
    move(2, 100, 2);
    move(1, 00, 2);

  }else if (rightIsBlack() == true && midIsBlack() == true && leftIsBlack() == true){
    digitalWrite(LEDPin, HIGH);
    digitalWrite(LEDPin, LOW);
    move(1, 100, 1); //motor 1, half speed, right
    move(2, 100, 0);

Other than the main logic, we also wrote four different methods: bool midIsBlack(), bool leftIsBlack(), boolean rightIsBlack(). All three methods return a boolean value based on BlackThreshold that is calculated in the sensor calibration algorithm beblow.

bool leftIsBlack(){
  return (leftReading < 550);
bool rightIsBlack(){
  return (rightReading < 550);
bool midIsBlack(){
  return (midReading < 550);

Sensor Module:

After many tests and programs, we have developed an enclosed sensor module. Lighting condition is always a variable in the system. The sensor calibration algorithms that we came up with did not solve this problem. With help from other group members, we created an enclosure to eliminate this variable. We put duct tape around the sensor module and added LED to the sensors for lighting. After several tests, the result of the reading under any lighting conditions were consistent



Pictures of the Final Robot

Final Code:






(This source goes in depth about L293D Motor Driver, IR module, and the code)







Posted by:NeilNie

Student at Columbia University, School of Engineering and Applied Sciences. Prev. software engineer intern at Apple. More than six years of experience developing iOS and macOS applications. Experienced in electrical engineering/microcontrollers. From publishing several apps to presented a TEDx talk in machine learning. Striving to use my knowledge, skills, and passion to positively impact the world.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.