Richard B. Wagner
Navdeep Bahia
CSC 460: Project Three
Laser Tank Game
The main purpose of this project was to combine the work done in Projects One and Two in order to facilitate communication between two stations using Bluetooth and deploying tasks using a real time operating system (RTOS). There is a remote station that is placed on top of the “tank”, the Roomba 600, that receives input from a controller or base station. This controller can manually operate the tank’s movements, toggle between manual and autonomous control, as well as fire the laser attached to the tank. The remote station possesses a light sensor that will halt the tank’s movement when it gets hit, the aforementioned laser, and additional hardware for connecting to the Roomba. Both stations communicate via Bluetooth modules and each has an Arduino Mega 250 microcontroller which is used to control the various elements and run the software that provides the required functionality.
The elements from Project One that were re-implemented for this include the methods for Bluetooth communication, reading joystick inputs, toggling laser state remotely, as well as applying some of the techniques used in understanding the TTA scheduler to make full use of the RTOS. While the original methods of implementation were done in the Arduino IDE, this project required translating all of that into C code. From Project 2, the RTOS implementation was used to launch the various tasks that are required to start up and control the tank, along with the other various functions, including polling the sensors and controlling the other hardware elements.
The Process and Design section details the design and setup of the hardware needed for the two stations. It also contains a detailed description, diagrams, and explanation of the code of the two main phases of this project. Phase One required the implementation of manual control of the Roomba, along with the ability to fire the laser and have the light sensor detect when it has been struck. The details of the implementation of this phase can be found in the Phase 1 subsection. Phase Two required autonomous behaviour be added to the design so that the tank can roam and avoid obstacles without user input. The details can be found in the Phase 2 subsection.
The Source Code section contains a link to the Github repository where the code for this project can be found. Results details the end product of this project, while Debugging lists the various methods that were used to analyze and fix the problems that were encountered. Testing has screenshots of the output of the logic analyzer to show how the system was tested, and Obstacles outlines the struggles this project faced. Finally, References contains credit given to code bases that were borrowed from as well as a few key pieces of documentation.
The following is a list of the hardware used in both phases of the project:
1 x iRobot Roomba 600
2 x Arduino Mega 2560 Microcontrollers
2 x Bluetooth Radio HC-05/06
1 x Arduino KY-023 XY-axis Joystick Module
1 x SG-90 Tower Pro Servo Motor
1 x KY-008 Arduino Laser Module
1 x Analog Light Sensor/Photocell
1 x 2N3904 NPN Power MOSFET Transistor
1 x LCD Keypad Shield Display
1 x 10 ㏀ Resistor
2 x Breadboards
1 x Red Plastic Cup
There are two major components in this system: the base station, which acts as a manual controller, and the remote station that sits on top of the Roomba. The base station consists of an Arduino Mega 2560 microcontroller, the joystick that a user can manually control the Roomba’s movement with and fire the laser, as well as a Bluetooth module to communicate with the remote station. The remote station also makes use of an Arduino Mega 2560 microcontroller and Bluetooth module to communicate with the base station. It also contains the light sensor, placed on a wooden base in the red plastic cup, the laser,and a servo motor which the laser is attached to. The various components of both these stations are affixed to sheets of plexiglass with strips of velcro for ease of transportation and attachment.
Figure 1: Wiring Diagram of Base Station
Figure 2: Wiring Diagram of Remote Station
Please note that the servo attachment is from Project One, it doesn’t serve any purpose in this project except to act as convenient mount for the laser.
Figure 3: Base Station
Figure 4: Remote Station
Please note that in the above image, the breadboard has been attached to the top of the Arduino Mega 250 microcontroller.
Figure 5: Remote Station Connected on Top of Roomba
Figure 6: Bottom of Light Sensor Setup
The following is a block diagram that depicts the major elements of both the base and remote station. It visualizes how the components in each station communicates with each other and the other station. This diagram will be further decomposed in later sections.
Figure 7: Overall System Design
This phase of the project entailed using the base station to communicate with the remote setup on top of the Roomba in order to facilitate manual control of the Roomba’s movements by the user. It was also required that it must be possible to fire the laser attached to the remote station from the base, and that the light sensor be calibrated such that the detection of laser light stops the motion of the Roomba. The code for this manual control had to make use of the real time operating systems that were designed and implemented in Project Two. However, since the RTOS designed by this group had missing functionality, a working RTOS design was borrowed from a different group. Their work is credited in the References section at the end of this report. A note about the UART channels: UART1 and UART2 are used to communicate between the stations, among the components, and the Roomba, while UART0 is used in conjunction with the serial monitor in the Arduino IDE for debugging purposes.
This is the diagram depicting the interaction among the tasks between the two stations for the implementation of the manual control. The arrows indicate the ways the components and functions interact, including RTOS function calls.
Figure 8: Block Diagram of Phase 1
The code for the two stations is supported by three libraries: avr-uart, roomba-lib, and rtos. All of these can be found in the project_3/src/lib folder. Avr-uart contains functions that assist with reading values from and writing values to the UART connections established between the two stations. Roomba-lib contains functions for testing for valid Roomba commands and a massive header file (roomba.h) that contains multiple structs pertaining to Roomba operation codes, sensor packets, and the definitions of various useful constants. Rtos contains the RTOS implementation (i.e os,h, cswitch.S, etc).
The code for base station can be found in the folder basestation in the file main.c. The following is an explanation of the main functions of this code, as seen on Figure 8 above.
Figure 9: a_main() in basestation/main.c
a_main() is responsible for initializing various analog and digital pins, before calling adc_init(), a function that is explained further down in the report. It also initializes communication with Roomba by calling uartx_init(), functions from the uart library, with appropriate baud rate and then creating both the idle task and the pole_sensors task using RTOS functions before terminating.
Figure 10: adc_init() in basestation/main.c
adc_init() opens up the channels for communication among the various hardware components on the base station, like the joystick.
Figure 11: read_adc() in basestation/main.c
read_adc() is used in conjunction with analog pin numbers to read input from the joystick and other devices in different parts of the code base.
Figure 11: pole_sensors() in basestation/main.c
pole_sensors() is responsible for the bulk of the work done by the basestation. It initializes communication along UART1 with the correct baud rate to maintain ongoing contact with the Roomba and along the Bluetooth connection (UART0 is used for debugging and explained in the relevant part of the report). It also takes in input from the X- and Y-axes of the joystick before performing the calculations necessary to convert them into the correct range for radius and velocity respectively. Further on in the function, these values are split into two bytes and passed along UART1 to the remote station. pole_sensors() also takes in the value of the joystick button for triggering the laser on the remote station as well. Sending a value of 1 prior to transmitting these inputs informs the remote station that input is incoming. Sending a 5 prior to the velocity and radius values informs that manual drive commands will be arriving. Sending a 3 prior to the joystick values informs that a laser state will be arriving.
Figure 12: LOW_BYTE and HIGH_BYTE definitions
When accepting manual drive commands, the Roomba splits the radius and velocity inputs into high and low bytes as defined in FIgure 12. These bytes are then converted to using hex and 2’s complement by the Roomba before movement takes place.
The code for the remote station can be found in the folder remotecontroller in the file main.c. The following is an explanation of the main functions of this code, as seen on Figure 8 above.
Figure 13: a_main() in remotecontroller/main.c
a_main() initializes the ports and pins used by the device detect pin (DD_PIN) that is used to upload code from the remote station’s Arduino microcontroller to the Roomba. It also creates a task that will call on roomba_init() before terminating.
Figure 14: roomba_init() in remotecontroller/main.c
roomba_init() begins communication with the Roomba over the DD_Pin using the appropriate baud rate. The function sleeps for 200ms to give the machine a chance to “wake up” and come online. The Roomba is then put into Safe mode for the purposes of this project. Then, the function creates a call to the layer_1() function (more on that in Phase 2) which calls the handle_radio() function detailed below. roomba_init() then creates a task to run the pole_sensors() function before terminating.
This main.c also makes use of the adc_init() and read_adc() functions as described in the base station portion of the report.
Figure 15: handle_radio() in remotecontroller/main.c
handle_radio() makes use of the Mutex locks in the RTOS to gather inputs over UART and then parse them to the appropriate functions.
Figure 16: update_roomba_state() in remotecontroller/main.c
This function uses the Roomba operation codes to query its sensors over UART. The exact numbers of these codes can be found in the header file roomba.h.
Figure 17: pole_sensors() in remotecontroller/main.c
pole_sensors() contains code to manipulate the Roomba’s onboard LCD display. It also reads the input from the light sensor and triggers the stop function when a certain threshold has been met.
Figure 18: toggle_laser() in remotecontroller/main.c
toggle_laser() does just that by writing certain values to the port that the laser is connected to depending on the value that was received from the base station.
Figure 19: roomba_stop() in remotecontroller/main.c
This function stops the Roomba’s movements when the light sensor is triggered by sending the required operation codes over UART.
The original design of this phase was to go straight and execute a turn when obstacles were encountered. The code below (Figure 20) shows the code that was used initially for turning. The same idea is done in the final version with the difference of the data being retrieved in a separate routine (Figure 21).
Figure 20: roomba_turn() in remotecontroller/main.c
Figure 21: autonomous() function
Phase I Demo: https://youtu.be/E7pXw85mCic
Phase II Demo: https://youtu.be/hDM3rV1CkMw
Roomba Interface Documentation:
http://breckwagner.github.io/CSC460/project_3/documentation/html/group__roomba-lib.html
https://github.com/breckwagner/CSC460/archive/0.1.zip
There were several methods that were used to debug issues that arose during the implementation of this project. The logic analyzer was the tool of choice to initially diagnose a problem. Using it makes it possible to determine what values are being sent over UART, when the RTOS deploys tasks, when Roomba returns sensor packets after receiving a query request, etc. In the screenshot of the logic analyzer below, it shows that the approximate time between the Roomba receiving a request and then responding and sending the data that was requested back is about 15 ms. Information like this is useful when trying to determine the cause of delays from software and hardware.
Figure 22: Logic Analyzer Screenshot
Code in the pole_sensors() function was used to print to the serial monitor associated with the Arduino IDE using UART0. This was done to ensure that was data was actually being sent across the Bluetooth connection and then determining what the values being sent across were actually accurate.
Figure 23: Code Snippet for Debugging Using UART0
There were times when neither of the aforementioned methods worked and it difficult to discern what was truly wrong. When this happened, simple trial and error was used to find the cause of errors. This resulted in discovering faulty wires, loose pins, and that the joystick button required a pull up resistor to work properly, among other things.
Testing the Roomba was done using the logic analyzer as described above; determining whether sensor packets were being sent and received correctly was the primary reason for doing this. After this, testing was primarily done uploading code to the Arduino microcontrollers and seeing what happened. This proved useful as it was difficult to figure out if the code was working as it should or if the Roomba data behaved as it was stated in the documentation without trying things.
Aside from the aforementioned difficulties the in Debugging and Testing sections, there were a few other obstacles that were encountered. First, since this group didn’t have a properly functioning RTOS implementation, the work posted by the classmates in the References section was used. It took some time to understand how their code was organized and how it operated. There was also some problems encountered with data types, as preserving accuracy meant more data was being sent over connections which yielded slow communication. It was also found that the Roomba sensors were subject to sensor drift, which often skewed calculations and potential solutions to other bugs in the code.
There were several issues with the Roombas as well. Sometimes, the sensor values that were returned were completely random and the cause of this was never found out. Interfacing the Arduino boards with the Roomba also lent itself to strange behaviour in terms of movement. No cause for that behaviour could be found in the code or the data transmission. It may have been an issue with the wiring of the connector cable.
The Bluetooth modules would often get out of sync and they had to be re-configured on a couple of separate occasions.
The RTOS code for this project was the implementation created by Chris Cook and Kevin Gill. It can be found on their project website at:
http://www.roombatank.com/index.html