Sunteți pe pagina 1din 100

Code document:

Muticore embedded robot

Jasper Maes
3rd Bachelor Computer Science
Enrollment: 89619
jasper.maes@vub.ac.be

May 22, 2011


Contents

1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1 Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2 Code created by others . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.1 RXTX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2 TimedKeyListener . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3 Swing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3 Most important code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3.1 Graphical User Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3.2 Robotcontroller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4 Description of Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4.1 Graphical User Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4.2 Robotcontroller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
5 Code Listings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
5.1 Graphical User Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
5.2 Robotcontroller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

Date Version Description


14 May 2011 First draft Setup document and code
15 May 2011 Second draft Added first descriptions of the code
16 May 2011 Third draft Completed describing all components, added scope
17 May 2011 Fourth Draft Editing the descriptions and correcting minor mistakes
18 May 2011 Fifth Draft Final spell checking
21 May 2011 Release candidate Code update and minor changes
22 May 2011 Final version Included latest bugfixes in the code listing

Change Log

1
1 Introduction
1.1 Purpose
This document shows how all components or entities in the project were implemented. These
entities are determined by the requirements from the specifications document[5]. First, an
overview is given of the libraries we used that were created by others. Followed by a description
of the most important components of both the graphical user interface and the robot control
program. After that, all other components are described briefly. The last part of the document
consists of all code that was written for the project.
Every section is divided in two parts. These parts correspond to the two parts of the project,
the graphical user interface and the robot control program.

1.2 Scope
With this project we will implement a robot, using a multicore embedded device[9]. The user
will be able to control and steer the robot using a remote control. The robot will use sensors to
be aware of its environment and respond appropriately. For example, if the user wants to drive
the robot into a wall, it will stop before hitting the wall.

1.3 References
[1] Anonymous. Bug #4153069. http://bugs.sun.com/view_bug.do?bug_id=4153069, June
1998.

[2] Eric J. Braude and Michael E. Bernstein. Software Engineering: Modern Approaches. Wiley,
second edition, 2011. ISBN 978-0-471-69208-9.

[3] Jasper Maes. Documentation graphical user interface. http://artoo.rave.org/public/


guiDocs/, May 2011.

[4] Jasper Maes. Documentation robot controller program. http://artoo.rave.org/public/


robotControllerDocs/, May 2011.

[5] Jasper Maes. Specifications document: Multicore embedded robot. http://artoo.rave.


org/public/specifications.pdf, January 2011.

[6] Jasper Maes. Technical document: Multicore embedded robot. http://artoo.rave.org/


public/technical.pdf, March 2011.

[7] Sun Microsystems. Java SE desktop overview. http://java.sun.com/javase/


technologies/desktop/, 2010.

[8] Oracle. Class serialport. http://download.oracle.com/docs/cd/E17802_01/products/


products/javacomm/reference/api/javax/comm/SerialPort.html, 2011.

[9] Christophe Scholliers. Multicore embedded robot. http://artoo.rave.org/public/


ProjectProposal.html, October 2010.

2
2 Code created by others
2.1 RXTX
The RXTX library is used in the control program to allow the program to communicate with
the robot using a wireless Zigbee connection. It is a popular library that is also used in the IDE
used to program an Arduino to connect to a device using a serial port. The programmer will
be notified of new data in an event based approach. The programmer can also choose which
signals can trigger an event. This can be a parity error or a frame error but in this project it
was sufficient to only use the data available signal.
The implementation of RXTX is based on the abstract SerialPort class in the Java API. The
documentation of this class can be found on the Oracle website[8].

2.2 TimedKeyListener
This class is used to correct a bug in the original Java implementation of the KeyListener.
Instead of calling the keyReleased signal once, when the key is released, it is fired repeatedly,
along with the keyTyped or keyPressed signal. This behavior only occurs on the Linux platform.
Instead of directly extending the KeyListener class, we extend the TimedKeyListener which
provides the correct functionality. Other platforms can use this implementation too even if the
original implementation is correct.

2.3 Swing
The Swing libraries were used to create the graphical user interface. These libraries are based
on the older, AWT libraries. The biggest improvement of Swing over AWT is the ability to
create cross-platform applications. More information can be found on the Swing website [7].

3 Most important code


Both subsections describe the most important components in that part of the program. All
components are required to make the program look and work the way it does but some perform
a bigger task. They define how the program looks and works.

3.1 Graphical User Interface


This part of the project was implemented in Java using two external libraries, RXT for the serial
communication and the Swing libraries to visualize the sensor data.

3.1.1 SerialConn
This component takes care of the connection between the XBee and the computer. It can open
and close a serial port on the computer. The data that arrives on this serial port is made
available to the application.
First, an instruction code is read. The instruction code is used to find the number of integers
that have to be read. Those integers are the arguments for the instruction. When all arguments
are read, the data is sent to the input parser which will extract the data and process it. All
this is done in a procedure that is implemented as a state machine and called when a new byte
becomes available. This has also been described in the technical document[6].

3
3.1.2 Input parser
The input parser is a singleton class to allow only one parser to process the data. One parser
also results in one action that is performed when new data is available. The most important
method of this class is the parse method. It takes an instruction code and a number of integer
arguments as input.
Every instruction was assigned a different action. Every call to the parse function contains an
identification from the sensor that sent the value. Based on that, the correct method from the
datastore instance is called to store the value in the right place.

3.1.3 Datastore
This is also a singleton class and the model in the Model-View-Controller design pattern[2] we
used. This means that there is only one data store which keeps all the data of the system. This
data is used by the Canvas to draw the GUI.
Some values can be derived from other values. For example, if the number of rotations per
minute is updated, the driven distance is also updated.

3.1.4 Canvas
This is one of the two main constituents that form the view part of the MVC pattern. It reads
the data from the datastore and draws it on the window. Every sensor is drawn in a separate
part of the window. The components displayed on the canvas make extensive use of the Swing
libraries.

3.2 Robotcontroller
The second part of the project was created in XC and C. XC is used to access procedures and
data types that are specific on the XMOS platform. The C programming language was used to
be able to use pointers which are mainly used in the sensor data structure.

3.2.1 Sensor and SensorManager


The sensor struct and the sensormanager are always used together as sensors use pointers and
XC doesn’t support the usage of pointers. The sensormanager hides these pointers by providing
functions that don’t have pointers in their signature but use them internally. For example to
read the value of a sensor, in XC a function is called with an index and a core number. In this
function, the pointer to the sensor struct is looked up and the function that is contained in this
sensor is called.
A sensor struct contains all data that must be known about that sensor such as how the sensor
must be read, how a value must be compared with the threshold. Sometimes the value must be
smaller than the threshold where in other cases the value must be bigger. The identification of
the sensor that is required by the computer to be able to store the data in the right place is also
in this sensor struct.
The sensormanager keeps a number of sensor structs in an array and provides functions that are
syntactic sugar for retrieving and performing an operations on the sensors themselves.

4
3.2.2 Main
This is the core of the program, the main function is the most important part. Here the different
threads are started that will control the robot such as reading the sensor values, transmitting
and receiving data, controlling the motors and others.

4 Description of Code
This section contains a description of the other components. These are the less important parts
in both programs yet they are necessary to give the applications their functionality.

4.1 Graphical User Interface


The following component’s make up the graphical user interface. Every components functionality
briefly described here. In the code itself at the end of the document (section 5), more detailed
comments are given alongside the code.

4.1.1 AboutDialog
This is the about dialog which shows information about the program. It has no real functionality
in the program.

4.1.2 Message
The message class allows the program to show messages to the user. The advantage of using a
separate class for this is that the programmer can decide how the messages should be displayed,
they can be displayed in a popup box, in a separate window or on the window itself.
There are two types of messages, regular messages and error messages.

4.1.3 PreferencesDialog
In the preferences dialog, the user can set the different threshold values. The port to which the
XBee is connected on the computer can also be changed here.

4.1.4 RobotControllerApp
This class contains the main method of the application. It is the first class that will be loaded
and it will initialize some values in the constants class. It also sets the application icon and
other platform specific settings, especially on the Mac OSX platform.

4.1.5 RobotControllerView
This is the window that is the application, it creates an instance of the canvas class and adds
it to the window which is the second part of the view component in the MVC pattern. It also
creates and adds the menubar.
If a key is pressed in the window, an action is triggered and that command is sent to the robot.

5
4.1.6 UpdateAbleSensor
This class is a utility class that combines an input box from the preferences dialog with the
datastore procedure that corresponds to that input box. It keeps track of the threshold value
before the dialog was shown. If the current value is different from the previous value, the new
value is sent to the robot.

4.2 Robotcontroller
ADClib
This library is used to read the analog value that was converted to a 12 bit digital number by
the analog to digital converter. There are 4 channels available on the hardware but the code
also supports the 7 channel version of the ADC we used.

4.2.1 Initialization
This component initializes the data structures such as the sensor manager and the protocol
array for the input parser.

4.2.2 InputParser
The input parser here is the counterpart of the input parser in the graphical user interface. All
commands that are sent by the computer are parsed here and the appropriate action is called.

4.2.3 LightSensor, RangeSensor, RpmSensor and TemperatureSensor


The four sensor structs that are used in the program contain operations to read the sensor, an
action that is called when the threshold is passed, a function to compare a value to the threshold

4.2.4 Motor
This component contains the procedures that control the motors. The commands they send
require precise timing. If this timing is incorrect, the motor could rotate backwards instead of
forward.

4.2.5 XBeelib
The XBee library takes care of sending and receiving data over the Zigbee network. It can send
and receive byte and integer values.

4.2.6 xcWrapper
This library is a collection of utility functions that perform specific XC operations that C cannot
perform. By hiding the XC-specific operations inside a function, C-code can also perform these
operations. This is needed in some operations in a C file.

6
5 Code Listings
All code was documented in a style so that Doxygen can generate the documentation. This
documentation can be found online for both the graphical user interface [3] and the robot
control program [4].

5.1 Graphical User Interface


5.1.1 AboutDialog.java

1 package robotcontroller;
2
3 /∗∗
4 ∗
5 ∗ @file AboutDialog.java
6 ∗
7 ∗ This class creates and displays an about dialog.
8 ∗
9 ∗ @author Jasper Maes <jasper.maes@gmail.com>
10 ∗
11 ∗/
12 public class AboutDialog extends javax.swing.JDialog {
13
14 /∗∗
15 ∗ Creates and shows a new AboutDialog.
16 ∗
17 ∗ @param parent The parent window of the dialog
18 ∗/
19 public AboutDialog(java.awt.Frame parent) {
20 super(parent, true);
21 initComponents();
22
23 setVisible(true);
24 }
25
26
27
28 /∗∗ This method is called from within the constructor to
29 ∗ initialize the form.
30 ∗ WARNING: Do NOT modify this code. The content of this method is
31 ∗ always regenerated by the Form Editor.
32 ∗/
33 @SuppressWarnings(”unchecked”)
34 // <editor−fold defaultstate=”collapsed” desc=”Generated
Code”>//GEN−BEGIN:initComponents
35 private void initComponents() {
36
37 jLabel1 = new javax.swing.JLabel();
38 jLabel2 = new javax.swing.JLabel();
39
40 setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE ON CLOSE);
41 org.jdesktop.application.ResourceMap resourceMap =
org.jdesktop.application.Application.getInstance(robotcontroller.RobotControllerApp.class).getContext().ge

7
42 setBackground(resourceMap.getColor(”Form.background”)); // NOI18N
43 setModal(true);
44 setName(”Form”); // NOI18N
45 setResizable(false);
46
47 jLabel1.setText(resourceMap.getString(”jLabel1.text”)); // NOI18N
48 jLabel1.setName(”jLabel1”); // NOI18N
49
50 jLabel2.setIcon(resourceMap.getIcon(”jLabel2.icon”)); // NOI18N
51 jLabel2.setText(resourceMap.getString(”jLabel2.text”)); // NOI18N
52 jLabel2.setName(”jLabel2”); // NOI18N
53
54 org.jdesktop.layout.GroupLayout layout = new
org.jdesktop.layout.GroupLayout(getContentPane());
55 getContentPane().setLayout(layout);
56 layout.setHorizontalGroup(
57 layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
58 .add(layout.createSequentialGroup()
59 .addContainerGap()
60 .add(jLabel1, org.jdesktop.layout.GroupLayout.PREFERRED SIZE,
org.jdesktop.layout.GroupLayout.DEFAULT SIZE,
org.jdesktop.layout.GroupLayout.PREFERRED SIZE))
61 .add(jLabel2)
62 );
63 layout.setVerticalGroup(
64 layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
65 .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
66 .add(jLabel2)
67 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED,
org.jdesktop.layout.GroupLayout.DEFAULT SIZE, Short.MAX VALUE)
68 .add(jLabel1, org.jdesktop.layout.GroupLayout.PREFERRED SIZE,
org.jdesktop.layout.GroupLayout.DEFAULT SIZE,
org.jdesktop.layout.GroupLayout.PREFERRED SIZE)
69 .addContainerGap())
70 );
71
72 pack();
73 }// </editor−fold>//GEN−END:initComponents
74
75 // Variables declaration − do not modify//GEN−BEGIN:variables
76 private javax.swing.JLabel jLabel1;
77 private javax.swing.JLabel jLabel2;
78 // End of variables declaration//GEN−END:variables
79
80 }
5.1.2 Canvas.java

1 package robotcontroller;
2
3 import java.awt.AlphaComposite;
4 import java.awt.Color;
5 import java.awt.Font;
6 import java.awt.Graphics;

8
7 import java.awt.Graphics2D;
8 import java.awt.Rectangle;
9 import java.awt.RenderingHints;
10 import java.awt.event.MouseEvent;
11 import javax.swing.JPanel;
12 import java.awt.Image;
13 import java.awt.Point;
14 import java.awt.event.MouseAdapter;
15 import java.awt.geom.AffineTransform;
16 import java.awt.image.BufferedImage;
17
18 /∗∗
19 ∗
20 ∗ @file canvas.java
21 ∗
22 ∗ This class contains methods that are used to draw the different sensor values on a JPanel object.
23 ∗
24 ∗ @author Jasper Maes <jasper.maes@gmail.com>
25 ∗
26 ∗/
27 public class Canvas extends JPanel {
28
29 /∗∗
30 ∗ This Rectangle object contains the area where the connection icon is drawn.\n
31 ∗ It is also used to check if the user clicked this icon.
32 ∗/
33 private static final Rectangle CONN RECT = new Rectangle(555, 350,
Globals.connLostImage.getWidth(null), Globals.connLostImage.getHeight(null));
34 /∗∗ At this point, the speed information will be drawn. ∗/
35 private static final Point SPEED POINT = new Point(60, 390);
36 /∗∗ At this point, the driven distance information will be drawn. ∗/
37 private static final Point DISTANCE POINT = new Point(360, 390);
38 /∗∗
39 ∗ This Rectangle object contains the area where the warning icon is drawn.\n
40 ∗ It is also used to check if the user clicked this icon.
41 ∗/
42 private static final Rectangle WARN RECT = new Rectangle(230, 320,
Globals.warning.getWidth(null), Globals.warning.getHeight(null));
43 /∗∗ This object is used to make the images less visible. It sets the transparency to 85%. ∗/
44 private static final AlphaComposite transp =
AlphaComposite.getInstance(AlphaComposite.SRC OVER, 0.15f);
45 /∗∗ This object is used to make the images visible. It sets the transparency to 0%. ∗/
46 private static final AlphaComposite notransp =
AlphaComposite.getInstance(AlphaComposite.SRC OVER, 1.0f);
47 /∗∗
48 ∗ This variable is used to create the image of the distance sensor and the robot together.
49 ∗ This is used to make it possible to turn the whole as the robot rotates.
50 ∗/
51 private BufferedImage buffer = new BufferedImage(Globals.distanceSensor.getWidth(),
Globals.distanceSensor.getHeight(), BufferedImage.TYPE INT ARGB);
52 /∗∗ The graphics object that is used to draw on the buffer image. ∗/
53 private Graphics2D bufferGraphics = buffer.createGraphics();
54 /∗∗ The image that is shown when the connection was lost. ∗/

9
55 private Image lostImage = null;
56 /∗∗ An italic font used for drawing text. ∗/
57 private static final Font itFont = new Font(”Serif”, Font.ITALIC, 20);
58 /∗∗ A font used to draw the numbers. ∗/
59 private static final Font numFont = new Font(”Serif”, Font.PLAIN, 60);
60 /∗∗ This variable contains the instance of the DataStore. ∗/
61 private static final DataStore data = DataStore.getInstance();
62
63 /∗∗
64 ∗ This class extends the MouseAdapter class to make the application react
65 ∗ when a mouse button is clicked. It is implemented as an private inner class
66 ∗ to hide it from the rest of the program.
67 ∗/
68 private class canvasMouseListener extends MouseAdapter {
69
70 /∗∗
71 ∗ The procedure that is called when the a mouse button is clicked.
72 ∗
73 ∗ @param e A MouseEvent object containing information about the mouse click that occurred
74 ∗
75 ∗/
76 @Override
77 public void mouseClicked(MouseEvent e) {
78 if (e.getButton() == MouseEvent.BUTTON1) {
79 if (CONN RECT.contains(e.getPoint())) {
80 if (SerialConn.isConnected()) {
81 SerialConn.close();
82 } else { // Open new connection
83 new SerialConn(Globals.prefs.get(Globals.pref Port, Globals.def Port));
84 }
85
86 }
87 }
88 }
89 }
90
91 /∗∗
92 ∗ Creates new canvas
93 ∗
94 ∗ @param parent A RobotControllerView window. The new canvas will be part of this window.
95 ∗/
96 public Canvas(RobotControllerView parent) {
97 addMouseListener(new canvasMouseListener());
98
99 setSize(Globals.MIN WIDTH, Globals.MIN HEIGHT);
100
101 parent.getContentPane().setBackground(Color.BLACK);
102
103 setOpaque(false);
104 }
105
106 /∗∗
107 ∗ This method draws a given string at the given point using a graphics object.

10
108 ∗
109 ∗ @param s The string to be drawn
110 ∗ @param p The position of the string
111 ∗ @param g2 The graphics object that is used for drawing
112 ∗/
113 private static void drawString(String s, Point p, Graphics2D g2) {
114 g2.drawString(s, p.x, p.y);
115 }
116
117 /∗∗
118 ∗ This method is used to draw the different sensors and their values on the canvas.
119 ∗
120 ∗ @param g A graphics object, used to paint with
121 ∗/
122 @Override
123 public void paint(Graphics g) {
124 Graphics2D g2 = (Graphics2D) g;
125 super.paintComponent(g2);
126
127 g2.setRenderingHint(RenderingHints.KEY ANTIALIASING,
RenderingHints.VALUE ANTIALIAS ON);
128
129 boolean connected = data.getConnectionStatus();
130
131 if (!connected) { // Set transparency of all following draw operations
132 g2.setComposite(transp);
133 }
134
135 // Draw the robot and the distance sensor value
136 bufferGraphics.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
137
138 // Draw the robot image and distance sensor
139 bufferGraphics.drawImage(Globals.distanceSensor, 0, 0, this);
140 bufferGraphics.setColor(Color.BLACK);
141 int[] val = data.getDistanceSensor();
142 if (connected) {
143 bufferGraphics.fillRect(0, 0, 250, val[0] ∗ 27 + 11);
144 bufferGraphics.fillRect(250, 0, 500, val[1] ∗ 27 + 11);
145 }
146
147 bufferGraphics.drawImage(Globals.robot, 7, Globals.robot.getHeight() / 2 − 30, this);
148
149 AffineTransform at = new AffineTransform();
150 if (connected) {
151 at.rotate(data.getRotation(), 270, 210); // theta, x, y
152 }
153 at.translate(165, 30); //x, y
154 at.scale(.5, .5); // x, y
155 g2.drawImage(buffer, at, this);
156
157 // Draw the speed and driven distance
158 g2.setColor(Color.YELLOW);
159 g2.setFont(numFont);

11
160 if (connected) {
161 String s = new Integer(data.getSpeed()).toString();
162 for (int i = 0; i <= 3 − s.length(); i++) {
163 s = ”0” + s;
164 }
165
166 drawString(s, SPEED POINT, g2);
167
168 s = new Integer(data.getDriven()).toString();
169 for (int i = 0; i <= 3 − s.length(); i++) {
170 s = ”0” + s;
171 }
172
173 drawString(s, DISTANCE POINT, g2);
174 } else {
175 drawString(”000”, SPEED POINT, g2);
176 drawString(”000”, DISTANCE POINT, g2);
177 }
178 g2.setFont(itFont);
179 g2.drawString(Globals.SpeedString, SPEED POINT.x + 110, SPEED POINT.y);
180 g2.drawString(Globals.DistanceString, DISTANCE POINT.x − 30, DISTANCE POINT.y);
181
182 // Lightsensor
183 at = new AffineTransform();
184 at.translate(560, 30);
185 at.scale(0.65, 0.65);
186 g2.setColor(Color.yellow);
187 if (connected) {
188 g2.fillRect(560, (int) (30 + (26 + data.getLightSensor() ∗ 70) ∗ 0.65), (int) (31 ∗ 0.65),
(int) ((DataStore.MAX LIGHT SENSOR − data.getLightSensor()) ∗ 70 ∗ 0.65));
189 }
190 g2.drawImage(Globals.lightSensor, at, this);
191
192 // Temperaturesensor
193 at = new AffineTransform();
194 at.translate(500, 45);
195 at.scale(0.55, 0.55);
196 g2.setColor(Color.red);
197 int height = (int) ((75 + data.getTemperatureSensor() ∗ 4.2) ∗ 0.55);
198 if (connected) {
199 g2.fillRect(505, 318 − height, 35, height);
200 }
201 g2.drawImage(Globals.temperatureSensor, at, this);
202
203 // Connection status
204 Image connection = null;
205 if (connected) {
206 connection = Globals.connectedImage;
207 lostImage = null;
208 } else {
209 connection = Globals.connLostImage;
210 lostImage = Globals.lostMessage;
211 }

12
212
213 g2.drawImage(connection, (int) CONN RECT.getX(), (int) CONN RECT.getY(), this);
214
215 // draw all next things transparent
216 if ((data.getDistanceSensor()[0] != DataStore.MAX DISTANCE SENSOR) ||
(data.getDistanceSensor()[1] != DataStore.MAX DISTANCE SENSOR)) {
217 g2.setComposite(transp);
218 }
219
220 // Draw the warning symbol
221 g2.drawImage(Globals.warning, WARN RECT.x, WARN RECT.y, this);
222
223 g2.setComposite(notransp);
224 g2.drawImage(lostImage, 5, 120, this);
225 }
226
227 /∗∗
228 ∗ This method is called when new data is available in the DataStore
229 ∗/
230 public synchronized void newDataAvailable() {
231 repaint();
232 }
233 }
5.1.3 DataStore.java

1 package robotcontroller;
2
3 /∗∗
4 ∗
5 ∗ @file DataStore.java
6 ∗
7 ∗ The data store implemented as a singleton class.\n
8 ∗ It contains the value of each sensor as it was sent to the computer.
9 ∗
10 ∗ @author Jasper Maes <jasper.maes@gmail.com>
11 ∗
12 ∗/
13 public class DataStore {
14
15 /∗∗ The only instance of this singleton class ∗/
16 private static final DataStore INSTANCE = new DataStore();
17 /∗∗ Connection status. True if connected ∗/
18 private boolean connectionStatus = false;
19 /∗∗ Variable that stores the speed of the left motor. ∗/
20 private int leftSpeed = 0;
21 /∗∗ Variable that stores the speed of the right motor. ∗/
22 private int rightSpeed = 0;
23 /∗∗ Variable that stores whether the speed should be updated on the canvas or not. ∗/
24 private static boolean speedEnabled = true;
25 /∗∗ The distance the left wheel has driven. ∗/
26 private long leftDriven = 0;
27 /∗∗ The distance the right wheel has driven. ∗/
28 private long rightDriven = 0;

13
29 /∗∗ The previous value of the distance the left wheel has driven. ∗/
30 private double lastLeftDriven = 0;
31 /∗∗ The previous value of the distance the right wheel has driven. ∗/
32 private double lastRightDriven = 0;
33 /∗∗ Variable that stores whether the driven distance should be updated on the canvas or not. ∗/
34 private static boolean drivenEnabled = true;
35 /∗∗ The number of rotations per minute the left wheel makes. ∗/
36 private int leftRpm = 0;
37 /∗∗ The number of rotations per minute the right wheel makes. ∗/
38 private int rightRpm = 0;
39 /∗∗
40 ∗ The last time the left rpm value was updated.
41 ∗/
42 private long lastleftrpmtime = System.currentTimeMillis() / 1000;
43 /∗∗
44 ∗ The last time the right rpm value was updated.
45 ∗/
46 private long lastrightrpmtime = System.currentTimeMillis() / 1000;
47 /∗∗
48 ∗ The circumference of the wheels on the robot.
49 ∗ This value is used to calculate the driven distance and the speed.
50 ∗/
51 private static double WHEEL CIRC = 0;
52 /∗∗
53 ∗ The distance between both wheels on the robot. This is used to
54 ∗ calculate how the robot turns.
55 ∗/
56 private static double WHEEL DISTANCE = 0;
57 /∗∗
58 ∗ The number of radians the robot has rotated.
59 ∗/
60 private double rotation = 0;
61 /∗∗
62 ∗ The boolean value that stores whether the rotation should be shown on the canvas.
63 ∗/
64 private static boolean rotationEnabled = true;
65 /∗∗
66 ∗ The value of the left distance senor.\n
67 ∗ The value was optimized to be displayed on the canvas.
68 ∗/
69 private byte leftDistanceSensor = MIN DISTANCE SENSOR;
70 /∗∗
71 ∗ The value of the right distance senor.\n
72 ∗ The value was optimized to be displayed on the canvas.
73 ∗/
74 private byte rightDistanceSensor = MIN DISTANCE SENSOR;
75 /∗∗ The minimal value of the distance sensor on the canvas in number of blocks. ∗/
76 public static final byte MIN DISTANCE SENSOR = 0;
77 /∗∗ The maximal value of the distance sensor on the canvas in number of blocks. ∗/
78 public static final byte MAX DISTANCE SENSOR = 8;
79 /∗∗ The boolean value that stores whether the distance to objects should be shown on the canvas. ∗/
80 private static boolean distanceSensorEnabled = true;
81 /∗∗ The value of the light sensor, optimized to be displayed on the canvas. ∗/

14
82 private byte lightSensor = MAX LIGHT SENSOR;
83 /∗∗ The minimal value of the light sensor on the canvas in number of light bulbs. ∗/
84 public static final byte MIN LIGHT SENSOR = 0;
85 /∗∗ The maximal value of the distance sensor on the canvas in number of light bulbs. ∗/
86 public static final byte MAX LIGHT SENSOR = 6;
87 /∗∗ The boolean value that stores whether the value of the light sensor should be shown on the
canvas. ∗/
88 private static boolean lightEnabled = true;
89 /∗∗ The value of the temperature sensor. ∗/
90 private byte temperatureSensor = MIN TEMPERATURE SENSOR;
91 /∗∗ The minimal value of the light sensor on the canvass. ∗/
92 public static final byte MIN TEMPERATURE SENSOR = 0;
93 /∗∗ The maximal value of the distance sensor on the canvas. ∗/
94 public static final byte MAX TEMPERATURE SENSOR = 100;
95 /∗∗ The boolean value that stores whether the value of the temperature sensor should be shown on
the canvas. ∗/
96 private static boolean temperatureEnabled = true;
97
98 /∗∗
99 ∗ The constructor of this class is private so that no new objects can be created.\n
100 ∗ In a singleton class, there should only be 1.\n
101 ∗ This function is called when the application is initialized to create the instance
102 ∗ that is used throughout the application.
103 ∗/
104 public DataStore() {
105 double WHEEL DIAM = Globals.prefs.getInt(Globals.pref WheelDiam,
Globals.def WheelDiam) / 1000;
106 WHEEL CIRC = Math.PI ∗ WHEEL DIAM;
107 WHEEL DISTANCE = Globals.prefs.getInt(Globals.pref WheelDist, Globals.def WheelDist) /
1000;
108 }
109
110 /∗∗
111 ∗ This function returns the only instance of this class. It can then be used to get
112 ∗ a sensor value or to update a value.
113 ∗
114 ∗ @return The instance of this class
115 ∗/
116 public static DataStore getInstance() {
117 return INSTANCE;
118 }
119
120 /∗∗
121 ∗ Returns the connection status
122 ∗
123 ∗ @return True or false depending on the status of the connection
124 ∗/
125 public boolean getConnectionStatus() {
126 return connectionStatus;
127 }
128
129 /∗∗
130 ∗ Updates the connection status.

15
131 ∗
132 ∗ @param conn A boolean indicating whether the connection is active or not.
133 ∗/
134 public void setConnectionStatus(boolean conn) {
135 connectionStatus = conn;
136 }
137
138 /∗∗
139 ∗ Method to set the left rpm.\n
140 ∗ It also updates the current speed and rotation.
141 ∗
142 ∗ @param r The number of rotations per minute of the left motor
143 ∗/
144 public void setLeftRpm(int r) {
145 updateDriven();
146 lastleftrpmtime = System.currentTimeMillis() / 1000;
147 leftRpm = r;
148 updateSpeed();
149 updateRotation();
150 }
151
152 /∗∗
153 ∗ Method to set the right rpm.\n
154 ∗ It also updates the current speed and rotation.
155 ∗
156 ∗ @param r The number of rotations per minute of the right motor
157 ∗/
158 public void setRightRpm(int r) {
159 updateDriven();
160 lastrightrpmtime = System.currentTimeMillis() / 1000;
161 rightRpm = r;
162 updateSpeed();
163 updateRotation();
164 }
165
166 /∗∗
167 ∗ Method to set the rpm of both the left and right motor at the same time.\n
168 ∗ It also updates the current speed and rotation.
169 ∗
170 ∗ @param rleft The number of rotations per minute of the left motor
171 ∗ @param rright The number of rotations per minute of the right motor
172 ∗/
173 public void setRpm(int rleft, int rright) {
174 setLeftRpm(rleft);
175 setRightRpm(rright);
176 }
177
178 /∗∗
179 ∗ Method to recalculate and set the new speed of the robot based on the
180 ∗ number of rotations per minute and the size of the wheels.
181 ∗/
182 private void updateSpeed() {
183 setLeftSpeed((int) (leftRpm ∗ WHEEL CIRC / 1000));

16
184 setRightSpeed((int) (rightRpm ∗ WHEEL CIRC / 1000));
185 }
186
187 /∗∗
188 ∗ Method to update the driven distance of the robot based on the
189 ∗ speed and the time that has passed since the last update.
190 ∗/
191 private void updateDriven() {
192 long time = System.currentTimeMillis() / 1000;
193 addLeftDriven(getLeftSpeed() ∗ 1000 ∗ (time − lastleftrpmtime) / (60 ∗ 60));
194 addRightDriven(getRightSpeed() ∗ 1000 ∗ (time − lastrightrpmtime) / (60 ∗ 60));
195 }
196
197 /∗∗
198 ∗ Accessor for the speed of the right motor.
199 ∗
200 ∗ @return The speed of the right motor
201 ∗/
202 private int getRightSpeed() {
203 return rightSpeed;
204 }
205
206 /∗∗
207 ∗ Accessor for the speed of the left motor.
208 ∗
209 ∗ @return The speed of the left motor
210 ∗/
211 private int getLeftSpeed() {
212 return leftSpeed;
213 }
214
215 /∗∗
216 ∗ Returns the speed of the robot by taking the mean of the speed of the
217 ∗ left motor and the right motor.
218 ∗
219 ∗ @return The speed of the robot
220 ∗/
221 public int getSpeed() {
222 if (speedEnabled) {
223 return (getLeftSpeed() + getRightSpeed()) / 2;
224 } else {
225 return 0;
226 }
227 }
228
229 /∗∗
230 ∗ Setter for the speed of the left motor
231 ∗
232 ∗ @param spd The speed of the left motor
233 ∗/
234 private void setLeftSpeed(int spd) {
235 leftSpeed = spd;
236 }

17
237
238 /∗∗
239 ∗ Setter for the speed of the right motor
240 ∗
241 ∗ @param spd The speed of the right motor
242 ∗/
243 private void setRightSpeed(int spd) {
244 rightSpeed = spd;
245 }
246
247 /∗∗
248 ∗ This method will change whether the speed must be displayed or not.\n
249 ∗ If it was true, it becomes false and the other way around.
250 ∗/
251 public static void switchEnableSpeed() {
252 speedEnabled = !speedEnabled;
253 }
254
255 /∗∗
256 ∗ Returns the speed of the robot by taking the mean of the speed of the
257 ∗ left motor and the right motor.
258 ∗
259 ∗ @return The speed of the robot
260 ∗/
261 public int getDriven() {
262 return (int) ((leftDriven + rightDriven) / 2);
263 }
264
265 /∗∗
266 ∗ Add a distance that was driven to the current driven distance for the left motor.
267 ∗
268 ∗ @param drv The amount to be added.
269 ∗/
270 private void addLeftDriven(long drv) {
271 lastLeftDriven = drv;
272 leftDriven += drv;
273 }
274
275 /∗∗
276 ∗ Add a distance that was driven to the current driven distance for the right motor.
277 ∗
278 ∗ @param drv The amount to be added.
279 ∗/
280 private void addRightDriven(long drv) {
281 lastRightDriven = drv;
282 rightDriven += drv;
283 }
284
285 /∗∗
286 ∗ This method will change whether the driven distance must be displayed or not.\n
287 ∗ If it was true, it becomes false and the other way around.
288 ∗/
289 public static void switchEnableDriven() {

18
290 drivenEnabled = !drivenEnabled;
291 }
292
293 /∗∗
294 ∗ Accessor for the distance sensor values.
295 ∗
296 ∗ @return An array of 2 integers, the left and right distance sensor
297 ∗/
298 public int[] getDistanceSensor() {
299 int[] result;
300 if (distanceSensorEnabled) {
301 result = new int[]{leftDistanceSensor, rightDistanceSensor};
302 } else {
303 result = new int[]{MIN DISTANCE SENSOR, MIN DISTANCE SENSOR};
304 }
305 return result;
306 }
307
308 /∗∗
309 ∗ Set the value of the left distance sensor. It’s value is scaled to fit
310 ∗ within the range that can be displayed on the canvas.
311 ∗
312 ∗ @param val The new value of the distance sensor
313 ∗/
314 public void setLeftDistanceSensor(int val) {
315 leftDistanceSensor = scaleValue(val, MIN DISTANCE SENSOR, MAX DISTANCE SENSOR,
Globals.pref MaxDist, Globals.def MinDist, Globals.def MaxDist);
316 }
317
318 /∗∗
319 ∗ Set the value of the right distance sensor. It’s value is scaled to fit
320 ∗ within the range that can be displayed on the canvas.
321 ∗
322 ∗ @param val The new value of the distance sensor
323 ∗/
324 public void setRightDistanceSensor(int val) {
325 rightDistanceSensor = scaleValue(val, MIN DISTANCE SENSOR,
MAX DISTANCE SENSOR, Globals.pref MaxDist, Globals.def MinDist,
Globals.def MaxDist);
326 }
327
328 /∗∗
329 ∗ This method will change whether the distance to objects must be displayed or not.\n
330 ∗ If it was true, it becomes false and the other way around.
331 ∗/
332 public static void switchEnableDist() {
333 distanceSensorEnabled = !distanceSensorEnabled;
334 }
335
336 /∗∗
337 ∗ Returns how much radians the robot has rotated.
338 ∗
339 ∗ @return The number of radians

19
340 ∗/
341 public double getRotation() {
342 if (rotationEnabled) {
343 return rotation;
344 } else {
345 return 0;
346 }
347 }
348
349 /∗∗
350 ∗ Update the rotation based on the distance that was driven by the left and right
351 ∗ motor and the distance between the wheels.
352 ∗/
353 private void updateRotation() {
354 addRotation((lastLeftDriven − lastRightDriven) / WHEEL DISTANCE);
355 }
356
357 /∗∗
358 ∗ Add a number of radians to the rotation.
359 ∗
360 ∗ @param radians The number of radians to be added.
361 ∗/
362 private void addRotation(double radians) {
363 rotation += radians;
364 }
365
366 /∗∗
367 ∗ Add a number of degrees to the rotation.
368 ∗
369 ∗ @param degrees The number of degrees to be added.
370 ∗/
371 public void addRotationDegrees(int degrees) {
372 addRotation(Math.toRadians(degrees));
373 }
374
375 /∗∗
376 ∗ This method will change whether the rotation of the sensor must be displayed or not.\n
377 ∗ If it was true, it becomes false and the other way around.
378 ∗/
379 public static void switchEnableRotation() {
380 rotationEnabled = !rotationEnabled;
381 }
382
383 /∗∗
384 ∗ Returns the value of the light sensor, scaled to be displayed on the canvas.
385 ∗
386 ∗ @return The value of the light sensor
387 ∗/
388 public int getLightSensor() {
389 if (lightEnabled) {
390 return lightSensor;
391 } else {
392 return MAX LIGHT SENSOR;

20
393 }
394 }
395
396 /∗∗
397 ∗ Setter for the light sensor value. The value is scaled to fit within the
398 ∗ ranges that can be displayed on the canvas.
399 ∗
400 ∗ @param val The new value light intensity
401 ∗/
402 public void setLightSensor(int val) {
403 lightSensor = scaleValue(val, MIN LIGHT SENSOR, MAX LIGHT SENSOR,
Globals.pref MaxLight, Globals.def MinLight, Globals.def MaxLight);
404 }
405
406 /∗∗
407 ∗ This method will change whether the light intensity must be displayed or not.\n
408 ∗ If it was true, it becomes false and the other way around.
409 ∗/
410 public static void switchEnableLight() {
411 lightEnabled = !lightEnabled;
412 }
413
414 /∗∗
415 ∗ Returns the value of the temperature sensor, scaled to be displayed on the canvas.
416 ∗
417 ∗ @return The value of the temperature sensor
418 ∗/
419 public int getTemperatureSensor() {
420 if (temperatureEnabled) {
421 return temperatureSensor;
422 } else {
423 return MIN TEMPERATURE SENSOR;
424 }
425 }
426
427 /∗∗
428 ∗ Setter for the temperature sensor value. The value is scaled to fit within the
429 ∗ ranges that can be displayed on the canvas.
430 ∗
431 ∗ @param temp The new value temperature
432 ∗/
433 public void setTemperatureSensor(int temp) {
434 temperatureSensor = scaleValue(temp, MIN TEMPERATURE SENSOR,
MAX TEMPERATURE SENSOR, Globals.pref MaxTemp, Globals.def MinTemp,
Globals.def MaxTemp);
435 }
436
437 /∗∗
438 ∗ This method will change whether the temperature must be displayed or not.\n
439 ∗ If it was true, it becomes false and the other way around.
440 ∗/
441 public static void switchEnableTemp() {
442 temperatureEnabled = !temperatureEnabled;

21
443 }
444
445 /∗∗
446 ∗ This method is used to scale a value to fit in the range that can be displayed by the canvas.\n
447 ∗ If the value is larger than the threshold, the minimal displayable value is returned. The same is
448 ∗ applied when the value is smaller than the threshold. In that case the largest possible value is
returned.
449 ∗ If not, the range between the minimal value of a sensor and it’s threshold is divided into as
much parts as
450 ∗ can be displayed by the canvas. Based on that, the value that has to be displayed can be
determined.
451 ∗
452 ∗ @param v The value to be scaled
453 ∗ @param min The minimal value that can be displayed
454 ∗ @param max The maximal value that can be displayed
455 ∗ @param sThres The string to read the threshold from the preferences
456 ∗ @param minDef The minimal value of the sensor
457 ∗ @param maxDef The default maximal value (used if the threshold is not in the preferences)
458 ∗
459 ∗ @return The scaled value, between min and max.
460 ∗/
461 private byte scaleValue(int v, byte min, byte max, String sThres, int minDef, int maxDef) {
462 double thres = Globals.prefs.getInt(sThres, maxDef);
463
464 if (v > thres) { // If the value is larger than the threshold
465 return min; // return the minimal value
466 }
467
468 if (v < minDef) { // If the value is smaller than the threshold
469 return min; // return the maximal value
470 }
471
472 double parts = max − min; // calculate the number of parts that can be displayed
473 double intervalSize = (thres − minDef) / parts; // calculate the size of 1 part compared to
the interval that can be displayed
474
475 byte curr = (byte) ((v − minDef) / intervalSize); // calculate the value that is to be displayed
476
477 return (byte) (max − curr);
478 }
479 }
5.1.4 Globals.java

1 package robotcontroller;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import java.awt.image.BufferedImage;
6 import java.io.IOException;
7 import java.util.prefs.Preferences;
8 import javax.swing.Timer;
9 import javax.imageio.ImageIO;
10

22
11 /∗∗
12 ∗
13 ∗ @file Globals.java
14 ∗
15 ∗ This class contains all global variables used throughout the program.
16 ∗
17 ∗ @author Jasper Maes <jasper.maes@gmail.com>
18 ∗
19 ∗/
20 public class Globals {
21
22 /∗∗ Milliseconds to block the application while waiting for port to open. ∗/
23 public final static int SerialWait = 3000;
24 /∗∗ Milliseconds to wait before sending next byte. ∗/
25 public final static int BIT TIME = 600;
26 /∗∗ The default value for the port name. ∗/
27 public final static String def Port = ”/dev/ttyUSB0”;
28 /∗∗ Default bits per second for COM port. ∗/
29 public final static int def DataRate = 9600;
30 /∗∗ The time the robot gets to respond to a ping request. ∗/
31 public final static int def Timeout = 7000;
32 /∗∗ The default wheel diameter. ∗/
33 public final static int def WheelDiam = 135;
34 /∗∗ The default distance between the wheels. ∗/
35 public final static int def WheelDist = 40;
36 /∗∗ The number of data bits to be sent in 1 byte. ∗/
37 public final static int def DataBits = 8;
38 /∗∗ The parity check when sending data. ∗/
39 public final static String def Parity = ”None”;
40 /∗∗ The number of stop bits when sending data. ∗/
41 public final static String def StopBits = ”1”;
42 /∗∗ The default maximum speed. ∗/
43 public final static int def MaxSpeed = 25;
44 /∗∗ The default maximum light intensity. ∗/
45 public final static int def MaxLight = 2000;
46 /∗∗ The default maximum temperature. ∗/
47 public final static int def MaxTemp = 40;
48 /∗∗ The default maximum distance to an object. ∗/
49 public final static int def MaxDist = 80;
50 /∗∗ The default minimum speed. ∗/
51 public final static int def MinSpeed = 0;
52 /∗∗ The default minimum light intensity. ∗/
53 public final static int def MinLight = 1200;
54 /∗∗ The default minimum temperature. ∗/
55 public final static int def MinTemp = 10;
56 /∗∗ The default minium distance to an object. ∗/
57 public final static int def MinDist = 10;
58 /∗∗ The preference string for the data rate of the serial connection. ∗/
59 public static final String pref DataRate = ”DataRate”;
60 /∗∗ The preference string for the number of data bits of the serial connection. ∗/
61 public static final String pref DataBits = ”DataBits”;
62 /∗∗ The preference string for the type of parity check of the serial connection. ∗/
63 public static final String pref Parity = ”Parity”;

23
64 /∗∗ The preference string for the number of stop bits of the serial connection. ∗/
65 public static final String pref StopBits = ”StopBits”;
66 /∗∗ The preference string for the timeout of a ping request. ∗/
67 public static final String pref Timeout = ”Timeout”;
68 /∗∗ The preference string to retrieve the name of the serial port. ∗/
69 public static final String pref Port = ”Port”;
70 /∗∗ The preference string for the maximum speed. ∗/
71 public static final String pref MaxSpeed = ”MaxSpeed”;
72 /∗∗ The preference string for the maximal light intensity. ∗/
73 public static final String pref MaxLight = ”MaxLight”;
74 /∗∗ The preference string for the maximum temperature. ∗/
75 public static final String pref MaxTemp = ”MaxTemp”;
76 /∗∗ The preference string for the maximum distance. ∗/
77 public static final String pref MaxDist = ”MaxDist”;
78 /∗∗ The preference string for the wheel diameter. ∗/
79 public static final String pref WheelDiam = ”WheelDiam”;
80 /∗∗ The preference string for the distance between the 2 wheels. ∗/
81 public static final String pref WheelDist = ”WheelDist”;
82 /∗∗ The image for the connected status button. ∗/
83 public static BufferedImage connectedImage = null;
84 /∗∗ The image for the connection lost status button. ∗/
85 public static BufferedImage connLostImage = null;
86 /∗∗ The image of the robot used as application icon and in the window. ∗/
87 public static BufferedImage robot = null;
88 /∗∗ A warning symbol. ∗/
89 public static BufferedImage warning = null;
90 /∗∗ The distance sensor image. ∗/
91 public static BufferedImage distanceSensor = null;
92 /∗∗ The temperature sensor image. ∗/
93 public static BufferedImage temperatureSensor = null;
94 /∗∗ The light sensor image. ∗/
95 public static BufferedImage lightSensor = null;
96 /∗∗ the lost connection image. ∗/
97 public static BufferedImage lostMessage = null;
98 /∗∗ The width of the window. ∗/
99 public static final int MIN WIDTH = 620;
100 /∗∗ The height of the window ∗/
101 public static final int MIN HEIGHT = 450;
102 /∗∗ The number of bits an integer requires on the XMOS device. ∗/
103 public static final int INT SIZE = 32;
104 /∗∗ The number of bits a byte requires on the XMOS device. ∗/
105 public static final int BYTE SIZE = 8;
106 /∗∗ The number of bytes in integer on the XMOS device. ∗/
107 public static final int INT BYTE CNT = INT SIZE / BYTE SIZE;
108 /∗∗ The canvas on which the data is drawn. ∗/
109 public static Canvas cv = null;
110 /∗∗ The time between 2 pings. ∗/
111 public final static int PING INTERVAL = 1000;
112 /∗∗ The timer which should be restarted within the timeout value, if not, the connection is
considered to be broken. ∗/
113 public static Timer pingTimeoutTimer = null;
114 /∗∗ The timer that will send the ping commands. ∗/
115 public static Timer pingTimer = null;

24
116 /∗∗ The object that stores all the users preferences. ∗/
117 public static final Preferences prefs = Preferences.userNodeForPackage(Globals.class.getClass());
118 /∗∗ The command code to update a threshold value on the robot. ∗/
119 public static final char ThresholdCode = ’T’;
120 /∗∗ The command code for the ping request ∗/
121 public static final char PingCode = ’P’;
122 /∗∗ The command code to make the robot turn left ∗/
123 public static final char MotorLeftCode = ’L’;
124 /∗∗ The command code to make the robot turn right ∗/
125 public static final char MotorRightCode = ’R’;
126 /∗∗ The command code to make the robot move forward ∗/
127 public static final char MotorForwardCode = ’F’;
128 /∗∗ The command code to make the robot move backward ∗/
129 public static final char MotorBackwardCode = ’B’;
130 /∗∗ The command code to make the robot stop ∗/
131 public static final char MotorStopCode = ’S’;
132 /∗∗ The command code for a sensor value ∗/
133 public static final char SensorValueCode = ’V’;
134 /∗∗ The type code for a distance sensor value ∗/
135 public static final char DistanceTypeCode = ’D’;
136 /∗∗ The type code for a rpm sensor value ∗/
137 public static final char RPMTypeCode = ’R’;
138 /∗∗ The type code for a temperature sensor value ∗/
139 public static final char TemperatureTypeCode = ’T’;
140 /∗∗ The type code for a light sensor value ∗/
141 public static final char LightTypeCode = ’L’;
142 /∗∗ The id for a left sensor value ∗/
143 public static final char LeftId = ’L’;
144 /∗∗ The id for a right sensor value ∗/
145 public static final char RightId = ’R’;
146 /∗∗ The string that indicates the unit in which the speed is measured. ∗/
147 public static final String SpeedString = ”km/h”;
148 /∗∗ The string that indicates the unit in which the driven distance is measured. ∗/
149 public static final String DistanceString = ”m”;
150
151 /∗∗
152 ∗ The method that must be called before creating a canvas. This reads different image files from
the
153 ∗ resources and puts them in an image object. The 2 timers for the ping are also
154 ∗/
155 public static void initialise() {
156
157 pingTimer = new Timer(Globals.PING INTERVAL, new ActionListener() {
158
159 @Override
160 public void actionPerformed(ActionEvent e) {
161 if (!pingTimeoutTimer.isRunning()) {
162 pingTimeoutTimer.start();
163 }
164 SerialConn.write(’P’);
165 }
166 });
167 pingTimer.stop();

25
168 pingTimer.setRepeats(true);
169
170 pingTimeoutTimer = new Timer(Globals.PING INTERVAL, new ActionListener() {
171
172 @Override
173 public void actionPerformed(ActionEvent e) {
174 pingTimer.stop();
175 pingTimeoutTimer.stop();
176 DataStore.getInstance().setConnectionStatus(false);
177 Globals.cv.newDataAvailable();
178 }
179 });
180 pingTimeoutTimer.stop();
181 pingTimeoutTimer.setRepeats(true);
182 pingTimeoutTimer.setInitialDelay(PING INTERVAL);
183
184 try {
185 connectedImage =
ImageIO.read(RobotControllerApp.class.getResourceAsStream(”resources/connected.png”));
186 connLostImage =
ImageIO.read(RobotControllerApp.class.getResourceAsStream(”resources/connLost.png”));
187 robot =
ImageIO.read(RobotControllerApp.class.getResourceAsStream(”resources/robot.png”));
188 warning =
ImageIO.read(RobotControllerApp.class.getResourceAsStream(”resources/warning.png”));
189 distanceSensor =
ImageIO.read(RobotControllerApp.class.getResourceAsStream(”resources/distanceSensor.png”));
190 lightSensor =
ImageIO.read(RobotControllerApp.class.getResourceAsStream(”resources/light.png”));
191 temperatureSensor =
ImageIO.read(RobotControllerApp.class.getResourceAsStream(”resources/temperature.png”));
192 lostMessage =
ImageIO.read(RobotControllerApp.class.getResourceAsStream(”resources/lostMessage.png”));
193
194 } catch (IOException e) {
195 System.out.println(e.getMessage());
196
197 }
198 }
199 }
5.1.5 InputParser.java

1 package robotcontroller;
2
3 import java.lang.reflect.InvocationTargetException;
4 import java.lang.reflect.Method;
5 import java.util.ArrayList;
6
7 /∗∗
8 ∗
9 ∗ @file InputParser.java
10 ∗
11 ∗ The input parser implemented as a singleton class.\n

26
12 ∗ This class contains a few method that can be used to parse a code and
13 ∗ integer values, add a view that has to be notified of new data or remove
14 ∗ such a view.
15 ∗
16 ∗ @author Jasper Maes <jasper.maes@gmail.com>
17 ∗
18 ∗/
19 public class InputParser {
20
21 /∗∗ The instance of this singleton class. ∗/
22 private static final InputParser instance = new InputParser();
23 /∗∗ The views that must be notified when new data is added to the DataStore. ∗/
24 private static ArrayList<Object> views;
25 /∗∗ The array that contains how many integer values follow on a certain operation code. ∗/
26 private static int[] protocol;
27 /∗∗ This variable contains the instance of the DataStore. ∗/
28 private static final DataStore data = DataStore.getInstance();
29
30 /∗∗
31 ∗ The private constructor from this class. It is called when the application is
32 ∗ initialized to create an instance.\n
33 ∗ It initializes the protocol array with the required codes and their corresponding amount of
integer values.
34 ∗/
35 public InputParser() {
36 views = new ArrayList<Object>();
37 protocol = new int[128];
38
39 for (int i = 0; i < protocol.length; i++) {
40 protocol[i] = −1;
41 }
42
43 protocol[Globals.PingCode] = 0;
44 protocol[Globals.SensorValueCode] = 3; // sensor type, sensor number and value
45
46 }
47
48 /∗∗
49 ∗ This method adds a view that will be notified of the new data.
50 ∗
51 ∗ @param v The view to be added. This can be any object as long as it
52 ∗ has a newDataAvailable method that can be called.
53 ∗/
54 public void addView(Object v) {
55 views.add(v);
56 }
57
58 /∗∗
59 ∗ Remove a previously added view that sits at an index i.
60 ∗
61 ∗ @param v The view to be removed
62 ∗/
63 public void removeView(Object v) {

27
64 views.remove(v);
65 }
66
67 /∗∗
68 ∗ This method is called when new data was added to the DataStore.\n
69 ∗ It calls the newDataAvailable method in each of these views. If there is no such method,
70 ∗ the view is removed so it won’t be considered the next time.
71 ∗/
72 public void alertAll() {
73 for (Object view : views) {
74 try {
75 Method method = view.getClass().getMethod(”newDataAvailable”);
76 method.invoke(view);
77 } catch (NoSuchMethodException e) {
78 removeView(view);
79 } catch (InvocationTargetException e) {
80 } catch (IllegalAccessException e) {
81 removeView(view);
82 }
83 }
84 }
85
86 /∗∗
87 ∗ The method that will parse a command without arguments.
88 ∗
89 ∗ @param code The command code
90 ∗/
91 public void parse(char code) {
92 parse(code, null);
93 }
94
95 /∗∗
96 ∗ The method that will parse a command and it’s arguments.
97 ∗
98 ∗ @param code The command code
99 ∗ @param args The arguments to be processed
100 ∗/
101 public void parse(char code, int[] args) {
102 switch (code) {
103 case Globals.PingCode:
104 Globals.pingTimeoutTimer.stop();
105 break;
106 case Globals.SensorValueCode:
107 char type = (char) args[0];
108 char id = (char) args[1];
109 int val = args[2];
110 switch (type) {
111 case Globals.DistanceTypeCode:
112 if (id == Globals.LeftId) {
113 data.setLeftDistanceSensor(val);
114 } else if (id == Globals.RightId) {
115 data.setRightDistanceSensor(val);
116 }

28
117 break;
118 case Globals.RPMTypeCode:
119 if (id == Globals.LeftId) {
120 data.setLeftRpm(val);
121 } else if (id == Globals.RightId) {
122 data.setRightRpm(val);
123 }
124 break;
125 case Globals.TemperatureTypeCode:
126 data.setTemperatureSensor(val);
127 break;
128 case Globals.LightTypeCode:
129 data.setLightSensor(val);
130 break;
131 }
132
133 break;
134 }
135
136 alertAll();
137 }
138
139 /∗∗
140 ∗ Get the instance of this class
141 ∗
142 ∗ @return The InputerParser instance
143 ∗/
144 public static InputParser getInstance() {
145 return instance;
146 }
147
148 /∗∗
149 ∗ Getter for the number of integer values that accompany a command code.
150 ∗
151 ∗ @param code The code whose argument count is needed
152 ∗
153 ∗ @return The number of integer values that the code requires
154 ∗/
155 public static int getProtocolCount(char code) {
156 return protocol[code];
157 }
158
159 /∗∗
160 ∗ The length of the protocol, the number of possible commands.
161 ∗
162 ∗ @return The number of commands that are possible
163 ∗/
164 public static int getProtocolLength() {
165 return protocol.length;
166 }
167 }
5.1.6 Message.java

29
1 package robotcontroller;
2
3 import javax.swing.JOptionPane;
4
5 /∗∗
6 ∗
7 ∗ @file message.java
8 ∗
9 ∗ This class allows the program to display messages to the user.\n
10 ∗ The implementation can vary as to what is needed.
11 ∗
12 ∗ @author Jasper Maes <jasper.maes@gmail.com>
13 ∗
14 ∗/
15 public class Message {
16
17 /∗∗
18 ∗ A normal, informative message that has to be displayed.
19 ∗
20 ∗ @param s The string to be displayed
21 ∗/
22 public static void normal(String s) {
23 JOptionPane.showMessageDialog(null, s);
24 }
25
26 /∗∗
27 ∗ An error message that has to be displayed.
28 ∗
29 ∗ @param s The message to be displayed
30 ∗/
31 public static void error(String s) {
32 JOptionPane.showMessageDialog(null, ”ERROR: ” + s);
33 }
34 }
5.1.7 PreferencesDialog.java

1 package robotcontroller;
2
3 import java.awt.event.WindowEvent;
4 import gnu.io.CommPortIdentifier;
5 import java.awt.event.WindowAdapter;
6 import java.util.ArrayList;
7 import java.util.Enumeration;
8 import java.util.Iterator;
9
10 /∗∗
11 ∗
12 ∗ @file PreferencesDialog.java
13 ∗
14 ∗ The preferences dialog implemented as a singleton class so that the values of
15 ∗ the input boxes stays preserved when the window is hidden and reopened later.
16 ∗
17 ∗ @author Jasper Maes <jasper.maes@gmail.com>

30
18 ∗
19 ∗/
20 public class PreferencesDialog extends javax.swing.JDialog {
21
22 /∗∗
23 ∗ The instance of this singleton class.
24 ∗/
25 private static final PreferencesDialog INSTANCE = new PreferencesDialog();
26 /∗∗
27 ∗ The updateAble sensor object that are used when updating the threshold values.
28 ∗/
29 private final ArrayList<UpdateAbleSensor> components = new
ArrayList<UpdateAbleSensor>();
30
31 /∗∗
32 ∗ Creates new window for the PreferencesDialog. The constructor is private because
33 ∗ it is a singleton class.
34 ∗/
35 private PreferencesDialog() {
36 // Allow only input to this window
37 setModal(true);
38
39 initComponents();
40
41 Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
42 //Iterate through the enumeration, adding each port name to the combobox
43 while (portEnum.hasMoreElements()) {
44 CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
45 Port.addItem(currPortId.getName());
46 }
47
48 // Add currently connected port name
49 if (!SerialConn.getName().isEmpty()) {
50 Port.addItem(SerialConn.getName());
51 }
52
53 // Initialize the components ArrayList with the UpdateAbleSensor object
54 // created from the input boxes and default values for that sensor
55 UpdateAbleSensor uas = new UpdateAbleSensor(maxSpeed, Globals.pref MaxSpeed,
Globals.def MaxSpeed, ’R’, new char[]{’L’, ’R’});
56 components.add(uas);
57 uas = new UpdateAbleSensor(maxDist, Globals.pref MaxDist, Globals.def MaxDist, ’D’, new
char[]{’L’, ’R’});
58 components.add(uas);
59 uas = new UpdateAbleSensor(maxTemp, Globals.pref MaxTemp, Globals.def MaxTemp, ’T’,
new char[]{’x’});
60 components.add(uas);
61 uas = new UpdateAbleSensor(maxLight, Globals.pref MaxLight, Globals.def MaxLight, ’L’,
new char[]{’x’});
62 components.add(uas);
63
64 addWindowListener(new WindowAdapter() {
65

31
66 /∗∗
67 ∗ When a window is closed, it should be set to hidden and the current values should be
added
68 ∗ to the preferences. When a sensor value was edited, it should also be sent to the robot.
69 ∗/
70 @Override
71 public void windowClosing(WindowEvent e) {
72 setVisible(false);
73 Globals.prefs.put(Globals.pref DataRate, DataRate.getSelectedItem().toString());
74 Globals.prefs.putInt(Globals.pref DataBits,
Integer.parseInt(DataBits.getValue().toString()));
75 Globals.prefs.put(Globals.pref Parity, Parity.getSelectedItem().toString());
76 Globals.prefs.put(Globals.pref StopBits, StopBits.getSelectedItem().toString());
77 Globals.prefs.putInt(Globals.pref Timeout,
Integer.parseInt(Timeout.getValue().toString()));
78 Globals.prefs.put(Globals.pref Port, Port.getSelectedItem().toString());
79
80 Globals.prefs.putInt(Globals.pref WheelDiam,
Integer.parseInt(wheelDiam.getValue().toString()));
81 Globals.prefs.putInt(Globals.pref WheelDist,
Integer.parseInt(wheelDist.getValue().toString()));
82
83 Iterator<UpdateAbleSensor> componentsIter = components.iterator();
84 while (componentsIter.hasNext()) {
85 componentsIter.next().update();
86 }
87
88 }
89 });
90
91 // Add the initial value for the input boxes
92 DataRate.setSelectedItem(Globals.prefs.get(Globals.pref DataRate,
Integer.toString(Globals.def DataRate)));
93 DataBits.setValue(Globals.prefs.getInt(Globals.pref DataBits, Globals.def DataBits));
94 Parity.setSelectedItem(Globals.prefs.get(Globals.pref Parity, Globals.def Parity));
95 StopBits.setSelectedItem(Globals.prefs.get(Globals.pref StopBits, Globals.def StopBits));
96 Timeout.setValue(Globals.prefs.getInt(Globals.pref Timeout, Globals.def Timeout));
97 Port.setSelectedItem(Globals.prefs.get(Globals.pref Port, Globals.def Port));
98
99 wheelDiam.setValue(Globals.prefs.getInt(Globals.pref WheelDiam, Globals.def WheelDiam));
100 wheelDist.setValue(Globals.prefs.getInt(Globals.pref WheelDist, Globals.def WheelDist));
101
102 setResizable(true);
103 }
104
105 /∗∗
106 ∗ Returns the instance of this class
107 ∗ @return The singleton instance
108 ∗/
109 public static PreferencesDialog getInstance() {
110 return INSTANCE;
111 }
112

32
113 /∗∗ This method is called from within the constructor to
114 ∗ initialize the form.
115 ∗ WARNING: Do NOT modify this code. The content of this method is
116 ∗ always regenerated by the Form Editor.
117 ∗/
118 @SuppressWarnings(”unchecked”)
119 // <editor−fold defaultstate=”collapsed” desc=”Generated
Code”>//GEN−BEGIN:initComponents
120 private void initComponents() {
121 java.awt.GridBagConstraints gridBagConstraints;
122
123 PreferenceTabs = new javax.swing.JTabbedPane();
124 jPanel2 = new javax.swing.JPanel();
125 jPanel1 = new javax.swing.JPanel();
126 jLabel1 = new javax.swing.JLabel();
127 maxSpeed = new javax.swing.JSpinner();
128 jLabel2 = new javax.swing.JLabel();
129 maxLight = new javax.swing.JSpinner();
130 maxTemp = new javax.swing.JSpinner();
131 maxDist = new javax.swing.JSpinner();
132 wheelDist = new javax.swing.JSpinner();
133 jLabel3 = new javax.swing.JLabel();
134 jLabel4 = new javax.swing.JLabel();
135 jLabel6 = new javax.swing.JLabel();
136 jLabel8 = new javax.swing.JLabel();
137 wheelDiam = new javax.swing.JSpinner();
138 jPanel3 = new javax.swing.JPanel();
139 jPanel4 = new javax.swing.JPanel();
140 jLabel5 = new javax.swing.JLabel();
141 DataRate = new javax.swing.JComboBox();
142 jLabel7 = new javax.swing.JLabel();
143 jLabel9 = new javax.swing.JLabel();
144 jLabel10 = new javax.swing.JLabel();
145 jLabel11 = new javax.swing.JLabel();
146 jLabel12 = new javax.swing.JLabel();
147 StopBits = new javax.swing.JComboBox();
148 Port = new javax.swing.JComboBox();
149 Parity = new javax.swing.JComboBox();
150 Timeout = new javax.swing.JSpinner();
151 DataBits = new javax.swing.JSpinner();
152
153 setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE ON CLOSE);
154 org.jdesktop.application.ResourceMap resourceMap =
org.jdesktop.application.Application.getInstance(robotcontroller.RobotControllerApp.class).getContext().ge
155 setTitle(resourceMap.getString(”Form.title”)); // NOI18N
156 setName(”Form”); // NOI18N
157 setResizable(false);
158
159 PreferenceTabs.setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL TAB LAYOUT);
160 PreferenceTabs.setName(”PreferenceTabs”); // NOI18N
161
162 jPanel2.setName(”Robot”); // NOI18N
163 jPanel2.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

33
164
165 jPanel1.setName(”jPanel1”); // NOI18N
166 jPanel1.setLayout(new java.awt.GridBagLayout());
167
168 jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
169 jLabel1.setLabelFor(maxSpeed);
170 jLabel1.setText(resourceMap.getString(”jLabel1.text”)); // NOI18N
171 jLabel1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
172 jLabel1.setName(”jLabel1”); // NOI18N
173 gridBagConstraints = new java.awt.GridBagConstraints();
174 gridBagConstraints.gridx = 0;
175 gridBagConstraints.gridy = 0;
176 gridBagConstraints.ipadx = 11;
177 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
178 jPanel1.add(jLabel1, gridBagConstraints);
179
180 maxSpeed.setModel(new javax.swing.SpinnerNumberModel(1, 1, 30, 1));
181 maxSpeed.setName(”MaxSpeed”); // NOI18N
182 maxSpeed.setPreferredSize(new java.awt.Dimension(70, 30));
183 gridBagConstraints = new java.awt.GridBagConstraints();
184 gridBagConstraints.gridx = 1;
185 gridBagConstraints.gridy = 0;
186 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
187 gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
188 jPanel1.add(maxSpeed, gridBagConstraints);
189
190 jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
191 jLabel2.setLabelFor(maxTemp);
192 jLabel2.setText(resourceMap.getString(”jLabel2.text”)); // NOI18N
193 jLabel2.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
194 jLabel2.setName(”jLabel2”); // NOI18N
195 gridBagConstraints = new java.awt.GridBagConstraints();
196 gridBagConstraints.gridx = 0;
197 gridBagConstraints.gridy = 2;
198 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
199 jPanel1.add(jLabel2, gridBagConstraints);
200
201 maxLight.setModel(new javax.swing.SpinnerNumberModel(0, 0, 2000, 5));
202 maxLight.setName(”MaxLight”); // NOI18N
203 maxLight.setPreferredSize(new java.awt.Dimension(70, 30));
204 gridBagConstraints = new java.awt.GridBagConstraints();
205 gridBagConstraints.gridx = 1;
206 gridBagConstraints.gridy = 1;
207 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
208 jPanel1.add(maxLight, gridBagConstraints);
209
210 maxTemp.setModel(new javax.swing.SpinnerNumberModel(0, 0, 100, 1));
211 maxTemp.setName(”MaxTemp”); // NOI18N
212 maxTemp.setPreferredSize(new java.awt.Dimension(70, 30));
213 gridBagConstraints = new java.awt.GridBagConstraints();
214 gridBagConstraints.gridx = 1;
215 gridBagConstraints.gridy = 2;
216 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;

34
217 jPanel1.add(maxTemp, gridBagConstraints);
218
219 maxDist.setModel(new javax.swing.SpinnerNumberModel(80, 10, 80, 1));
220 maxDist.setName(”MaxDist”); // NOI18N
221 maxDist.setPreferredSize(new java.awt.Dimension(70, 30));
222 gridBagConstraints = new java.awt.GridBagConstraints();
223 gridBagConstraints.gridx = 1;
224 gridBagConstraints.gridy = 3;
225 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
226 jPanel1.add(maxDist, gridBagConstraints);
227
228 wheelDist.setModel(new javax.swing.SpinnerNumberModel(50, 10, 100, 1));
229 wheelDist.setName(”WheelDist”); // NOI18N
230 wheelDist.setPreferredSize(new java.awt.Dimension(70, 30));
231 gridBagConstraints = new java.awt.GridBagConstraints();
232 gridBagConstraints.gridx = 1;
233 gridBagConstraints.gridy = 5;
234 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
235 jPanel1.add(wheelDist, gridBagConstraints);
236
237 jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
238 jLabel3.setLabelFor(maxDist);
239 jLabel3.setText(resourceMap.getString(”jLabel3.text”)); // NOI18N
240 jLabel3.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
241 jLabel3.setName(”jLabel3”); // NOI18N
242 gridBagConstraints = new java.awt.GridBagConstraints();
243 gridBagConstraints.gridx = 0;
244 gridBagConstraints.gridy = 3;
245 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
246 gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 5);
247 jPanel1.add(jLabel3, gridBagConstraints);
248
249 jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
250 jLabel4.setLabelFor(wheelDiam);
251 jLabel4.setText(resourceMap.getString(”jLabel4.text”)); // NOI18N
252 jLabel4.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
253 jLabel4.setName(”jLabel4”); // NOI18N
254 gridBagConstraints = new java.awt.GridBagConstraints();
255 gridBagConstraints.gridx = 0;
256 gridBagConstraints.gridy = 4;
257 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
258 jPanel1.add(jLabel4, gridBagConstraints);
259
260 jLabel6.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
261 jLabel6.setIcon(resourceMap.getIcon(”jLabel6.icon”)); // NOI18N
262 jLabel6.setLabelFor(wheelDist);
263 jLabel6.setText(resourceMap.getString(”jLabel6.text”)); // NOI18N
264 jLabel6.setName(”jLabel6”); // NOI18N
265 gridBagConstraints = new java.awt.GridBagConstraints();
266 gridBagConstraints.gridx = 0;
267 gridBagConstraints.gridy = 5;
268 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
269 jPanel1.add(jLabel6, gridBagConstraints);

35
270
271 jLabel8.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
272 jLabel8.setLabelFor(maxLight);
273 jLabel8.setText(resourceMap.getString(”jLabel8.text”)); // NOI18N
274 jLabel8.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
275 jLabel8.setName(”jLabel8”); // NOI18N
276 gridBagConstraints = new java.awt.GridBagConstraints();
277 gridBagConstraints.gridx = 0;
278 gridBagConstraints.gridy = 1;
279 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
280 jPanel1.add(jLabel8, gridBagConstraints);
281
282 wheelDiam.setModel(new javax.swing.SpinnerNumberModel(10, 5, 30, 1));
283 wheelDiam.setName(”WheelDiam”); // NOI18N
284 wheelDiam.setPreferredSize(new java.awt.Dimension(70, 30));
285 gridBagConstraints = new java.awt.GridBagConstraints();
286 gridBagConstraints.gridx = 1;
287 gridBagConstraints.gridy = 4;
288 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
289 jPanel1.add(wheelDiam, gridBagConstraints);
290
291 jPanel2.add(jPanel1);
292
293 PreferenceTabs.addTab(resourceMap.getString(”Robot.TabConstraints.tabTitle”), jPanel2);
// NOI18N
294
295 jPanel3.setName(”jPanel3”); // NOI18N
296 jPanel3.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
297
298 jPanel4.setEnabled(false);
299 jPanel4.setName(”jPanel4”); // NOI18N
300 jPanel4.setLayout(new java.awt.GridBagLayout());
301
302 jLabel5.setText(resourceMap.getString(”jLabel5.text”)); // NOI18N
303 jLabel5.setName(”jLabel5”); // NOI18N
304 gridBagConstraints = new java.awt.GridBagConstraints();
305 gridBagConstraints.gridx = 0;
306 gridBagConstraints.gridy = 0;
307 gridBagConstraints.ipadx = 11;
308 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
309 jPanel4.add(jLabel5, gridBagConstraints);
310
311 DataRate.setModel(new javax.swing.DefaultComboBoxModel(new String[] { ”300”, ”1200”,
”2400”, ”4800”, ”9600”, ”14400”, ”19200”, ”28800”, ”38400”, ”57600”, ”115200” }));
312 DataRate.setSelectedIndex(4);
313 DataRate.setName(”DataRate”); // NOI18N
314 DataRate.setPreferredSize(new java.awt.Dimension(120, 27));
315 gridBagConstraints = new java.awt.GridBagConstraints();
316 gridBagConstraints.ipadx = 6;
317 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
318 jPanel4.add(DataRate, gridBagConstraints);
319
320 jLabel7.setText(resourceMap.getString(”jLabel7.text”)); // NOI18N

36
321 jLabel7.setEnabled(false);
322 jLabel7.setName(”jLabel7”); // NOI18N
323 gridBagConstraints = new java.awt.GridBagConstraints();
324 gridBagConstraints.gridx = 0;
325 gridBagConstraints.gridy = 1;
326 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
327 jPanel4.add(jLabel7, gridBagConstraints);
328
329 jLabel9.setText(resourceMap.getString(”jLabel9.text”)); // NOI18N
330 jLabel9.setEnabled(false);
331 jLabel9.setName(”jLabel9”); // NOI18N
332 gridBagConstraints = new java.awt.GridBagConstraints();
333 gridBagConstraints.gridx = 0;
334 gridBagConstraints.gridy = 2;
335 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
336 jPanel4.add(jLabel9, gridBagConstraints);
337
338 jLabel10.setText(resourceMap.getString(”jLabel10.text”)); // NOI18N
339 jLabel10.setName(”jLabel10”); // NOI18N
340 gridBagConstraints = new java.awt.GridBagConstraints();
341 gridBagConstraints.gridx = 0;
342 gridBagConstraints.gridy = 5;
343 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
344 gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 6);
345 jPanel4.add(jLabel10, gridBagConstraints);
346
347 jLabel11.setText(resourceMap.getString(”jLabel11.text”)); // NOI18N
348 jLabel11.setEnabled(false);
349 jLabel11.setName(”jLabel11”); // NOI18N
350 gridBagConstraints = new java.awt.GridBagConstraints();
351 gridBagConstraints.gridx = 0;
352 gridBagConstraints.gridy = 3;
353 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
354 jPanel4.add(jLabel11, gridBagConstraints);
355
356 jLabel12.setText(resourceMap.getString(”jLabel12.text”)); // NOI18N
357 jLabel12.setName(”jLabel12”); // NOI18N
358 gridBagConstraints = new java.awt.GridBagConstraints();
359 gridBagConstraints.gridx = 0;
360 gridBagConstraints.gridy = 4;
361 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
362 jPanel4.add(jLabel12, gridBagConstraints);
363
364 StopBits.setModel(new javax.swing.DefaultComboBoxModel(new String[] { ”1”, ”1.5”, ”2”
}));
365 StopBits.setEnabled(false);
366 StopBits.setName(”StopBits”); // NOI18N
367 StopBits.setPreferredSize(new java.awt.Dimension(120, 27));
368 gridBagConstraints = new java.awt.GridBagConstraints();
369 gridBagConstraints.gridx = 1;
370 gridBagConstraints.gridy = 3;
371 gridBagConstraints.ipadx = 6;
372 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;

37
373 jPanel4.add(StopBits, gridBagConstraints);
374
375 Port.setMaximumSize(new java.awt.Dimension(200, 32767));
376 Port.setMinimumSize(new java.awt.Dimension(100, 27));
377 Port.setName(”Port”); // NOI18N
378 Port.setPreferredSize(new java.awt.Dimension(200, 27));
379 gridBagConstraints = new java.awt.GridBagConstraints();
380 gridBagConstraints.gridx = 1;
381 gridBagConstraints.gridy = 5;
382 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
383 gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
384 jPanel4.add(Port, gridBagConstraints);
385
386 Parity.setModel(new javax.swing.DefaultComboBoxModel(new String[] { ”Even”, ”Odd”,
”Mark”, ”Space”, ”None” }));
387 Parity.setSelectedIndex(4);
388 Parity.setEnabled(false);
389 Parity.setName(”Parity”); // NOI18N
390 Parity.setPreferredSize(new java.awt.Dimension(120, 27));
391 gridBagConstraints = new java.awt.GridBagConstraints();
392 gridBagConstraints.gridx = 1;
393 gridBagConstraints.gridy = 2;
394 gridBagConstraints.ipadx = 6;
395 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
396 jPanel4.add(Parity, gridBagConstraints);
397
398 Timeout.setModel(new javax.swing.SpinnerNumberModel(5, 5, 20, 1));
399 Timeout.setMinimumSize(null);
400 Timeout.setName(”Timeout”); // NOI18N
401 Timeout.setPreferredSize(new java.awt.Dimension(120, 30));
402 gridBagConstraints = new java.awt.GridBagConstraints();
403 gridBagConstraints.gridx = 1;
404 gridBagConstraints.gridy = 4;
405 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
406 gridBagConstraints.insets = new java.awt.Insets(0, 2, 0, 0);
407 jPanel4.add(Timeout, gridBagConstraints);
408
409 DataBits.setModel(new javax.swing.SpinnerNumberModel(8, 5, 8, 1));
410 DataBits.setEditor(new javax.swing.JSpinner.NumberEditor(DataBits, ””));
411 DataBits.setEnabled(false);
412 DataBits.setName(”DataBits”); // NOI18N
413 DataBits.setPreferredSize(new java.awt.Dimension(120, 30));
414 gridBagConstraints = new java.awt.GridBagConstraints();
415 gridBagConstraints.gridx = 1;
416 gridBagConstraints.gridy = 1;
417 gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
418 gridBagConstraints.insets = new java.awt.Insets(0, 2, 0, 0);
419 jPanel4.add(DataBits, gridBagConstraints);
420
421 jPanel3.add(jPanel4);
422
423 PreferenceTabs.addTab(resourceMap.getString(”jPanel3.TabConstraints.tabTitle”), jPanel3);
// NOI18N

38
424
425 org.jdesktop.layout.GroupLayout layout = new
org.jdesktop.layout.GroupLayout(getContentPane());
426 getContentPane().setLayout(layout);
427 layout.setHorizontalGroup(
428 layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
429 .add(PreferenceTabs, org.jdesktop.layout.GroupLayout.PREFERRED SIZE, 333,
org.jdesktop.layout.GroupLayout.PREFERRED SIZE)
430 );
431 layout.setVerticalGroup(
432 layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
433 .add(PreferenceTabs, org.jdesktop.layout.GroupLayout.PREFERRED SIZE,
org.jdesktop.layout.GroupLayout.DEFAULT SIZE,
org.jdesktop.layout.GroupLayout.PREFERRED SIZE)
434 );
435
436 pack();
437 }// </editor−fold>//GEN−END:initComponents
438 // Variables declaration − do not modify//GEN−BEGIN:variables
439 private javax.swing.JSpinner DataBits;
440 private javax.swing.JComboBox DataRate;
441 private javax.swing.JComboBox Parity;
442 private javax.swing.JComboBox Port;
443 private javax.swing.JTabbedPane PreferenceTabs;
444 private javax.swing.JComboBox StopBits;
445 private javax.swing.JSpinner Timeout;
446 private javax.swing.JLabel jLabel1;
447 private javax.swing.JLabel jLabel10;
448 private javax.swing.JLabel jLabel11;
449 private javax.swing.JLabel jLabel12;
450 private javax.swing.JLabel jLabel2;
451 private javax.swing.JLabel jLabel3;
452 private javax.swing.JLabel jLabel4;
453 private javax.swing.JLabel jLabel5;
454 private javax.swing.JLabel jLabel6;
455 private javax.swing.JLabel jLabel7;
456 private javax.swing.JLabel jLabel8;
457 private javax.swing.JLabel jLabel9;
458 private javax.swing.JPanel jPanel1;
459 private javax.swing.JPanel jPanel2;
460 private javax.swing.JPanel jPanel3;
461 private javax.swing.JPanel jPanel4;
462 private javax.swing.JSpinner maxDist;
463 private javax.swing.JSpinner maxLight;
464 private javax.swing.JSpinner maxSpeed;
465 private javax.swing.JSpinner maxTemp;
466 private javax.swing.JSpinner wheelDiam;
467 private javax.swing.JSpinner wheelDist;
468 // End of variables declaration//GEN−END:variables
469 }
5.1.8 RobotControllerApp.java

1 package robotcontroller;

39
2
3 import javax.swing.JOptionPane;
4 import org.jdesktop.application.Application;
5 import org.jdesktop.application.SingleFrameApplication;
6
7 /∗∗
8 ∗
9 ∗ @mainpage
10 ∗
11 ∗ These documentation files form the documentation of the graphical user interface that can be used
to control the robot.\n
12 ∗
13 ∗ @author Jasper Maes <jasper.maes@gmail.com>
14 ∗
15 ∗ \image html logos.png
16 ∗
17 ∗/
18
19 /∗∗
20 ∗
21 ∗ @file RobotControllerApp.java
22 ∗
23 ∗ This class is the core of the application, it creates and initializes the windows and every component.
24 ∗
25 ∗ @author Jasper Maes <jasper.maes@gmail.com>
26 ∗
27 ∗/
28 public class RobotControllerApp extends SingleFrameApplication {
29
30 /∗∗
31 ∗ When the application starts, a new view should be created.
32 ∗/
33 @Override
34 protected void startup() {
35 show(new RobotControllerView(this));
36 }
37
38 /∗∗
39 ∗ A convenient static getter for the application instance.
40 ∗
41 ∗ @return The instance of RobotControllerApp
42 ∗/
43 public static RobotControllerApp getApplication() {
44 return Application.getInstance(RobotControllerApp.class);
45 }
46
47 /∗∗
48 ∗ Main method launching the application.
49 ∗
50 ∗ @param args The arguments to the application (none needed)
51 ∗/
52 public static void main(String[] args) {
53 // Set different Mac specific values. This has no influence on other platforms

40
54 System.setProperty(”com.apple.mrj.application.apple.menu.about.name”, ”Robot controller”);
55 System.setProperty(”apple.laf.useScreenMenuBar”, ”true”);
56 System.setProperty(”apple.awt.textantialiasing”, ”true”);
57
58 // Check if the program is ran in 32 bit mode
59 if (System.getProperty(”sun.arch.data.model”).equals(”64”)) {
60 JOptionPane.showMessageDialog(null, ”Please run in 32 bit mode. Start the
application with: java −d32 −jar filename.jar”);
61 System.exit(0);
62 }
63
64 // Initialise must come after the previous settings
65 Globals.initialise();
66
67 // Do specific Mac operations with special classes that are only available on Mac.
68 if (System.getProperty(”os.name”).contains(”Mac”)) {
69 MacSpecific.macInitializeApp();
70 }
71
72 launch(RobotControllerApp.class, args);
73 }
74 }
5.1.9 RobotControllerView.java

1 package robotcontroller;
2
3 import java.awt.Dimension;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import java.awt.event.KeyEvent;
7 import java.awt.event.WindowAdapter;
8 import java.awt.event.WindowEvent;
9 import java.util.prefs.Preferences;
10 import javax.swing.JCheckBoxMenuItem;
11 import javax.swing.JFrame;
12 import javax.swing.JMenu;
13 import javax.swing.JMenuBar;
14 import javax.swing.JMenuItem;
15 import javax.swing.KeyStroke;
16 import org.jdesktop.application.SingleFrameApplication;
17
18 /∗∗
19 ∗
20 ∗ @file RobotControllerView.java
21 ∗
22 ∗ The data store implemented as a singleton class.\n
23 ∗ It contains the value of each sensor as it was sent to the computer.
24 ∗
25 ∗ @author Jasper Maes <jasper.maes@gmail.com>
26 ∗
27 ∗/
28 public class RobotControllerView extends JFrame {
29

41
30 /∗∗
31 ∗ This class overrides the TimedKeyListener to make the application call
32 ∗ certain actions when keys on the keyboard are pressed
33 ∗/
34 private class KeyListener extends TimedKeyListener {
35
36 /∗∗
37 ∗ The code of the last key that was pressed is cached.
38 ∗/
39 private int lastKey = 0;
40
41 /∗∗
42 ∗ This action is called when a key is pushed down.
43 ∗
44 ∗ @param e This variable contains information about the event
45 ∗/
46 @Override
47 public void keyPressed(KeyEvent e) {
48 super.keyPressed(e);
49 /∗∗
50 ∗ First compare if the currently pressed key is the same as the last one,
51 ∗ if so, do not send the command again.\n
52 ∗ This is needed because a keypressed signal is fired repeatedly and the
53 ∗ command does not have to be sent every time.
54 ∗/
55 if (lastKey != e.getKeyCode()) {
56 switch (e.getKeyCode()) {
57 // Move left
58 case KeyEvent.VK LEFT:
59 case KeyEvent.VK KP LEFT:
60 case KeyEvent.VK A:
61 sendCommand(Globals.MotorLeftCode);
62 break;
63 //Move right
64 case KeyEvent.VK RIGHT:
65 case KeyEvent.VK KP RIGHT:
66 case KeyEvent.VK D:
67 sendCommand(Globals.MotorRightCode);
68 break;
69 //Move forward
70 case KeyEvent.VK UP:
71 case KeyEvent.VK KP UP:
72 case KeyEvent.VK W:
73 sendCommand(Globals.MotorForwardCode);
74 break;
75 //Move backward
76 case KeyEvent.VK DOWN:
77 case KeyEvent.VK KP DOWN:
78 case KeyEvent.VK S:
79 sendCommand(Globals.MotorBackwardCode);
80 break;
81 default:
82 return;

42
83 }
84 // Store the curent keycode
85 lastKey = e.getKeyCode();
86 }
87 }
88
89 /∗∗
90 ∗ This action is called when a key is released.
91 ∗
92 ∗ @param e This variable contains information about the event
93 ∗/
94 @Override
95 public void keyReleased(KeyEvent e) {
96 super.keyReleased(e);
97 // Check for real key release
98 if (getReleased()) {
99 lastKey = 0;
100
101 switch (e.getKeyCode()) {
102 // Move left
103 case KeyEvent.VK LEFT:
104 case KeyEvent.VK KP LEFT:
105 case KeyEvent.VK A:
106 //Move right
107 case KeyEvent.VK RIGHT:
108 case KeyEvent.VK KP RIGHT:
109 case KeyEvent.VK D:
110 //Move forward
111 case KeyEvent.VK UP:
112 case KeyEvent.VK KP UP:
113 case KeyEvent.VK W:
114 //Move backward
115 case KeyEvent.VK DOWN:
116 case KeyEvent.VK KP DOWN:
117 case KeyEvent.VK S:
118 sendCommand(Globals.MotorStopCode);
119 break;
120 }
121 }
122 }
123 }
124
125 /∗∗
126 ∗ Creates new window for the RobotControllerApp.
127 ∗
128 ∗ @param app The application of which this frame is part
129 ∗/
130 public RobotControllerView(SingleFrameApplication app) {
131 // Create a Canvas and add it to the window
132 Canvas canv = new Canvas(this);
133 add(canv);
134 InputParser.getInstance().addView(canv);
135 Globals.cv = canv;

43
136
137 //Set different application window options
138 setDefaultCloseOperation(JFrame.EXIT ON CLOSE);
139 setTitle(”Robot controller program”);
140 setMinimumSize(new Dimension(Globals.MIN WIDTH, Globals.MIN HEIGHT + 20));
141 setResizable(false);
142 setIconImage(Globals.robot);
143
144 //The close handler for non−Mac platforms
145 if (!System.getProperty(”os.name”).contains(”Mac”)) {
146 addWindowListener(new WindowAdapter() {
147
148 @Override
149 public void windowClosing(WindowEvent e) {
150 SerialConn.close();
151 System.exit(0);
152 }
153 });
154 }
155
156 addKeyListener(new KeyListener());
157
158 //Create the menu bar and add the options
159 JMenuBar menuBar = new JMenuBar();
160 JMenu menu = new JMenu(”Options”);
161 JMenuItem preferencesItem = new JMenuItem(”Preferences”, KeyEvent.VK P);
162
163 preferencesItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK P,
ActionEvent.ALT MASK));
164 preferencesItem.getAccessibleContext().setAccessibleDescription(”Show the preferences
window”);
165 preferencesItem.addActionListener(new ActionListener() {
166
167 @Override
168 public void actionPerformed(ActionEvent e) {
169 PreferencesDialog.getInstance().setVisible(true);
170 }
171 });
172
173
174 JMenuItem aboutItem = new JMenuItem(”About”, KeyEvent.VK A);
175
176 aboutItem.getAccessibleContext().setAccessibleDescription(”Show the about window”);
177 aboutItem.addActionListener(new ActionListener() {
178
179 @Override
180 public void actionPerformed(ActionEvent e) {
181 AboutDialog a = new AboutDialog(null);
182 }
183 });
184
185 menu.setMnemonic(KeyEvent.VK O);
186 menu.getAccessibleContext().setAccessibleDescription(”The menu with different options”);

44
187 menuBar.add(menu);
188
189 JCheckBoxMenuItem cbMenuItem = new JCheckBoxMenuItem(”Distance sensor”);
190 cbMenuItem.setState(true);
191 cbMenuItem.addActionListener(new ActionListener() {
192
193 @Override
194 public void actionPerformed(ActionEvent e) {
195 DataStore.switchEnableDist();
196 }
197 });
198 menu.add(cbMenuItem);
199
200 cbMenuItem = new JCheckBoxMenuItem(”Speed sensor”);
201 cbMenuItem.setState(true);
202 cbMenuItem.addActionListener(new ActionListener() {
203
204 @Override
205 public void actionPerformed(ActionEvent e) {
206 DataStore.switchEnableSpeed();
207 }
208 });
209 menu.add(cbMenuItem);
210
211 cbMenuItem = new JCheckBoxMenuItem(”Distance driven sensor”);
212 cbMenuItem.setState(true);
213 cbMenuItem.addActionListener(new ActionListener() {
214
215 @Override
216 public void actionPerformed(ActionEvent e) {
217 DataStore.switchEnableDriven();
218 }
219 });
220 menu.add(cbMenuItem);
221
222 cbMenuItem = new JCheckBoxMenuItem(”Rotation sensor”);
223 cbMenuItem.setState(true);
224 cbMenuItem.addActionListener(new ActionListener() {
225
226 @Override
227 public void actionPerformed(ActionEvent e) {
228 DataStore.switchEnableRotation();
229 }
230 });
231 menu.add(cbMenuItem);
232
233 cbMenuItem = new JCheckBoxMenuItem(”Temperature sensor”);
234 cbMenuItem.setState(true);
235 cbMenuItem.addActionListener(new ActionListener() {
236
237 @Override
238 public void actionPerformed(ActionEvent e) {
239 DataStore.switchEnableTemp();

45
240 }
241 });
242 menu.add(cbMenuItem);
243
244 cbMenuItem = new JCheckBoxMenuItem(”Light sensor”);
245 cbMenuItem.setState(true);
246 cbMenuItem.addActionListener(new ActionListener() {
247
248 @Override
249 public void actionPerformed(ActionEvent e) {
250 DataStore.switchEnableLight();
251 }
252 });
253 menu.add(cbMenuItem);
254
255
256 if (!System.getProperty(”os.name”).contains(”Mac”)) {
257 menu.addSeparator();
258 menu.add(preferencesItem);
259 menu.addSeparator();
260 menu.add(aboutItem);
261 }
262
263 setJMenuBar(menuBar);
264
265 }
266
267 /∗∗
268 ∗ This method sends a command to the robot by writing it to the serial port.
269 ∗
270 ∗ @param c A command character to be sent
271 ∗/
272 private void sendCommand(char c) {
273 SerialConn.write(c);
274 }
275 }
5.1.10 SerialConn.java

1 package robotcontroller;
2
3 import java.io.InputStream;
4 import java.io.OutputStream;
5 import gnu.io.CommPortIdentifier;
6 import gnu.io.SerialPort;
7 import gnu.io.SerialPortEvent;
8 import gnu.io.SerialPortEventListener;
9 import java.io.IOException;
10 import java.util.prefs.Preferences;
11
12 /∗∗
13 ∗
14 ∗ @file SerialConn.java
15 ∗

46
16 ∗ The serial connection class. There can be only 1 connection at any time
17 ∗ when running the program.
18 ∗
19 ∗ @author Jasper Maes <jasper.maes@gmail.com>
20 ∗
21 ∗/
22 public class SerialConn implements SerialPortEventListener {
23
24 /∗∗ The serial port to which all data must be written. ∗/
25 private static SerialPort serialPort = null;
26 /∗∗ The input stream from the port. ∗/
27 private static InputStream input = null;
28 /∗∗ The output stream to the port. ∗/
29 private static OutputStream output = null;
30 /∗∗ The command code that is read from the serial port. ∗/
31 private char opcode = 0;
32 /∗∗ A number of bytes that is read from the serial port. ∗/
33 private byte[] bytes;
34 /∗∗ The number of integers that has to be read for the current opcode. ∗/
35 private int requiredInts;
36 /∗∗ The number of integers that were already read. ∗/
37 private int currentInt = 0;
38 /∗∗ A number of integers that were read. ∗/
39 private int[] ints;
40 /∗∗
41 ∗ A state for when reading input from the port. It indicates that the
42 ∗ next byte has to be an instruction code.
43 ∗/
44 private final int READ OPCODE = 0;
45 /∗∗
46 ∗ A state for when reading input from the port. It indicates that the next
47 ∗ groups of 4 bytes that arrive are to be transformed into an integer and
48 ∗ serve as arguments to the command
49 ∗/
50 private final int READ INT = 1;
51 /∗∗ A variable indicating the current state. ∗/
52 private int state = READ OPCODE;
53 /∗∗ This variable contains the instance of the InputParser. ∗/
54 private static final InputParser inputParser = InputParser.getInstance();
55
56
57 /∗∗
58 ∗ The constructor for the serial connection. It immediately connects to a port.
59 ∗
60 ∗ @param portName The textual representation of the port to which the application must send
data
61 ∗/
62 public SerialConn(String portName) {
63 open(portName);
64 }
65
66 /∗∗
67 ∗ The operation that opens a serial connection on the specified port

47
68 ∗ @param portName The name of the port to connect to
69 ∗/
70 public final void open(String portName) {
71
72 try {
73 CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(portName);
74
75 // close any port that is open
76 close();
77
78 // open serial port, and use class name for the appName.
79 serialPort = (SerialPort) portId.open(this.getClass().getName(),
80 Globals.SerialWait);
81
82 // set port parameters
83 serialPort.setSerialPortParams(Globals.prefs.getInt(Globals.pref DataRate,
Globals.def DataRate),
84 SerialPort.DATABITS 8,
85 SerialPort.STOPBITS 1,
86 SerialPort.PARITY NONE);
87
88 // open the streams
89 input = serialPort.getInputStream();
90 output = serialPort.getOutputStream();
91
92 // add event listeners
93 serialPort.addEventListener(this);
94 serialPort.notifyOnDataAvailable(true);
95
96 Preferences prefs = Preferences.userNodeForPackage(getClass());
97 Globals.pingTimer.setDelay(Globals.PING INTERVAL);
98 Globals.pingTimeoutTimer.setDelay(prefs.getInt(Globals.pref Timeout,
Globals.def Timeout));
99
100 Globals.pingTimer.start();
101 Globals.pingTimeoutTimer.start();
102
103 DataStore.getInstance().setConnectionStatus(true);
104
105 } catch (Exception e) {
106 Message.error(”Could not connect to ” + portName);
107 }
108 }
109
110 /∗∗
111 ∗ This should be called when you stop using the port.\n
112 ∗ It will remove the lock on the port
113 ∗/
114 public static synchronized void close() {
115 if (isConnected()) {
116 serialPort.removeEventListener();
117 serialPort.close();
118 serialPort = null;

48
119 input = null;
120 output = null;
121 Globals.pingTimer.stop();
122 Globals.pingTimeoutTimer.stop();
123 DataStore.getInstance().setConnectionStatus(false);
124 }
125 }
126
127 /∗∗
128 ∗ Write a character to the currently opened serial port.
129 ∗ @param c The character to be written
130 ∗ @return A boolean value indicating if the value was written successfully or not
131 ∗/
132 public static synchronized boolean write(char c) {
133 // Check whether there is a currently opened serial port
134 if (serialPort != null) {
135 try {
136 output.write(c);
137 } catch (IOException e) {
138 if (c != Globals.PingCode) {
139 Message.error(”Error writing to port”);
140 }
141 return false;
142 }
143 }
144
145 // Wait before sendind the next character
146 try {
147 Thread.sleep(Globals.BIT TIME);
148 } catch (InterruptedException e) {
149 }
150
151 return true;
152 }
153
154 /∗∗
155 ∗ Write an integer value to serial port. This is done by dividing the
156 ∗ integer into 4 bytes and writing these one by one.
157 ∗
158 ∗ @param value The integer value
159 ∗ @return A boolean value indicating whether the integer was written successfully
160 ∗/
161 public static synchronized boolean write(int value) {
162 boolean res = true;
163
164 res &= write((char)(value >> 24));
165 res &= write((char)(value >> 16));
166 res &= write((char)(value >> 8));
167 res &= write((char)(value));
168
169 return res;
170 }
171

49
172 /∗∗
173 ∗ A utility function to convert an array of bytes to an integer.
174 ∗
175 ∗ @param b The byte array
176 ∗ @param offset The conversion will start at this point and end 4 bytes later
177 ∗
178 ∗ @return The integer value of the 4 bytes starting at offset
179 ∗/
180 private static int byteArrayToInt(byte[] b, int offset) {
181 int value = 0;
182
183 value |= ((b[0 + offset] & 0xFF) << 24);
184 value |= ((b[1 + offset] & 0xFF) << 16);
185 value |= ((b[2 + offset] & 0xFF) << 8);
186 value |= (b[3 + offset] & 0xFF);
187
188 return value;
189 }
190
191 /∗∗
192 ∗ Handle an event on the serial port. Read the data and send it to the parser.
193 ∗
194 ∗ @param event This variable contains information about the event such as the type of event that
has occured.
195 ∗/
196 @Override
197 public synchronized void serialEvent(SerialPortEvent event) {
198 // If new data is available
199 if (event.getEventType() == SerialPortEvent.DATA AVAILABLE) {
200 try {
201 // State machine to read new data from the serial port
202 switch (state) {
203 case READ OPCODE: // Reading a new command code
204 bytes = new byte[1];
205 input.read(bytes, 0, 1);
206 opcode = (char) bytes[0];
207 if (opcode < InputParser.getProtocolLength()) {
208 requiredInts = InputParser.getProtocolCount(opcode);
209
210 if (requiredInts > 0) {
211 currentInt = 0;
212 ints = new int[requiredInts];
213 state = READ INT; // Change state to reading arguments
214 } else if (requiredInts == 0) {
215 inputParser.parse(opcode);
216 }
217 } else {
218 System.err.println(”Code not in protocol (” + opcode + ”)”);
219 opcode = 0;
220 }
221
222 break;
223 case READ INT: // Read integer arguments

50
224 if (input.available() >= 4) {
225 bytes = new byte[4];
226 input.read(bytes, 0, 4);
227 int v = byteArrayToInt(bytes, 0);
228 ints[currentInt] = v;
229 currentInt++;
230 }
231 if (currentInt == requiredInts) {
232 inputParser.parse(opcode, ints);
233 state = READ OPCODE;
234 }
235 break;
236 default: // An error has occured, the state is invalid
237 System.err.println(”Wrong state when reading data”);
238 state = READ OPCODE;
239 break;
240 }
241
242
243 } catch (Exception e) {
244 System.err.println(e.toString() + ”\nInput error.”);
245 }
246 }
247 // Ignore all the other eventTypes
248 }
249
250 /∗∗
251 ∗ Get the textual representation of the currently connected serial port.
252 ∗
253 ∗ @return The name of the serial port
254 ∗/
255 public static String getName() {
256 if (serialPort == null) {
257 return ””;
258 }
259 return serialPort.getName();
260 }
261
262 /∗∗
263 ∗ Check if the serial connection is opened.
264 ∗
265 ∗ @return A boolean value that indicates whether the serial port is open or not.
266 ∗/
267 public static boolean isConnected() {
268 return (serialPort != null);
269 }
270 }
5.1.11 UpdateAbleSensor.java

1 package robotcontroller;
2
3 import java.lang.reflect.InvocationTargetException;
4 import java.lang.reflect.Method;

51
5 import java.util.prefs.Preferences;
6
7 /∗∗
8 ∗
9 ∗ @file UpdateAbleSensor.java
10 ∗
11 ∗ This class combines an input box and current value of a threshold.
12 ∗ It can be compared with the new value. If the value has changed, it is sent to the robot,
13 ∗ if not, nothing happens. By using this, the amount of bytes that have to be sent
14 ∗ is kept as low as possible.
15 ∗
16 ∗ @author Jasper Maes <jasper.maes@gmail.com>
17 ∗
18 ∗/
19 public class UpdateAbleSensor {
20
21 /∗∗ The object that contains the value of the threshold. ∗/
22 private Object src;
23 /∗∗ The string which is used to find the value of the threshold in the preferences. ∗/
24 private String prefString;
25 /∗∗ The default threshold value. ∗/
26 private int defVal;
27 /∗∗ The preferences object. ∗/
28 private Preferences prefs = Preferences.userNodeForPackage(getClass());
29 /∗∗ The command code to update a threshold value on the robot. ∗/
30 private char code = ’T’;
31 /∗∗ The type of sensor. ∗/
32 private char type;
33 /∗∗ The id codes of the sensor. ∗/
34 private char[] ids;
35
36 /∗∗
37 ∗ The constructor of an updateAbleSensor object.
38 ∗
39 ∗ @param o The object whose value can possibly change
40 ∗ @param pref The string that is used to find the value in the preferences object
41 ∗ @param def The default threshold value
42 ∗ @param t The type code of the sensor
43 ∗ @param i The id codes of the sensors
44 ∗/
45 public UpdateAbleSensor(Object o, String pref, int def, char t, char[] i) {
46 src = o;
47 prefString = pref;
48 defVal = def;
49 type = t;
50 ids = i;
51 int prev = prefs.getInt(prefString, defVal);
52 try {
53 Method method = src.getClass().getMethod(”setValue”, Object.class);
54 method.invoke(src, prev);
55 } catch (NoSuchMethodException e) {
56 } catch (InvocationTargetException e) {
57 } catch (IllegalAccessException e) {

52
58 }
59 }
60
61 /∗∗
62 ∗ Return the threshold value, stored in the preferences.
63 ∗
64 ∗ @return The stored threshold
65 ∗/
66 public int getVal() {
67 return prefs.getInt(prefString, defVal);
68 }
69
70 /∗∗
71 ∗ Call the updateVal method of the object whose value is changed to change the threshold.
72 ∗/
73 public void update() {
74 try {
75 Method method = src.getClass().getMethod(”getValue”);
76 updateVal(method.invoke(src).toString());
77 } catch (NoSuchMethodException e) {
78 // Method newDataAvailable does not exist ==> Ignore
79 } catch (InvocationTargetException e) {
80 } catch (IllegalAccessException e) {
81 // Method newDataAvailable is private not exist ==> Ignore
82 }
83 }
84
85 /∗∗
86 ∗ Overloaded operator that updates the threshold value by first parsing a string.
87 ∗
88 ∗ @param s The new threshold value as a string
89 ∗/
90 public void updateVal(String s) {
91 updateVal(Integer.parseInt(s));
92 }
93
94 /∗∗
95 ∗ If the value has changed, change the threshold in the preferences and send the new ∗ value to
the computer.
96 ∗
97 ∗ @param val An integer, indicating the new threshold value
98 ∗/
99 public void updateVal(int val) {
100 if (alteredVal(val)) {
101 prefs.putInt(prefString, val);
102 sendValue(val);
103 }
104 }
105
106 /∗∗
107 ∗ Send the new threshold value to the robot by sending the identification codes of
108 ∗ the current sensor.
109 ∗

53
110 ∗ @param val The value to be sent
111 ∗/
112 private void sendValue(int val) {
113 try {
114 for (int i = 0; i < ids.length; i++) {
115 SerialConn.write(0);
116 SerialConn.write(code);
117 Thread.sleep(700);
118 SerialConn.write(type);
119 Thread.sleep(700);
120 SerialConn.write(ids[i]);
121 Thread.sleep(700);
122 SerialConn.write(val);
123 }
124 } catch (InterruptedException e) {
125 }
126 }
127
128 /∗∗
129 ∗ Determine whether the new value is different from the stored value.
130 ∗
131 ∗ @param val A new threshold value to be compared with the old one
132 ∗
133 ∗ @return A boolean value indicating whether the provided value is equal to the stored value
134 ∗/
135 private boolean alteredVal(int val) {
136 return (getVal() != val);
137 }
138 }
5.2 Robotcontroller
5.2.1 ADClib.h

1 /∗∗
2 ∗
3 ∗ @file ADClib.h
4 ∗
5 ∗ This file contains the procedures and datatypes that are available in the rest of the program used to
read values from the ADC.
6 ∗
7 ∗ @author Jasper Maes <jasper.maes@gmail.com>
8 ∗
9 ∗/
10
11 #ifndef ADCLIB H
12 #define ADCLIB H
13
14 /∗∗
15 ∗ The @a spi struct contains 4 ports, 3 output and 1 input. These correspond to the 4 control pins on
the ADC chip.
16 ∗/
17 typedef struct spi {

54
18 out port cssd; /∗∗< The @b cssd port is used to select which channel of the ADC must be
read. ∗/
19 out port mosi; /∗∗< The @b mosi is the port that will be used to send the read command to
the ADC. ∗/
20 out port sclk; /∗∗< The @b sclk port is a clock port. The ADC will use this port to measure
the length of the signals that are sent. ∗/
21 in port miso; /∗∗< The @b miso port is the only input port. On this port, the converted data
will arrive. ∗/
22 } spi;
23
24 void init(spi& s);
25 unsigned short read adc(spi& s, int inp);
26
27 #endif /∗ ADCLIB H ∗/
5.2.2 ADClib.xc

1 /∗∗
2 ∗
3 ∗ @file ADClib.xc
4 ∗
5 ∗ This file contains all the procedures that are needed to read a value from the Analog to Digtal
Convertor (ADC)
6 ∗
7 ∗ @author Jasper Maes <jasper.maes@gmail.com>
8 ∗
9 ∗/
10
11 #include <xs1.h>
12 #include <xclib.h>
13
14 #include ”ADClib.h”
15
16 /∗∗
17 ∗ The port clock speed, 100 MHz
18 ∗/
19 #define PORT CLK 100000000
20
21 /∗∗
22 ∗ The SPI clock tick duration. It takes this long to perform 1 measurement.\n
23 ∗ 2 MHz or 20 ticks per measurement at 100kHz or 100kbps (maximum data speed of the ADC)
24 ∗/
25 #define SPI CLK 2000000
26
27 /∗∗
28 ∗ The time that the microcontroller has to wait before sending the next signal on the line.\n
29 ∗ This will result in the ADC running at maximum speed (100kbps)
30 ∗/
31 #define SPI PERIOD (PORT CLK / ( 2 ∗ SPI CLK))
32
33 /∗∗
34 ∗ This bit pattern is the default pattern for the ADC. It puts the ADC in single−ended mode
35 ∗/
36 #define ADC BIT PATTR 0b01100000

55
37
38 /∗∗
39 ∗ The @a init function activates the ADC.\n
40 ∗ First, the ADC is disabled by setting the @a cssd or chip select port high.\\
41 ∗ The other 2 output ports (@a sclk and @a mosi) are put low.
42 ∗
43 ∗ @param s A reference to an ::spi struct
44 ∗/
45 void init(spi& s) {
46 s.cssd <: 1;
47 s.sclk <: 0;
48 s.mosi <: 0;
49 }
50
51 /∗∗
52 ∗ This function is a help function of the read adc function and performs 1 clock tick on the @a sclk
port.
53 ∗ It uses timed I/O to ensure that the operations occur at maximum speed.
54 ∗
55 ∗ @param s A reference to an ::spi struct
56 ∗/
57 void waitClockTick(spi& s){
58 unsigned int count;
59 s.sclk <: 0 @ count; // send 0 to clock port and put counter value in count
60 count += SPI PERIOD;
61 s.sclk @ count <: 1; // set clock port high at specified clock counter
62 count += SPI PERIOD;
63 s.sclk @ count <: 0; // set clock port low at specified clock counter
64 sync(s.sclk); // wait for clock port to finish
65 }
66
67 /∗∗
68 ∗ This function sends a read command to the ADC.\n
69 ∗ It outputs the 7 bits of the command one at a time. Between 2 bits, it waits 1 clock tick before
sending the next bit.
70 ∗
71 ∗ @param s A reference to an ::spi struct
72 ∗ @param cmd A 7 bit command
73 ∗/
74 void sendCommand(spi& s, unsigned int cmd){
75 for (int idx = 0; idx < 7; idx++){
76 s.mosi <: >> cmd; // Send 1 bit
77 waitClockTick(s); // Wait 1 clock tick
78 }
79 }
80
81 /∗∗
82 ∗ The @a read adc function enables the ADC, by setting the @a cssd port high.\n
83 ∗ After that, the ADC will respond to commands that are sent and start sampling and converting
data.\n
84 ∗ These 12 bits are then combined into an unsigned short. Every time a bit is read, the process waits 1
85 ∗ clock tick before reading the next. This is the same pattern as used when sending bits.
86 ∗

56
87 ∗ @param s A reference to an ::spi struct
88 ∗ @param ch A number that indicates the channel to be read
89 ∗
90 ∗ @return The result of the conversion by the ADC
91 ∗/
92 unsigned short read adc(spi& s, int ch){
93 if ((ch >= 0) | (ch <= 7)){
94 // Compose the command for the ADC
95 // The channel number is put into the command at the right position using bit
operations
96 unsigned int res = 0, cmd = bitrev(ADC BIT PATTR | ch << 2) >> 24;
97
98 // Enable the ADC
99 s.cssd <: 0;
100
101 sendCommand(s, cmd);
102
103 // Read the 12 bit value from the miso port
104 for (int idx = 0; idx < 13; idx++){
105 s.miso :> >> res; // read 1 bit
106 waitClockTick(s); // wait 1 clock tick
107 }
108
109 // Disable ADC
110 s.cssd <: 1;
111
112 waitClockTick(s);
113
114 // Reverse the bit order
115 return bitrev(res);
116 }
117 else{
118 // An invalid channel was provided
119 return 0;
120 }
121
122 }
5.2.3 DistanceSensor.h

1 /∗∗
2 ∗
3 ∗ @file distanceSensor.h
4 ∗
5 ∗ This file contains the publically available distance sensor−structs.
6 ∗
7 ∗ @author Jasper Maes <jasper.maes@gmail.com>
8 ∗
9 ∗/
10
11 #include ”Sensor.h”
12
13 #ifndef DISTANCESENSOR H
14 #define DISTANCESENSOR H

57
15
16 extern sensor distanceSensor1;
17 extern sensor distanceSensor2;
18
19 #endif /∗ DISTANCESENSOR H ∗/
5.2.4 DistanceSensor.c

1 /∗∗
2 ∗
3 ∗ @file distanceSensor.c
4 ∗
5 ∗ This file contains all procedures that are combined in the distance sensor−struct.\n
6 ∗ It reads the sensor, the action when the threshold is reached and how to compare the measured value
with the threshold.
7 ∗
8 ∗ @author Jasper Maes <jasper.maes@gmail.com>
9 ∗
10 ∗/
11
12 #include <math.h>
13 #include <xccompat.h>
14
15 #include ”DistanceSensor.h”
16 #include ”Sensor.h”
17 #include ”XcWrapper.h”
18
19 /∗∗
20 ∗ The number of times, the sensor must be read.\n
21 ∗ The sensor should always be read multiple times. Some sensors provide more consistent results and
don’t have to be read that often.
22 ∗/
23 #define SAMPLE SIZE 5
24
25 /∗∗
26 ∗ The ADC channel for the first distance sensor
27 ∗/
28 #define DIST1 0
29
30 /∗∗
31 ∗ The ADC channel for the second distance sensor
32 ∗/
33 #define DIST2 1
34
35 /∗∗
36 ∗ Read the ADC on the right channel and convert the value to a distance.
37 ∗
38 ∗ @param ch The ADC channel of a distance sensor
39 ∗
40 ∗ @return The range that was measured
41 ∗/
42 int getDistance(int ch) {
43 int result = 0;
44 int i = 0;

58
45 for (i = 0; i < SAMPLE SIZE; i++) {
46 result += readADC(ch);
47 }
48
49 return 33353.69 ∗ pow((result / SAMPLE SIZE), −1.05);
50 }
51
52 /∗∗
53 ∗ Read the first range sensor.
54 ∗
55 ∗ @return The value of the first distance sensor
56 ∗/
57 int getDistance1() {
58 return getDistance(DIST1);
59 }
60
61 /∗∗
62 ∗ Read the second range sensor.
63 ∗
64 ∗ @return The value of the second distance sensor
65 ∗/
66 int getDistance2() {
67 return getDistance(DIST2);
68 }
69
70 /∗∗
71 ∗ The action that will be called when the threshold has been passed.\n
72 ∗ It will stop the motor.
73 ∗
74 ∗ @param actionChan The chanend that will receive a code and perform a certain action.
75 ∗/
76 void doRangeAction(chanend actionChan) {
77 sendCharChan(’M’, actionChan);
78 }
79 ;
80
81 /∗∗
82 ∗ A compare function for the first distance sensor.
83 ∗
84 ∗ @param val The value to compare the threshold with
85 ∗
86 ∗ @return 0 or 1 depending if the value is smaller than the threshold or not
87 ∗/
88 int compare1(int val) {
89 return val < distanceSensor1.threshold;
90 }
91
92 /∗∗
93 ∗ A compare function for the second distance sensor.
94 ∗
95 ∗ @param val The value to compare the threshold with
96 ∗
97 ∗ @return 0 or 1 depending if the value is smaller than the threshold or not

59
98 ∗/
99 int compare2(int val) {
100 return val < distanceSensor2.threshold;
101 }
102
103 /∗∗
104 ∗ The left distance sensor with core number, threshold, read function, action, compare function and
identification for when the value is sent over the XBee network.
105 ∗/
106 sensor distanceSensor1 = { 80, getDistance1, doRangeAction, compare1, ’D’, ’L’ };
107
108 /∗∗
109 ∗ The right distance sensor with core number, threshold, read function, action, compare function and
identification for when the value is sent over the XBee network.
110 ∗/
111 sensor distanceSensor2 = { 80, getDistance2, doRangeAction, compare2, ’D’, ’R’ };

5.2.5 Initialization.h

1 /∗∗
2 ∗
3 ∗ @file initialization.h
4 ∗
5 ∗ This file contains all procedures each initialize a certain component of the robot.
6 ∗
7 ∗ @author Jasper Maes <jasper.maes@gmail.com>
8 ∗
9 ∗/
10
11 #ifndef INITIALIZATION H
12 #define INITIALIZATION H
13
14 extern int protocol[128];
15
16 void initializeInputParser();
17 void initializeSensorManagerCore0();
18 void initializeSensorManagerCore1();
19
20 #endif /∗ INITIALIZATION H ∗/
5.2.6 Initialization.c

1 /∗∗
2 ∗
3 ∗ @file initialization.c
4 ∗
5 ∗ This file contains all procedures that initialize a datacomponent of the program.\n
6 ∗ They must be called from the core they will be accessed from.
7 ∗
8 ∗ @author Jasper Maes <jasper.maes@gmail.com>
9 ∗
10 ∗/
11
12 #include <print.h>

60
13
14 #include ”DistanceSensor.h”
15 #include ”Initialization.h”
16 #include ”lightSensor.h”
17 #include ”RpmSensor.h”
18 #include ”SensorManager.h”
19 #include ”TemperatureSensor.h”
20 #include ”XcWrapper.h”
21
22 extern int protocol[128];
23
24 /∗∗
25 ∗ This function initializes the @a InputParser.\n
26 ∗ It initializes the protocol array before adding the required values.
27 ∗/
28 void initializeInputParser(){
29 int i;
30 // Initialize all entries at −1
31 for (i = 0; i < 128; i++){
32 protocol[i] = −1;
33 }
34
35 // Add the number of integer values that follow on the code
36 protocol[’P’] = 0;
37 protocol[’L’] = 0;
38 protocol[’R’] = 0;
39 protocol[’F’] = 0;
40 protocol[’B’] = 0;
41 protocol[’S’] = 0;
42 protocol[’T’] = 3;
43
44 printstr(”InputParser initialized\n”);
45 }
46
47 /∗∗
48 ∗ This function initializes the @a sensorManager.\n
49 ∗ It adds all sensor structs that are required for the robot to the manager of core 1.
50 ∗/
51 void initializeSensorManagerCore1(){
52 int core = get core id();
53
54 addSensor(&rpmSensor1, core);
55 addSensor(&rpmSensor2, core);
56
57 printstr(”Sensors Core 1 initialized\n”);
58 }
59
60 /∗∗
61 ∗ This function initializes the @a sensorManager.\n
62 ∗ It adds all sensor structs that are required for the robot to the manager of core 0 after initializing
the ADC.
63 ∗/
64 void initializeSensorManagerCore0(){

61
65 int core = get core id();
66
67 initializeADC();
68
69 addSensor(&distanceSensor1, core);
70 addSensor(&distanceSensor2, core);
71 addSensor(&temperatureSensor, core);
72 addSensor(&lightSensor, core);
73
74 printstr(”Sensors Core 0 initialized\n”);
75
76 }
5.2.7 InputParser.h

1 /∗∗
2 ∗
3 ∗ @file InputParser.h
4 ∗
5 ∗ This file contains the parser procedures and variables that are available in the rest of the program.
6 ∗
7 ∗ @author Jasper Maes <jasper.maes@gmail.com>
8 ∗
9 ∗/
10
11 #ifndef INPUTPARSER H
12 #define INPUTPARSER H
13
14 extern int protocol[128];
15
16 void parser(chanend input, chanend sensor, chanend motor, chanend pingReply);
17
18 #endif /∗ INPUTPARSER H ∗/
5.2.8 InputParser.xc

1 /∗∗
2 ∗
3 ∗ @file InputParser.xc
4 ∗
5 ∗ This file contains the procedure that will parse all commands.
6 ∗
7 ∗ @author Jasper Maes <jasper.maes@gmail.com>
8 ∗
9 ∗/
10
11 #include ”InputParser.h”
12 #include ”SensorManager.h”
13
14 /∗∗
15 ∗ The maximum number of arguments or integer values that can follow on a code.
16 ∗/
17 #define MAX ARGS 3
18

62
19 /∗∗
20 ∗ The array that contains how many integer values follow on each code.\n
21 ∗ The array is as big as there are 8 bit numbers. This is equal to the number of ACSII characters.
There are thus 128 places and a maximum of 128 codes.
22 ∗/
23 int protocol[128];
24
25
26 /∗∗
27 ∗ This function will receive the data that was read from the XBee and parse it.\n
28 ∗ It uses the ::protocol array to know the number of required arguments to the code that was
received.\n
29 ∗ When all data was read, a signal is sent to one of the channels that are available. These will then
perform the correct action.\n
30 ∗
31 ∗ @param input The chanend where all data will arrive
32 ∗ @param sensor The chanend where new thresholds will be sent to so they can be set in the right
sensor struct
33 ∗ @param motor The chanend where the motor commands will be sent to so the correct motor can be
activated
34 ∗ @param pingReply The chanend of which the other end will reply to the ping sent by the computer
35 ∗/
36 void parser(chanend input, chanend sensor, chanend motor, chanend pingReply){
37 char code = 0;
38 int cnt = 0;
39 int temp = 0;
40 int args[MAX ARGS];
41
42 input <: ’b’; // request a byte
43 input :> code; // code received
44 cnt = protocol[(int)code]; // the number of integer values required
45
46 if (cnt < 0){
47 // if the number of required integers is negative, there is no code assigned to that value
48 // it can thus be ignored
49 return;
50 }
51
52 // read the correct amount of integers for the code
53 for (int i = 0; i < cnt; i++){
54 input <: ’i’;
55 input :> temp;
56 args[i] = temp;
57 }
58
59 switch(code){
60 case ’T’: // Set the threshold
61 sensor <: (char)(args[0]); // Sensor type
62 sensor <: (char)(args[1]); // Sensor id
63 sensor <: args[2]; // New Threshold
64 break;
65 case ’P’: // Reply to the ping
66 pingReply <: ’P’;

63
67 break;
68 case ’L’: // Turn left
69 case ’R’: // Turn right
70 case ’S’: // Stop moving
71 case ’F’: // Move forward
72 case ’B’: // Move backward
73 motor <: code;
74 break;
75 }
76
77 }
5.2.9 LightSensor.h

1 /∗∗
2 ∗
3 ∗ @file lightSensor.h
4 ∗
5 ∗ This file contains the declaration of the light sensor−struct
6 ∗
7 ∗ @author Jasper Maes <jasper.maes@gmail.com>
8 ∗
9 ∗/
10
11 #include ”Sensor.h”
12
13 #ifndef LIGHTSENSOR H
14 #define LIGHTSENSOR H
15
16 extern sensor lightSensor;
17
18 #endif /∗ LIGHTSENSOR H ∗/
5.2.10 LightSensor.c

1 /∗∗
2 ∗
3 ∗ @file lightSensor.c
4 ∗
5 ∗ This file contains all procedures that are combined in the temperature sensor−struct.\n
6 ∗ It reads the sensor, the action when the threshold is reached and how to compare the light intensity
with the threshold.
7 ∗
8 ∗ @author Jasper Maes <jasper.maes@gmail.com>
9 ∗
10 ∗/
11
12 #include <xccompat.h>
13 #include ”XcWrapper.h”
14 #include <math.h>
15
16 #include ”Sensor.h”
17 #include ”lightSensor.h”
18

64
19 /∗∗
20 ∗ The number of times, the sensor must be read.\n
21 ∗ The sensor should always be read multiple times. Some sensors provide more consistent results and
don’t have to be read that often.
22 ∗/
23 #define SAMPLE SIZE 5
24
25 /∗∗
26 ∗ The channel number that must be selected in the ADC
27 ∗/
28 #define LIGHT 3
29
30 /∗∗
31 ∗ This function reads the ADC a number of times (::SAMPLE SIZE). The mean value is then
converted to a light intensity in Lumen.\n
32 ∗ The function that is used for that is
33 ∗
34 ∗ @return The light intensity
35 ∗
36 ∗/
37 int getLight(){
38 float result = 0;
39 int i = 0;
40
41 for (i = 0; i < SAMPLE SIZE; i++){
42 result += readADC(LIGHT);
43 }
44
45 result /= SAMPLE SIZE;
46
47 result = (220∗(42/10)/result)−220; // Convert the received value of the ADC to a resistance
value
48
49 return 1550 ∗ pow(0.99945, result); // Convert the resistance to a distance
50 }
51
52 /∗∗
53 ∗ An empty function that is called when the sensor threshold is reached.\n
54 ∗ Other applications can do something usefull here such as closing a sunscreen for example.
55 ∗
56 ∗ @param actionChan The chanend that will receive a code and perform a certain action.
57 ∗/
58 void doLightAction(chanend actionChan){
59 return;
60 };
61
62 /∗∗
63 ∗ The function that comapres a given value with the threshold.
64 ∗
65 ∗ @param val The value to be compared with the threshold
66 ∗
67 ∗ @return 0 or 1, indicating whether the given value is bigger than the threshold
68 ∗/

65
69 int compareLight(int val){
70 return val > lightSensor.threshold;
71 }
72
73 /∗∗
74 ∗ The sensor struct that contains functions to read the sensor and the action that must be performed
when the threshold is passed.\n
75 ∗ It also contains the core number and which codes must be sent to the computer to identify the
sensor.
76 ∗/
77 sensor lightSensor = {1900, getLight, doLightAction, compareLight, ’L’, ’x’};

5.2.11 Main.xc

1 /∗∗
2 ∗
3 ∗ @file main.xc
4 ∗
5 ∗ This file is the core of the program. It starts all threads and combines all of the robots functionality
using channels.
6 ∗
7 ∗ @author Jasper Maes <jasper.maes@gmail.com>
8 ∗
9 ∗/
10
11 #include <xs1.h>
12 #include <platform.h>
13 #include <print.h>
14
15 #include ”Initialization.h”
16 #include ”InputParser.h”
17 #include ”Motor.h”
18 #include ”SensorManager.h”
19 #include ”XBeelib.h”
20
21 /∗∗
22 ∗ The token that is passed around between the different cores when the sensors are read.
23 ∗/
24 #define TOKEN 1;
25
26 extern int protocol[128];
27 extern rxtx rxtx ports;
28
29 /∗∗
30 ∗ This function will send given sensor value along with it’s type and id over the provided channel.
31 ∗
32 ∗ @param val The value to be sent
33 ∗ @param type The type of the sensor
34 ∗ @param id The id of the sensor
35 ∗ @param txChan One end of the channel over which the value must be sent
36 ∗/
37 void sendSensorValue(int val, int type, int id, chanend txChan){
38 txChan <: ’b’;
39 txChan <: ’V’;

66
40
41 txChan <: ’i’;
42 txChan <: type;
43
44 txChan <: ’i’;
45 txChan <: id;
46
47 txChan <: ’i’;
48 txChan <: val;
49 }
50
51 /∗∗
52 ∗ This listener will send the data it receives on one of it’s channels over the Zigbee network
53 ∗
54 ∗ @param txChan The default channel over which it receives data
55 ∗ @param pingReplyChan The channel that is used to reply to a ping command
56 ∗/
57 void TXlistener(chanend txChan, chanend pingReplyChan){
58 char temp, c;
59 int i;
60 printstr(”TX ready\n”);
61
62 while (1) {
63 select {
64 case pingReplyChan :> temp:
65 // This is a special case that can only send a ping reply, it is used by the @a
InputParser.
66 txByte(rxtx ports.tx, ’P’);
67 break;
68 case txChan :> temp:
69 // In this case, a character indicates what kind of value has to be sent, either
a byte or an integer
70 switch(temp) {
71 case ’b’:
72 txChan :> c;
73 txByte(rxtx ports.tx, c);
74 break;
75 case ’i’:
76 txChan :> i;
77 txInt(rxtx ports.tx, i);
78 break;
79 }
80 break;
81 }
82 }
83 }
84
85 /∗∗
86 ∗ This listener receives data that was sent by the computer and outputs it through a channel.\n
87 ∗ The channel is also used to request values of a certain type. For example a byte or an integer.
88 ∗
89 ∗ @param rxChan The channel on which the received data is put and which indicates the requested
type of data (byte or integer)

67
90 ∗/
91 void RXlistener(chanend rxChan){
92 char temp;
93 printstr(”RX ready\n”);
94 while(1) {
95 rxChan :> temp;
96 switch(temp) {
97 case ’b’: // Request a byte
98 rxChan <: rxByte(rxtx ports.rx);
99 break;
100 case ’i’: // Request an integer
101 rxChan <: rxInt(rxtx ports.rx);
102 break;
103 }
104 }
105 }
106
107 /∗∗
108 ∗ This listener is used to control the motors. It receives it commands over a channel. There is a
second channel that is used to stop
109 ∗ the robot in case of emergency.
110 ∗
111 ∗ @param motorChan The default channel over which commands are sent
112 ∗ @param motorStopChan The emergency channel, no matter what code is sent over this channel, the
robot will always stop.
113 ∗/
114 void MotorListener(chanend motorChan, chanend motorStopChan){
115 char temp;
116 while(1) {
117 select {
118 case motorChan :> temp:
119 break;
120 case motorStopChan :> temp:
121 temp = ’S’;
122 break;
123 };
124
125 // select the appropriate action for each code
126 switch(temp) {
127 case ’B’: // Backward
128 Backward();
129 break;
130 case ’F’: // Forward
131 Forward();
132 break;
133 case ’L’: // Left
134 TurnLeft();
135 break;
136 case ’R’: // Right
137 TurnRight();
138 break;
139 case ’S’: // Stop
140 Stop();

68
141 break;
142 default: // If an other command is received, the robot is stopped to be safe
143 Stop();
144 break;
145 }
146 }
147 }
148
149 /∗∗
150 ∗ This listener is used to set the threshold of the different sensors on different cores.\n
151 ∗ It receives the data over 1 channel and depending on which type of sensor was given, it is outputted
on an other channel.
152 ∗
153 ∗ @param sensorChan The channel that is used to receive data
154 ∗ @param sensorChan0 The channel that will set the threshold of sensors on core 0
155 ∗ @param sensorChan1 The channel that will set the threshold of sensors on core 1
156 ∗/
157 void ThresholdListener(chanend sensorChan, chanend sensorChan0, chanend sensorChan1){
158 int val;
159 char type, id;
160 while (1) {
161 sensorChan :> type;
162 sensorChan :> id;
163 sensorChan :> val;
164
165 switch(type){
166 case ’D’:
167 case ’L’:
168 case ’T’:
169 sensorChan0 <: type;
170 sensorChan0 <: id;
171 sensorChan0 <: val;
172 break;
173 case ’R’:
174 sensorChan1 <: type;
175 sensorChan1 <: id;
176 sensorChan1 <: val;
177 break;
178 }
179
180 }
181 }
182
183 /∗∗
184 ∗ This is the listener that will effectively set the threshold of sensor. It has to be started once on each
core which has sensors connected to it.
185 ∗
186 ∗ @param sensorChan The channel over which the new threshold and target sensor identification will
arrive
187 ∗/
188 void setSensorThresholdListener(chanend sensorChan){
189 int val;
190 char type, id;

69
191 while (1) {
192 sensorChan :> type;
193 sensorChan :> id;
194 sensorChan :> val;
195 setSensorThreshold(type, id, val, get core id());
196 }
197 }
198
199 /∗∗
200 ∗ This function passes the token to the provided channel and waits for the sensor data.\n
201 ∗ If the data is not the end character, the value is sent.
202 ∗
203 ∗ @param coreChan The channel to the core that can start reading and sending values
204 ∗ @param txChan The channel used to send data to the computer
205 ∗/
206 void sendSensorValueLoop(chanend coreChan, chanend txChan){
207 int type, id;
208 int val=0;
209 coreChan <: TOKEN;// Send token
210
211 coreChan :> type;
212 coreChan :> id;
213 coreChan :> val;
214
215 while((char)val != ’E’){// Compare received value with end character
216 sendSensorValue(val, type, id, txChan);
217 coreChan :> type;
218 coreChan :> id;
219 coreChan :> val;
220 }
221 }
222
223 /∗∗
224 ∗ This listener is the control loop over the sensors. It allows the sensors of each core to send their
values one at a time.\n
225 ∗ It uses a round robin schedule to determine which core is allowed next.\n
226 ∗ The sensor value is put on the channel that will take care of sending it to the computer.
227 ∗
228 ∗ @param txChan The output channel, it will send the value to the computer
229 ∗ @param core0 The channel for communication with the sensors on core 0
230 ∗ @param core1 The channel for communication with the sensors on core 1
231 ∗/
232 void SensorSendMainListener(chanend txChan, chanend core0, chanend core1){
233 int i;
234 timer t;
235 unsigned time;
236
237 while(1){
238 for (i = 0; i < 2; i++){
239 switch(i){
240 case 0:
241 sendSensorValueLoop(core0, txChan);
242 break;

70
243 case 1:
244 sendSensorValueLoop(core1, txChan);
245 break;
246 }
247
248 // Wait a while for the computer to catch up
249 t :> time;
250 time += 40000000;
251 t when timerafter(time) :> void;
252
253 }
254 }
255 }
256
257 /∗∗
258 ∗ This function is used to read the value every sensor on that core. \n
259 ∗ The value is first sent over the channel so it can be sent before comparing
260 ∗ with the threshold and if necessary, calling the action.\n
261 ∗ This listener must be started on each core that has sensors connected to it.
262 ∗
263 ∗ @param coreChan The channel on which the sensor data is put
264 ∗ @param sensorActionChan The channel that is used when an action must be called
265 ∗/
266 void CheckSensorsListener(chanend coreChan, chanend sensorActionChan){
267 int i, val, coreNumber = get core id();
268
269 while(1){
270 coreChan :> val; // Receive the token
271 for (i = 0; i < getSensorCount(coreNumber); i++) {
272 coreChan <: (int)getSensorType(i, coreNumber);
273 coreChan <: (int)getSensorId(i, coreNumber);
274 coreChan <: getSensorValue(i, coreNumber);
275
276 // Check if the sensor value has passed the threshold
277 if (passedSensorThreshold(i, val, coreNumber)) {
278 doSensorAction(i, sensorActionChan, coreNumber);
279 }
280 }
281 // Send the codes to return the token
282 coreChan <: (int)’x’;
283 coreChan <: (int)’x’;
284 coreChan <: (int)’E’;
285 }
286 }
287
288 /∗∗
289 ∗ This listener receives action commands when a sensor action is called. These are then sent to an
other listener
290 ∗ who will perform a specific action.
291 ∗
292 ∗ @param sensorActionChan0 The channel for commands from core 0
293 ∗ @param sensorActionChan1 The channel for commands from core 1
294 ∗ @param motorStopChan The channel for commands that have to be sent to the motor

71
295 ∗/
296 void ActionListener(chanend sensorActionChan0, chanend sensorActionChan1, chanend
motorStopChan){
297 char code;
298 while (1) {
299
300 select { // Read the input from the first channel that provides a code
301 case sensorActionChan0 :> code: // The action channel for core 0
302 break;
303 case sensorActionChan1 :> code: // The action channel for core 1
304 break;
305 };
306
307 switch(code) {
308 case ’M’:
309 motorStopChan <: ’S’;
310 break;
311 default:
312 break;
313 }
314
315 }
316 }
317
318 /∗∗
319 ∗ The main function.\n
320 ∗ This function will start all threads, initialize all components and start all listeners.\n
321 ∗ It will also read the sensors and check their values against the threshold, if the value has passed the
threshold, that sensors action will be called.
322 ∗/
323 int main(void) {
324 chan core0, core1, rxChan, txChan, sensorChan, motorChan, motorStopChan,
pingReplyChan, sensorChan0, sensorChan1, sensorActionChan0, sensorActionChan1;
325
326 par {
327 /∗∗
328 ∗ This thread will send the data it receives over the XBee network.
329 ∗/
330 on stdcore[3] : {
331 TXlistener(txChan, pingReplyChan);
332 }
333
334 /∗∗
335 ∗ This thread will receive all data.\n
336 ∗ Other components must signal what type of data they require.
337 ∗/
338 on stdcore[3] : {
339 RXlistener(rxChan);
340 }
341
342 /∗∗
343 ∗ This thread will initialize and call the @a InputParser.
344 ∗/

72
345 on stdcore[1] : {
346 initializeInputParser();
347 while(1) {
348 parser(rxChan, sensorChan, motorChan, pingReplyChan);
349 }
350 }
351
352 /∗∗
353 ∗ This thread translates codes that are received to motor commands.
354 ∗/
355 on stdcore[2] : {
356 startUpMotors();
357 MotorListener(motorChan, motorStopChan);
358 }
359
360 /∗∗
361 ∗ This thread will receive the threshold requests and pass them to the right core.
362 ∗/
363 on stdcore[2] : {
364 ThresholdListener(sensorChan, sensorChan0, sensorChan1);
365 }
366
367 /∗∗
368 ∗ This thread is used to set the threshold value of different sensors on core 0
369 ∗/
370 on stdcore[0] : {
371 setSensorThresholdListener(sensorChan0);
372 }
373
374 /∗∗
375 ∗ This thread is used to set the threshold value of different sensors on core 1
376 ∗/
377 on stdcore[1] : {
378 setSensorThresholdListener(sensorChan1);
379 }
380
381 /∗∗
382 ∗ This thread will read the value from each sensor in the @a sensorManager of core 0
and send it to the computer.\n
383 ∗ If the threshold is passed, it will also call the action that corresponds to that sensor.
384 ∗/
385 on stdcore[0] : {
386 int coreNumber=get core id();
387
388 initializeSensorManagerCore0();
389
390 CheckSensorsListener(core0, sensorActionChan0);
391 }
392
393 /∗∗
394 ∗ This thread will read the value from each sensor in the @a sensorManager of core 1
and send it to the computer.\n
395 ∗ If the threshold is passed, it will also call the action that corresponds to that sensor.

73
396 ∗/
397 on stdcore[1] : {
398 int coreNumber=get core id();
399
400 initializeSensorManagerCore1();
401
402 CheckSensorsListener(core1, sensorActionChan1);
403 }
404
405 /∗∗
406 ∗ This thread is the general loop that will allow each sensorManager to read and send
it’s sensors values. Every sensorManager is processed in turn by passing the
token.
407 ∗/
408 on stdcore[2] : {
409 SensorSendMainListener(txChan, core0, core1);
410 }
411
412 /∗∗
413 ∗ This thread will listen to all actions that are used by the actions inside a sensor
that are called when the threshold is passed.\n
414 ∗ Based on the code it receives, the data is sent to other threads who will process the
code. These are the emergency channels, the code that is sent doesn’t matter, it
has always the same result.
415 ∗/
416 on stdcore[3] : {
417 ActionListener(sensorActionChan0, sensorActionChan1, motorStopChan);
418 }
419
420 }
421
422 return 0;
423 }
5.2.12 Motor.h

1 /∗∗
2 ∗
3 ∗ @file motor.h
4 ∗
5 ∗ This file contains all procedures that are available to control the motors of the robot.\n
6 ∗ It also includes the struct that contains both ports which are connected to both motors
7 ∗
8 ∗ @author Jasper Maes <jasper.maes@gmail.com>
9 ∗
10 ∗/
11
12 #ifndef MOTOR H
13 #define MOTOR H
14
15 /∗∗
16 ∗ A @a motors struct contains 2 ports, one to activate each motor.
17 ∗/
18 typedef struct motors {

74
19 out port M1; /∗∗< The motor that, when activated, makes the robot turn left. ∗/
20 out port M2; /∗∗< The other motor that will make the robot turn right. ∗/
21 } motors;
22
23 extern motors motor ports;
24
25 void Stop();
26 void Forward();
27 void Backward();
28 void TurnLeft();
29 void TurnRight();
30 void startUpMotors();
31
32 #endif /∗ MOTOR H ∗/
5.2.13 Motor.xc

1 /∗∗
2 ∗
3 ∗ @file motor.xc
4 ∗
5 ∗ This file contains all procedures that are needed to control the motors in robot.\n
6 ∗ There are also some private variables to be able to time the operations on the motor controller.
7 ∗
8 ∗ @author Jasper Maes <jasper.maes@gmail.com>
9 ∗
10 ∗/
11
12 #include <platform.h>
13 #include <print.h>
14
15 #include ”Motor.h”
16
17 /∗∗
18 ∗ 1 second at 100MHz
19 ∗/
20 #define SECOND 100000000
21
22 /∗∗
23 ∗ 1 millisecond at 100MHz
24 ∗/
25 #define MIL SEC SECOND/1000
26
27 /∗∗
28 ∗ The value that must be added to the default command to make M1 spin slower or faster
29 ∗/
30 #define MOTOR 1 DIFF 0
31
32 /∗∗
33 ∗ The value that must be added to the default command to make M2 spin slower or faster
34 ∗/
35 #define MOTOR 2 DIFF 0
36
37 /∗∗

75
38 ∗ The define of the stop command, 1.5 milliseconds
39 ∗/
40 #define STOP 3 ∗ MIL SEC/2
41
42 /∗∗
43 ∗ The define of the backward command 1.66 milliseconds
44 ∗/
45 #define BWD 2 ∗ MIL SEC − MIL SEC/3
46
47 /∗∗
48 ∗ The define of the forward command, 1.16 millisecond
49 ∗/
50 #define FWD MIL SEC + MIL SEC/6
51
52 extern motors motor ports;
53
54 /∗∗
55 ∗ This procedure will send a command to both ports in the ::motors struct.\n
56 ∗ Depending on the value of both integer parameters, the motor can be made to spin faster or slower.
This way, they can be aligned.\n
57 ∗ After sending both commands, there is a delay of 6 milliseconds in which the robotcontroller cannot
receive any commands.\n\n
58 ∗
59 ∗ For the timing when sending of a command, a timer has to be used instead of timed I/O which is
more precise.\n
60 ∗ The port counter that is used for timing the operations is only 16 bits big but 1 millisecond, the
shortest possible command,
61 ∗ is 20 bits when converted to 100MHz. This would cause an overflow of the counter and result in
incorrect timings.
62 ∗
63 ∗ @param INCR1 The time the command will last on M1
64 ∗ @param INCR2 The time the command will last on M2
65 ∗ @param motor ports A reference to a motors struct that contains the 2 output ports
66 ∗/
67 void MotorCommand(int INCR1, int INCR2, motors &motor ports){
68 unsigned time;
69 timer t;
70
71 motor ports.M1 <: 1;
72 t :> time;
73 t when timerafter(time+INCR1):>void;
74 motor ports.M1 <: 0;
75
76 motor ports.M2 <: 1;
77 t :> time;
78 t when timerafter(time+INCR2):>void;
79 motor ports.M2 <: 0;
80
81 t:>time;
82 t when timerafter(time+6∗MIL SEC):>void;
83 }
84
85 /∗∗

76
86 ∗ The procedure that will make the robot move forward.\n
87 ∗ It activates both motors in forward mode by sending a signal that is between 1 and 1.5 milliseconds
long.
88 ∗/
89 void Forward(){
90 MotorCommand(FWD + MOTOR 1 DIFF, FWD + MOTOR 2 DIFF, motor ports);
91 }
92
93 /∗∗
94 ∗ The procedure that will make the robot move backward.\n
95 ∗ It activates both motors in forward mode by sending a signal that is between 1.5 and 2 milliseconds
long.
96 ∗/
97 void Backward(){
98 MotorCommand(BWD, BWD, motor ports);
99 }
100
101 /∗∗
102 ∗ The procedure that will stop the motor.\n
103 ∗ It send a signal that is 1.5 milliseconds long to the motor controller.
104 ∗/
105 void Stop(){
106 MotorCommand(STOP, STOP, motor ports);
107 }
108
109 /∗∗
110 ∗ The procedure that will make the robot turn right by activating one of the motors.
111 ∗/
112 void TurnRight(){
113 MotorCommand(BWD, FWD + MOTOR 2 DIFF, motor ports);
114 }
115
116 /∗∗
117 ∗ The procedure that will make the robot turn left by activating one of the motors.
118 ∗/
119 void TurnLeft(){
120 MotorCommand(FWD + MOTOR 1 DIFF, BWD − MOTOR 2 DIFF, motor ports);
121 }
122
123 /∗∗
124 ∗ The procedure that that must be called before sending commands to the motorcontrollers.\n
125 ∗ Both motor ports are put low and there is a 10 second delay in which the motorcontrollers must be
turned on.
126 ∗/
127 void startUpMotors(){
128 timer t;
129 unsigned time;
130
131 motor ports.M1 <: 0;
132 motor ports.M2 <: 0;
133
134 printstr(”Connect the motor controllers in the next 5 seconds\n”);
135 t :> time;

77
136 t when timerafter(time + 5∗SECOND) :> void;
137 printstr(”Motors should be connected by now\n”);
138 }
5.2.14 RpmSensor.h

1 /∗∗
2 ∗
3 ∗ @file rpmSensor.h
4 ∗
5 ∗ This file contains all variables that are publically available for the rest of the program.
6 ∗
7 ∗ @author Jasper Maes <jasper.maes@gmail.com>
8 ∗
9 ∗/
10
11 #include <xccompat.h>
12
13 #include ”Sensor.h”
14
15 #ifndef RPMSENSOR H
16 #define RPMSENSOR H
17
18 extern sensor rpmSensor1;
19 extern sensor rpmSensor2;
20
21 #endif /∗ RPMSENSOR H ∗/
5.2.15 RpmSensor.c

1 /∗∗
2 ∗
3 ∗ @file rpmSensor.c
4 ∗
5 ∗ This file contains all procedures that are combined in the rpm sensor−struct.\n
6 ∗ It reads the sensor, the action when the threshold is reached and how to compare the measured rpm
with another.
7 ∗
8 ∗ @author Jasper Maes <jasper.maes@gmail.com>
9 ∗
10 ∗/
11
12 #include <xccompat.h>
13
14 #include ”RpmSensor.h”
15 #include ”Sensor.h”
16 #include ”XcWrapper.h”
17
18 /∗∗
19 ∗ The number of times, the sensor must be read.\n
20 ∗ The sensor should always be read multiple times. Some sensors provide more consistent results and
don’t have to be read that often.
21 ∗/
22 #define SAMPLE SIZE 5

78
23
24 /∗∗
25 ∗ Reads the sensor a number of times and returns the mean value.\n
26 ∗ This is because the sensor output isn’t stable.
27 ∗
28 ∗ @return The number of rotations per minute
29 ∗/
30 int getRpm(char c){
31 int result = 0;
32 int i = 0;
33 for (i = 0; i < SAMPLE SIZE; i++){
34 result += readRPM(c);
35 }
36
37 return result/SAMPLE SIZE;
38 }
39
40 /∗∗
41 ∗ This function measures the time between 2 pulses. There is 1 pulse for each rotation the wheel
makes.
42 ∗ It read the left sensor.
43 ∗
44 ∗ @return The number of rotations per minute
45 ∗/
46 int readSensorL(){
47 return readRPM(’L’);
48 }
49
50 /∗∗
51 ∗ This function measures the time between 2 pulses. There is 1 pulse for each rotation the wheel
makes.\n
52 ∗ It read the right sensor.
53 ∗
54 ∗ @return The number of rotations per minute
55 ∗/
56 int readSensorR(){
57 return readRPM(’R’);
58 }
59
60 /∗∗
61 ∗ The action that is called when the threshold is passed.\n
62 ∗ It could be used to prevent the robot from driving too fast.
63 ∗
64 ∗ @param actionChan The chanend that will receive a code and perform a certain action.
65 ∗/
66 void doRpmAction(chanend actionChan){};
67
68
69 /∗∗
70 ∗ The function that compares a given value with the threshold of the first rpmsensor.
71 ∗
72 ∗ @param val The value to be compared with the threshold
73 ∗

79
74 ∗ @return 0 or 1, indicating whether the given value is bigger than the threshold
75 ∗/
76 int compareRpm1(int val){
77 return val > rpmSensor1.threshold;
78 }
79
80 /∗∗
81 ∗ The function that compares a given value with the threshold of the second rpmsensor.
82 ∗
83 ∗ @param val The value to be compared with the threshold
84 ∗
85 ∗ @return 0 or 1, indicating whether the given value is bigger than the threshold
86 ∗/
87 int compareRpm2(int val){
88 return val > rpmSensor2.threshold;
89 }
90
91 /∗∗
92 ∗ The sensor struct that contains functions to read the sensor and the action that must be performed
when the threshold is passed.\n
93 ∗ It also contains the codes that must be sent to the computer to identify the sensor.
94 ∗/
95 sensor rpmSensor1 = {40000, readSensorL, doRpmAction, compareRpm1, ’R’, ’L’};
96
97 /∗∗
98 ∗ The sensor struct that contains functions to read the sensor and the action that must be performed
when the threshold is passed.\n
99 ∗ It also contains the codes that must be sent to the computer to identify the sensor.
100 ∗/
101 sensor rpmSensor2 = {40000, readSensorR, doRpmAction, compareRpm2, ’R’, ’R’};

5.2.16 Sensor.h

1 #ifndef SENSOR H
2 #define SENSOR H
3
4 /∗∗
5 ∗
6 ∗ @file sensor.h
7 ∗
8 ∗ This file contains all procedures that work on sensor structs and are only available in C files.\n
9 ∗ The sensor struct contains function pointers and the functions contain pointers to a sensor struct
and is thus only available in a C file as XC does not allow the use of pointers.
10 ∗
11 ∗ @author Jasper Maes <jasper.maes@gmail.com>
12 ∗
13 ∗/
14
15 #ifndef XC
16
17 #include <xccompat.h>
18
19 /∗∗

80
20 ∗ The sensor struct, it contains the core number on which the sensor is connected, the threshold, a
function to read the sensor,
21 ∗ the action that is called when the threshold is passed, a function to compare a value with the
threshold, a character that indicates
22 ∗ the type of the sensor and a character that is the id of the sensor. These 2 characters will be used
to identify the sensor whose value
23 ∗ was received on the computer.
24 ∗/
25 typedef struct {
26 int threshold; /∗∗< The threshold of the sensor ∗/
27 int (∗ read)(void); /∗∗< The function to read the value of the sensor ∗/
28 void (∗ doAction)(chanend); /∗∗< The action that will be called when the threshold is passed
∗/
29 int (∗ compare)(int); /∗∗< The function to compare a value with the sensor threshold ∗/
30 char type; /∗∗< The sensor type ∗/
31 char id; /∗∗< The sensor identification within the type ∗/
32 } sensor;
33
34 int getValue(sensor∗ s);
35 void setThreshold(sensor∗ s, int newThres);
36 int getThreshold(sensor∗ s);
37 void doAction(sensor∗ s, chanend actionChan);
38 int aboveThreshold(sensor∗ s, int val);
39 char getType(sensor∗ s);
40 char getId(sensor∗ s);
41
42 #endif
43
44 #endif
5.2.17 Sensor.c

1 /∗∗
2 ∗
3 ∗ @file sensor.c
4 ∗
5 ∗ This file contains procedures that are syntactic sugar for operations on sensor structs.\n
6 ∗ They were added to make it easier for the programmer to work with and to do some checking before
calling the procedure.
7 ∗
8 ∗ @author Jasper Maes <jasper.maes@gmail.com>
9 ∗
10 ∗/
11
12 #include ”Sensor.h”
13 #include ”XcWrapper.h”
14
15 /∗∗
16 ∗ This function sets the threshold of the given sensor to the new value.
17 ∗
18 ∗ @param s A pointer to a ::sensor struct
19 ∗ @param newThres The new threshold value
20 ∗/
21 void setThreshold(sensor∗ s, int newThres){

81
22 if (s != 0)
23 s−>threshold = newThres;
24 }
25
26 /∗∗
27 ∗ This function returns the threshold of the given sensor.
28 ∗
29 ∗ @param s A pointer to a ::sensor struct
30 ∗
31 ∗ @return The sensor threshold value or 0, if the provided sensor is a null pointer
32 ∗/
33 int getThreshold(sensor∗ s){
34 if (s != 0)
35 return s−>threshold;
36 else
37 return 0;
38 }
39
40 /∗∗
41 ∗ This function clls the action that is stored in the sensor
42 ∗
43 ∗ @param s A pointer to a ::sensor struct
44 ∗ @param actionChan The channel to which commands will be sent that then will be dispatched to an
action
45 ∗/
46 #pragma stackfunction 100
47 void doAction(sensor∗ s, chanend actionChan){
48 if (s != 0)
49 (∗s−>doAction)(actionChan);
50 }
51
52 /∗∗
53 ∗ This function compares the given value to the threshold of the given sensor.
54 ∗
55 ∗ @param s A pointer to a ::sensor struct
56 ∗ @param val The value to compare with the threshold
57 ∗
58 ∗ @return 0 or 1 depending on if the value is bigger than the sensor or not
59 ∗/
60 #pragma stackfunction 100
61 int aboveThreshold(sensor∗ s, int val){
62 if (s != 0)
63 return (∗s−>compare)(val);
64 else
65 return 0;
66 }
67
68 /∗∗
69 ∗ This function reads and returns the value of the given sensor.
70 ∗
71 ∗ @param s A pointer to a ::sensor struct
72 ∗
73 ∗ @return The value of the sensor or 0 if the sensor is a null pointer

82
74 ∗/
75 #pragma stackfunction 100
76 int getValue(sensor∗ s){
77 if (s != 0)
78 return (∗s−>read)();
79 else
80 return 0;
81 }
82
83
84 /∗∗
85 ∗ This function returns the type of the sensor.
86 ∗
87 ∗ @param s A pointer to a ::sensor struct
88 ∗
89 ∗ @return A character indicating the type of the sensor
90 ∗/
91 char getType(sensor∗ s){
92 if (s != 0)
93 return s−>type;
94 else
95 return 0;
96 }
97
98 /∗∗
99 ∗ This function returns the id of the sensor.
100 ∗
101 ∗ @param s A pointer to a ::sensor struct
102 ∗
103 ∗ @return A character indicating the id of the sensor
104 ∗/
105 char getId(sensor∗ s){
106 if (s != 0)
107 return s−>id;
108 else
109 return 0;
110 }
5.2.18 SensorManager.h

1 /∗∗
2 ∗
3 ∗ @file sensorManager.h
4 ∗
5 ∗ The sensor manager stores all sensor structs and provides function that make it easier to call
functions inside the struct.\n
6 ∗ All pointers were hidden inside the implementation so that the functions can be called from an XC
file.
7 ∗
8 ∗ @author Jasper Maes <jasper.maes@gmail.com>
9 ∗
10 ∗/
11
12 #ifndef SENSORMANAGER H

83
13 #define SENSORMANAGER H
14
15 #include <xccompat.h>
16
17 #include ”Sensor.h”
18
19 #ifndef XC
20 void addSensor(sensor∗ s, int coreNumber);
21 #endif
22
23 int getSensorValue(int idx, int coreNumber);
24 void setSensorThreshold(char type, char id, int newThres, int coreNumber);
25 int getSensorThreshold(int idx, int coreNumber);
26 void doSensorAction(int idx, chanend actionChan, int coreNumber);
27 int getSensorCoreNumber(int idx, int coreNumber);
28 int passedSensorThreshold(int idx, int val, int coreNumber);
29 int getSensorCount(int coreNumber);
30 char getSensorType(int idx, int coreNumber);
31 char getSensorId(int idx, int coreNumber);
32
33 #endif /∗ SENSORMANAGER H ∗/
5.2.19 SensorManager.c

1 /∗∗
2 ∗
3 ∗ @file sensorManager.c
4 ∗
5 ∗ This file contains the procedures and variables that provide a data structure where all sensor structs
can be saved in.\n
6 ∗ There are functions provided that are syntactic sugar for operations on the underlying structure that
stores the sensors.
7 ∗
8 ∗ @author Jasper Maes <jasper.maes@gmail.com>
9 ∗
10 ∗/
11
12 #include <xccompat.h>
13
14 #include ”Sensor.h”
15 #include ”SensorManager.h”
16 #include ”XcWrapper.h”
17
18 /∗∗
19 ∗ The maximum number of sensors that can be added to the sensorManager.
20 ∗/
21 #define MAX SENSOR COUNT 10
22
23 /∗∗
24 ∗ The struture that stores an array of sensors and the number of sensors that are in the array.
25 ∗/
26 typedef struct SensorManager {
27 int sensorCounter; /∗∗< The number of sensors in the array ∗/
28 sensor∗ sensors[MAX SENSOR COUNT]; /∗∗< The array that stores the array ∗/

84
29 } SensorManager;
30
31 /∗∗
32 ∗ The sensors connected to a port on core 0.\n
33 ∗ To be used in a SensorManager struct.
34 ∗/
35 sensor∗ core0Sensors[MAX SENSOR COUNT];
36
37 /∗∗
38 ∗ The sensors connected to a port on core 1.\n
39 ∗ To be used in a SensorManager struct.
40 ∗/
41 sensor∗ core1Sensors[MAX SENSOR COUNT];
42
43 /∗∗
44 ∗ The SensorManager for the sensors on core 0.
45 ∗/
46 SensorManager core0 = {0, core0Sensors};
47
48 /∗∗
49 ∗ The SensorManager for the sensors on core 1.
50 ∗/
51 SensorManager core1 = {0, core1Sensors};
52
53 /∗∗
54 ∗ This procedure returns the SensorManager struct that contains the sensors that are connected to
that core.
55 ∗
56 ∗ @param coreNumber The number of the core whose sensors are requested
57 ∗
58 ∗ @return The sensormanager object
59 ∗/
60 SensorManager∗ getManager(int coreNumber){
61 switch(coreNumber){
62 case 0:
63 return &core0;
64 case 1:
65 return &core1;
66 default:
67 return 0;
68 }
69 }
70
71 /∗∗
72 ∗ This function reads the amount of sensors from the ::SensorManager struct.
73 ∗
74 ∗ @return The number of sensors in the ::SensorManager
75 ∗/
76 int getSensorCounter(SensorManager∗ manager){
77 return manager−>sensorCounter;
78 }
79
80 /∗∗

85
81 ∗ Returns the number of sensors in the ::SensorManager of that core.
82 ∗
83 ∗ @return The number of sensors connected to that core
84 ∗/
85 int getSensorCount(int coreNumber){
86 return getSensorCounter(getManager(coreNumber));
87 }
88
89 /∗∗
90 ∗ Add a sensor to the sensormanager.\n
91 ∗ It doesn’t allow to add more sensors than the array is large.
92 ∗
93 ∗ @param s A pointer to a ::sensor struct
94 ∗ @param coreNumber The number of the core to which the sensor should be added
95 ∗/
96 void addSensor(sensor∗ s, int coreNumber){
97 SensorManager∗ manager = getManager(coreNumber);
98
99 if (getSensorCounter(manager) < MAX SENSOR COUNT){
100 manager−>sensors[manager−>sensorCounter++] = s;
101 }
102 }
103
104 /∗∗
105 ∗ Get the sensor at the given index in the ::SensorManager.
106 ∗
107 ∗ @param manager The sensor manager struct containing the sensors
108 ∗ @param idx The index in the array to be retrieved
109 ∗
110 ∗ @return A pointer to a ::sensor struct or 0 when the requested index is bigger than the number of
sensors
111 ∗/
112 sensor∗ getSensor(SensorManager∗ manager, int idx){
113 if (idx < getSensorCounter(manager))
114 return manager−>sensors[idx];
115 else
116 return 0;
117 }
118
119 /∗∗
120 ∗ Get the sensor at the given index on the given core.\n
121 ∗ It will first look up the correct ::SensorManager and return the sensor from it.
122 ∗
123 ∗ @param idx The index in the array to be retrieved
124 ∗ @param coreNumber The core on which the sensor resides
125 ∗
126 ∗ @return A pointer to a ::sensor struct or 0 when the requested index is bigger than the number of
sensors
127 ∗/
128 sensor∗ getSensorIdx(int idx, int coreNumber){
129 return getSensor(getManager(coreNumber), idx);
130 }
131

86
132 /∗∗
133 ∗ Syntactic sugar to retrieve the value of the sensor at the given index.\n
134 ∗ It is needed because the procedure on the sensor requires a pointer to a ::sensor struct.
135 ∗
136 ∗ @param idx The sensor index
137 ∗ @param coreNumber The core on which the sensor resides that is to be read
138 ∗
139 ∗ @return The sensor value
140 ∗/
141 int getSensorValue(int idx, int coreNumber){
142 return getValue(getSensorIdx(idx, coreNumber));
143 }
144
145 /∗∗
146 ∗ Syntactic sugar to retrieve the threshold value of the sensor at the given index.\n
147 ∗ It is needed because the procedure on the sensor requires a pointer to a ::sensor struct.
148 ∗
149 ∗ @param idx The sensor index
150 ∗ @param coreNumber The number of the core to which the sensor is connected whose threshold is
requested
151 ∗
152 ∗ @return The sensor threshold
153 ∗/
154 int getSensorThreshold(int idx, int coreNumber){
155 return getThreshold(getSensorIdx(idx, coreNumber));
156 }
157
158 /∗∗
159 ∗ This funtcion will set the threshold of thesensor identified by it’s type and id to the new value.
160 ∗
161 ∗ @param type The type of the sensor
162 ∗ @param id The id of the sensor
163 ∗ @param newThres The new value of the threshold
164 ∗ @param coreNumber The number of the core to which the sensor is connected
165 ∗/
166 void setSensorThreshold(char type, char id, int newThres, int coreNumber){
167 SensorManager∗ manager = getManager(coreNumber);
168 int i;
169
170 for (i = 0; i < getSensorCount(manager); i++){
171 sensor∗ s = getSensor(manager, i);
172 if ((getType(s) == type) & (getId(s) == id))
173 setThreshold(s, newThres);
174 }
175 }
176
177 /∗∗
178 ∗ Syntactic sugar to check a value against the threshold of the sensor at the given index.\n
179 ∗ It is needed because the procedure on the sensor requires a pointer to a ::sensor struct.
180 ∗
181 ∗ @param idx The sensor index
182 ∗ @param val The value to compare

87
183 ∗ @param coreNumber The number of the core on which the sensor resides whose threshold must be
compared
184 ∗
185 ∗ @return 0 or 1 indicating if the value is bigger than the threshold or not
186 ∗/
187 int passedSensorThreshold(int idx, int val, int coreNumber){
188 return aboveThreshold(getSensorIdx(idx, coreNumber), val);
189 }
190
191 /∗∗
192 ∗ Syntactic sugar to call the action of the sensor at the given index.\n
193 ∗ It is needed because the procedure on the sensor requires a pointer to a ::sensor struct.
194 ∗
195 ∗ @param idx The sensor index
196 ∗ @param actionChan The channel to which a code is sent to perfom a certain operation
197 ∗ @param coreNumber The number of the core on which the sensor resides whose action should be
called
198 ∗
199 ∗/
200 void doSensorAction(int idx, chanend actionChan, int coreNumber){
201 doAction(getSensorIdx(idx, coreNumber), actionChan);
202 }
203
204 /∗∗
205 ∗ This function returns the type of the ::sensor. The sensor is identified by an index number and a
core number.
206 ∗
207 ∗ @param idx The index of the sensor that is requested
208 ∗ @param coreNumber The number of the core to which the sensor is connected
209 ∗
210 ∗ @return A character indicating the type of sensor
211 ∗/
212 char getSensorType(int idx, int coreNumber){
213 return getType(getSensorIdx(idx, coreNumber));
214 }
215
216 /∗∗
217 ∗ This function returns the id of the ::sensor. The sensor is identified by an index number and a core
number.
218 ∗
219 ∗ @param idx The index of the sensor that is requested
220 ∗ @param coreNumber The number of the core to which the sensor is connected
221 ∗
222 ∗ @return A character indicating the id of sensor
223 ∗/
224 char getSensorId(int idx, int coreNumber){
225 return getId(getSensorIdx(idx, coreNumber));
226 }
5.2.20 TemperatureSensor.h

1 /∗∗
2 ∗
3 ∗ @file temperatureSensor.h

88
4 ∗
5 ∗ This file contains the temperature sensor struct that is available in the rest of the program.
6 ∗
7 ∗ @author Jasper Maes <jasper.maes@gmail.com>
8 ∗
9 ∗/
10
11 #include ”Sensor.h”
12
13 #ifndef TEMPERATURESENSOR H
14 #define TEMPERATURESENSOR H
15
16 extern sensor temperatureSensor;
17
18 #endif /∗ TEMPERATURESENSOR H ∗/
5.2.21 TemperatureSensor.c

1 /∗∗
2 ∗
3 ∗ @file temperatureSensor.c
4 ∗
5 ∗ This file contains all procedures that are combined in the temperature sensor−struct.\n
6 ∗ It reads the sensor, the action when the threshold is reached and how to compare the temperature
with another.
7 ∗
8 ∗ @author Jasper Maes <jasper.maes@gmail.com>
9 ∗
10 ∗/
11
12 #include <math.h>
13 #include <xccompat.h>
14
15 #include ”Sensor.h”
16 #include ”TemperatureSensor.h”
17 #include ”XcWrapper.h”
18
19 /∗∗
20 ∗ The number of times, the sensor must be read.\n
21 ∗ The sensor should always be read multiple times. Some sensors provide more consistent results and
don’t have to be read that often.
22 ∗/
23 #define SAMPLE SIZE 5
24
25 /∗∗
26 ∗ The channel to which the temperature sensor is connected on the ADC.
27 ∗/
28 #define TEMP CH 2
29
30 /∗∗
31 ∗ The resistance of the thermistor at 25 degrees Celsius.
32 ∗/
33 #define R0 4007
34

89
35 /∗∗
36 ∗ 25 degrees Celsius in Kelvin.
37 ∗/
38 #define T0 298.15
39
40 /∗∗
41 ∗ A constant that characterizes the thermistor.
42 ∗/
43 #define B 6472
44
45 /∗∗
46 ∗ Reads the ADC and converts the value to a temperature in degrees Celsius.
47 ∗
48 ∗ @return The temperature in degrees Celsius
49 ∗/
50 int getTemperature(){
51 float result = 0;
52 int i = 0;
53 float val;
54 for (i = 0; i < SAMPLE SIZE; i++){
55 result += readADC(TEMP CH);
56 }
57
58 result = result/SAMPLE SIZE;
59 result /= 1000;
60
61 float R = (220∗4.2/result)−220;
62
63 //Rinf = R0 ∗ eˆ(−B/T0)
64 float Rinf = R0∗exp(−B/T0);
65 // T = B / ln(R/Rinf)
66 val = B/(log(R/Rinf));
67 // Convert Kelvin to Celsius for return
68 return val−273.15;
69 }
70
71 /∗∗
72 ∗ The action that will be triggered when the threshold is passed.
73 ∗
74 ∗ @param actionChan The channel that is connected to a listener that will trigger the action (possibly
on an different core) that corresponds to the code that was sent
75 ∗/
76 void doTemperatureAction(chanend actionChan){};
77
78 /∗∗
79 ∗ The procedure that is used to compare a value with the threshold.
80 ∗
81 ∗ @param val The value to compare the threshold with.
82 ∗
83 ∗ @return 1 if the value is bigger than the threshold or 0 if it is not
84 ∗/
85 int compareTemp(int val){
86 return val > temperatureSensor.threshold;

90
87 }
88
89 /∗∗
90 ∗ The temperaturesensor struct with all procedures the core number, threshold, and which codes must
be sent when sending the value.
91 ∗/
92 sensor temperatureSensor = {60, getTemperature, doTemperatureAction, compareTemp, ’T’, ’x’};

5.2.22 XBeelib.h

1 /∗∗
2 ∗
3 ∗ @file XBeelib.h
4 ∗
5 ∗ The XBee library consists of a number of functions that will send data over the XBee network or
receive data from another node.
6 ∗
7 ∗ @author Jasper Maes <jasper.maes@gmail.com>
8 ∗
9 ∗/
10
11 #ifndef XBEELIB H
12 #define XBEELIB H
13
14 /∗∗
15 ∗ An rxtx struct contains 2 ports, one for receiving data and one for sending data
16 ∗/
17 typedef struct rxtx {
18 out port tx; /∗∗< The port to transmit data ∗/
19 in port rx; /∗∗< The port to receive data ∗/
20 } rxtx;
21
22 extern rxtx rxtx ports;
23
24 char rxByte (in port rt);
25 void rxByteChan (in port rt, chanend c);
26 int rxInt (in port rt);
27 void rxIntChan (in port rt, chanend c);
28 void txByte (out port rt, char byte);
29 void txInt (out port rt, int byte);
30
31 #endif /∗ XBEELIB H ∗/
5.2.23 XBeelib.xc

1 /∗∗
2 ∗
3 ∗ @file XBeelib.xc
4 ∗
5 ∗ The XBee library consists of a number of functions that will send data over the XBee network or
receive data from another node.
6 ∗
7 ∗ @author Jasper Maes <jasper.maes@gmail.com>
8 ∗

91
9 ∗/
10
11 #include <platform.h>
12 #include <xs1.h>
13
14 #include ”XBeelib.h”
15
16 /∗∗
17 ∗ The speed at which bits are sent. In number of bits per second.
18 ∗/
19 #define BIT RATE 9600
20
21 /∗∗
22 ∗ The time it takes to send one bit at the specified bitrate when the clockspeed is 100MHz.
23 ∗/
24 #define BIT TIME XS1 TIMER HZ / BIT RATE
25
26 /∗∗
27 ∗ The number of bits that are contained in the integer data type.
28 ∗/
29 #define INT SIZE 32
30
31 /∗∗
32 ∗ The number of bits that are contained in the byte data type.
33 ∗/
34 #define BYTE SIZE 8
35
36 /∗∗
37 ∗ The number of bytes that are contained in an integer.
38 ∗/
39 #define INT BYTE CNT INT SIZE/BYTE SIZE
40
41 /∗∗
42 ∗ The procedure that will send a byte over the XBee network.\n
43 ∗ The byte is divided into parts of 1 bit large. Every bit is then put onto the tx port for a specific time
before the next bit is sent.\n
44 ∗ This time is determined by the BIT TIME variable
45 ∗
46 ∗ @param rt The output port
47 ∗ @param byte The character (8 bit) to be sent
48 ∗/
49 void txByte(out port rt, char byte) {
50 unsigned time;
51 timer t;
52
53 // input initial time
54 t :> time;
55
56 // output start bit
57 rt <: 0;
58 time += BIT TIME;
59 t when timerafter (time) :> void;
60

92
61 // output data bits
62 for (int i=0; i < BYTE SIZE; i++) {
63 rt <: >> byte;
64 time += BIT TIME;
65 t when timerafter (time) :> void;
66 }
67
68 // output stop bit
69 rt <: 1;
70 time += BIT TIME∗2;
71 t when timerafter (time) :> void;
72 }
73
74 /∗∗
75 ∗ This function decomposes the provided integer value into a number of bytes which are then one by
one transmitted.
76 ∗
77 ∗ @param rt The output port
78 ∗ @param value The integer to be sent
79 ∗/
80 void txInt(out port rt, int value) {
81 // divide the int in INT BYTE CNT bytes and transmit them one by one
82 for (int i = INT BYTE CNT; i > 0; i−−){
83 txByte(rt, (value >> (i ∗ 8)));
84 }
85 }
86
87 /∗∗
88 ∗ The procedure that will read a byte that was sent over the XBee network.\n
89 ∗ The byte is composed of 8 bits that are received and put together by byteshifting.\n
90 ∗
91 ∗ @param rt The input port
92 ∗
93 ∗ @return A character (8 bit) that contains the received value
94 ∗/
95 char rxByte(in port rt) {
96 unsigned byte;
97 unsigned time;
98 char val;
99
100 // Wait for start bit
101 rt when pinseq (0) :> void @ time;
102 time += BIT TIME / 2;
103
104 // Input data bits
105 for (int i = 0; i < BYTE SIZE; i++) {
106 time += BIT TIME;
107 rt @ time :> >> byte;
108 }
109
110 // Input stop bit
111 time += BIT TIME;
112 rt @ time :> void;

93
113
114 val = (byte >> 24);
115 return val;
116 }
117
118 /∗∗
119 ∗ This function is the same as the rxByte function except for the fact that the value is sent over a
channel insted of returned.
120 ∗
121 ∗ @param rt The input port
122 ∗ @param c The channel to which the value must be sent
123 ∗/
124 void rxByteChan(in port rt, chanend c) {
125 c <: rxByte(rt);
126 }
127
128 /∗∗
129 ∗ The procedure that will read an integer value that was sent over the XBee network.\n
130 ∗ The byte is composed of 8 bits that are received and put together by byteshifting.
131 ∗
132 ∗ @param rt The input port
133 ∗
134 ∗ @return An integer value that contains the received value
135 ∗/
136 int rxInt(in port rt) {
137 int val = 0;
138 for (int j = 0; j < INT BYTE CNT; j++) {
139 val += rxByte(rt) << 8 ∗ (INT BYTE CNT − 1 − j);
140 }
141 return val;
142 }
143
144 /∗∗
145 ∗ This function is the same as the rxInt function except for the fact that the value is sent over a
channel insted of returned.
146 ∗
147 ∗ @param rt The input port
148 ∗ @param c The channel to which the value must be sent
149 ∗/
150 void rxIntChan(in port rt, chanend c) {
151 c <: rxInt(rt);
152 }
5.2.24 xcWrapper.h

1 /∗∗
2 ∗
3 ∗ @file xcWrapper.h
4 ∗
5 ∗ This file is a collection of functions that perform certain specific XC functions such as output data
to ports or send a value over a channel.\n
6 ∗ Using these functions, a C file can do those XC functions.
7 ∗
8 ∗ @author Jasper Maes <jasper.maes@gmail.com>

94
9 ∗
10 ∗/
11
12 #ifndef XC WRAPPER H
13 #define XC WRAPPER H
14
15 #include <platform.h>
16
17 unsigned getTimerValue();
18 void waitPulse(port p, char pulse );
19 void sendCharChan(char v, chanend c);
20 void sendIntChan(int v, chanend c);
21 unsigned short readADC(int ch);
22 void initializeADC();
23 unsigned int readRPM(char c);
24
25 #endif /∗ XC WRAPPER H ∗/
5.2.25 xcWrapper.xc

1 /∗∗
2 ∗
3 ∗ @file xcWrapper.xc
4 ∗
5 ∗ This file is a collection of functions that perform certain specific XC functions such as output data
to ports or send a value over a channel.\n
6 ∗ Using these functions, a C file can do those XC functions.
7 ∗
8 ∗ @author Jasper Maes <jasper.maes@gmail.com>
9 ∗
10 ∗/
11
12 #include ”ADClib.h”
13 #include ”Motor.h”
14 #include ”XBeelib.h”
15 #include ”XcWrapper.h”
16
17 /∗∗
18 ∗ A timer that is used in other functions.
19 ∗/
20 timer tmr;
21
22 /∗∗
23 ∗ Returns the current value of the timer that was defined in this file
24 ∗
25 ∗ @return An unsigned integer value that contains the current timer value
26 ∗/
27 unsigned getTimerValue(){
28 unsigned t;
29 tmr :> t;
30 return t;
31 }
32
33 /∗∗

95
34 ∗ This procedure waits untill the requested value is put on the line.
35 ∗
36 ∗ @param p A port to listen on
37 ∗ @param pulse The value that the procedure must wait for (0 or 1)
38 ∗/
39 void waitPulse(port p, char pulse){
40 p when pinseq(pulse) :> void;
41 }
42
43 /∗∗
44 ∗ The ::spi struct that contains the ports to which the ADC is connected.
45 ∗/
46 spi spi ports = {
47 on stdcore[0] : XS1 PORT 1A,
48 on stdcore[0] : XS1 PORT 1C,
49 on stdcore[0] : XS1 PORT 1D,
50 on stdcore[0] : XS1 PORT 1B};
51
52 /∗∗
53 ∗ The function that reads the given ADC channel using the ::spi ports variable.
54 ∗
55 ∗ @param ch The channel to be read.
56 ∗/
57 unsigned short readADC(int ch){
58 return read adc(spi ports, ch);
59 }
60
61 /∗∗
62 ∗ The function that initializes the ADC that is connected to the ports in the ::spi ports variable.
63 ∗/
64 void initializeADC(){
65 init(spi ports);
66 }
67
68 /∗∗
69 ∗ The ::rxtx struct that contains the ports to which the XBee is connected.
70 ∗/
71 rxtx rxtx ports = {
72 on stdcore[3] : XS1 PORT 1F,
73 on stdcore[3] : XS1 PORT 1E};
74
75 /∗∗
76 ∗ Send a character over the given channel.
77 ∗
78 ∗ @param v The character to be sent
79 ∗ @param c The channel to send the value over
80 ∗/
81 void sendCharChan(char v, chanend c){
82 c <: v;
83 }
84
85 /∗∗
86 ∗ Send an integer over the given channel.

96
87 ∗
88 ∗ @param v The integer to be sent
89 ∗ @param c The channel to send the value over
90 ∗/
91 void sendIntChan(int v, chanend c){
92 c <: v;
93 }
94
95 /∗∗
96 ∗ The ::motors struct that contains the ports to which the motors are connected.
97 ∗/
98 motors motor ports = {
99 on stdcore[2] : XS1 PORT 1A,
100 on stdcore[2] : XS1 PORT 1B};
101
102
103 /∗∗
104 ∗ The RPM sensor struct containing the ports to which both sensors are connected.
105 ∗/
106 typedef struct {
107 port left; /∗∗< The left sensor ∗/
108 port right; /∗∗< The right sensor ∗/
109 } rpm;
110
111 /∗∗
112 ∗ The ::rpm sensor struct to be used for reading the rpm sensor values.
113 ∗/
114 rpm rpm ports = {
115 on stdcore[1] : XS1 PORT 1A,
116 on stdcore[1] : XS1 PORT 1B};
117
118 /∗∗
119 ∗ This function will measure the time a pulse lasts on a given port.
120 ∗
121 ∗ @param p The port on which the pulse will arrive
122 ∗ @param pulse The pulse (0/1) whose duration must be measured
123 ∗
124 ∗ @return An unsigned integer indicating the duration of a pulse
125 ∗/
126 unsigned int timePulse(in port p, int pulse){
127 unsigned t1, t2;
128 timer tmr;
129
130 p when pinseq(pulse) :> void; // wait for pulse
131 tmr :> t1;
132
133 p when pinseq(!pulse) :> void; // wait for opposite pulse
134 tmr :> t2;
135
136 return t2 − t1;
137 }
138
139 /∗∗

97
140 ∗ This function will read the number of rotations the wheel makes in 1 second by measuring the time
between pulses generated by the sensor.
141 ∗
142 ∗ @param c A character indicating to read the left or right port
143 ∗
144 ∗ @return An unsigned integer indicating the number of rotations per minute made by the wheel
145 ∗/
146 unsigned int readRPM(char c){
147 unsigned long res = 0;
148
149 if (c == ’L’){
150 res = timePulse(rpm ports.left, 1);
151 }
152 else{
153 res = timePulse(rpm ports.right, 1);
154 }
155
156 res /= 100000000; // Result in seconds
157
158 if (res != 0)
159 return 60/res; // convert to rotations per minute
160 else
161 return 0;
162 }

98
Listings

AboutDialog.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Canvas.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
DataStore.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Globals.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
InputParser.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Message.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
PreferencesDialog.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
RobotControllerApp.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
RobotControllerView.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
SerialConn.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
UpdateAbleSensor.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
ADClib.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
ADClib.xc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
DistanceSensor.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
DistanceSensor.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Initialization.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Initialization.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
InputParser.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
InputParser.xc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
LightSensor.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
LightSensor.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Main.xc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Motor.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Motor.xc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
RpmSensor.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
RpmSensor.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Sensor.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Sensor.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
SensorManager.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
SensorManager.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
TemperatureSensor.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
TemperatureSensor.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
XBeelib.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
XBeelib.xc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
xcWrapper.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
xcWrapper.xc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

99

S-ar putea să vă placă și