Professional Documents
Culture Documents
1/07)
2010/2011
Academic Session:
Certified by :
NOTES : * If the thesis is CONFIDENTIAL or RESTRICTED, please attach with the letter from
the organisation with period and reasons for confidentiality or restriction.
DECLARATION
I hereby declare that I have read this thesis and in my opinion this thesis is
sufficient in terms of scope and quality for the award of the degree of
Bachelor of Engineering (Electrical Mechatronics)
Signature : .
Name of Supervisor : MOHD ARIFFANAN BIN MOHD BASRI
Date : 16 MAY 2011
MAZE SOLVING ROBOT
MAY 2011
ii
DECLARATION
Signature :
Name : LAW SEI CUI
Date : 16 MAY 2011
iii
DEDICATION
ACKNOWLEDGEMENT
ABSTRACT
ABSTRAK
Maze solving robot adalah sebuah autonomi robot yang dapat menerokai
maze yang diberikan dalam masa sesingkat mungkin. Maze solving robot itu boleh
mengetahui laluan terpendek dari titik awal ke titik akhir dalam maze tersebut. Robot
tersebut bergerak mengikut garis berwarna hitam dengan banyak persimpangan dan
enam IR sensor analog digunakan sebagai penderian dalam pergerakan. Sebuah
encoder digunakan untuk mengukur jarak perjalanan maze solving robot. Maklumat
yang diperolehi akan dipaparkan kepada LCD. Segala perantaramukaan dikawal
oleh microchip PIC30F4011. Di samping itu, algoritma Dijkstra diimplementasikan
untuk mencari laluan terpendek dari titik awal ke semua titik lain.
vii
TABLE OF CONTENTS
1. INTRODUCTION
1.1. Project Background 1
1.2. Objective 1
1.3. Scope 2
1.4. Problem Statement 3
2. LITERATURE REVIEW
2.1. Introduction 4
2.2. University of East London 4
2.2.1. 1999 Micromouse 4
2.3. Previous Final Year Projects in UTM 6
2.3.1. 2006 Micromouse I 6
2.3.2. 2006 Micromouse II 7
2.3.3. 2008 Micromouse Maze Solving Robot 8
viii
REFERENCES 50
APPENDICES 51
x
LIST OF TABLES
LIST OF FIGURES
LIST OF ABBREVIATIONS
A - Ampere
cm - Centi-meter
DC - Direct current
FYP - Final year project
GPIO - General purpose input and output pins
IC - Integrated circuit
IDE - Integrated Development Environment
IR - Infra red
I/O - Input or output
kg - Kilogram
LCD - Liquid crystal display
LED - Light emitter diode
MHz - Mega Hertz
mm - Milimeter
PCB - Printed circuit board
pF - Pico-farad
PWM - Pulse-width modulation
QEI - Quadrature Encoders Interface
rpm - Revolution per minute
R/W - Read or write
uF - Micro-farad
UTM - Universit Teknologi Malaysia
V - Volt
xiv
LIST OF APPENDICES
INTRODUCTION
Maze solving robot is one of the autonomous robots which aim to negotiate a
maze. The idea of the autonomous Micro-mouse robot as a maze solving device was
firstly introduced by the IEEE Spectrum Magazine in 1977. Many such competitions
were then held all around the world. In fact, this robot is an advanced tool for
military uses. For example, in 1944, robot bombs have killed many people and
destroyed houses in six weeks of bombardment in London. Fewer of these bombs
had reached this land through the maze of defense device. This is a conspicuous case
of advantage to use such robots. By the way, this technology can also be used for
many other applications such as car park systems, object searching and so on.
1.2. Objective
The main objective of this project is to design and build an autonomous robot
that is able to negotiate a maze in the shortest possible time. Besides, Dijkstras
algorithm is implemented in the robot to calculate the shortest path from all possible
pairs of starting point and end point.
2
1.3. Scope
The main task the maze solving robot must do is to explore the maze given
and then finds out the shortest route from starting point to a specified end point.
During process of explore maze given, the robot will obtain the distance that read
through encoder (QEI). Once finished explore, the robot will analyze all the data
stored using Dijkstras algorithm to find out shortest route.
The maze solving robot is designed to explore in a 3x3 maze in matrix form
as shown as Figure 1.1. There can be many paths from a fixed starting point to a
fixed end point. Each bullet shown is actually a junction in real maze and it can be
moved to any position as long as the arrangement of nodes is in 3x3 matrix order.
The maze solving robot stores the distance from one junction to another junction
during line following. The distance is then sending to LCD for displaying purpose so
that we can know whether the robot counts distance correctly. The movement of
robot during meet junction is programmed and it can memorize all the direction it
passed through. Once the maze solving robot returned to starting point, it will
process the data using Dijkstras algorithm and then heading to shortest route.
END
START
LITERATURE REVIEW
2.1. Introduction
This chapter describes a few project related to maze solving robot that have
been done by previous students and researchers. The specification and design of
previous robot can be served as a guideline to this project.
The Figure 2.1 shows the Micromouse by Michael Gims, Sonja Lenz and
Dirk Becker [1]. The PCB circuit design make the circuit look tidy but the
arrangement of cables and connectors are still needed some improvement. The big
size of wheels increased the stability of robot. This is a good consideration when
constructing a robot.
5
Components used:
Figure 2.1: Micromouse UEL 1999 by Michael Gims, Sonja Lenz and Dirk Becker
6
There are totally four previous final year projects in UTM which are related
to maze solving robot. The projects are listed as below:
The Figure 2.2 shows the Micromouse UTM FYP 2006 by Louis Wong Siang
San [2]. The wooden plank base is not suitable for robot because it is heavy and this
will affect the robot performance since the stepper motor may not has sufficient
torque to function effectively. Besides, there are many cables that out of robot. This
condition may cause the robot fault during performance. Therefore, a good circuit
design and arrangement is needed in the process of developing a robot.
Figure 2.2: Micromouse UTM FYP 2006 by Louis Wong Siang San
7
Components used:
i) PIC16F627.
ii) PCB circuit design
iii) IR sensors
iv) 2 stepper motors drive with darlington array IC
v) Wooden plank base with castor
The Figure 2.3 shows the Micromouse UTM FYP 2006 by Indran A/L
Thandavarian [3]. This robot is bad in circuit arrangement. As we can see from
Figure 2.3, the outlook of micromouse robot is very messy. This is not a good robot
design. Hence, the circuit arrangement is a very critical issue during circuit design.
Components used:
i) MC68HC11E
ii) Two stepper motors
iii) Whisker sensor
iv) IR sensors
v) Aluminum chassis base
8
The Figure 2.4 shows the Micromouse Maze Solving Robot UTM FYP 2008
by Chang Yuen Chung [4]. The circuitry with different layer is making the robot
look nice. But there are many connectors from board to board. This is also not a good
way to link circuits. Thus, all the inputs and outputs are recommended to place
together so that only one cable with a number of ways is needed for the circuit.
Figure 2.4: Micromouse Maze Solving Robot UTM FYP 2008 by Chang Yuen
Chung
Components used:
i) PIC18F452
ii) 2 stepper motor
iii) 3 analogue distance sensors
iv) Wheel mounted with rubber
v) Acrylic casing
vi) Wheel chair design supporting with castor
The Figure 2.5 shows Explorer Robot UTM FYP 2009 by Lew Chong Hao
[5]. This robot design is similar to Micromouse Maze Solving Robot UTM FYP
2008 by Chang Yuen Chung, which are circuitry with different layer and many
connectors from board to board. Three different layers may make the robot unstable
due to the gravity of robot. Hence, the number of layers should reduce to increase the
stability of robot.
Figure 2.5: Explorer Robot UTM FYP 2009 by Lew Chong Hao
Components used:
i) PIC18F452
ii) 2 stepper motor
iii) Analogue distance sensors
iv) O-ring and wheels
v) Acrylic casing
Algorithm: A*
10
2.4. Summary
The literature review done in this chapter has exposed the advantages and
disadvantages of each previous project. As a summary, the following are list out as
my major preferences.
My target for this project is to construct a maze solving robot using lowest
possible cost. Thus, reliable devices with reasonable cost such as Tamiya motor, card
board platform, analogue IR sensor, mouse modified encoder and dsPIC30F4011 are
chosen.
There are several path finding algorithm such as A*, B*, flood fill, Floyd-
Warshall algorithm, Johnsons algorithm, Dijkstras algorithm, etc. Each algorithm
has its own features and advantages. A* and Dijkstras algorithm are widely used
and most popular among those path finding algorithms. In this project, Dijkstras
algorithm is implemented in the robot. This is because Dijkstras algorithm is easier
to implement compare to A*. A* is a modification upon Dijkstra's basic algorithm
[6], so we have to understand Dijkstra's first in order to use A*. A* is faster than
Dijkstras, but not always as good. It uses heuristics, and tries to go towards the
target and around obstacles [7]. This can lead to it finding a more direct but possibly
more expensive path. For a small program such as 100 nodes and below, the
difference of speed between A* and Dijkstras would be negligible [8]. There are 9
nodes in my project, so Dijkstras is the best choice to achieve objectives stated.
CHAPTER 3
3.1. Introduction
The maze solving robot basically consists of four primary components, which
are maze mechanical drawing, mechanical hardware, software programming and
electronic circuitry. There are some considerations to be taken in account when
designing every single part for a better stability and reliability. Each part is essential
to the completion of the project.
Figure 3.2 shows the flow of this project. Every single step was carried out
according to schedule planned.
Literature Review
2
Software development
6
Implementation
8
Documentation
10
The foremost step is getting idea and concept for final year project where my
project title is maze solving robot. To gain the knowledge and idea for this project,
literature review of previous project or other related articles has been done.
14
Next, the mechanism of maze solving robot was designed. Since a light and
small in size of robot is required to perform a smooth movement, the electronic
circuitry boards are designed to install directly to the Tamiya motor as the robots
body. Thus, a complete set of electronic circuitry is needed to accomplish the robot
mechanism.
Then, the software algorithm and flow chart were developed and analyzed
using Microchips MPLAB IDE in C programming language. The Dijkstras
algorithm and path planning are implemented to the robot. Lastly, the system was
tested and fine tuned to get a better performance.
There are many motor such as stepper motor, servo motor, linear motor,
tamiya motor and so on. Each motor has its own features and characteristics. Servo
motor is widely used in educational robotic project. It can be used to control rotation
angle well compare to other motors. Linear motor is the most expensive among
several types of motor due to its specifications. It provides linear actuation in normal
electric motor. Stepper motor has an excellent low speed torque and good
repeatability. It can drive many loads without gearing and returns to the same
position accurately.
A pair of custom-designed
custom designed plastic wheel as shown in Figure 3.4 is used
together with Tamiya motor. It has a rubber tire measuring 54mm in diameter and fit
with the output shafts on Tamiya twin motor.
3.3.3. Castor
Figure 3.5 shows a screw typed castor that used to support the robot structure.
This type of castor is chosen due to its economically cost and light weight. It is 7mm
in diameter and 30mm in length.
To save the project cost, an encoder set is dissected from an unused computer
mouse. One of the important elements that can be applied in my project is the rubber
encoder wheel. It is 22mm in diameter and placed beside of the right mini wheel. The
encoder wheel is used to count distance that the robot travels.
The main function of circuitry is to interface with environment that the robot
situated in. Then the data received will be analyzed and the shortest path from start
point to end point will then be calculated. The circuitry consists of embedded system
to execute algorithm and control the movement of robot.
The circuit design divided into 3 boards. Every board is arranged according to
its functionality. The top layer is main board, which consists of power supply circuit,
push button, led as indicator, LCD display, switches and microchip dsPIC30F4011.
The middle layer is motor driver and encoder circuitry board while bottom layer is
sensor board which used for line sensing. The schematics are firstly designed and
sketched using gEDA Schematic Editor. All of the circuit boards are then constructed
and tested.
18
The power supply circuit is used to provide voltage to other components such
as microchip, comparator, motor driver, sensor, etc. There are three voltage
regulators in my circuit design as shown in Figure 3.7. Two units of 7805 and one
unit of 7809 are used for different purposes. The output voltage from 7805 circuit set
is +5V while 7809 circuit set generates +9V. Both of 7805 voltage regulator circuits
are used as power supply for microcontroller and comparator. The main function of
7809 circuit set is to supply power to motor driver.
A switch is connected series with power supply to on and off power of whole
circuitry. A diode IN4007 is also connected series with switch so that it will act as an
open circuit when the input voltage is inversed. This is a safety precaution to prevent
voltage regulator from damage or burning. 1000uF and 0.1uF capacitors are used to
stabilize the output voltage. LED indicators are used to indicate the proper function
of the circuit.
3.4.2. Microcontroller
The Figure 3.12 shows a schematic of LCD that constructed a complete LCD
device. This LCD is used as an output device to the microcontroller. The 5th pin of
LCD which is R/W enables the LCD to read or write data.
There are two units of push button used for mode execution to the robot.
Figure 3.13 shows the push button image. The push buttons are inputs to the
microcontroller. The circuit connection of push button is shown as Figure 3.14.
The Figure 3.15 shows a simple schematic for interfacing a DC motor using
L293D [11]. L293 H-Bridge IC is a dual H-Bridge motor driver. It is used to
interface two DC motors which can be controlled in both clockwise and counter
clockwise direction. L293D has output current of 600mA and peak output current of
1.2A per channel. The output supply has a wide range from 4.5V to 36V, which has
made L293D a best choice for DC motor driver. There are two PWM pin that used to
control rpm of motor.
In order to find out the shortest path from a point to another point, the
distance between the two points must be known. The best way to save cost and
calculate distance accurately is to use the incremental encoder of an unused mouse.
The encoder wheel as shown in Figure 3.18 has been extracted from a mouse.
There are six Infra Red (IR) sensors used for purpose of line sensing. The
basic idea is to send infra red light through IR-LED, which is then reflected by the
black colored tape in front of the sensor. There is another IR-LED used for detecting
the reflected IR light. Figure 3.21 illustrates the basic design of the Infra Red sensor.
Since there are only four sensors available for one comparator LM324, two
units of LM324 are required in order to connect six sensors in this project. Therefore,
the circuit connection of comparator is assigned as second part. Figure 3.25 shows
the schematic of comparator LM324.
3.5. Software
Some theories and design techniques will be implemented into the maze
solving robot. The programming part includes path planning, line following, distance
measurement and Dijkstras algorithm. The sections below give a more detailed
overview into each of them.
Figure 3.26 illustrates the overall concept of algorithm for maze solving robot.
The combination of all algorithms yields a functional maze solving robot that able to
move following line, measured distance accurately, memorized maze and finds out a
shortest path. These steps are shown below as a flowchart.
Start
Line following
Distance Measurement
Maze exploration
No
Complete path?
Yes
Dijkstras algorithm
End
The maze solving robot is moved following black colored tape. The six units
of IR sensors used to read analogue value from reflection of those black colored tape.
The analogue values of IR sensors are then digitalized by two comparators as
mentioned in Section 3.4.7. The flowchart of line following features is shown in
Figure 3.27.
Start
Speed adjustment
Yes
Out of line? Direction adjustment
No
No
Need to stop?
Yes
Stop
End
ii. Digital Filter Control Register (DFLTCON) To control the digital input
filter operation.
iii. Position Count Register (POSCNT) To read and write of the 16-bit position
counter.
The path planning is very crucial for the maze solving robot to identify every
single point passed through. There is a 3x3 in matrix form of maze. Basically the
starting point and ending point are fixed as shown as Figure 1.1 before maze solving
robot start to explore the maze. There are two sets of path planning. One is for maze
exploration and another one for shortest path execution. The path planning is based
on maze of Figure 1.1. The Coordinate of starting point as (2, 1) and ending point is
(0, 1). The flowchart of maze exploration is shown in Figure 3.29.
After the maze exploration done, the maze solving robot will then analyses
the data obtained through Dijkstras algorithm. At last, the maze solving robot will
direct move to the destination in shortest route. The flowchart of shortest path
execution is shown in Figure 3.30.
Start
Yes
Current Y < Previous Y?
Overwrite previous Y
No
No Done considering
all neighbors?
Yes
End
In the following steps, the lowest distance not yet visited node is chosen and
it is checked if there is a node that can be reached from there with lower distance
than before. Dijkstra's algorithm will assign some initial distance values and will try
to improve them step by step. Let node A to be initial node.
Step 3: For current node A, consider all its unvisited neighbors that are node B and C.
Tentative distance from the initial node to node B and node C will be calculated.
Since the distance B and C are less than the previously recorded distance which is
infinity in the beginning, the distances have been overwritten.
35
Step 4: Since all neighbors of the current node A have been done considering, node
A is marked as visited.
Step 5: The visited node A will not be checked ever again. Thus, its distance
recorded now is final and minimal. The unvisited node C with the smallest distance
from the initial node is set as the next current node and continues from step 3.
Step 6: The node C is marked as visited and will not be checked anymore. The
unvisited node B with the smallest distance from the initial node is set as the next
current node and continues from step 3.
Step 7: The node B is marked as visited. The unvisited node D with the smallest
distance from the initial node is set as the next current node and continues from
step 3.
Step 8: All of the nodes have been visited and a shortest path from initial node A to
node E is found.
Figure 3.30 and Table 3.5 above illustrate the shortest path from node A to node E
and distance accumulated for each node. The result is: A C B D E.
The different patterns of card boards that used to construct maze is shown as
figure below.
Here some examples for the maze that combined with several patterns of card
board.
Junction
Destination
Starting point
Junction
Destination
Starting point
4.1. Introduction
The results obtained are discussed in this chapter. This section involves
design of hardware, circuitry and maze field, and some features such as line-
following and distance measurement. Maze solving test is discussed in the last
section.
The Figure 4.1 below shows the different view of maze solving robot.
The electronic circuitry consists of three boards, namely the main embedded
microcontroller board, motor control board and sensor board. The main controller
board consists of microcontroller dsPIC30F4011 from the Arizona Microchip and
other integrated circuit such as push button, LCD and the like. The motor control
board is used to control the direction of robot while the sensor board provides the
feedback of the current position of robot.
Voltage
regulator
dsPIC30F4011 LCD
Comparator
LM324
Encoder
IR Sensors
Motor Driver L293D
The overall concept of a maze for the robot is described in Section 3.6 Maze
Mechanical Drawing. Figure 4.4 shows the complete maze field that using for the
exploration of maze solving robot. The maze field constructed is light in weight, easy
to build up and flexible to construct any path.
The line-following feature is very crucial for the maze solving robot to find a
correct path from a point to another point. The maze solving robot is able to move
according to the input from IR sensors that used for black colored line sensing as
shown in Figure 4.5.
43
0mm
Initial
523mm 523mm
Result 4 Result 5
The data obtained was analyzed. The average error and percentage error of
distance measurement using rotary encoder were then calculated.
The robot arm is being tested in the maze shown in Figure 4.8. The shortest
path is shown in that figure.
The robot will firstly start its exploration to the maze. Then, Dijkstras
algorithm is implemented to analyze the shortest path. The next route of robot will be
executed by the result calculated using Dijkstras algorithm.
Ultimately, the maze solving robot was succeed to explore the test maze and
direct go the destination at second route. The main objective of this project is finally
achieved.
46
Figure 4.8 shows the test maze that being used for maze solving robot.
END
START
After the maze solving robot done the exploration as shown in Figure 4.9, the
shortest path found. The maze solving robot was heading to the destination through
shortest path as shown in Figure 4.10.
CONCLUSION
5.1. Conclusion
In the nutshell, the objectives of the project have been achieved. A maze
solving robot that able to negotiate a maze has been constructed. It can finds out the
shortest path in a maze by using Dijkstras algorithm. The maze solving robot is also
able to perform some features such as line following and distance measurement.
Several tests have been done to determine the proficiency of maze solving robot.
The comprehensive planning and design of maze solving robot at earlier stage
made the construction process carry out easy. Even using low cost material, the maze
solving robot is still able to perform well. The Dijkstras algorithm is implemented
and shown a good result in path finding case.
Besides, this project provides a good platform for academic learning. We can
apply some of the theories learnt during class and practice in this project. During
practical time, we are able to understand the actual condition to carry out a project
and trying to solve all the problems faced. Hence, critical thinking and problem
solving are the major issues for us to bring out a final year project succeedfully.
49
5.2. Recommendation
There are still some limitations of the maze solving robot that can be further
improved to achieve goal. The possible improvements to be carried out if the project
is undertaken by somebody else in the future are listed below:
1. Actuator In order to save cost, Tamiya motor is selected as the actuator for
maze solving robot. To get a faster and stable response, there are some other
commercially available advanced motors might be to use such as stepper, DC
motor, etc. But this will increases the cost of the project dramatically.
3. PCB boards for circuitry All of the embedded systems are constructed and
soldered using hand. Sometimes, it is take time to trouble shoot and check the
circuit. This condition leads to instability of maze solving robot during
performance. A PCB layout will better improve the system circuitry.
4. Maze field This kind of maze field is easy to build up and flexible. At the
same time, the platforms are easy to move once it is not stick strongly. This
caused the robot can not perform well. Hence, a good maze field is required to
enhance the performance of maze solving robot.
50
REFERENCES
[3] Indran A/L Thandavarian. Micromouse The Maze Solving Robot. Bachelor
Thesis. University Technology Malaysia; 2006.
[6] http://en.wikipedia.org/wiki/A*_search_algorithm
[7] http://allmybrain.com/2008/06/02/the-difference-between-dijkstras-
algorithm-and-a/
[8] http://www.xtremevbtalk.com/showthread.php?t=86509
[9] http://www.cytron.com.my/
[10] http://www.futurlec.com/dsPIC30F4011_Controller.shtml
Dijkstra.h
#ifndef DIJKSTRA_H
#define DIJKSTRA_H
void Dijkstra_send_data(unsigned char cEdge1, unsigned char cEdge2, unsigned long lDistance);
void Dijkstra_analyse_data(void);
void Dijkstra_go_path(int dest);
#endif
Encoder.h
#ifndef ENCODER_H
#define ENCODER_H
void Encoder_distance_measurement(void);
void Encoder_set_distance(unsigned char Encoder_instruction);
#endif
LCD_Commands.h
#ifndef LCD_COMMANDS_H
#define LCD_COMMANDS_H
#include <p30fxxxx.h>
#define RS _LATC13
#define ENA _LATC14
#endif
Motor_Control.h
#ifndef MOTOR_CONTROL_H
#define MOTOR_CONTROL_H
#include "MSR_Config.h"
void Motor_Control_line_following(void);
unsigned char Motor_Control_update_line(void);
void Motor_Control_Send_Data(void);
void Motor_Control_Run_Dijkstra(void);
void Motor_Control_forward(void);
void Motor_Control_backward(void);
void Motor_Control_turn_left(void);
void Motor_Control_turn_right(void);
void Motor_Control_stop(void);
void Motor_Control_break(void);
void Motor_Control_rotate_left(void);
void Motor_Control_rotate_right(void);
void Motor_Control_junc_rotate_right(void);
void Motor_Control_junc_rotate_left(void);
#endif
MSR_Config.h
#ifndef MSR_CONFIG_H
#define MSR_CONFIG_H
//Input
#define Button1 _RF4
54
//Output
#define led _LATE8
#define Motor_Left_1 _LATF0
#define Motor_Left_2 _LATE2
#define Motor_Right_1 _LATF1
#define Motor_Right_2 _LATE0
#define pwm_Left PDC1
#define pwm_Right PDC2
//Constant
#define _1s 1999998UL
#define _100ms (_1s / 10)
#define _10ms (_100ms / 10)
#define _1ms (_10ms / 10)
//in unit of mm
#define config_encoder_perimeter 78
#define config_encoder_pulse 12
#define config_total_encoder_pulse (4 * config_encoder_pulse)
#define config_min_poscnt 2000
//Dijkstra's Algorithm
//Number of nodes
#define config_nodes 3
#define config_no_of_nodes (config_nodes * config_nodes)
#define config_no_of_edges (config_nodes * (config_nodes - 1) * 2)
#define config_INFINITY -1
//Structure
typedef union {
struct {
//0: Out of line during line following
unsigned out_of_line : 1;
//0: No corner found
//1: Turn left
55
typedef union {
struct {
//1: Valid edge, proceed to path planned
unsigned send_dijkstra : 1;
//1: Done analyzed, proceed to shortest path
unsigned run_dijkstra : 1;
//1: Destination reached, the end of path
unsigned end_path : 1;
//1: Meet junction during running dijstra algorithm
unsigned junction_dijkstra : 1;
//1: Non-valid edge
unsigned detect_edge : 1;
unsigned end_dijkstra : 1;
unsigned : 2;
};
unsigned char byte;
} flag_t;
typedef union {
struct {
unsigned node_3 : 1;
unsigned node_4 : 2;
unsigned node_5 : 1;
unsigned node_6 : 2;
unsigned node_8 : 2;
unsigned node_9 : 1;
unsigned node_10 : 2;
unsigned node_13 : 2;
unsigned node_15 : 1;
unsigned count_valid : 1;
unsigned : 1;
};
unsigned int word;
} direction_t;
//*****************************Function Prototype*************************
void Delay(unsigned long lInterval);
void init(void);
void __attribute__((__interrupt__,auto_psv)) _QEIInterrupt(void);
void __attribute__((__interrupt__,auto_psv)) _T3Interrupt(void);
void __attribute__((__interrupt__,auto_psv)) _T4Interrupt(void);
void __attribute__((__interrupt__,auto_psv)) _OscillatorFail(void);
void __attribute__((__interrupt__,auto_psv)) _AddressError(void);
void __attribute__((__interrupt__,auto_psv)) _StackError(void);
void __attribute__((__interrupt__,auto_psv)) _MathError(void);
//Variable Declaration
extern unsigned int pwm_Left_acc, pwm_Right_acc;
#endif
56
Path.h
#ifndef PATH_H
#define PATH_H
void Path_fixed_point_new(void);
#endif
Task.h
#ifndef TASK_H
#define TASK_H
#include "MSR_Config.h"
#endif
57
Dijkstra.c
#include "Dijkstra.h"
#include "MSR_Config.h"
#include "LCD_Commands.h"
Dijkstra_lEdge_Dist[cEdge1][cEdge2] = lDistance;
Dijkstra_lEdge_Dist[cEdge2][cEdge1] = lDistance;
if(++count_edges == config_no_of_edges) {
count_edges = 0;
Dijkstra_analyse_data();
}
}
minimum = i;
}
}
58
Dijkstra_lShortest_Dist[i] =
Dijkstra_lShortest_Dist[minimum] +
Dijkstra_lEdge_Dist[minimum][i];
Dijkstra_lPrev[i] = minimum;
}
}
}
}
}
//Recursive function
if (Dijkstra_lPrev[dest] != -1)
Dijkstra_go_path(Dijkstra_lPrev[dest]);
Dijstra_Dest[i++] = dest;
}
Encoder.c
#include <p30fxxxx.h>
#include "Encoder.h"
#include "MSR_Config.h"
#include "Motor_Control.h"
#include "LCD_Commands.h"
if(motor_control_dijkstra.junction_dijkstra == 0) {
//Display the current distance travelled
LCD_printxy_string(0, 0, "Dist:");
LCD_int_to_no(6, 0, 6, encoder_lCurrentDistance);
59
}
}
temp_lPosElapsed = encoder_lPosElapsed;
temp_lCurrentDistance = encoder_lCurrentDistance;
switch(Encoder_instruction) {
case junction_turn : lDesiredDisplacement = 43; break;
case out_of_line_turn : lDesiredDisplacement = 50; break;
case _90turn : lDesiredDisplacement = 80; break;
default : break;
}
do {
Encoder_distance_measurement();
lDistance = encoder_lCurrentDistance - temp_lCurrentDistance;
} while (encoder_lPosElapsed <= (temp_lPosElapsed + lDesiredPos));
}
LCD_Commands.c
#include "LCD_Commands.h"
while(*buffer++) {
string_size++; }
buffer -= buffer2;
}
60
LCD_print_string(buffer);
}
else if(string_size > 16 && string_size < 33) {
if(y == 1){
//actually it is (15 - buffer2 + 1), 1 is the blank space
LCD_set_cursor((16-buffer2)/2);
} else if(y == 3){
LCD_set_cursor(0x10+(16-buffer2)/2);
}
while(buffer2--){
LCD_print(*buffer++);
}
buffer++;
if(y == 1){
LCD_set_cursor(0x40+(16-string_size)/2);
} else if(y == 3){
LCD_set_cursor(0x50+(16-string_size)/2);
}
LCD_print_string(buffer);
}
}
while(*buffer++){
string_size++;
}
LCD_print_string(buffer);
if(position == 0){
LCD_erase(0,0,4);
} else if(position == 1){
LCD_erase(12,0,4);
} else if(position == 2){
LCD_erase(16,0,4);
} else if(position == 3){
LCD_erase(28,0,4);
}
Delay(display_delay);
}
}
}
if(y == 1){
LCD_set_cursor(x);
} else if(y == 0){
LCD_set_cursor(0x40+x);
} else if(y == 3){
LCD_set_cursor(0x10+x);
} else if(y == 2){
LCD_set_cursor(0x50+x);
}
while(*buffer) {
LCD_print(*buffer++);
Delay(display_delay);
}
}
LCD_print_string(buffer);
}
62
LCD_print(character);
}
if(y == 1){
LCD_set_cursor(x);
} else if(y == 0){
LCD_set_cursor(0x40+x);
}
if(y == 1){
LCD_set_cursor(x);
} else if(y == 0){
LCD_set_cursor(0x40+x);
}
63
void LCD_int_to_no(unsigned char x, unsigned char y, unsigned char digit_no, unsigned int integer) {
unsigned char ten = 0, hundred = 0, thousand = 0, ten_thousand = 0;
if(y == 1){
LCD_set_cursor(x);
} else if(y == 0){
LCD_set_cursor(0x40+x);
}
LCD_print(ten_thousand);
}
if(digit_no > 3){
LCD_print(thousand);
}
if(digit_no > 2){
LCD_print(hundred);
}
if(digit_no > 1){
LCD_print(ten);
}
if(digit_no > 0){
LCD_print(integer);
}
}
ENA=1;
switch(LCD_instruction) {
case clear_display : a = 0b00000001; break;
case return_home : a = 0b00000010; break;
case cursor_increment : a = 0b00000110 + (entry_mode_set &0b00000001);
entry_mode_set |= 0b00000010; break;
case cursor_decrement : a = 0b00000100 + (entry_mode_set &0b00000001);
entry_mode_set &= 0b11111101; break;
case display_shift_on : a = 0b00000101 + (entry_mode_set &0b00000010);
entry_mode_set |= 0b00000001; break;
case display_shift_off : a = 0b00000100 + (entry_mode_set &0b00000010);
entry_mode_set &= 0b11111110; break;
case display_on : a = 0b00001100 + (display_control&0b00000011);
display_control |= 0b00000100; break;
case display_off : a = 0b00001000 + (display_control&0b00000011);
display_control &= 0b11111011; break;
case cursor_on : a = 0b00001010 + (display_control&0b00000101);
display_control |= 0b00000010; break;
case cursor_off : a = 0b00001000 + (display_control&0b00000101);
display_control &= 0b11111101; break;
case blink_on : a = 0b00001001 + (display_control&0b00000110);
display_control |= 0b00000001; break;
case blink_off : a = 0b00001000 + (display_control&0b00000110);
65
LCD_write_data(a);
ENA=1;
RS=0;
Delay(1);
ENA=0;
if(a == 0b00000001)
Delay(5454);
else if(a == 0b00000010)
Delay(5454);
else
Delay(1080);
}
void LCD_init(void) {
//LCD initialization
Delay(40905);
LCD(0b00110000, write_IR);
Delay(11454);
LCD(0b00110000, write_IR);
Delay(300);
LCD(0b00110000, write_IR);
Delay(300);
//8 bits data,2 line display, 5x8 font
LCD(0b00111000, write_IR);
//turn off display, cursor
LCD(0b00001000, write_IR);
//clear display
LCD(0b00000001, write_IR);
//auto-increment, end of LCD initialization
LCD(0b00000110, write_IR);
//turn on display, cursor, blinking
LCD(0b00001100, write_IR);
entry_mode_set = 0b00000010;
display_control = 0b00000100;
function_set = 0b00011000;
}
switch (LCD_instruction) {
case 22 : // write_IR
RS=0;
//1 Tcy=100ns / Delay1TCY();
ENA=1;
Delay(1);
ENA=0;
if(data == 0b00000001)
Delay(5454);
else if(data == 0b00000010)
Delay(5454);
else
Delay(1080);
break;
case 23 : //write_DR
RS=1;
ENA=1;
Delay(1);
ENA=0;
Delay(2000);
break;
}
}
Motor_Control.c
#include <p30fxxxx.h>
#include "Motor_Control.h"
#include "MSR_Config.h"
#include "Dijkstra.h"
#include "Encoder.h"
67
#include "LCD_Commands.h"
void Motor_Control_line_following(void) {
unsigned char temp_QEIM = 0;
unsigned char cLine = Motor_Control_update_line();
static status_t status;
if(!(motor_control_dijkstra.end_path)) {
Motor_Control_forward();
if(motor_control_dijkstra.junction_dijkstra == 0) {
LCD_printscr_string(1, "Maze Exploration");
} else {
if(motor_control_dijkstra.end_dijkstra == 0)
LCD_printscr_string(1, "Heading to destination...");
}
(status.corner_turn == 2) ?
Motor_Control_rotate_right():
Motor_Control_rotate_left();
status.corner_turn = 0;
} //Out of line during line following
else {
temp_QEIM = QEICONbits.QEIM;
QEICONbits.QEIM = 0;
69
(status.out_of_line == 1) ?
Motor_Control_rotate_right() :
Motor_Control_rotate_left();
}
(status.out_of_line == 1) ?
Motor_Control_rotate_right() :
Motor_Control_rotate_left();
} else {
//Disable QEI to ignore the distance travel after out of line
temp_QEIM = QEICONbits.QEIM;
QEICONbits.QEIM = 0;
(status.out_of_line == 1) ?
Motor_Control_rotate_right() :
Motor_Control_rotate_left();
}
if((Motor_Control_update_line() != 0b00001100)
|| (Motor_Control_update_line() != 0b00000100)
|| (Motor_Control_update_line() != 0b00001000)) {
if((Motor_Control_update_line() == 0b00010000)
|| (Motor_Control_update_line() == 0b00011000)
|| (Motor_Control_update_line() == 0b00001000)) {
Motor_Control_turn_left();
} else if((Motor_Control_update_line() == 0b00000001)
|| (Motor_Control_update_line() == 0b00000011)
|| (Motor_Control_update_line() == 0b00000010)) {
Motor_Control_turn_right();
}
Delay(_100ms * 5);
//Enable QEI to continue count distance after out of line
QEICONbits.QEIM = temp_QEIM;
LCD_int_to_no(6, 1, 6, encoder_lCurrentDistance);
Motor_Control_forward();
}
}
}
if(!Sensor_Left_Most){
cLine |= 0b00100000; }
if(!Sensor_Left){
cLine |= 0b00010000; }
if(!Sensor_Middle_Left){
cLine |= 0b00001000; }
if(!Sensor_Middle_Right){
cLine |= 0b00000100; }
if(!Sensor_Right){
cLine |= 0b00000010; }
if(!Sensor_Right_Most){
cLine |= 0b00000001; }
return cLine;
}
void Motor_Control_forward(void){
Motor_Left_1 = Motor_Right_1 = 0;
Motor_Left_2 = Motor_Right_2 = 1;
}
void Motor_Control_backward(void){
Motor_Left_1 = Motor_Right_1 = 1;
Motor_Left_2 = Motor_Right_2 = 0;
}
71
void Motor_Control_turn_left(void){
Motor_Left_1 = Motor_Right_1 = Motor_Left_2 = 0;
Motor_Right_2 = 1;
}
void Motor_Control_turn_right(void){
Motor_Left_1 = Motor_Right_1 = Motor_Right_2 = 0;
Motor_Left_2 = 1;
}
void Motor_Control_stop(void){
pwm_Left = pwm_Right = 0;
}
void Motor_Control_break(void){
Motor_Left_1 = Motor_Right_1 = Motor_Right_2 = Motor_Left_2 = 0;
}
void Motor_Control_rotate_left(void){
Motor_Left_2 = Motor_Right_1 = 0;
Motor_Left_1 = Motor_Right_2 = 1;
}
void Motor_Control_rotate_right(void){
Motor_Left_1 = Motor_Right_2 = 0;
Motor_Left_2 = Motor_Right_1 = 1;
}
void Motor_Control_junc_rotate_right(void) {
pwm_Left = pwm_Right = 0;
Motor_Control_rotate_right();
pwm_Left = pwm_Right = config_pwm_junction_path;
void Motor_Control_junc_rotate_left(void) {
pwm_Left = pwm_Right = 0;
Motor_Control_rotate_left();
pwm_Left = pwm_Right = config_pwm_junction_path;
MSR.c
#include <p30fxxxx.h>
#include "MSR_Config.h"
#include "Dijkstra.h"
#include "Encoder.h"
72
#include "Task.h"
#include "Motor_Control.h"
#include "Path.h"
#include "LCD_Commands.h"
#if __DEBUG
_FBORPOR(PBOR_ON & BORV_27 & PWRT_64 & MCLR_DIS);
#else
_FBORPOR(PBOR_OFF & PWRT_64 & MCLR_DIS);
#endif
//*************************************Mode**********************************
void Mode(unsigned char action) {
switch(action) {
case 0 : {
LCD_command(clear_display);
LCD_printscr_string(1, "MODE 23");
LCD_printxy_string(1, 0, "Line Following");
Delay(_1s);
LCD_command(clear_display);
Motor_Control_forward();
Task_add(Motor_Control_line_following, 1);
Task_add(Encoder_distance_measurement, 10);
Task_add(Path_fixed_point_new, 10);
while(1) { }
break;
}
default : {
unsigned char i;
Delay(_1s * 2);
//*********************************Main Function*************************
int main(void) {
//For 2nd digit, _x
unsigned char mode_scroll_2 = 1;
73
init();
Delay(_1ms * 5);
while(1){
LCD_int_to_no(7, 0, 1, mode_scroll_1);
LCD_int_to_no(8, 0, 1, mode_scroll_2);
if(!(Button1)){
Delay(_100ms);
if(++mode_scroll_2 == 6){
mode_scroll_2 = 0;
}
} else if(!(Button2)){
while(!(Button2)){
if(++mode_delay > 500000L){
LCD_command(clear_display);
LCD_printscr_string(1, "Mode Selected");
while(!Button2);
Delay(_100ms);
Mode((mode_scroll_1*10) + mode_scroll_2);
}
}
if(++mode_scroll_1 == 6){
mode_scroll_1 = 0;
}
}
Delay(_100ms);
mode_delay = 0;
}
}
Mode(0);
return 0;
}
MSR_Config.c
#include <p30fxxxx.h>
#include "MSR_Config.h"
#include "LCD_Commands.h"
#include "Motor_Control.h"
#include "Task.h"
74
void init(void){
//**1 as input; 0 as output
TRISB = 0x0130;
TRISC = 0x8000;
TRISD = 0x000F;
TRISE = 0x0000;
TRISF = 0x0070;
//**PWM
PWMCON1 = 0x0f30;
PWMCON2 = 0x0004;
PTCON = 0x2003;
PTPER = 511;
PTMR = 0x0000;
SEVTCMP = 0x0000;
FLTACON = 0x0000;
OVDCON = 0xFF00;
PDC1 = PDC2 = 0;
//**QEI
QEICON = 0x2780;
DFLTCON = 0x01a0;
POSCNT = config_min_poscnt;
MAXCNT = 0xffff;
//**Interrupt
//Disable all user's interrupt
SRbits.IPL = 7;
INTCON1 = 0;
INTCON2 = 0;
//Clear all interrupt flag
IFS0 = IFS1 = IFS2 = 0;
IEC0 = IEC1 = IEC2 = 0;
_T3IP = 4;
_T4IP = 5;
_T3IE = 1;
_T4IE = 1;
75
//Enable interrupt
SRbits.IPL = 0;
//**Enable rigisters
PTCONbits.PTEN = 1;
T3CONbits.TON = 1;
T4CONbits.TON = 1;
//**"Reset" detection
#if __DEBUG
if(!(RCONbits.BOR && RCONbits.POR)){
LCD_printscr_string(1, "Reset");
while(1){
led =~ led;
Delay(_100ms * 5);
}
}
RCON = 0;
#endif
}
//*********************************Interrupt*****************************
void __attribute__((__interrupt__,auto_psv)) _QEIInterrupt(void) {
_QEIIF=0;
encoder_iPosWrapped++;
POSCNT = config_min_poscnt;
led = 1;
}
_T4IF=0;
msr_iTMR4Wrapped++;
iTimes++;
#ifdef __DEBUG
while(1) {
LCD_printscr_string(1, "Oscillator Fail");
}
#endif
}
76
#ifdef __DEBUG
while(1) {
LCD_printscr_string(1, "Address Error");
}
#endif
}
#ifdef __DEBUG
while(1) {
LCD_printscr_string(1, "Stack Error");
}
#endif
}
#ifdef __DEBUG
while(1) {
LCD_printscr_string(1, "Math Error");
}
#endif
}
Path.c
#include "Path.h"
#include "Motor_Control.h"
#include "MSR_Config.h"
#include "Dijkstra.h"
#include "Encoder.h"
#include "LCD_Commands.h"
void Path_fixed_point_new(void) {
static signed char current_point = 0;
static unsigned char motor_control_count_nodes = 0;
if(motor_control_dijkstra.send_dijkstra) {
motor_control_dijkstra.send_dijkstra = 0;
if(!motor_control_dijkstra.run_dijkstra) {
if(!(motor_control_dijkstra.detect_edge)) {
++motor_control_count_nodes;
77
} else {
motor_control_dijkstra.detect_edge = 0;
direction.count_valid = 1;
}
switch(motor_control_count_nodes) {
case 2 : Path_Dist[1] = temp_encoder_lCurrentDistance;
break;
case 3 : if(direction.count_valid == 0)
Path_Dist[2] = temp_encoder_lCurrentDistance;
else
++direction.node_3;
Motor_Control_junc_rotate_left();
break;
case 4 : if(direction.count_valid == 0)
Path_Dist[3] = temp_encoder_lCurrentDistance;
else
++direction.node_4;}
Motor_Control_junc_rotate_left();
break;
case 5 : {
if(direction.count_valid == 0)
Path_Dist[4] = temp_encoder_lCurrentDistance;
else
++direction.node_5;
Motor_Control_junc_rotate_right();
break;
case 6 : if(direction.count_valid == 0)
Path_Dist[5] = temp_encoder_lCurrentDistance;
else
++direction.node_6;
Motor_Control_junc_rotate_left();
break;
case 7 : Path_Dist[6] = temp_encoder_lCurrentDistance;
break;
case 8 : if(direction.count_valid == 0)
Path_Dist[7] = temp_encoder_lCurrentDistance;
else
++direction.node_8;
Motor_Control_junc_rotate_left();
break;
case 9 : if(direction.count_valid == 0) {
Path_Dist[8] = temp_encoder_lCurrentDistance;
else
++direction.node_9;
Motor_Control_junc_rotate_right();
break;
case 10 : if(direction.count_valid == 0)
Path_Dist[9] = temp_encoder_lCurrentDistance;
else
++direction.node_10;
Motor_Control_junc_rotate_left();
break;
78
if(direction.node_9)
Motor_Control_junc_rotate_right();
else
Motor_Control_junc_rotate_right();
break;
case 16 : if((direction.node_8 == 0) || (direction.node_8 == 2)) {
if(direction.node_8 == 0)
Motor_Control_junc_rotate_right();
else
Motor_Control_junc_rotate_left();
}
break;
case 17 :
unsigned char i = 0;
Dijkstra_send_data(6, 8, Path_Dist[9]);
} else if(i == 11) {
Dijkstra_send_data(7, 9, Path_Dist[3]);
} else if(i == 12) {
Dijkstra_send_data(8,9, Path_Dist[10]);
}
}
Dijkstra_analyse_data();
Dijkstra_go_path(config_no_of_nodes);
motor_control_dijkstra.junction_dijkstra = 1;
Motor_Control_junc_rotate_left();
Delay(_100ms);
LCD_command(clear_display);
break;
default : break;
}
led = 0;
direction.count_valid = 0;
} else {
switch(Dijstra_Dest[current_point]) {
case 1 : if(Dijstra_Dest[current_point + 1] == 3) {
Motor_Control_junc_rotate_right();
} else if(Dijstra_Dest[current_point + 1] == 2) {
Motor_Control_junc_rotate_left();
} else { }
break;
case 2 : if(direction.node_6 == 0) {
Motor_Control_junc_rotate_right();
} else if(direction.node_6 == 2) {
Motor_Control_junc_rotate_left();
} else { }
break;
case 3 : if(direction.node_6 == 0) {
Motor_Control_junc_rotate_left();
} else if(direction.node_6 == 2) {
Motor_Control_junc_rotate_right();
} else { }
break;
case 4 : if(Dijstra_Dest[current_point + 1] == 7) {
if(Dijstra_Dest[current_point - 1] == 2) {
if(direction.node_5 == 0)
Motor_Control_junc_rotate_left();
} else {
if(direction.node_13 != 1)
Motor_Control_junc_rotate_right();
}
} else {
if(direction.node_13 != 0)
Motor_Control_junc_rotate_right();
}
break;
case 5 : if(((Dijstra_Dest[current_point - 1] == 1) &&
(Dijstra_Dest[current_point + 1] == 4)) ||
((Dijstra_Dest[current_point - 1] == 4) &&
Dijstra_Dest[current_point + 1] == 9))) {
Motor_Control_junc_rotate_left();
80
Motor_Control_junc_rotate_right();
}
break;
case 6 : if(Dijstra_Dest[current_point + 1] == 8) {
if(Dijstra_Dest[current_point - 1] == 3) {
if(direction.node_9 == 0)
Motor_Control_junc_rotate_left();
} else {
if((direction.node_9 == 1)
|| (direction.node_15 == 1)) {
Motor_Control_junc_rotate_left();
}
}
} else {
if(direction.node_15 != 1)
Motor_Control_junc_rotate_left();
}
break;
case 7 : if(direction.node_4 == 0) {
Motor_Control_junc_rotate_right();
} else if(direction.node_4 == 2) {
Motor_Control_junc_rotate_left();
} else { }
break;
case 8 : if(direction.node_10 == 0) {
Motor_Control_junc_rotate_left();
} else if(direction.node_10 == 2) {
Motor_Control_junc_rotate_right();
} else { }
motor_control_dijkstra.end_dijkstra = 1;
LCD_command(clear_display);
LCD_printscr_string(1, "THE END");
break;
default : break;
}
if(Dijstra_Dest[current_point++] == config_no_of_nodes) {
motor_control_dijkstra.end_path = 1;
Motor_Control_break();
}
}
Task.c
#include "Task.h"
81
#include "MSR_Config.h"