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.

 

Advertisements

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.