Magnet switch – test #2

The next step is to make sure that the magnet switch can be triggered once installed on the underside of the buy lid. I created a new lid design with a recessed pocket for the magnet switch and hardware. The goal was to get the magnet switch as close as possible to the exterior surface of the lid to minimize the distance between the sensor and the magnet used to trigger the awake/sleep modes.

Here is a video showing the final test with the magnet sensor mounted under the lid. Everything seems to be working ok – I had anticipated that I might need a stronger magnet to trigger the switch but was able to use the magnet that came with the sensor after all.

 

CAD model of the new lid, name “Container – top – v5”

Link to downloads for CAD…

I also took this opportunity to use a general purpose 2-part epoxy to mount the solar panel to the lid. In the future I plan to use a marine grade epoxy which would better stand up to the ocean water – but this Loctite epoxy should be sufficient for now while testing in a pool or a pond.

IMG_1785

Mounting the magnet switch to the underside of the buoy lid.

Round solar panel, 6V 100mA, epoxied to the top of the lid.

 

Bill of Materials – V4

Received a request for a more detailed list of materials and parts. So here is an updated Bill of Materials (BOM) for version 4 of the buoy. It is built around the Adafruit nRF52 Feather and LoRa breakout board.

*I have not yet integrated the GPS, IMU, RTC, or SD card reader/writer into the newest PCB design with the nRF52 board, so these are missing from the list.*

Screen Shot 2018-07-01 at 11.25.39 AM

Download Excel or PDF files…

Screen Shot 2018-07-01 at 12.02.40 PM.png

BOM table was exported from Fusion360 using the Bommer app.

 

Magnets and Hardware Interrupts

I’m working with a cheap hall effect sensor so that I will be able to put the buoy into sleep mode without the need for a mechanical on/off switch. The magnet sensor will be inside the lid of the buoy so there will be no moving parts for water to penetrate, keeping everything water tight (in theory).

IMG_1683.jpg

This first code example is written for the Arduino UNO or the Adafruit nRF52 Feather. It attaches a hardware interrupt to one of the pins and reads the status of the magnetic switch as it changes from HIGH or LOW. When the two magnets get close enough, the small switch inside closes and the signal goes LOW triggers a falling edge that is detected by the hardware interrupt. This jumps to the Interrupt Service Router (ISR) and runs a bit of code to toggle the LED on or off based on its previous state. The basic code was provided by the friendly folks at Sparkfun. Thanks for the awesome video!

Example #1 – Hardware Interrupt

The nRF52 Feather can use any of its pins for a hardware interrupt, but the Arduino UNO must use Pin2 for Int0 and Pin3 for Int1.

If using the UNO, there is a handy function to determine which interrupt you will be using based on the UNO pin you chose to connect to your switch or button. You can call

digitalPinToInterrupt(button_pin)

when setting up your interrupt to automatically determine the interrupt you are mapping to. But, this neat little trick does NOT work with the Feather. Be warned!

There is a 10K ohm resistor between +V and the input pin. This is to pull the pin HIGH so that it does not float while we wait for the magnet switch to activate.

// Filename: 01_HardwareInterrupt.ino
// Description: Basic external interrupt example for 
// Original code: https://www.youtube.com/watch?v=J61_PKyWjxU
// By: Sparkfun
// Modified: June 23,2018
// By: Nick Raymond

// Pins
 const uint8_t btn_pin = 2; // uncomment for UNO
//const uint8_t btn_pin = 7;    // uncomment for nRF52 Feather
const uint8_t led_pin = LED_BUILTIN;

// Globlas
uint8_t led_state = HIGH;

void setup() {
  Serial.begin(115200);
  pinMode(btn_pin, INPUT);
  pinMode(led_pin, OUTPUT);

  digitalWrite(led_pin, led_state);

  // Setup the interrupt
  attachInterrupt(digitalPinToInterrupt(btn_pin), toggle, FALLING); // uncomment for UNO
  //attachInterrupt(btn_pin, toggle, FALLING); // uncomment for nRF52 Feather, does not work with the "digitalPinToInterrupt" function!

}

void loop() {
  // Pretend we do something here
  Serial.println("do something");
  delay(500);
}


// Interrupt Service Routine
void toggle(void){
  led_state = !led_state;
  digitalWrite(led_pin, led_state);
  Serial.print("ISR   ");Serial.print("LED state = ");Serial.println(led_state);
}



With this implementation the LED will toggle ON and OFF very quickly and can be prone to accidental changes in state due to the sensitivity of the system. This is bad, since we do not want to accidentally have the buoy switch into sleep mode by mistake.

 

The following image is a plot showing the current usage during the on/off toggling for the Arduino UNO. We see that the UNO has a rather large idle current of approximately 33 mA, and draws about 35 milliamps with the onboard LED turned on. This is simply the sum total of the current needed for all the parts on the Arduino and  includes the current used for the microcontroller chip, the USB to serial convertor, the onboard voltage regulator, system clock and other bits and pieces. We can reduce this considerably by placing the UNO into a deep sleep mode which I will talk about in a later post. But for now,  just keep in mind that while the UNO is a great off-the-shelf general purpose prototyping board is may be a bit limiting for our lower power application inside the buoy.

Screen Shot 2018-06-24 at 11.07.24 AM

And this is a plot showing the current usage during the ON/OFF toggling for the nRF52 Feather. We see that the Feather has a fairly low idle current and draws approximately 6.9 mA at rest, and draws about 8.2 milliamps with the red onboard LED turned on. It is possible to get even lower values than this – with a few things to keep in mind.

Screen Shot 2018-06-24 at 10.16.53 AM

A. The nRF52 feather uses a schedule task manager to take care of scheduling events so that the BLE and MCU can both co-exist on one chip in harmony. By default this task scheduler will put the board into a low idle mode when nothing is happening in the loop. This is handled by a macro waitForEvent() but apparently you can also just add a delay in the loop and the board will automatically drop to this low idle state also. COOL!

B. Unfortunately, it was discovered that the USB to serial converter chip on the original version of the nRF52 Feather was sucking up a decent amount of power preventing the board from being able to get sub-milliamp current draws when in a deep sleep mode. This is all tracked on the Adafruit help forum and a new update version of the board is now available that addresses this issue. I have an older version of the board but will be ordering the new boards once they are back in stock. So for now, the best I can expect from my feather is about 6.9 – 7 mA when in “sleep mode”.

Example #2 – Interrupt + Debounce

The next example combines the hardware interrupt with a simple debounce example. With the debounce code we can control the sensitivity of the system by requiring that the switch stay closed for a specified amount of time as defined by

unsigned long debounceDelay = 3000;    // the debounce time

In this second example we want the user to hold the magnets together for at-least three seconds before the LED changes it state. In this implementation it also means that we need to WAIT at least three seconds before we try to change the state of the LED again. In this way we prevent an accidental ON/OFF situation and the system becomes more reliable for this buoy + magnet application.

The hardware doesn’t change for this example, just the code. The source code is based off off the example code  in the directory Arduino > Examples > 02. Digital > Debounce with the added hardware interrupt code chunk from Example #1:

/*
  Debounce

  Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
  press), the output pin is toggled from LOW to HIGH or HIGH to LOW. There's a
  minimum delay between toggles to debounce the circuit (i.e. to ignore noise).

  The circuit:
  - LED attached from pin 13 to ground
  - pushbutton attached from pin 2 to +5V
  - 10 kilohm resistor attached from pin 2 to ground

  - Note: On most Arduino boards, there is already an LED on the board connected
    to pin 13, so you don't need any extra components for this example.

  created 21 Nov 2006
  by David A. Mellis
  modified 30 Aug 2011
  by Limor Fried
  modified 28 Dec 2012
  by Mike Walters
  modified 30 Aug 2016
  by Arturo Guadalupi
  modified 24 Jun 2016
  by Nick Raymond

  This example code is in the public domain.

  http://www.arduino.cc/en/Tutorial/Debounce
*/

// Pins
 const uint8_t btn_pin = 2; // uncomment for UNO
//const uint8_t btn_pin = 7;    // uncomment for nRF52 Feather
const uint8_t led_pin = LED_BUILTIN;

// Variables will change:
int led_state = HIGH;         // the current state of the output pin
int button_state;             // the current reading from the input pin
int lastbutton_state = LOW;   // the previous reading from the input pin
int flag = 0;                 // change if interrupt is activated
int sleep = 0;                // when == 1, go to sleep            

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 3000;    // the debounce time; increase if the output flickers

void setup() {
  Serial.begin(115200);
  pinMode(btn_pin, INPUT);
  pinMode(led_pin, OUTPUT);

  // set initial LED state
  digitalWrite(led_pin, led_state);
  
  // Setup the interrupt
  attachInterrupt(digitalPinToInterrupt(btn_pin), toggle, FALLING); // uncomment for UNO
  //attachInterrupt(btn_pin, toggle, FALLING); // uncomment for nRF52 Feather, does not work with the "digitalPinToInterrupt" function!

}

void loop(){

  if(sleep == 0){
    Serial.println("Awake    ");
    // turn on LED:
    digitalWrite(led_pin, HIGH);

  }
  else if(sleep == 1 && flag == 0){
    Serial.println("Sleep    ");
    // turn off LED:
    digitalWrite(led_pin, LOW);

  }

  // call the debounce() function, check if switch is being held down
  debounce();
  delay(500);
  Serial.println("\n\n");
}



// Debounce function definition
void debounce() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(btn_pin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastbutton_state) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  Serial.print((millis() - lastDebounceTime)); Serial.print("  "); // debugging check the counter
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    Serial.print("button_state "); Serial.print(button_state); Serial.print("reading "); Serial.println(reading);
    // if the button state has changed:
    if (reading != button_state) {
      button_state = reading;

      // only toggle the LED if the new button state is LOW
      if (button_state == LOW) {
        led_state = !led_state; // change state of LED
        sleep = !sleep;         // change state of sleep mode
        flag = 0;               // change state of the flag to 0
      }
    }
  }

  // save the reading. Next time through the loop, it'll be the lastbutton_state:
  lastbutton_state = reading;
}



// Interrupt Service Routine
void toggle(void){
  flag = 1;
  Serial.println("ISR");
  Serial.print("sleep "); Serial.print(sleep); Serial.print(" flag "); Serial.println(flag);
}

And this is the current draw from the Arduino running the above code. The current draw during idle and LED ON is about the same as last time. The signal is a bit noisy – I suspect this is because I am providing +5V to the Arduino UNO Vin pin when it should be more like 9-12V for stable operation. The orange line in the plot represents a simple low pass filter that was added by applying a moving average to the data using a window size of 5 data points. When transitioning from OFF to ON we see a slightly higher than normal current draw as the UNO powers on the LED. For both the On and OFF states we can also see a slight increase in current as the Arduino runs through the debounce code for three seconds before changing the state of OFF/ON.

Screen Shot 2018-06-24 at 11.38.27 AM

And here is what it looks like for the nRF52 Feather with a much cleaner signal. One reason I suspect we get a cleaner signal is because we are sending 5V into the USB pin which then regulates the voltage down to 3.3V for the nRF52 chip. So the nRF52 is operating in a more stable condition as compared to under powered UNO in the last example. I could switch power supplies when powering the UNO vs nRF52 but I damaged one of my Feathers when I accidentally sent 9V into the USB in pin and toasted the onboard USB to Serial converter.  So this is just me being lazy/cautious.

Here we are able to more clearly see the transitions in the code between OFF to ON and the debounce() routine.

Screen Shot 2018-06-24 at 10.15.12 AM

Below is a zoomed in view so show the transitions so we can discuss the details!

From 42 – 44 seconds the LED is OFF and the Feather is in idle mode pulling 6.9 mA. At second 44  I moved the magnets close together which trigger the hardware interrupt when there was a falling edge on pin2. This then called the Interrupt Service Routine (ISR) and changed the state of the variable flag = 1.

In the void loop the debounce() routine was being called and ran for about three seconds pulling 7.2 mA while it did the computations. At 47 seconds the debounce() routine has been satisfied and the LED is turned on. There is some transience in the signal as the LED is powered on with a max draw around 8.5 mA. After the LED has been on for a second it reaches a steady state pulling 8.2 mA. Nothing happens for several seconds, then I triggered the hardware interrupt again by moving the magnets back together.

When the program jumps back to the main loop the debounce() routine continues to run. The debounce routine runs for 3-4 seconds while I hold the magnets close together before finally transitioning to the LED OFF state with a current draw of about 6.9 mA again. And this all repeats over and over.

Screen Shot 2018-06-24 at 12.00.32 PM

BUT, there is a major flaw with this code!

The problem is that the debounce() function is called once every time in the void loop() regardless of the status of interrupt. So even when we should be in SLEEP mode, we are still running the debounce() function instead of waiting for the hardware interrupt to determine when we check the status of the switch. While we see from the plots that the ISR is being activated by the magnets, it is not controlling when the debounce() function gets called. This is not good – we want a way to have the ISR prompt the debounce() function so that we only read the pin state once the hardware interrupt has been called. This way we can set the MCU to go to sleep for long period of time to save power and only be woken up when the magnet switch is held together for at least three.

Example #3 – Interrupt + Debounce + Sleep

Still a work in progress… but the functionality is all there. The code can be simplified and optimized but that is for another day. This will at least get me up and running with something to test in the field. All the serial.print() calls are to help with debugging and are not needed during actual implementation.

// Filename: 03_ToggleSleepMode.ino
// Description: External interrupt with debounce code to trigger sleep or awake mode
// Created: June 23,2018
// By: Nick Raymond
// Notes: needs to be cleaned up / simplified 

// Pins
// const unint8_t btn_pin = 2; // pull pin high with 10k resistor to +V, uncommnet for UNO
const uint8_t btn_pin = 7;    // pull pin high with 10k resistor to +V, uncomment for nRF52 Feather
const uint8_t led_pin = LED_BUILTIN;

// Variables will change:
int led_state = HIGH;         // the current state of the output pin
int button_state;             // the current reading from the input pin
int lastbutton_state = LOW;   // the previous reading from the input pin
int flag = 0;                 // change if interrupt is activated
int sleep = 0;                // when == 1, go to sleep
int counter = 1;              // counter to track through debounce looping


// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 3000;    // the debounce time; increase if the output flickers


void setup() {
  Serial.begin(115200);
  pinMode(btn_pin, INPUT);
  pinMode(led_pin, OUTPUT);

  digitalWrite(led_pin, led_state);

  // Setup the interrupt
  //attachInterrupt(digitalPinToInterrupt(btn_pin), pinInterrupt, FALLING); // uncomment for UNO
  attachInterrupt(btn_pin, toggle, FALLING); // uncomment for nRF52 Feather

}

void loop() {

  // Put MCU into awake mode
  if (sleep == 0) {
    Serial.println("---- Awake ---- ");
    digitalWrite(led_pin, HIGH); // turn LED ON
    debounce();

    //******************************************************************//
    //*********** Put code in here to run during awake mode ************//
    //******************************************************************//
    
     delay(500); // added here to simulate polling sensors and logging data

    //******************************************************************//
    //******************************************************************//

  }
  
  // Put MCU into sleep mode
  if (sleep == 1){
    
    // Prepare for sleep mode
    if(flag == 0){
      Serial.println(" ");
      Serial.println("---- Remove the magnet!----");
      Serial.println(" ");

      // flash the red LED 10 times, warn user to remove the magnet
      for (int i = 1; i <= 10; i++) {
        digitalWrite(led_pin, HIGH);
        delay(250);
        digitalWrite(led_pin, LOW);
        delay(250);
      }
      flag = 1;
    }
    // Check button status before going to sleep
    else if (flag == 1) {
      Serial.println(" ");
      Serial.println("---- CHECK - should I wake up?----");
      Serial.println(" ");
      Serial.print("counter ");Serial.print(counter);Serial.print("flag ");Serial.println(flag);
      
      // need to check if we should wake up
      for (int i = 1; i <= 10; i++) {         debounce();         delay(500);       }       if(flag == 1){         Serial.println(" ");         Serial.println("---- Go to Sleep!----");         Serial.println(" ");         flag = !flag;         while (!flag) {           //__WFI(); // put into low power mode           delay(300); // wait in low power mode         }       }     }     else{       Serial.print("*****else --- flag ");Serial.print(flag);Serial.print("Sleep ");Serial.print(sleep);       while(counter > 10){
        debounce();
        delay(500);
        counter++; // keep track of number of times we call debounce outside of AWAKE mode 
      }
      flag = 0;
      counter = 0;
   }
  }
}


// Interrupt Service Routine
void toggle(void) {
  flag = 1;
  Serial.println("ISR");
  Serial.print("sleep "); Serial.print(sleep); Serial.print(" flag "); Serial.println(flag);
}


// Debounce function definition
void debounce() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(btn_pin);

  // check to see if you just pressed the button
  // (i.e. the input went from HIGH to LOW), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastbutton_state) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  Serial.println(millis() - lastDebounceTime); // for debugging ONLY
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:
    Serial.print("button_state "); Serial.print(button_state); Serial.print("reading "); Serial.println(reading);

    // if the button state has changed:
    if (reading != button_state) {
      button_state = reading;

      // only toggle the LED if the new button state is LOW
      if (button_state == LOW) {
        led_state = !led_state;
        sleep = !sleep;
        flag = 0;
        Serial.println("Debounce function");
        Serial.print("sleep changed:"); Serial.println(sleep);
        Serial.print("flag changed:"); Serial.println(flag);
      }
    }
  }

  // set the LED:
  //digitalWrite(led_pin, led_state);

  // save the reading. Next time through the loop, it'll be the lastbutton_state:
  lastbutton_state = reading;
}

And this is what the current draw looks like. Very similar to example #2 – mainly because the nRF52 Feather has such a low idle current draw thanks to the onboard task manager. The power saving for the UNO would be expected to be fairly significant if you setup a deep sleep mode. Running out of time today…but hopefully can show an example with the UNO later on.

The major benefit of running this code as compared to Example #2 is that now the debounce() function should only get called when the hardware interrupt detects a falling edge. The Example #3 code has the MCU go to “sleep” and will remain asleep until the hardware interrupt runs the ISR. These two major differences make it possible to use the magnet switch to place the MCU in a long sleep mode where it will wait for an input from the user before waking up. If it detects a change then the MCU will check that the switch has been closed for more than three seconds before waking back up. If it detects a change on the hardware interrupt pin BUT the switch was NOT closed for three seconds then the MCU will go back to sleep.

Below of the current usage from the demo in the video.

Screen Shot 2018-06-24 at 2.39.59 PM.png

Next I’ll update the CAD model of the lid to be able to mount the magnetic sensor to the underside near the solar panel. Once the magnet sensor is mounted to the bottom of the lid I’ll need to use a stronger magnet to penetrate through and activate the switch. Based on some preliminary testing this should be ok.

Also on the to-do list is setup a RPi to read the power monitor sensor and create log files while running headless. This way I can monitor both the solar panel output and the MCU power draw over a period of a few days to get a better idea of the overall energy budget with the GPS and LoRa and SD card. Oh – and water testing soon to verify that the 3D prints + epoxy will make a water tight container.

Basestation + Raspberry Pi

*Big thanks to Shawn from the Sensor the Earth project who helped me setup the Raspberry Pi and problem solve to get it talking to the Arduino!*

IMG_1533.JPG

With the buoy test mule up and running the next big step is to setup the basestation to push the sensor readings online. I had already setup an Arduino UNO + LoRa radio to act as the basestation and listen for the buoy transmission using one of the generic RadioHead example sketches. This displays the message from the buoy onto Serial Monitor and sends a confirmation message back to the buoy every-time the buoy sends out a broadcast. But this required that the basestation be plugged into my laptop every time I wanted to verify that the basestation was receiving a signal from the buoy.

So instead of using the laptop to power the basestation I decided to setup an RPi to be on my wifi network and communicate directly with the Arduino over USB. This way I could use Secure Shell protocol (SSH) to login to the RPi via my laptop and see the data streaming from the basestation WITHOUT ever having to physically connect to the basestation to my laptop.

Step 1: configure the RPi for headless operation on a wifi network

Download the latest Rasbian distribution and use ApplePi-Baker to upload the image file onto a 16 Gb SD card. I am running Rasbian Stretch Lite, this version does not have a graphical user interface (GUI) running desktop graphics as I plan to SSH into the RPi from my laptop and only use the terminal for communication and control.

Screen Shot 2018-06-04 at 8.40.17 PM.png

You can also use ApplePi-Baker to flash one of your backup image files onto the SD card.Screen Shot 2018-06-04 at 8.20.08 PM.png

If you are using a clean Rasbian install you will want to setup the RPi to allow SSH on boot and also configure the wifi setup so the RPi will connect to the wifi network on boot. To enable SSH on boot you will need to add an empty text file named “SSH” to the root directory of the boot disc and then delete the file extension. Drag and drop this into the boot disc. To setup the RPi to auto connect to the wifi create a new file wpa_supplicant.conf using the information below.

filename: wpa_supplicant.conf

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
    ssid="SSID"
    psk="PWD"
    key_mgmt=WPA-PSK
}

Be sure to change the values for SSID and PWD inside the quotes to match your local network settings.

Then boot up the RPI!

Step 2: boot up the RPi and find the IP

Plug in the RPi to a power source and wait for it to boot up. I used a program called IP Scanner (there is a free and pay-to-play version) that will scan all the devices on your local network and report their IP and MAC addresss. Pretty handy – so I bought the pro version for $30. The free version will display up to 6 devices, so if you have alot of traffic on your network the RPi may not show up if you use the free version.

Screen Shot 2018-06-04 at 7.47.32 PM.png

If you do not see the RPi IP on the network right away you may want to hook up an ethernet cable directly to the RPi and then try again. I had some issues at first getting all this to work, and was finally able to find the IP by directly connecting the RPi to my router with an ethernet cable. This will help finish configuring some of the time/region/language settings if this is the first time setting up the boot disc. In theory you shouldn’t need to connect to a router…but now you know.

Step 3: setup Coda2 for easy-peezy  SSH

The program Coda2 is a neat piece of software that makes it easy to SSH into multiple devices like the RPi. Once you know the device IP you can setup a profile for the specific device and save the username and password. This way every-time you want to connect to the device you simply pull up the saved profile and hit CONNECT.

Screen Shot 2018-06-04 at 9.27.44 PM.png

You can create multiple profiles for various devices and set it up for terminal access.

Screen Shot 2018-06-04 at 9.25.57 PM

Once connected, Coda2 shows you the working directory of the device so that you can create new files, edit existing files, and even delete files in the working directory of the device. This is all done remotely from you computer in real time and creates a backup on your local machine also.

Screen Shot 2018-06-04 at 9.29.50 PM.png

This is how I created a new python program to open the RPi USB port and read data from the Arduino.

*Edit July 8 ,2018*

To find the name of the Arduino serial port  (like /dev/ttyACM0)  you can type the following command into the terminal.

 ls /dev/ttyUSB*

And you will see something like the following. For is an example I had an nRF52 Feather plugged into the USB port on the RPi and it was assigned the port /dev/ttyUSB0.

Screen Shot 2018-07-08 at 9.23.47 PM

Simply right click on the directory (if this is a clean Rasbian install it will be empty) and then create a new file and name it basestation.py. Then copy and paste the code below into the new file you created in Coda2 and save the file.

filename: basestation.py

import time
import serial


ser = serial.Serial(

	port='/dev/ttyACM0',
	baudrate = 115200,
	parity=serial.PARITY_NONE,
	stopbits=serial.STOPBITS_ONE,
	bytesize=serial.EIGHTBITS,
	timeout=1
)
counter=0


while 1:
	x=ser.readline()
	print(x)

Screen Shot 2018-06-04 at 9.32.32 PMScreen Shot 2018-06-04 at 9.32.43 PMScreen Shot 2018-06-04 at 9.33.06 PM

Be sure to save this new file. You will see a small icon in the top right of the screen to indicate that the file was saved and pushed to the device.

Screen Shot 2018-06-04 at 9.34.25 PM

Before we can run the program we need to add a few things to the RPi to use the serial library.

Step 4: use the terminal in Coda2 to install some libraries

Another great feature of Coda2 is that you can open a terminal to the device  in a new tab and still keep all your working files open. Just click on the terminal icon to start working.

If you try to run the code right now, you will get an error.

To try it out type the following:

sudo python basestation.py

The code will not run because we are missing the library the allows the RPi to communicate with the USB serial port plugged into the Arduino running the basestation code.

Screen Shot 2018-06-04 at 9.36.04 PM.png

In the terminal type the following command to install the python serial library.

sudo apt-get install python-serial

Screen Shot 2018-06-04 at 9.43.41 PM.png

Once the install is complete, try to run the basestation.py program again by typing the following into the terminal. Or hit the up arrow on the keyboard to access your previously entered commands:

sudo apt-get install python-serial

You should now see data streaming from the basestation onto the terminal in Coda2.

Screen Shot 2018-06-04 at 9.45.52 PM.png

Thats all for today. In the near future I’ll continue to work on posting this data from the buoy onto a website. Shawn from Sensor the Earth has been making some awesome progress on a web-service and API, you can see a few of Adafruit Show and Tell videos here and here fore more info.

Hope some of this was helpful.

Buoy Electronics – *test mule*

Buoy - tempSensor - source-01.png

I hobbled together a “test mule” to streamline work on the buoy electronics. The test mule jargon is borrowed from the  automotive industry and typically refers to a prototype vehicle used for road testing which looks physically different from the production model – this is done to evaluate the performance of the vehicle without revealing the final exterior design.

I’m not concerned about revealing the final design of the buoy (no secrets there, pretty sure will be a yellow float!) but I wanted a bare-bones test platform to experiment with new features without worrying about integrating all the sensors and other bits. So I  stripped out the GPS, IMU, SD card and MEGA, and replaced it with the smaller nRF52 BLE Feather, 0.6W solar panelsolar charger,  LoRa module and DHT22 temperature sensor. Then I crammed everything inside a 3D printed container and put it outside. The container was printed in white PLA and coated with fiberglass resin to weatherproof it, hence the slight yellowish color. *We will see how this holds up during the foggy and moist environmental testing this week*

Buoy - tempSensor - source call out-01.png

*nRF52, not 95 like shown in the image- oops*

Now I can streaming temperature and humidity data to the base station in my kitchen while the test mule is outside in the backyard working away. Or, stream the data over the Adafruit app and see the data on your smartphone for debugging. The code tracks the number of data packets transmitted so it is easy to see if there was an error during transmision.

It may seem trivial, but I see this as a BIG ACCOMPLISHMENT – woot! I’ll see how long the battery can last and monitor if any data packets get dropped while the electronics live outside for the week.

Oh, and the base station saw some love too. It has a bigger antenna and some professionally installed electrical tape to provide all the necessary structural support. Gatta love tape.

Base station - call outs

 

Features that need to be added :

  • put the microcontroller to sleep in between sensor readings (10 second delay)
  • connect the base station to a Raspberry Pi and steam the data to a website
  • fix issue with signal interference, the BLE drops sometime when LoRa is broadcasting
  • add power monitoring hardware, to track solar panel output and microcontroller needs
  • add magnetic on/off/reset switch

 

All the example code and hardware is sourced from Adafruit – they are AWESOME! I need to clean up the code a bit before sharing, but when it is ready I’ll post the files on the downloads page. You can find all the other source files there also.

Circuit board – MEGA

Needed more program memory for all the breakout board libraries to run. Redesigned the circuit board to stack on top of an Arduino MEGA 2560 using all the same sensor components. Added a color changing RGB LED on/off switch. The LED acts as an indicator light to show the status of the buoy.

Front view:

Wave Buoy - MEGA - r2 - 1

Wave Buoy - MEGA - r2 - 5.JPG

Rear view:

Wave Buoy - MEGA - r2 - 4

Still working on the firmware to read all the sensors for the buoy. Close, but needs more work. This update demonstrates the framework I’ve created for having the buoy communicate with the base station and is based loosely on the BLE concept (from what I have read thus far). The base station will act as the central device while the buoy will act as a peripheral device. The central device (base station) is responsible for establishing a communication link with the peripheral device (buoy), then the central device determines back-and-forth communication speed.

The base station is seen below. This is one of the previous prototype circuit boards for the Arduino UNO. The UNO has enough program memory to run the base station code.

Base station - r2.JPG

Here is a quick example video showing the basic communication protocol for the buoy and base station:

 

Schematic design:

IMAGE - Wave Buoy - MEGA - R2_4

Circuit board design:

 

Download source files > sorry no github yet, coming soon!

Example running firmware on buoy (left) and base station (right).

Screen Shot 2018-05-13 at 2.55.24 PM

Base station successfully established communication link with the buoy,  and then the base station issues each of the different commands to the buoy to verify the response.

Screen Shot 2018-05-13 at 2.55.38 PM

Next up, need to get all the sensors working and sending real data back to the base station.

Circuit board with Arduino UNO

IMG_1279

“Fail early and fail often”

In an effort to get something in the water as quickly as possible I decided to go back to the basics. A lot has happened since my last post – so this an effort to fill in the gaps.

This will talk about the first version of a new circuit board design. I’ve since completed a second version based on lessons learned.

——————————————————- FLASH BACK! ———————————————————–

I was having problems integrating the LoRa radio with the BLE nRF52 Feather. There seemed to be an issue with getting the RadioHead library to work with nRF52 hardware. According to Adafruit the nRF52 feather is under ongoing development. Here is the link to the customer forum post that is tracking this topic. The most recent updated says there is now a fix.  Pushing firmware updates to the buoy wirelessly over BLE would be handy – but it is certainly not required at this stage of the project.

So, I decided to drop the BLE for now. Digging around in my electronics bin I found two Arduino UNOs, one MEGA 2560, and two 10,000 mAH lipo USB battery packs. These Arduino boards all require 5V input – one reason I wanted to use a 3.3V rated microcontroller like the BLE Feather.  Not a big deal for now,  I can ditch the solar panel and charging circuit and use the lipo battery packs for initial testing. Awesome, just removed two more components from the build!

The electronics layout and design was done in Eagle CAD using my own custom library components. Creating each component was TEDIOUS… but now I can reuse the components in the future. My first design aptly named “Wave Buoy – Arduino UNO – V1”  had the UNO and the breakout boards mounted on the top surface of the board. This was done to minimize the overall height of the assembly since there was limited space inside the buoy.

Schematic - Wave Buoy - UNO - R3.png

Once the schematic is completed in Eagle you switch over to board layout mode and place all the components. This is where creating custom library components really helps because you can define the footprint and pinout for the actual hardware. In my case, most of the pieces being mounted to the circuit board are all breakout boards, not discrete surface mounted components.  Placement of the components is KEY. A clever arrangement will help minimize the number of vias and keeping the trace paths as simple as possible.

The schematic for revision 1 (R1) to revision 3 (R3) of the board did not change much, but the layout was improved during each revision. R1 was full of mistakes, the UNO was mounted in the wrong orientation and the board was only powered through the UBS port. R2 was a huge improvement and my first fully working board; it added an ON/OFF switch to control the lipo battery power, but the assembly process was slow as I had lot of vias to transfer traces from the bottom to the top layer. R3 reduced the number of vias  after moving the components around, and added ground planes to the top and bottom layers to minimize signal noise. I must have tried six unique layouts for before milling the first boards. Below shows R3 with *most* of the issues from R1 and R2 fixed.

 

 

I used an Othermill desktop CNC machine to fabricate all of the boards. This required a V-bit tool to engrave the traces and pads, and a 1/32″ flat end mill to droll the holes and cut out the board profile.

 

An image of the R2 board with the UNO and all the boards mounted. I didn’t want to solder the breakbout board directly to the copper board. Instead I soldered on headers to the copper board so that the breakout boards could be easily removed and reused. This was critical, since I went through three revisions of the board before fixing most of the errors. All of this could fit within the footprint of the lipo battery pack.

IMAGES - wave buoy - Arduino UNO Build - 9 copy

With the board fully assembled I tested each component individually to verify proper function. At this time I was only  interested in verifying each part was working as a stand-alone unit to test that all solder points and traces were OK.

The battery and circuitboard were then mounted to a thin flat mounting plate using lots of yellow and white electrical tape. Not a long term solution, but it works. The mounting plate was superglued to the underside of the buoy lid so everything was hanging from the bottom  and easy access and work on.

IMAGES - wave buoy - Arduino UNO Build - 6IMAGES - wave buoy - Arduino UNO Build - 8

Finally, I pulled all the example programs for each of the components into a single Arduino sketch and hit UPLOAD to the Arduino UNO……

FAIL!

The sketch size exceeded the available program memory on the UNO – and not by a trivial amount. So rather than modifying all the code and library files to minimize the memory requirements I decided it was best to use a different microcontroller with more memory. By comparison, the MEGA 2560 has 8x more flash memory than the UNO. This would give me plenty of extra memory to work with so I could focus on the firmware functionality and worry less about optimizing code to save bits of memory.

So, many lessons learned. Most importantly, it would have been better to create a sample firmware program BEFORE I chose to design the circuit board around the UNO microcontroller. Even an rough draft of the code would have indicated that all the libraries needed to support the breakout-board would be pushing the limits of the UNO. But, at least I have another reason to design and fabricate a new circuit board!

Next post, I redesign the circuit board to be compatible with the Arduino MEGA 2560 and dive into the firmware.

 

nRF52 – program sketches “Over the Air”

The electronics will be sealed in a water-tight canister. To simplify the debugging process I want to be able to wirelessly update the microcontroller’s firmware using Bluetooth LE from my iphone or laptop.

So I’ve upgraded to the Adafruit nRF52 Feather microcontroller. This board can be programmed using the Arduino IDE (super easy!) and offers users the ability to update the sketches wirelessly. This is referred to as Over the Air (OTA) Device Firmware Update (DFU) mode.

This is a quick tutorial on how I was able to get OTA DFU working. Please note the following warning about OTA DFU from Adafruit’s website, as of March 11, 2018:

Screen Shot 2018-03-11 at 4.08.29 PM

For this tutorial you will need the following items (sorry I’ve only tested usng iphone + mac)

  • Adafruit nRF52 Feather
  • Micro USB programing cable // connect computer to the Feather
  • iPhone // tested with iOS 11.2.6
  • NRF Toolbox app //to push OTA DFU, tested with V4.4.4
  • Adafruit Bluefruit Connect App // optional, tested with V3.3.1
  • iTunes // wireless file transfer zip files to iPhone, tested with V12.7.3.46
  • iphone data transfer cable // connect iPhone to laptop via USB
  • Arduino IDE // set to have verbose output during compilation, tested with V1.8.5

 

Step 0

Download and install the NRF Toolbox app. Optionally, you can also choose to install the Adafruit Bluefruit Connect App. *Note – the Adafruit App also offers OTA DFU, but I was not able to figure this out yet – hopefully in the near future this will work and then you would only need the Adafruit app. Also – I like the Adafruit UI better than the NRF Toolbox when testing UART messages, just a personal preference.*

IMG_0768

Step 1

Setup your Arduino IDE following the instruction on the Adafruit Learning Guide. Then verify everything is working with their included blink.ino sketch in the nRF52 Feather examples.

Step 2

Upload the sketch “_03_TEST_BLE_UART.ino” (shown below) using a wired USB connection to the nRF52 Feather. This sketch will set the Feather into BLE search mode so that you can connect to the device. Once a connection is established you can open a UART connection and receive messages to the iphone.

</pre>
/*********************************************************************
This is an example for our nRF52 based Bluefruit LE modules

Pick one up today in the adafruit shop!

Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

MIT license, check LICENSE for more information
All text above, and the splash screen below must be included in
any redistribution
*********************************************************************/

&nbsp;

// BLE UART - TEST
#include 

BLEUart bleuart;

void setup(void)
{
Serial.begin(115200);
Serial.println(F("Adafruit Bluefruit52 Controller App Example"));
Serial.println(F("-------------------------------------------"));

Bluefruit.begin();
Bluefruit.setName("Bluefruit52");

// Configure and start the BLE Uart service
bleuart.begin();

// Set up the advertising packet
setupAdv();

// Start advertising
Bluefruit.Advertising.start();

// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}

void setupAdv(void)
{
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();

// Include the BLE UART (AKA 'NUS') 128-bit UUID
Bluefruit.Advertising.addService(bleuart);

// There is no room for 'Name' in the Advertising packet
// Use the optional secondary Scan Response packet for 'Name' instead
Bluefruit.ScanResponse.addName();
}

/**************************************************************************/
/*!
@brief Constantly poll for new command or response data
*/
/**************************************************************************/
void loop(void)
{
// send message to BLE UART
bleuart.println(" BLE UART TEST - 00");

// flash the onboard red LED
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000);

}
<pre> 

 

Step 3

Open up the Adafruit app and verify that the UART message is correct. It should look something like this:

Adafruit Bluefruit Connect App

Step 4

Setup the Arduino IDE for verbose output.

Screen Shot 2018-03-11 at 3.44.12 PM

Step 5

Modify the message within the sketch to say something new. I updated the end of the message so say “99” and saved it with a new file name “_03_TEST_BLE_UART_II.ino”.

Screen Shot 2018-03-11 at 4.20.42 PM

This is the new sketch that we want to wirelessly send to the nRF52 Feather and have it update over the air. At this point, hit the VERIFY button, but do NOT upload this new sketch to the board. This is how we test to verify the the OTA DFU worked in the later steps. If you accidentally upload this new code to the board, just change the message back to the original before proceeding.

With the verbose output during compilation turned ON, you should see messages at the bottom of the Arduino IDE screen. One of these messages tells us the location of a ZIP file that was created during the compile process – WE NEED THIS ZIP FILE!

Look for the directory location, it is a temporary file – copy and paste the address into the SEARCH toolbar. You may need to delete the zip file name, and just look for the folder.

Screen Shot 2018-03-11 at 4.26.58 PM.png

Once you find the folder that is holding the zip file, it will look something like THIS:

Screen Shot 2018-03-11 at 4.34.08 PM

Copy/paste the zip file to the desktop or your downloads folder.

Step 6

Setup your iphone + NRF Toolbox app to receive wireless file transfers.  The NRF Toolbox app provides instructions.

Open the NRF Toolbox app and click on the “DFU” button, then click on “Select File”, then click on “User Files” and then click on “How to…” for the instructions about syncing iTunes with the iphone for zip file transfer to the app.

With iTunes open and the iphone paired to the laptop, transfer the zip file to the NRF Toolbox app. You will need to use a USB to setup the paired connection, but once it has been setup you can wirelessly transfer the zip files from the laptop to the iphone app. YAY – no more cables!

Screen Shot 2018-03-11 at 4.44.34 PM

Step 7

Now when you open the NRF Toolbox app and go into the DFU mode,  you should see the zip file in your “USER” files. Pair to the nRF52 Feather, select the zip file and hit UPLOAD. You will see a progress bar to verify the upload is happening. If you see a “Connecting” message for more than 5 seconds then something is not correct and you will need to abort the upload. This may even require that you reflash the firmware via the USB cable.

 

 

Once the DFU process is complete, the nRF52 Feather will reboot itself. Open up the UART using the iphone app and check the message to see if it has changed to “99”. It should look like this if everything worked!

IMG_0784

 

YAHOO! Now we can update the code running on the microcontroller wirelessly.

BUT remember, this has the potential to brick your microcontroller so it is not recommended that you do this – at this time. Based on the Adafruit help forum, is sounds like they are working to make this process safe and reliable from within the Adafruit Bluefruit Connect app – so I’ll try to figure that out later.

 

 

Buoy Float – pool filter

I’ve decided to resurrect an old idea and use a pool chlorine filter as the primary floatation for the buoy project. While I have been very attached to the yellow 3D printed sphere, I’ve had concerns that using an entirely 3D printed hull was not the most practical choice.

So… looks like I am back to one of my original designs…

 

 

The yellow sphere is not very easy to manufacture (long print time…) and it combined both the floatation and electronics housing into a single form factor. If something where to strike the yellow sphere and damage the hull, it’s likely the impact would cause a leak and ruin the electronics inside. After more consideration, I’d prefer to have a redundant design that would be more resilient to damage and allow me to quickly/easily transfer the electronics to a different float if needed.
For this latest idea the electronics are housed inside a canister that can be secured into the center of a standard pool float, the type used to dispense chlorine into residential pools. I sourced mine online and found several options ranging from $8 – $15  with free shipping.

Ocean Buoy - 1

The canister will be water tight. It is made up to three pieces: a top part that will hold a round solar panel, a bottom piece to hold the electronics and battery, and a black gasket sandwiched in-between the top and bottom pieces which forms a water tight seal. The top/bottom parts were 3D printed in white ABS on a Lulzbot Taz 6, super awesome printer! I printed my own gasket from black Ninja Flex filament, is is very flexible and feels like rubber. Not sure how it will hold up to sea water… more experiments are needed!

Ocean Buoy - 2Ocean Buoy - 3

The 3D printed parts are not yet water tight, so I’m going to try and infuse them with marine epoxy. Maybe I’ll try using a vacuum bag method or some way to force the epoxy into all the voids and crevices. This will give the parts added strength and make them suitable for being submerged underwater. Thats the thought, at least.

I’m use 316 stainless steel hardware ordered from McMaster-Carr. They have EVERYTHING! The twist-resistant threaded inserts were press-fit into the top of the canister after drilling out 4.7mm holes. They inserts appear to be holding up pretty well, even after repeated use. But it may be a good idea to use some epoxy for added strength during the installation. One change for next time, I’ll be ordering 10mm long machine screws.

Buoy - Hardware

 

The bottom part of the canister has two tabs that are designed to interlock with the pool float.  These mimic the same functionality as  the tabs molded into the lid of the pool float and provide a snap lock. To mount the canister into the pool float,  you drop the canister into the float,  insert to metal posts of the tool into the top of canister, and rotate 180 degrees to lock the canister securely in place. Ocean Buoy - 4Ocean Buoy - 5

The 3D printed tool has two metal posts, 1/8″ diameter riots, jammed into the handle. The metal posts fit into two receiving holes in the top of the canister and allow the user to lock the canister into the float.Ocean Buoy - 6Ocean Buoy - 7Ocean Buoy - 8Ocean Buoy - 10Ocean Buoy - 11

The top piece of the canister will hold a round solar panel. I’ll use marine epoxy to secure it in place. The solar panel is rated for a 0.6W output.  I am hopeful that I can drill a hole through the solar panel to allow the LoRa antenna to poke through. While this is a round solar panel,  the actual solar cells are rectangular so there is some empty space on either side of the cells. Ocean Buoy - 13

 

 

LoRa Radio – test #1 : one mile

LoRa Radio

I’d like to transmit data from a buoy floating in the water to a base station on shore. Power consumption and broadcast range are primary considerations. The amount of data being transmitted is expected to be minimal.

Screen Shot 2017-11-28 at 12.11.50 AM

I purchased two of the Adafruit RFM95W LoRa Radios to see if this might be a suitable solution. They were fairly inexpensive so I figured it was worth a test. The modules transmit on a license-free frequency and the Adafruit website says signals can travel 2 km – 20 km (1.4 – 12.4 miles) depending on the type of antenna used.

During the Thanksgiving holiday I had the opportunity to test the range of two LoRa radios in a neighborhood in Eugene, Oregon.  I wired up an Arduino Uno and Pro Trinket following the Adafruit provides tutorial, see their tutorial for all the details.

The Pro Trinket was setup as the Transmitter, this was located at the house. The Uno was setup as the Receiver and plugged into my laptop so I could watch the serial monitor as I walked around the neighbor hood. I was happily surprised, the radios transmitted one mile through in the suburban area with lots of trees and buildings in the way. While this isn’t ground breaking news, it was nice to conduct a real-world test and verify the websites claim. Below is the google maps screen shot from my phone that was used to verify the distance of approximately one mile.

IMG_9751

Unfortunately I had to end the walk-about when it began to rain. But I plan to conduct more range tests to see how far these little radios and -2dB quad band antennas can broadcast. One interesting observation: I was not getting all of the data being sent from the transmitter at the house. The simple “hello world” example sketch included a counter to track the number of messages being sent out by the transmitter. At the end, it appears that every fifth message was being received. I’ll need to learn more about mitigating this issue in the future, but for now this is a good enough “first test”.

Screen Shot 2017-11-27 at 10.01.23 PM

Terrain will play in big factor  in determining maximum range, so I’d also like to run another test over a large body of water to see how the signal attenuates. This would be more similar to the conditions experience when the buoy is deployed. Maybe I can use a kayak and deploy a really simple buoy in the harbor and see if I can receive a message from my office building in Sausalito, CA.

More exploration onto the world or radios is needed!