Sei sulla pagina 1di 45

Project report

Robotics and Autonomous systems 2D1426


Nada, KTH
Erik Joelsson, Stefan Nyström and Fredrik Sjögren
31st May 2002

Abstract
In the course 2D1426 Robotics and Autonomous systems at Nada, KTH,
groups of three people were to build a robot capable of playing a special
game called robot hockey. Some vital parts, like motors and various detec-
tors, were given each group but most of the design and construction was
done by the students. This paper describes in detail how Jaws, one of these
robots, was built and programmed.

1
Contents
1 Background 4
1.1 The game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Constraints on the robot . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Material . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2 Sensing 6
2.1 IR sensors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2 Reflex sensors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

3 Manipulation, locomotion and navigation 10


3.1 Construction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.2 Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.3 Navigation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.4 Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.5 Goal swing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

4 Communication 11

5 Programming environment and computer hardware 11


5.1 PIC microcontrollers . . . . . . . . . . . . . . . . . . . . . . . . . 11
5.2 Boards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
5.3 Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
5.4 Bootloader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

6 Electronics 13
6.1 Power . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
6.2 Motors and speaker . . . . . . . . . . . . . . . . . . . . . . . . . . 14
6.3 IR sensors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
6.4 The main PIC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
6.5 LED driver board . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

7 Software implementation 14
7.1 Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
7.2 Watchdog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

8 Results and conclusions 15

9 References 17

A RAS Motherboard schematic 18

B Parts list 19

C Source code 20

D Extra pictures 44

2
List of Figures
1 The rink. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2 The puck. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3 One of the goals. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4 The placement of the sensors. . . . . . . . . . . . . . . . . . . . . 7
5 The placement of the puck sensor. . . . . . . . . . . . . . . . . . 8
6 The placement of the reflex sensors (yellow circles), the motors
and the support points. . . . . . . . . . . . . . . . . . . . . . . . . 9
7 The placement of the boards. . . . . . . . . . . . . . . . . . . . . 12
8 Updating the software. . . . . . . . . . . . . . . . . . . . . . . . . 13
9 The question tree. . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3
Figure 1: The rink.

1 Background
An important part of the course 2D1426 Robotics and Autonomous Systems [3]
at NADA, KTH was constructing a robot. The students formed teams of three
and all teams built a robot capable of playing robot hockey. At the end of the
course all robots competed in a course tournament.

1.1 The game


In each game [4] two robots faced each other on a rink that measured approxi-
mately 2.40×1.20 m (See image 1 on page 4). At both ends of the rink there was
a semicircular black goal zone that the robots were not allowed to enter (See
image 3 on page 6). Both goals, the puck and all robots were equipped with
IR LEDs blinking at different frequencies. By sorting these frequencies out the
robots were able to navigate the rink.
A goal was scored when the puck (See image 2 on page 5) was in contact
with the red area in the center of the goal zone. The robot had to be aware that
it has scored a goal and show this by playing a tune. Failure to do this would
result in the goal being discarded. The robots were not allowed to grab the
puck but they did have a stick to guide it with.

1.2 Constraints on the robot


There were several constraints a robot must meet in order to participate in
the competition [4]. Among these were constraints on the size and shape of
the robot as well as restrictions on what kinds of devices the robot may be
equipped with.

4
Figure 2: The puck.

5
Figure 3: One of the goals.

1.3 Material
Each group were given some basic equipment to start from. A complete list
can be found in Appendix B. Among these were motors, a speaker for goal
signaling and a mothorboard with controller circuits. Some prewritten code for
low level control of motors, interpretation of IR signals and sound generation,
were also given.

2 Sensing
2.1 IR sensors
The robot Jaws used five different IR sensors [11] for sensing its environment.
Four of these sensors were used for sensing the direction and distance to
different objects such as the two goals, the puck and the opponent. These
sensors were placed around the robot at different angles. By sensing which
was the strongest and the second strongest sensor for an object, and checking
the IR values for these sensors, it was possible to decide when the robot was
turned towards that object using a ratio between the strongest and the sec-
ond strongest sensor combined with some ad hoc solutions. The sensors also
enabled the robot to sense if it was close to an object using non trivial thresh-
olding. See figure 4 on page 7 and appendix C (questions.h).
The fifth sensor was located at the front of the robot, sensing if the robot
had the puck. This sensor was placed lower than the other sensors, level with
the IR transmitters of the puck. The reason for this was that it was only used
for sensning the puck and never any other objects. The sensor was placed in
level with the IR transmitters of the puck. If the input of the puck on this sensor
was higher than a threshold value, the robot thought it had the puck. This way

6
Sensor 0 Sensor 1

Forward

Robot

Sensor 3 Sensor 2

Figure 4: The placement of the sensors.

7
Figure 5: The placement of the puck sensor.

no mecanical sensor, like for example a button, was needed for sensing if the
robot had the puck. See figure 5 on page 8.

2.2 Reflex sensors


Under the robot there were three reflex sensors. See figure 6 on page 9. These
were used for detecting the black markings on the white surface of the rink. By
sending the input from these sensors to an A/D-converter and then comparing
readings with threshold values, it was possible to find out if the sensor was
located above a white surface or a black marking.
One of the reflex sensors also had another task. When the robot moved
the small vibrations and the small changes of color on the floor would give a
small but detectable change in the the reading from the sensor. If the change
was smaller than a threshold value for twelve subsequent readings, the robot
thought it was stuck and would do an evasive maneuver. This way it was
possible to detect almost every time it happened, even if the wheels did not
stop because of the slipperiness of the floor. Sensors detecting the rotation of
the wheel could not have accomplished that.

8
Figure 6: The placement of the reflex sensors (yellow circles), the motors and
the support points.

9
3 Manipulation, locomotion and navigation
3.1 Construction
To be able to move, Jaws was equiped with two wheels driven by separate
motors [9]. The wheels position can be viewed in figure 4 on page 7. The speed
and direction of each motor could be controlled individually which made it
possible to make the robot both spin around on the spot and go forwards and
backwards.
With only two wheels a robot would have a hard time keeping its balance.
Jaws had two supporting points in addition to the wheels to make this possible.
The first stick was just a bit of meccano sticking out from the robot body. It
was effective enough but we wanted the robot to be able to turn faster while
guiding the puck. Since the rules stated that the robot was not permitted to
grab the puck, it was decided to build a stick with a rotating rubber band using
a third motor [10] (see figure 5 on page 8). By also putting rubber on the robot
body the intention was to make the puck stick there. It did not prove to be an
enormous improvement but it probably gave some effect.

3.2 Strategy
The strategy was simple. First look for the puck, turn to face it and then go to
it. Whith the puck securely between the stick and the body of the robot, try to
find the opponents goal and turn anti-clockwise, positioning it in front of the
robot. Go forward until the goal is reached and do the special goal swing to
score.

3.3 Navigation
To navigate the rink input from the IR sensors was used. In some cases it was
hard to find constant threshold values to compare the input to. The reason was
that the IR sensors was very sensitive to direction but not in a linear way, thus
giving much stronger input from a target in front of one sensor than if the target
was between two sensors. This problem was never completely solved but the
method used was taking the quotient of the strongest and second strongest IR
input and comparing it with a threshold value. The exact expression can be
found in the source code.

3.4 Manipulation
The most obvious actions will not be described here, instead we will look into
some of the harder problems encountered.
An early idea was to almost never let the robot go straight forward. The
reason was that the motors were not equally strong, and it was hard to exactly
face a target.
When the robot was looking for the puck it often turned too much and too
quickly, describing a pendular motion back and forth, instead of just facing
the puck. Also when it came forward at full speed it knocked away the puck
and had to follow it for a while before getting hold of it. The solution to this
problem was to reduce the speed when close to the puck.

10
When turning with the puck it was hard to keep it close enough to the
robot’s body. Therefore the center of rotation was moved from the center of the
robot to the left wheel. Later that wheel was even given a little speed forward
to be able to turn around even faster with the puck. The obvious drawback
was the increased radius of a turn, resulting in the robot getting stuck against
the wall.
It was also very hard for the robot to stop fast enough before the goal zone.
Trying to slow down was very hard when the motors had reached a high speed
and going slow also meant losing power. If the motors were set to go as slow
as was needed when coming at full speed they would not have enough power
to move the puck from zero speed. The solution was to let the motors alter-
nate between full speed and stop for short periods of time (about 50 ms). This
proved very effective and the robot always stopped in time.
As described above the floor sensors were used to detect if the robot was
moving at all. If it was not, the robot most likely had the puck pushed against
a wall and was trying to turn to the goal (anti-clockwise). A simple way to get
out of this situation was to back the left wheel a bit to turn the robot from the
wall without losing the puck.

3.5 Goal swing


Many different techniques for scoring were tried and discarded. The final
choice was to stop at the goal zone, turning anti-clockwise a little bit to put
the puck in the right position and then turn clockwise at full speed hitting the
Puck staight into the goal. In the first turn the technique with full speed at
short intervalls was used to get the puck in a more accurate position.

4 Communication
The main means of communication of the Jaws robot was the LCD situated
on its top. The LCD displayed the current values of the different sensors as
well as other useful debug information. Also used for debugging were two
LEDs (positioned as the eyes of the robot). These LEDs indicated if the main
program and the interrupt routine were running. The speaker of the robot was
also used to communicate information. It played a tune at startup to ensure
that everything was switched on and to detect if the robot had reset. It also
played a tune to communicate that the robot had reached the edge of the goal
zone. When the robot scored a goal it played the theme of Alfons Åberg [1].
In order to be able to play such an advanced tune the handed out code was
altered slightly to enable longer tunes.

5 Programming environment and computer hardware


5.1 PIC microcontrollers
The robot was based on two PIC micro controllers [7]. One of these, a PIC16F876,
was preprogrammed by the course director to control the IR beacon and per-
form the analysis of the IR values. The simplified data was transmitted to the

11
Figure 7: The placement of the boards.

main microcontroller, a PIC16F877. The main microcontroller did all the work
controlling the robot.

5.2 Boards
The robot contained several boards (See image 7 on page 12). The most impor-
tant was the main board containing the two PICs, electronics for controlling the
motors, speakers and servos and connectors for the IR receivers. To the main-
board a RS232 connector board was connected. The IR beacon and the reflex
detectors was connected to a LED driver board. An LCD was connected to the
mother board for debugging. The whole robot was powered by a 7.2 V battery.
A voltage booster card, which transformed the 7.2 V from the battery to 14.5 V,
was used to give more power to the main motors and the LED driver board.

5.3 Compiler
All code was written in C using MPLAB [8] as a developing environment.
MPLAB used Hi-Tech PIC C [6] for compiling.

5.4 Bootloader
A special program, the bootloader, was preprogrammed into the main PIC by
the course director. The bootloader made it possible to, via the serial RS232
interface, download an updated version of the program for the main PIC (not
including the bootloader) and write it into the onboard flash memory. The
bootloader was normally not the program started when the robot was reset. To
make this happen pin RC0 on the main PIC had to be changed from 1 (Normal

12
Figure 8: Updating the software.

mode) to 0 (Bootloader mode). This was done by connecting a switch to this


pin which could change the level between 1 and 0.
To update the program, the robot was connected to an ordinary PC via a
serial adapter. To activate the bootloader, the switch to pin RC0 had to be
changed from 1 to 0 and the robot reset. The bootloader would then start and
wait for a program to be sent on the serial port. The PC then had to start the
program ntload.exe that would send a HEX-file (generated by MPLAB) to the
robot. The command line to use with ntload.exe looked like this:

ntload -PCOM1 -DEBUG_MODE=1 jaws.hex

6 Electronics
6.1 Power
The motherboard (see Appendix A) was connected to the 7.2 V battery as well
as to a voltage booster card with 14 V output. The higher voltage was used
to power the locomotion motors while the low voltage was used for the rest

13
of the motherboard. The high voltage was also connected to the LED driver
board which controlled the IR LEDs and the reflex detectors.

6.2 Motors and speaker


The two motors used for locomotion [9] were connected to the J11 pins (motor1)
(see Appendix A bottom right). The speaker and the stick motor [10] were
connected to pins J12 (motor2) (see Appendix A bottom right). All motors
(including the speaker) were controlled by the J8 pins (see Appendix A bottom
middle) which were connected to the main PIC.

6.3 IR sensors
The five IR sensors [11] were connected to the five locking headers J3 through
J7 (see Appendix A top left). These were in turn connected to the IR PIC.

6.4 The main PIC


The reflex detectors output signal was connected to the RA0 through RA3 A/D
inputs of the PIC (see Appendix A). Pins RA4 and RA5 were used as direction
pins for the locomotion motors. The enable pins for the locomotion motors
were pins 16 and 17. The sound was controlled by pins RE0 and RE1. The stick
motor was controlled by pins RB6 and RB7.
Pin 15 was used to decide if the bootloader should be run at startup. It was
connected to a button on top of the robot.
Pins 18, 23 and 24 was where the main PIC got IR sensor data from the IR
PIC.
The LCD was connected to pins 19 through 22 and 27 through 30. RB0 and
RB (pins 33 and 34) were connected to two LEDs (the eyes of the robot) for
debugging purposes.

6.5 LED driver board


The LED driver board controlled the IR LEDs that told the opponent where the
robot was. It also controlled the reflex detectors situated under the robot.

7 Software implementation
All implementation was done in PIC C [6]. Some extra functions for handling
basic steering, sensor input and speaker and LCD output were given by the
course director.
The source code was divided into separate files for sensing, locomotion,
stick manipulation, music playing, LCD printing, questions and state defini-
tions.
The program flow was constructed so that the main loop always executed
without any delays. At the beginning of the loop all sensor values were up-
dated and some debug info was displayed on the LCD. Then it checked whether
the special delay state flag was set or not, and if it was, the rest of the loop was
canceled. This was a way of implementing a delay without prolonging the

14
Has puck?
Yes No

No No
Turned puck? Turn to puck
Turned goal? Turn to goal

Yes Yes
No
No
Cloase goal or at goal? Evasive maneuver
Close goal? Go to goal

Yes Yes

No No
Close puck? Go to puck
At goal? Go to goal slow

Yes Yes

Go to puck slow
Score

Figure 9: The question tree.

main loop’s execution time. The rest of the loop was more or less a traversal
a tree of questions to determine what actions to take. There were also some
special states, when scoring for example, where state transitions were forced.

7.1 Questions
To be able to determine what situation the robot was currently in, a number of
questions were formulated. The complete question tree is displayed in figure 9
on page 15.
To answer these questions, input from the sensors described earlier was
used.

7.2 Watchdog
There was some trouble with the program hanging. It happened every now
and then and at different places in the code, sometimes often and sometimes
less often. Since the interrupt routine continued to operate and as no other
solution seemed to appear, a software watchdog timer was implemented. The
interrupt routine made sure that the main loop had executed the last 200 ms
and if not, the program counter was set to zero, thus restarting the PIC.

8 Results and conclusions


Overall the robot performed well. It could locate, move to and get the puck. It
did have some problems seeing the puck over a long distance because of the
background light being stronger than the IR sent from the puck. There was
no real solution for this, but after being confused for a while, as it didn’t see

15
the puck, the robot almost always got a glimpse of something so it could start
going in the right direction.
The stick, with its rotating rubber band, worked well. During rotation with
puck the robot seldom lost control of it.
The robot could locate the goal and approach it with rather high precision.
Detecting the goal zone using the reflex detectors worked well most of the time
but sometimes the robot had problems stopping. This was probably caused by
the changing friction depending on how much potato powder there was on
the rink. The shooting mecanism could, if the robot had stopped at the right
position, shoot the puck into the goal with good margin.
The biggest problem was probably the robots inability to stop itself from
going into its own goal zone. The reason for this was mostly lack of time but it
was also easy to forget since Jaws never got to practise against real opponents.
Jaws received many penalties for this during the tournament and at least one
game could have been won otherwise.
Because of the unidentified bug, causing the program to hang, in combina-
tion with the software watch dog, the robot reset itself about once every two
minutes. This caused almost no trouble since the software was almost stateless.
The only critical point was during the scoring sequence.
During the tournament the robot obtained a third place in the group play
and therefor did not make it to the semifinals. This was a shame since we
think our robot could have had a good chance on the third place in the whole
tournament.

16
9 References
References
[1] Andersson P., Alfons Åberg, official homepage:
http://www.alfons.se,
Bok-makaren AB, 2002
[2] Bengtsson, F., Flodström, P., Roterman M., Project report for The Slider
robot:
http://www.nada.kth.se/kurser/kth/2D1426/reports2001/
Slider.pdf,
2D1426 Robotics and Autonomous Systems, 2001
[3] Bratt, Mattias, Course homepage:
http://www.nada.kth.se/kurser/kth/2D1426,
Robotics and autonom systems, 2002
[4] Bratt, Mattias, Rules for the game:
http://www.nada.kth.se/kurser/kth/2D1426/rules2002.
pdf,
Robotics and autonom systems, 2002
[5] Danielsson, K., Elvers G., Jacobsson B., Report on project work:
http://www.nada.kth.se/kurser/kth/2D1426/reports2001/
Kakmonstret.pdf,
2D1426 Robotics and Autonomous Systems, 2001
[6] Hi-tech, PIC C Manual, Hi-Tech, 2002
[7] Microchip Technology Inc., Datasheet for 20-pin 8-Bit CMOS FLASH
Micro controller PIC:
http://www.microchip.com/download/lit/pline/picmicro/
families/16f87x/30292c.pdf,
Microchip Technology Inc., 2001
[8] Microchip Technology Inc., MPLAB Manual. MPLAB IDE, Simulator, Ed-
itor User’s Guide, Microchip Technology Inc., 2002
[9] Micromotors, Data for 12 V motor:
http://www.stegia.se/Produkter/Micromotors/pages/
hv149.htm,
Micromotors, 2002
[10] Micromotors, Data for 6 V motor:
http://www.stegia.se/english/Products/Micromotors/
pages/l149.htm,
Micromotors, 2002
[11] Texas Instruments, Datasheet for IR Light-to-Voltage Optical Sensor
TSL261:
http://www.taosinc.com/pdf/tsl260.pdf,
Texas Instruments, 2000

17
A

1 2 3 4 5 6 7 8

A
RAS Motherboard Schematic Main PIC
Vcc
RR2 J18 Vcc J1
8 Vcc
R8 7 1 2 1
R7 6 3 4 R7 0.1uF C0 2
R6 5 5 6 3
R5 4 7 8 4.7k 4
R4 9 10 0.1uF C1 5
Vcc Vcc 3
R3 2 11 12 S1 6
J3 9 CM R2 1 13 14 R6 7
R1 R1 15 16 8
B 1 Pre−programmed PIC RESET 81
2 100k 8x4.7k 8JPS GND
3
Vcc MC1 J13 J2 J19 RR3
IR0
1 1 MCLR RB7 40 1 1 1 2 8 R8
J4 J15 2 2 RA0/AN0 RB6 39 2 2 3 4 7 R7
R2 3 38 6
1 MC2 J17 RR4 3 4 RA1/AN1 RB5 37 3 3 5 6 5 R6
2 100k 4 5 RA2/AN2 RB4 36 4 4 7 8 4 R5
3 1 2 5 6 RA3/AN3/Vref RB3 35 5 5 9 10 3 R4
Vcc 3 4 6 7 RA4/T0CKi RB2 34 6 6 11 12 2 R3
IR1 5 6 7 RA5/AN4 RB1 7 7 13 14 R2
8 33 1 9
J5 7 8 8 9 RE0/AN5 RB0/INT 32 8 8 15 16 R1 CM
C R3 9 10 9 10 RE1/AN6 Vdd 31 9
1 11 12 10 11 RE2/AN7 Vss 30 10 8LEDS 8x470
2 100k 30p 13 14 12 Vdd RD7 29 1
3 15 16 J16 13 Vss RD6 28 2
Vcc C5 Y2 14 OSC1 RD5 27 3 J21 J20 RR1
IR2 20M 8LEDS 8x470 OSC2 RD4 4
30p 15 26 8
J6 16 RC0 RC7 25 5 1 2 1 2 7 R8
R4 Vcc 17 RC1/CCP2 RC6 24 6 3 4 3 4 6 R7
1 C6 gnd RC2/CCP1 RC5/SDO 7 5 6 5 6 R6
2 18 RC3/SCK RC4/SDI 23 8 7 8 7 8 5 R5
100k 19 22 4
3 C4 20 RD0 RD3 21 9 9 10 9 10 3 R4
Vcc PIC16F876 RD1 RD2 10 11 12 11 12 2 R3
IR3 13 14 13 14 R2
D 0.1uF 15 16 15 16 1 R1 CM 9
J7 PIC16F877 J14

18
1
R5
2
J10 CTRL 8JPS 8LEDS 8x470
100k

1
2
3
3
IR4
30p
Vcc C2
RR6
1
R1 CM
9 Y1
2 30p 20M Vs
3 R2 RA4 is open drain
4 R3
RAS Motherboard schematic

E 5 R4
6 R5 C3 Vcc S3
7 R6
8 R7
R8 C7 Locomotion PWR

5
4
3
2
1
8x4.7k J22 SERVO
0.1uF
S2 V8 J23 V6, Vcc Vcc Motor Drivers

8
7
6
5
4
3
2
1
U3 L293NE
1 ENBL1 Vs 8
J24 GND 9

8
7
6
5
4
3
2
1
F ENBL2 Vss 16 J11
U1A 2 INP1 OUT1 3 1
14.4V in Vs 7 6
Voltage regulators Vcc 10 INP2 OUT2 11 2
Vcc 5V 15 INP3 OUT3 14 3
750 mA max RR5 J8 U1B INP4 OUT4 4
J9 U4 LM2940 9 1 4 13 0.1uF MOTOR1
S4 CM R1 2 1 5 GND GND 12
+ 1 R9 1 3 R2 3 2 GND GND V8
− 2 IN OUT R3 3 C8
4
+ 3 8.2, 6W R4 5 4 1 8
C10 R5 6 5 9 ENBL1 Vs 16

GND 2
BATT C11 0.47uF R6 7 6 ENBL2 Vss J12
G R7 8 7 U1C 2
22uF R8 8 INP1 OUT1 3 1
7 6
10 INP2 OUT2 11 2
8x4.7k MOT_CTRL INP3 3
15 OUT3 14
U1D INP4 OUT4 4
V8 8V 4 MOTOR2
Vs 1 A max 5 GND GND 13
U5 7808CV GND GND 12
R10 74HCT04 L293DN
1 U2
IN OUT 3
3.9, 6W
Vcc

GND 2
H 0.1uF C12 C9
C13 0.33uF (74HCT04)
0.1uF
B Parts list
• 3 reflex detectors ITR8307
Subminiature High Sensitivity Photo Interrupter
Manufacturer: Everlight
Part no: ITR8307

• 1 PIC PIC16F876 20-pin 8-Bit CMOS FLASH Micro controller


Manufacturer: Microchip Technology Inc
Part no: PIC16F876

• 1 PIC PIC16F877 40-pin 8-Bit CMOS FLASH Micro controller


Manufacturer: Microchip Technology Inc
Part no: PIC16F877

• 4 IR diodes SFH485P GaAlAs Infrared Emitter


Manufacturer: Siemens
Part no: SFH485P
• 5 IR sensors TSL261 IR Light-to-Voltage Optical Sensor
Manufacturer: Texas Advanced Optoelectronic Solutions (TAOS)
Part no: TSL261

• 2 12Vmotors HL149 12V 10:1 Motor


Manufacturer: Micromotors
Part no: HL149

• 1 6V motor

• 2 7.2V NiCd accumulator packs


• 1 Mother board

• 1 LCD display

• 1 LED driver board


• 1 Voltage booster card

• 1 Serial RS232 card

19
C Source code
jaws.c

#include <pic.h>
#include <conio.h>
#include "lib\defines.h"
#include "lib\lcd.h"
#include "lib\adc.h"
#include "lib\sprint.h"
#include "lib\ir_comm.h"
#include "lib\eeprom.h"
#include "lib\pwm.h"
#include "lib\intr.h"
//#include "lib\serialio.h"
#include "question.h"
#include "club.h"
#include "sensors.h"
#include "printinf.h"
#include "move.h"
#include "music.h"
#include "states.h"

// no code protect, no WDT, no BOD, power up timer, HS Xtal


// (has no effect when writing the program using the
// boot loader)
__CONFIG(0x3FB2);

/* clrwdt */

main() {

reset_soft_wdt();

TRISB1 = TRISB0 = 0;

ir_init(); //initialise IR co-processor communication


init_pwm(); //initialise pwm for motor control
init_soft_tmr();
init_sound(); //initialise sound generator

/* Our own initializations */


init_floor_sens(); //initialize floor sensors
init_club(); //initialize club rotation control

// enable interrupts
PEIE = 1; // peripheral interrupts enable
ei(); // global interrupt enable

20
set_lcd_power(1); //turn on lcd

// wait for 100ms


SET_HOLD(100);
while (IS_HOLDING)
reset_soft_wdt();
RESET_HOLD;

// and then
init_lcd();

// play ’laser’ sound at startup


play_tune(laser);

// start rotation of club


rot_club_in();

/**********************
* Start of Main loop.
*/
for (;;) {

// Reset the software watchdog timer


reset_soft_wdt();

// Flip debug LED. (Also used as angry twinkling eye)


RB1 = !RB1;

// Update sensor input


read_floor_sens();
update_ir_max_dir();

// Print some information. Some lines commented out.


// print_floor_sens();
print_front_sens();
// sprint16(buffer, soft_time());
// lcd_print1("", 9);
// lcd_print_at_cursor(buffer);
// lcd_print_at_cursor(" ");

// Check for hold state


// (a hold state lasts a certain amount of time)
if (IS_NOT_HOLDING) {
RESET_HOLD;
// Flib debug LED. (Also used as other angry twinkling eye)
RB0 = !RB0;

21
/******************************************************
* States directly following a previous state: (score)
******************************************************/
if (STATE_IS(SCORE_FIRST_STOP)) {

/* Score push puck */


hold_state = 13;
SET_STATE(SCORE_PUSH_PUCK);
SET_HOLD(score_push_puck_go());

} else if (STATE_IS(SCORE_PUSH_PUCK)) {
if (hold_state > 0) {

/* Score push puck state (continue) */


if (hold_state-- & 1) {
SET_HOLD(score_push_puck_stop());
} else {
SET_HOLD(score_push_puck_go());
}

} else {

/* Score smash puck state */


SET_STATE(SCORE_SMASH_PUCK);
SET_HOLD(score_smash_puck());
}
} else if (STATE_IS(SCORE_SMASH_PUCK)) {

/* Score go middle state */


SET_STATE(SCORE_GO_MIDDLE);
SET_HOLD(score_go_middle());

} else if (has_not_moved()) {

/* Get loose state */


SET_STATE(GET_LOOSE);
SET_HOLD(get_loose());

/***********************************************
* Normal states (as described question tree)
***********************************************/
else if (HAS_PUCK) {

print_ir_max_dir(OFF_GOAL);
if (TURNED_GOAL) {

22
if (CLOSE_GOAL) {
if (AT_GOAL) {

/* Score first stop */


SET_STATE(SCORE_FIRST_STOP);
play_tune(laser);
SET_HOLD(score_first_stop());

} else {

/* Go goal slow state */


if (STATE_IS(GO_GOAL)) {
SET_STATE(GO_GOAL_SLOW_FIRST_STOP);
SET_HOLD(go_goal_slow_first_stop());
}

if (STATE_NOT(GO_GOAL_SLOW_STOP)) {
SET_STATE(GO_GOAL_SLOW_STOP);
SET_HOLD(go_goal_slow_stop());
} else {
SET_STATE(GO_GOAL_SLOW_GO);
SET_HOLD(go_goal_slow_go());
}
}
} else if (STATE_NOT(GO_GOAL_SLOW_GO)) {

/* Go goal state */
SET_STATE(GO_GOAL);
go_goal();

}
} else { /* !TURNED_GOAL */
if (CLOSE_GOAL) {
if (AT_GOAL) {

/* Turn goal close state */


SET_STATE(TURN_GOAL_CLOSE);
turn_goal_close();
play_tune(laser);
} else {

/* Turn goal slow state */


SET_STATE(TURN_GOAL_SLOW);
turn_goal_slow();

}
} else {

/* Turn goal state */


SET_STATE(TURN_GOAL);

23
turn_goal();

}
}
} else {
/* Looking for puck, print sensor values */
print_ir_max_dir(PUCK);

if (TURNED_PUCK) {
if (AT_GOAL_NOT_CLUB && CLOSE_GOAL) {

/* Flee goal state */


SET_STATE(FLEE_GOAL);
SET_HOLD(flee_goal());
play_tune(laser);
} else {
if (CLOSE_PUCK) {

/* Go puck slow state */


SET_STATE(GO_PUCK_SLOW);
go_puck_slow();

} else {

/* Go puck state */
SET_STATE(GO_PUCK);
go_puck();

}
}
} else {

/* Turn puck state */


SET_STATE(TURN_PUCK);
turn_puck();

}
}

// Print current state on lcd


print_state();
}
}
}

states.h
/*
* Definitions and variables for state transmissions

24
*/

unsigned int hold = 0;


char hold_state = 0;
bank1 static unsigned int sometime;

#define SET_STATE(x) (state = (x))


#define STATE_NOT(x) (state != (x))
#define STATE_IS(x) (state == (x))
#define STATE state
#define SET_HOLD(x) sometime=soft_time(); hold = (x)
#define IS_HOLDING hold != 0 && !passed(sometime+hold)
#define IS_NOT_HOLDING hold == 0 || passed(sometime+hold)
#define RESET_HOLD hold = 0;

// Defines for states


#define SCORE_PUSH_PUCK 1
#define SCORE_SMASH_PUCK 2
#define SCORE_GO_MIDDLE 3
#define GO_GOAL_SLOW_GO 4
#define GO_GOAL_SLOW_STOP 5
#define GO_GOAL 6
#define TURN_GOAL_CLOSE 7
#define TURN_GOAL_SLOW 8
#define TURN_GOAL 9
#define FLEE_GOAL 10
#define GO_PUCK_SLOW 11
#define GO_PUCK 12
#define TURN_PUCK 13
#define GET_LOOSE 14
#define GO_GOAL_SLOW_FIRST_STOP 15
#define SCORE_FIRST_STOP 16

question.h
/*
* Macros and declarations for questions we like to ask
* often.
*/

#define HAS_PUCK (ir_value(4, PUCK) > 4900)

#define CLOSE_PUCK (ir_value(4, PUCK) > 1500)

#define VISIBLE_PUCK (ir_value(irpmax, PUCK) > 10)

#define TURNED_PUCK (((irpmax + irpnmax == 1) && \


(ir_value(irpmax, PUCK) + \
ir_value(irpnmax, PUCK) < 300)) || \

25
((irpmax == 1 && irpnmax == 0) && \
((ir_value(irpmax, PUCK) << 8) / \
(ir_value(irpnmax, PUCK) + 1) < (256))))

#define TURNED_GOAL (((irgmax == 0 && irgnmax == 1) && \


((ir_value(irgmax, OFF_GOAL) << 6) / \
(ir_value(irgnmax, OFF_GOAL) + 1) < (11*64)) && \
(ir_value(1, OFF_GOAL) - ir_value(3, OFF_GOAL) > 6)) || \
((irgmax == 1 && irgnmax == 0) && \
((ir_value(irgmax, OFF_GOAL) << 6) / \
(ir_value(irgnmax, OFF_GOAL) + 1) < (6*64))))

#define CLOSE_GOAL (((irgmax + irgnmax == 1) && \


((ir_value(irgmax, OFF_GOAL) >> 1) * \
(ir_value(irgnmax, OFF_GOAL) >> 1) > 700)) || \
((ir_value(irgmax, OFF_GOAL) >> 1) * \
(ir_value(irgnmax, OFF_GOAL) >> 1) > 1100))

#define AT_GOAL (floor[0] > 235 || floor[1] > 220 || \


floor[2] > 220)
#define AT_GOAL_NOT_CLUB (floor[1] > 220 || \
floor[2] > 220)

#define SCORE_PUSH_FINISHED (floor[2] < 210)

extern char has_not_moved();

question.c

#include "sensors.h"
#include "lib\defines.h"

#define LOCKED_COUNT 12

/*
* This question had to be a function because of its complexity.
*/
char has_not_moved() {
static int count = 0;
if (ABS(floor[1] - floor_old) < 2) {
++count;
if (count == LOCKED_COUNT) {
return 1;
}
} else {
count = 0;
}
return 0;

26
}

move.h

/*
* Functions controling the movement (locomotion) of the robot.
*/

extern void turn_puck();


extern void go_puck();
extern void go_puck_slow();
extern void turn_goal();
extern void turn_goal_slow();
extern void turn_goal_close();
extern void go_goal();
extern unsigned int go_goal_slow_go();
extern unsigned int go_goal_slow_stop();
extern unsigned int go_goal_slow_first_stop();
extern unsigned int score_first_stop();
extern unsigned int score_push_puck_go();
extern unsigned int score_push_puck_stop();
extern unsigned int score_smash_puck();
extern unsigned int score_go_middle();
extern unsigned int get_loose();
extern unsigned int flee_goal();

move.c

#include <pic.h>
#include "lib\pwm.h"
#include "lib\ir_comm.h"
#include "lib\defines.h"
#include "lib\intr.h"
#include "lib\lcd.h"
#include "sensors.h"
#include "club.h"
#include "music.h"
#include "lib\sprint.h"

/*
* Turn towards the puck. Turn fast if puck is behind robot.
*/
void turn_puck() {
if (irpmax == 1)
motors(95, -95);
else if (irpmax == 2)

27
motors(127, -128);
else if (irpmax == 0)
motors(-95, 95);
else /* irpmax == 3) */
motors(-128, 127);
}

/*
* Go forward or almost forward after the puck.
*/
void go_puck() {
if (ABS(ir_value(irpmax, PUCK) - ir_value(irpnmax, PUCK)) < 200)
motors(127, 127);
if (irpmax == 0)
motors(120, 127);
else if (irpmax == 1)
motors(127, 120);
}

/*
* Go forward or almost forward after the puck at slower speed.
* Used when close to the puck.
*/
void go_puck_slow() {
if (ABS(ir_value(irpmax, PUCK) - ir_value(irpnmax, PUCK)) < 200)
motors(100, 100);
if (irpmax == 0)
motors(95, 105);
else if (irpmax == 1)
motors(105, 95);
}

/*
* Turn anti-clockwise to goal.
*/
void turn_goal() {
motors(40, 115);
}

/*
* Turn anti-clockwise to goal but slower.
* Used when close to the goal.
*/
void turn_goal_slow() {
motors(0, 110);
}

/*
* Turn to goal but rotate slowly around robot center.
* Used when very close to the goal. (floor sensor in goal zone)

28
*/
void turn_goal_close() {
motors(-100, 100);
}

/*
* Go forward or almost forward towards the goal.
*/
void go_goal() {
if (irgmax == 0)
motors(120, 127);
else if (irgmax == 1)
motors(127, 120);
}

/*
* Go forward or almost forward towards the goal for 40 milliseconds.
*/
unsigned int go_goal_slow_go() {
if (irgmax == 0)
motors(105, 123);
else if (irgmax == 1)
motors(123, 105);
return 40;
}
/*
* Stand still for 70 milliseconds.
*/
unsigned int go_goal_slow_stop() {
motors(0, 0);
return 70;
}
/*
* Stand still for 200 milliseconds.
*/
unsigned int go_goal_slow_first_stop() {
motors(0, 0);
return 200;
}

/*
* These functions make up the scoring sequense.
*/
unsigned int score_first_stop() {
motors(-128, -128);
return 20;
}
unsigned int score_push_puck_go() {
motors(-128, 127);
return 40;

29
}
unsigned int score_push_puck_stop() {
motors(0, 0);
return 70;
}
unsigned int score_smash_puck() {
motors(127, -128);
return 1300;
}
unsigned int score_go_middle() {
motors(127, 127);
play_tune(alfons);
return 1100;
}

/*
* Called when stuck somewhere
*/
unsigned int get_loose() {
motors(-128, 0);
return 600;
}

/*
* Called when trying to go inte the goal zone without the puck
*/
unsigned int flee_goal() {
motors(-128, -128);
return 500;
}

musicdef.h

/*
* Pic Music Markup Language. ;)
*/

#define END 0,0

/* Note length */
#define T 8
#define S 16
#define Sp 24
#define E 32
#define Ep 48
#define Q 64
#define Qp 96
#define H 128

30
#define Hp 192
#define W 256

/* Note length for non legato tones */


#define SS 15, 0xff, 1
#define SE 31, 0xff, 1
#define SEp 47, 0xff, 1
#define SQ 63, 0xff, 1
#define SQp 95, 0xff, 1
#define SH 127, 0xff, 1
#define SHp 191, 0xff, 1
#define SW 255, 0xff, 1

/* Note length at different speed */


/*
#define T 5
#define S 10
#define Sp 15
#define E 20
#define Ep 30
#define Q 40
#define Qp 60
#define H 80
#define Hp 120
#define W 160

#define SS 9, 0xff, 1
#define SE 19, 0xff, 1
#define SEp 29, 0xff, 1
#define SQ 39, 0xff, 1
#define SQp 59, 0xff, 1
#define SH 79, 0xff, 1
#define SHp 119, 0xff, 1
#define SW 159, 0xff, 1
*/

#define P 0xFF

/* Key definitions */
#define C0 0x00
#define Db0 0x01
#define D0 0x02
#define Eb0 0x03
#define E0 0x04
#define F0 0x05
#define Gb0 0x06
#define G0 0x07
#define Ab0 0x08
#define A0 0x09

31
#define Bb0 0x0A
#define B0 0x0B

#define C1 0x10
#define Db1 0x11
#define D1 0x12
#define Eb1 0x13
#define E1 0x14
#define F1 0x15
#define Gb1 0x16
#define G1 0x17
#define Ab1 0x18
#define A1 0x19
#define Bb1 0x1A
#define B1 0x1B

#define C2 0x20
#define Db2 0x21
#define D2 0x22
#define Eb2 0x23
#define E2 0x24
#define F2 0x25
#define Gb2 0x26
#define G2 0x27
#define Ab2 0x28
#define A2 0x29
#define Bb2 0x2A
#define B2 0x2B

#define C3 0x30
#define Db3 0x31
#define D3 0x32
#define Eb3 0x33
#define E3 0x34
#define F3 0x35
#define Gb3 0x36
#define G3 0x37
#define Ab3 0x38
#define A3 0x39
#define Bb3 0x3A
#define B3 0x3B

music.h

extern const char laser[];


extern const char laser2[];
extern const char alfons[];

32
music.c

#include "musicdef.h"

/*
* Short tune to signal minor events.
*/
const char laser[]={0x00,2,0x02,2,0x04,2,0x06,2,0x08,2,0x0A,2,
0x10,2,0x12,2,0x14,2,0x16,2,0x18,2,0x1A,2,
0x20,2,0x22,2,0x24,2,0x26,2,0x28,2,0x2A,2,
0x30,2,0x32,2,0x34,2,0x36,2,
0,0};

/*
* Three laser in a row. Used to signal goals when testing
* as the other tune is a bit long
*/
const char laser2[]={0x00,2,0x02,2,0x04,2,0x06,2,0x08,2,0x0A,2,
0x10,2,0x12,2,0x14,2,0x16,2,0x18,2,0x1A,2,
0x20,2,0x22,2,0x24,2,0x26,2,0x28,2,0x2A,2,
0x30,2,0x32,2,0x34,2,0x36,2,
0x00,2,0x02,2,0x04,2,0x06,2,0x08,2,0x0A,2,
0x10,2,0x12,2,0x14,2,0x16,2,0x18,2,0x1A,2,
0x20,2,0x22,2,0x24,2,0x26,2,0x28,2,0x2A,2,
0x30,2,0x32,2,0x34,2,0x36,2,
0x00,2,0x02,2,0x04,2,0x06,2,0x08,2,0x0A,2,
0x10,2,0x12,2,0x14,2,0x16,2,0x18,2,0x1A,2,
0x20,2,0x22,2,0x24,2,0x26,2,0x28,2,0x2A,2,
0x30,2,0x32,2,0x34,2,0x36,2,
0,0};

/*
* The goal tune. Theme from Alfons Åberg.
*
* The arrangement tries to simulate accompainment by fast
* switching between many short tones.
*
* The first note on each line is the melody tone (played by a sax
* in the original) and the rest is an approximation of the comp
* (played by a trombone) in the first part of the tune. In the
* second part it’s just the base and fifth of the cords. (Since
* I couldn’t make out the trombone part there)
*
* To be able to play this the index variable of the playing routine
* had to be decleared int instead of char and the routine modified
* according to that.
*/
const char alfons[]={Gb2,S, D1,S, A0,S,
A2,SS,

33
A2,S, A0,S,
Gb2,S, A0,S,
Gb2,S, D1,S,
E2,S, D1,S,
E2,S, A0,S,
D2,S, A0,S,

Gb2,S, D1,S, A0,S,


A2,SS,
A2,S, A0,S,
Gb2,S, A0,S,
Gb2,S, B0,S,
E2,S, B0,S,
D2,S, D1,S,

Gb2,S, A0,S, D1,S,


A2,SS,
A2,S, D1,S,
Gb2,S, D1,S,
Gb2,S, A0,S,
E2,S, A0,S,
E2,S, D1,S,
D2,S, D1,S,

Gb2,S, A0,S, D1,S,


A2,SS,
A2,S, D1,S,
Gb2,S, D1,S,
Gb2,S, A0,S,
E2,S, B0,S,
D2,S, D1,S,

B2,S, B0,S, B2,S, Gb1,S,


D3,S, B0,S, D3,S, Gb1,S,
Db3,S, B0,S,
A2,S, Gb1,S,
B2,S, B0,S,
D3,S, Gb1,S,
Db3,S, B0,S,
A2,S, Gb1,S,
B2,S, B0,S,

G2,S, E1,S, G2,S, B1,S,


B2,S, E1,S, B2,S, B1,S,
A2,S, E1,S,
Gb2,S, B1,S,
G2,S, E1,S,
B2,S, B1,S,
A2,S, E1,S,

34
Gb2,S, B1,S,
G2,S, E1,S,

E2,S, C1,S, E2,S, G1,S,


G2,S, C1,S, G2,S, G1,S,
Gb2,S, C1,S,
D2,S, G1,S,
E2,S, C1,S,
G2,S, G1,S,
Gb2,S, C1,S,
D2,S, G1,S,
E2,S, C1,S,

A1,S, A0,S, A1,S, E1,S,


A1,S, A0,S, A1,S, E1,S,
A1,S,
END
};

printinf.h

extern char buffer[7];


extern char state;
extern void print_ir_max_dir(int);
extern void print_front_sens();
extern void print_state();
extern void print_floor_sens();

printinf.c

#include "lib\sprint.h"
#include "lib\lcd.h"
#include "lib\ir_comm.h"
#include "sensors.h"

#define DELAY 2

char state;
bank1 char buffer[7];

void print_ir_max_dir(int thing) {


int ir_max;
int ir_nmax;
if (thing == PUCK) {
ir_max = irpmax;
ir_nmax = irpnmax;
}

35
if (thing == OFF_GOAL) {
ir_max = irgmax;
ir_nmax = irgnmax;
}

sprint16(buffer, ir_max);
lcd_print1("m:", 0);
lcd_print_at_cursor(buffer);
sprint16(buffer, ir_nmax);
lcd_print2("n:", 0);
lcd_print_at_cursor(buffer);
sprint16(buffer, ir_value(ir_max, thing));
if (ir_value(ir_max, thing) < 10)
lcd_print1(" ", 4);
else if (ir_value(ir_max, thing) < 100)
lcd_print1(" ", 4);
else if (ir_value(ir_max, thing) < 1000)
lcd_print1(" ", 4);
else
lcd_print1("", 4);
lcd_print_at_cursor(buffer);
sprint16(buffer, ir_value(ir_nmax, thing));
if (ir_value(ir_nmax, thing) < 10)
lcd_print2(" ", 4);
else if (ir_value(ir_nmax, thing) < 100)
lcd_print2(" ", 4);
else if (ir_value(ir_nmax, thing) < 1000)
lcd_print2(" ", 4);
else
lcd_print2("", 4);
lcd_print_at_cursor(buffer);

if (thing == PUCK)
lcd_print2("P", 14);
else
lcd_print2("G", 14);
}

void print_front_sens() {
sprint16(buffer, ir_value(4, PUCK));
if (ir_value(4, PUCK) < 10)
lcd_print1("f: ", 9);
else if (ir_value(4, PUCK) < 100)
lcd_print1("f: ", 9);
else if (ir_value(4, PUCK) < 1000)
lcd_print1("f: ", 9);
else
lcd_print1("f:", 9);
lcd_print_at_cursor(buffer);

36
}

void print_state() {
sprint16(buffer, state);
lcd_print2("s:", 9);
lcd_print_at_cursor(buffer);
lcd_print_at_cursor(" ");
}

void print_floor_sens() {
sprint16(buffer, floor[0]);
lcd_print1("", 0);
lcd_print_at_cursor(buffer);
lcd_print_at_cursor(" ");
sprint16(buffer, floor[1]);
lcd_print2("", 0);
lcd_print_at_cursor(buffer);
lcd_print_at_cursor(" ");
sprint16(buffer, floor[2]);
lcd_print1("", 5);
lcd_print_at_cursor(buffer);
lcd_print_at_cursor(" ");
}

sensors.h

/* New definition of ir_value(x,y) to make it point to


* our copy of the read values.
*/
#define ir_value(x,y) ir_values[(x)][(y)]

/* max and nmax are indexes of the maximum and second to maximum
* ir sensores on p = puck and g = goal
*/
extern unsigned int irgmax, irgnmax, irpmax, irpnmax;
/* Floor sensors */
extern char floor[3];
/* Used for reading movement */
extern char floor_old;
/* Safe copies of ir readings */
extern bank2 int ir_values[5][2];

extern void init_floor_sens();


extern void read_floor_sens();
extern void update_ir_max_dir();

37
sensors.c

#include <pic.h>
#include "lib\adc.h"
#include "lib\ir_comm.h"
#include "lib\lcd.h"

#define ir_value(x,y) ir_values[(x)][(y)]

unsigned int iter, irgmax, irgnmax, irpmax, irpnmax;


char floor[3];
char floor_old;
int bank2 ir_values[5][2];

void update_ir_max_dir() {
ir_wait();
for (iter = 0; iter < 5; ++iter) {
di(); /* Entering critical section */
ir_values[iter][PUCK] = ir_value_cs(iter, PUCK);
ir_values[iter][OFF_GOAL] = ir_value_cs(iter, OFF_GOAL);
ei(); /* Critical section end */
}

// Find sensor with the largest value: irXmax


irpmax = 0;
for (iter = 1; iter < 4; ++iter) {
if (ir_value(iter, PUCK) > ir_value(irpmax, PUCK)) {
irpmax = iter;
}
}
irgmax = 0;
for (iter = 1; iter < 4; ++iter) {
if (ir_value(iter, OFF_GOAL) > ir_value(irgmax, OFF_GOAL)) {
irgmax = iter;
}
}

// Find sensor with the second largest value: irXnmax


irpnmax = (irpmax == 0 ? 1 : 0);
for (iter = irpnmax+1; iter < 4; ++iter) {
if (iter != irpmax && ir_value(iter, PUCK) >
ir_value(irpnmax, PUCK)) {
irpnmax = iter;
}
}
irgnmax = (irgmax == 0 ? 1 : 0);
for (iter = irgnmax+1; iter < 4; ++iter) {
if (iter != irgmax && ir_value(iter, OFF_GOAL) >
ir_value(irgnmax, OFF_GOAL)) {

38
irgnmax = iter;
}
}
}

void init_floor_sens() {
//use only three (of five) A/D channel (AN0) (see adc.h)
ADCON1 = 0b10000010;
TRISA0 = TRISA1 = TRISA2 = 1;
}

void read_floor_sens() {
floor_old = floor[1];
floor[0] = sample_ad_channel(0);
floor[1] = sample_ad_channel(1);
floor[2] = sample_ad_channel(2);
}

club.h

/*
* Functions to control rotation of club rubber band
*/

/*
* Initiate use of club motor by setting data direction on
* the control pins of the pic.
*/
extern void init_club();

extern void rot_club_in();


extern void rot_club_out();
extern void rot_club_stop();

club.c

#include <pic.h>

#define CLUB_MOTOR RB7


#define CLUB_MOTOR_DIR RB6

/*
* Initiate use of club motor by setting data direction on
* the control pins of the pic.

39
*/
void init_club() {
TRISB6 = TRISB7 = 0;
}

void rot_club_in() {
CLUB_MOTOR_DIR = 1;
CLUB_MOTOR = 1;
}

void rot_club_out() {
CLUB_MOTOR_DIR = 0;
CLUB_MOTOR = 1;
}

void rot_club_stop() {
CLUB_MOTOR = 0;
}

inter.c

// ***************************** intr.c

#include <pic.h>
#include "ir_comm.h"
#include "pwm.h"
#include "defines.h"

/*
* New end of soung set to largest value of an unsigned int
*/
#define SOUND_END 0xffff

//pins for controlling the speaker driver (use 6V motor driver IC)
//connect sound pin to dir and sound enbl pin to enbl
//with these settings connect:
//
// pin8 RE0 <---> fifth motor control pin
// pin9 RE1 <---> sixth motor control pin
//
// Then connect speaker with series resistance to motor terminal 3

#define SOUND_PIN RE1


#define SOUND_PIN_TRIS TRISE1
#define SOUND_ENBL_PIN RE0
#define SOUND_ENBL_PIN_TRIS TRISE0
// note that the use of port E pins as digital I/O requires
// ADCON1 to be properly set

40
int soft_wdt;

//constant vector to give right frequencies for all notes


const char wave_per_add[16]={0,14,28,41,53,64,75,85,95,104,112,
120,128,135,142,148};

const char * notes;


/*
* sound_index declared as unsigned int to be able to play tunes
* longer than 127 notes
*/
unsigned int sound_index=SOUND_END;
unsigned int note_time;

bit has_passed;
unsigned int soft_tmr;
unsigned int soft_tmr_copy;

//initialise tone generator


void init_sound() {
SOUND_PIN_TRIS=0;
SOUND_ENBL_PIN_TRIS=0;

//init TIMER0
T0CS=0; //internal clock
PSA=0; //prescaler assigned to WDT
T0IF=0;
T0IE=1;
}

//start playing a tune


//(non-blocking)
void play_tune(const char* tune){
sound_index=0;
if(tune[sound_index]==0&&tune[sound_index+1]==0)
sound_index=SOUND_END;
else {
notes=tune;
//copy two lowest bytes of soft_tmr
note_time=soft_tmr;
}
}

//Variable def to access both 8-bit regs of TIMER1 together as an int


volatile unsigned int TMR1 @ 0x0E;

41
// initialise the soft timer
// uses TIMER1
void init_soft_tmr() {

//0xFFFF-4999 will overflow (reach beyond 0xFFFF) in 1 ms


TMR1=60536;
//TMR1 on in internal clock (timer) mode without prescaler
T1CON=0b00000001;
TMR1IE=1;
}

void interrupt service_routine(void) {

char note;
char prescale;

//calling functions from the interrupt routine should be


//avoided, so we include the code we need right here instead.
//That way we can still use separate files.
//First some declarations in *.irh files (interrupt routine headers)
#include "ir_comm.irh"
//#include "serialio.irh"
//then the code itself in *.irc files (interrupt routine C source)
#include "ir_comm.irc"

// update soft timer if appropriate


if(TMR1IF){

/*
* Software watchdog timer
*/
if (++soft_wdt > 200) {
PCLATH = 0;
PCL = 0;
}

TMR1IF=0;
soft_tmr++;
TMR1ON=0;
TMR1+=60532;
TMR1ON=1;
}

// handle sound generation


if(T0IF) {
T0IF=0;
if(sound_index!=SOUND_END) {
// a tune is playing

// check if it is time for the next note

42
if(((unsigned int)soft_tmr
- (note_time+((unsigned int)notes[sound_index+1]<<3)))<0x8000) {
//time is up; next note
sound_index+=2;
//check end of tune
if(notes[sound_index]==0&&notes[sound_index+1]==0) {
sound_index=SOUND_END;
SOUND_ENBL_PIN=0;
// max prescaling to avoid unnecessarily many irrelevant interr
PS0=PS1=PS2=1;
}
note_time=soft_tmr;
}
if(sound_index!=SOUND_END) {
// tune is still playing
// continue to play note
note=notes[sound_index];
// if this is a pause (quiet note)
if((note&0xF0)!=0xF0) {
// not a pause

// set prescaler depending on octave 0, 1, 2, or 3


prescale=0b100-((note&0x30)>>4);
OPTION|=prescale;
OPTION&=(prescale|0b11111000);
// set timer 0 to overflow when sound pin needs
// to be toggled next time (new TMR0 interrupt then)
TMR0+=wave_per_add[note&0x0F];
// toggle sound pin and make sure enable pin is high
SOUND_PIN=!SOUND_PIN;
SOUND_ENBL_PIN=1;
} else SOUND_PIN=SOUND_ENBL_PIN=0; //pause
}
}
}
}

43
D Extra pictures

44
45

Potrebbero piacerti anche