Need to find your diving, fishing, or kayaking partner buddy out in the open ocean. We should stick with each other at all times, but sometimes we get separated. Trying to find your far off buddy when you are low in the water is a tad bit difficult.
No readily available single device (well, would be a pair of devices) that I know of exists to solve the problem. Closest solution would be that both party members have a VHF radio and GPS device on them and then relay coordinates to each other.
The problem with VHF and GPS is that a party member needs to respond to a call. This might not be possible with diving since divers are usually dragging their float behind them. Or maybe your kayak partner hooked up a huge fish and is too busy fighting the fish to respond. Also, separate VHF and GPS devices would be a bit pricey.
A pair of devices that automatically communicate with each other and giving each other its own coordinates. The devices can then calculate the bearing of the paired device and display that to the user visually via a NeoPixel ring and textually on a display.
The Sony Spresense handles obtaining GPS data and communicating between the pair of devices. The Spresense controls an nRF24L01 module, OLED display, and communicates serially to an Arduino Nano. The Nano is used to read a magnetometer and control the NeoPixel ring.
A light on the NeoPixel ring turns red to show where north is. A blue light points to the direction of where the other device is (purple if north and direction of buddy are the same). The OLED screen displays GPS connectivity, battery level, distance and bearing to the other device. Although there is a LiPo protection circuit (cut off is ~2.4V), you should never let the battery get lower than 3.3V. The protection circuit is just to make sure nothing catastrophic happens when battery's voltage drops too low.
You are going to need 2 of everything since this project works only as a pair. The project works marginally when bread boarded and really needs to be permanently soldered together. When I tried to test moving one module, the jumpers would jiggle and lose connection causing the radio and/or display to go bonkers.
Follow the Fritzing diagram for connections. Sorry, its a bit messy. There are points in the diagram that are not Fritzing connected, I just did my best guess to where on the device they need to connect. The overview video above explains the different parts of the project that you don't get from just looking at the diagram. Remember, you will need two of these modules. One module will have D25 connected to GND as this lets the module know if it's the master or slave of the pair. The diagram shows two 4 channel logic level converters but I just used one 8 channel converter (no Fritzing part for 8 channel that looks like the one I used).
nRF Adapter Modification
The case is small and the nRF module and adapter as is would not be able to fit nicely. I removed the female headers from the adapter to save on space and directly wired the nRF24l01 module to the logic level converter (the nRF24l01 is 5V tolerant). I still needed the adapter board as it has the 3.3V regulator.
I had communication problems when I tried to use the high power amplification setting. Worked fin with the low setting but I want the maximum possible distance. Reading posts all over the web, people suggested connected capacitors as the module will eat up a lot of current. That is the reason for the 100uf, 10uf, 1uf, and 0.1uf after the 3.3V regulator and a 100uf before the regulator. Seems like overkill but the radio doesn't work properly if any of those caps are missing.
I believe shielding is a must. You can read about it at Fixing your cheap nrf24l01+ pa/lna module by Oitzu. I used heat shrink tubing that was meant for fishing pole grips instead of the plastic cling film (Saran Plastic Wrap). A bit overkill since the shrink wrap is a lot thicker than electrical shrink wrap.
nRF24l01 Masking Caution
Be very careful of the modules you obtain. I bought a bunch of modules from various sellers over time (mainly because I misplace them, buy new ones, then end up finding the previous ones I bought). I almost wired up one of the modules incorrectly due to the mask on the bottom referencing either looking at the top of the board or from the bottom of the board. See the following picture. Best bet is that the ground pin has square pad and then you can tell what orientation the mask is describing.
Need for the Nano
The Arduino Nano is used to control the NeoPixel ring and the LSM303 module. The NeoPixels has a very strict timing requirment timing so I did not want to chance trying to get it to work with the Spresense board which is already handling the GPS, radio, and display.
I originally wanted to put the magnetometer with the Spresense. The magnetometer would not respond to the Spresense board. I had a cheap magnetometer from eBay that didn't work. So I bought a fairly pricey module from Adafruit thinking maybe what I got before was just eBay junk. The Adafruit module also did not work. I looked into the LSM303 datasheet, minimum timing requirement on the I2C clock standard mode for low is 4.7uS and high is 4.0us. The logic analyzer shows that the clock low time the Spresense is 4.5uS. That is why I think the magnetometer cannot communicate with the Spresense board.
I tried both white and blue OLED displays. I found the blue display much easier to read due to the milkyness of the Plano case I used. If you use another case that has a crystal clear cover like a Pelican waterproof case, I'm sure a white OLED display would be easy to read.
The case I used is a Plano 3400. I like them because they are water tight and relatively cheaper than Pelican waterproof cases (about ~1/3 the cost). I use the Plano case for fishing and the only water that gets in, is when I open it up to get more lures out. The case is small and just big enough to hold all the components of the project.
I hot glued several of the components to craft foam to keep them from moving around too much in the case. I left the Spresense free floating. This is okay since the wires are stiff enough to keep the board away from the other components. Also, I left the main board floating because I need a way to move it just a bit so I can re-flash code changes. Probably could have had the main board rotated 180 degrees but I wanted to keep the GPS antenna as far from the other components like the radio antenna. Not sure if that makes a difference or not, but seemed like the right thing to do.
The entire device is powered from one 3.7V battery. I used a 1S RC battery and put in a LiPo protection circuit since the battery lacks one. The battery is boosted to 5V using a LM2596 buck converter. Probably could've use something smaller but that is what I had on hand. I did not put a switch thinking that much safer to pull the battery instead of switching off then forgetting about it.
To power the Spresense, the battery's positive terminal is directly connected to the positive terminal of CN1 (ground will get conected through one of the board's ground pins). The battery connector doesn't come with the board. You'll instead see a + and - solder pads to right of the 4 LEDs on the board (if you had the GPS antenna pointing away from you and the USB port towards you). The document says power with recommended 3.6V to 4.4V and no more than 7V. I thought about connecting to 5V from the boost converter but just opted to connect straight to the battery since that is what it looks like it was really meant for.
Power Protection Issue
I put in a LiPo Protection circuit since the battery I used does not have it built-in. Sometimes when connecting the battery, the protection circuit trips and cuts off the battery from the circuit. My only guess is that while connecting the battery, the connector contacts intermittently disconnect till seated correctly and the protection circuit sees this as under voltage. The work around is to quickly jumper the protection unit's output ground with the input ground.
If you use a battery with built-in protection, you won't have to worry about what I experienced above.
Download the code from the Open Ocean Buddy Locator repo at GitHub. The code has been tested and compiled from Arduino 1.8.8 on Ubuntu 18.10. Read the Compiling gotchas section to get the project to compile.
The project consists of two Arduino projects, one for the Spresense and the other for the Arduino Nano. Please refer to the Spresense documentation "Spresense Arduino Library Getting Started Guide" for using the Arduino IDE with the Spresense board.
Spresense project (OpenOceanBuddyLocator) contains 15 files. I tried to break the project down into little files instead of having a giant unwieldy.ino file. The code should be pretty much self-explanatory, but ask away in the comments if you have any. The GPS file is a modified version of the Spresense example. The RF24 files are a modified version of TMRh20's nRF24L01 drivers to work with the Spresense.
The Nano project (OpenOceanBuddyLocatorNano) just has one .ino file. This file should be self-explanatory also.
I am watching Clean Code videos by Robert C. Martin and trying to practice what I learned from his videos. He's a bit, hrmmmm, interesting to watch but quite edutaining. Most of my code, I hope is explanatory by variable/function naming and structure. I did not change much of modified example code as those were very informative to begin with, but will try to apply the Clean Code practices to them in the future.
- Adafruit LSM303 Libraries
- Adafruit NeoPixel Libraries
- Adafruit SSD1306 libraries
- TMRh20 2014 - Optimized Fork of NRF24L01+ Driver (modified version already in project)
The Spresense SPI driver is not compatible with the Adafruit SSD1306 libraries. Some modifications will need to be done to the Adafruit libraries in order to compile for the Spresense.
Adafruit SSD1306 - Comment out the contents of the HAVE_PORTREG blocks in the begin function. These are lines 482-485 and 495-499 in the Adafruit_SSD1306.cpp file of the Adafruit SSD1306 Version 1.2.9 library.
The symbol HAVE_PORTREG gets defined in Adafruit_SSD1306.h if __AVR__ is defined. You could track down where __AVR__ is defined and undefine it but not sure if that will cause problems for other libraries so I took the easy way out and just commented out the code in Adafruit_SSD1306.cpp.
Adafruit GFX Libarary - Remove or rename the Adafruit_SPITFT.* files to.bak so the compiler does not try to compile those files.
No need to modify the RF24 class as I have already modified it to work with the Spresense board. Modifications include:
- Redefine _SPI to use SPI5 - Thats the SPI of the Spresense main board.
- Slow down SPI_SPEED to 1MHz - Only speed I could get the nRF24l01 module to work properly. Any faster and the radio module was very flakey, sometimes would not initialize correctly other times would initialize but then could not set registers properly.
- Remove RF24_LINUX, LITTLEWARE, XMEGA_D3, and ATtiny blocks - Not sure if this was necessary since that symbols should not have been defined. I think the removal was to strip the code down to bare necessities to try and get it working. I think the main factors to get the module to work was to use SPI5 and slow the SPI to 1MHz.
Just a few quick notes of issues I came across while working with the RF24 library. If you know of a fix or worked for you, please leave a comment.
- Could not set payload size with RF24::setPayloadSize(uint8_t size). I wanted to set payload the size of two doubles in hopes that transmitting less than default 32 bytes will allow for greater transmitting distances. The radio was not able to transmit anything. I even tried to hard code just sending 1 byte and was still unsuccessful.
- Early iterations I removed the manual controlling of the SPI chip select, RF24::csn(bool mode). I tried using the Spresense built-in chip select (SPI5_CS_X). I could not get the radio to initialize. Analyzing the SPI bus during SPI transaction, the CS line goes low when writing on the MOSI line then back high right after, then back to low before next block of data to write. So the CS line is jumping low then high, low then high, repeatedly during the transaction. The default RF24 holds the CS line low until the entire SPI transaction is done. So unsure if the radio module can take the high low switching on the CS line for a transaction.
Best to wire and solder connection as bread boarded doesn't work so well when moved.
The following is a video of testing the devices on land in an open field. Tried to get my kids to help me but kids aren't the best test partners. They at least helped show that in an open area, the devices could communicate with each other.
The devices were still able to communicate about 160 meters apart (would have tried further but I was already at the end of my street). The communication wasn't constant, I could tell from the display that there were dropped packets or unable to communicate every so often but no longer than about 5-10 seconds.
The following is a water test that worked out very well, I even found dinner while I was at it. The weather was good and the area I tested at tends to be relatively flat most of the time so no test of how waves would influence the devices.
Results of the test show that the devices respond to each other even though they are low to the water. I was surprised because the module I carried with me floated at the surface of the water and still could connect to the module on the float. I expected that I would have to lift my module out of the water, but didn't have to. My guess if that both modules were mounted on a float, they would have no problems at all communicating with each other.
Thank you for reading through this project.