Introduction to the Device
Beac0n allows us to explore the tacit human understanding of technological feedback.
The Beac0n is a gps pathfinder that is designed to be completely intuitive to the user. The goal is for the user to pick up the device, and with a small amount of exploration, understand it and its functions entirely. The “trailblazer” will walk a path with the device and set particular GPS waypoints. The “hiker” will then “discover” the device, pick it up, and begin to walk with it. Various forms of feedback (lights, sounds, and vibrations) will tell the user if they are performing well, (in this case, going in the right direction,) or performing poorly (going in the wrong direction.)
High Level Design
Rationale for the project
The rationale behind this project came from our desire to explore the human understanding of technological feedback. In the world today, we have all been taught that green means go, and red means stop. With this in mind, we designed our LED feedback system to primarily use green and red as indicators of the correct direction. With computers today, a pleasant “beep” often means that the task at hand has been completed, and the user may move on to the next task. For this reason, our device beeps when a waypoint has been reached, leading the user to understand that they now have the next waypoint loaded onto the device. Another aspect of the rationale is that the device can be used for games. To get people to play outside more these days, it seems technology should be integrated into their play-time. For instance, this device could be used for hide-and-seek, or some sort of exciting maze game. The possibilities are completely up to the user.
There are four algorithms for our project:
1) Compass Heading
Our compass heading function returns values of 0-360, but we quickly discovered that these values were not evenly distributed angles. We designed a correction, where the user finds the “true,” compass directions starting North and defining the direction every 45 degrees. The readings are then distributed evenly between every 45 degrees, so if North is read as 0 and North East is 50, the readings are distributed linearly so that a reading of (50/2)=25 will return as (45/2)=23 (rounded).
2) GPS angle
Our GPS angle function is simply passing atan2 (arctangent) with the next point’s coordinates minus the users current GPS position Example below is not directly from the code
This is then compared to the Compass heading, but that will be discussed later on. atan2 returns values between -180 and 180, (-180 and 180 are both West). This is converted into 0-360 by simply adding 180.
The distance function is a simple point to point distance calculation. Used used to measure the distance between the user and the next point.
To update the color of the LED, a simple comparison of the Compass Heading and the GPS angle is used. The absolute value of their difference is passed to a function called update_LEDs(int). This function handles what color to change the LEDs to. The descriptions of these algorithms will be expanded in the software section down the page.
The structure of this program is as follows: data from the compass and GPS are taken into the microcontroller, and is then processed to determine where the user is in space, and which direction they are facing. Based on these data, the device then generates feedback on whether or not they are getting closer to the right place, or are even facing the right direction.
Hardware and Software Tradeoffs
The crucial parts of our project needed to be done in software, as interpreting GPS or compass data via hardware is extremely difficult, if not impossible. Hardware that was necessary included voltage conversion to power the different components, and the buttons that would allow us to switch modes. Our hardware lacked complexity due to our focus and time spent on developing software.
The GPS Module (Skylab SKM53)
The GPS hardware is extremely simple, it’s default configuration has it send data over Uart at 9600 BAUD as soon as it has power, so it requires no software setup. We did however modify code by Jeff Melville and Matt Kuzbeda to work at 9600 BAUD (their uart worked at 4800 BAUD). We also had to take into consideration the stability of this data, since it is sent at 2.85 Volts high from the GPS and received at 5 Volts (3 Volt minimum) High at the atmega 1284p, so it is technically below the proper logic level. This proved to not be a problem, but would definitely be something to fix with a unidirectional logic level converter from 2.85 to 5 volts in the future. The GPS is powered by the Arduino +5 Volts (connected to GPS Vcc, which is designed for 5 Volts despite the 2.85 logic level output) and the ground pin is connected to the universal ground.
Compass (HMC5883L on the GY 85 intertial measurement unit)
The compass hardware was very difficult to set up. The compass is part of a larger unit, the GY 85, which also includes an accelerometer and gyroscope, both of which are unused. The compass works over I2C protocol, so the SCL and SDA pins must be connected to the designated SCL and SDA pins on the atmega 1284p. These pins on the 1284p are C0 (SCL) and C1 (SDA), but in Peter Fleury’s I2C library the assembly file has the pins set to D4 and D5. We changed these pins and then we had to also change the assembly file to include atmega 1284p as part of it’s supported MCUs. We also needed to add pullup resistors from the SDA and SCL lines to the 3.3V power source (same line as powers the compass, check the circuit diagram for clarification).
Switches and Button
The switches and the button function fairly regularly, the switches are treated as a 2 bit binary number, so when they are checked, they return a value from 0-3. (more information in the check_switches() function). When the button is pressed, it returns low, so we had to code with that in mind. The button is only updated in the switches call of the main function (or the compass calibration, but that is it’s own loop).
The ‘meat’ of the program comes in the form of a large while loop with many nested if statements to check the various conditions governing the feedback systems. We used old GPS code from Jeff Melville and Matt Kuzdeba. We also used a modified version of Joerg Wunsch’s Uart code (modified by Jeff Melville and us). Another library used by us is Peter Fleury’s I2C library (recommended by Bruce and everybody on the internet). The tricky parts came from finding small errors or incompatabilities. For instance in the I2C library, there was no definition for the ATMEGA1284p in the assembler file, so we had to write our own. The I2C was difficult to use even after we got the library working, we had to research the protocol itself, and search for the proper registers on the compass datasheet. Aditionally, we originally thought that using fscanf() to fetch the GPS data string would work, but we were mistaken. We did end up finding the old GPS code, but we had to modify parts of it and understand how it functions. It did provide us with a great alternative to fscanf(), using the Uart interrupt it is able to collect the GPS and store it in a circular buffer, which we then interpret into a character array.
The Main Function
The Main() function has the initialization phase and the infinite while loop. When the program enters the main function, it begins by running the individual initializations (described in full in the initializations function of software) and initializing variables that are used exclusively in the main loop, such as the latitude and longitude list, a universal iterator, and sets the button and switches, initializing them to their correct values. The main loop then enters an infinite while loop where it runs three separate subroutines; the GPS, the compass and the switches/buttons subroutines. These are called when their respective counts are zero. When they are called, they reset their counter to it’s proper value, allowing us to set separate delays for each subroutine. The counters are decremented every millisecond in the timer0 interrupt (covered in the next section). The gps delay is 750 ms, the compass is 200 ms, and the switches are 100 ms. The subroutines each have different functionalities depending on the mode the device is in, as determined by the latest running of the switches/buttons subroutine.
The compass subroutine does nothing for mode 0 (trailblazer mode) it simply passes the control back to the main loop after resetting it’s count. In mode 1 (hiker mode) the compass flashes red and green quickly if the universal iterator x is 0. x keeps track of where in the list of coordinates we are, so if x==0, we have completed the trail or have not initialized it yet. If x>0, then it updates the LEDs with the absolute value of the difference between the corrected compass heading (see the heading section) and the GPS calculated angle (see related section) then returns control to the main function. If the mode is 2 or 3, the compass subroutine enters the compass calibration mode, which is covered in it’s own section, since it stops normal functionality and enters it’s own loop.
This subroutine records the reading from the last time the GPS subroutine was run in the variables llat and llon (last lat and last lon). It then runs NmeaProcessTask(), which sets lat and lon to the current reading from the GPS. If longitude == latitude, then it blinks the LED so as to let the user know that the GPS is outputting bad data. This is because when longitude == latitude, the most common case is they are both 0.00 coming from the GPS. This technically means that the GPs will not work at certain points on earth where longitude==latitude, but in Ithaca, we’re at ~42, ~ -76, so we are very safely not near one of these points. If we have latitudes and longitudes that are nonzero, then we check which mode the device is in. If the device is in mode 0, trailblazer mode, then we check to see if the current coordinates equal the last coordinates. If these coordinates are the same, it means we are receiving a stable location from the satellite, so we indicate this to the user by setting the red LED low and the green LED high. If we are setting the first point of the path, then that is all we do, but if we are not at the first point, we check to make sure the distance between the last point set and our current location is above a certain threshold (15-30 feet, but our code handles this as essentially unitless distances). If it isn’t then the LED remains red, this is so that we cannot set two points in a row that are within the “arrival” distance from one anohter. If we are far from our last point, and the reading is stable the LED turns green, and in the switches section we are allowed to record the point. If the mode is 1 during hte GPS call, hiker mode is enabled and we want to seek the path that we just set. We do this by checking x. If x is 0, then the device flashes red and green to signify that the path has been completed by the hiker or not initialized beforehand. If x is greater than 0, we calculate the euclidian distance between our coordinates and the next coordinates, and set hte blue LED to the appropriate intensity based on our distance. The intensity of the blue LED is set to arbitrary intensities at arbitrary distances. We then check to see if our distance is below our accepted “arrival,” threshold, and if it is, then we have arrived at the next point in our path. Upon arrival, we play a beeping sound, decrement x, and set the next target coordinates (nlat and nlon) to the next coordinate on the list. No matter which mode we are in, at the end of the GPS subroutine we update the calculated angle of the GPS relative to it’s next point.
In the switches/button (sw/b) subroutine, the device checks the switches and updates the mode first. Then it checks the mode, and if we are in trailblazer mode, with a stable signal (checks if the green LED is on), the distance between our current coordinates and the last point set is above a threshold and the button is pressed, iterate x and record the current waypoint in the waypoints list.We skip calculating distance if x = 0 because there is no next waypoint and the program tries to evaluate the coordinates list with a negative index (which will crash the system half hte time and return -3400000000000000000000.0000000000000 the other half). If the distance is far enough from the last point, and the green LED is on (meaning the signal is stable) and the button is pressed when this subroutine is run, it plays a sound updates the list and increments x.
|Atmega 1284||Lab Stock||$5||1||$5|
|SKM53 (GPS Module)||ebay (user: nooelec)||$22.75||1||$22.75|
|GY 85 IMU (Included Compass)||ebay (user: alice1101983)||$10.98||1||$10.98|
|Arduino Due (Power Supply)||ebay (user: power59296)||$10.99||1||$10.99|
|Perf Boards||ebay (user: jpmultiserve)||$6.56||1||$6.56|
|ECE 4760 ATMega Board||Lab Stock||$5||1||$5|
|push buttons||Lab Stock||$0||1||$0|
|Piezoelectric Speaker||Lab Stock||$2||1||$2|
|9V Battery||Dollar Store||$2||1||$2|
|Wood||Found in Trash||$0||1||$0|
|Wires and Resistors||Lab Stock||$0||many||$0|
For more detail: Beacon: A Zero Instruction Navigation Device Using atmega1284