2

My Raspberry Pi, model B, is going to be sent up on a hydrogen balloon to collect data on some solar panels. I've written a python script to collect data from these panels using 3 INA219s connected to the Pi via GPIOs.

The script, GPIO.py takes the data from the INA219s, and appends the data to a file, sol_data.dat.

The pi is being powered by a 4400mAh battery during the flight.

One of the things I was told is that the battery may disconnect during the landing, as the payloads land upwards of 7 mph.

Testing of the Pi by running the python script, GPIO.py, and then pulling the power during has left no data in sol_data.dat.

My question is, how can I make sure the data is saved to the file even if there is power loss?

Code for GPIO.py

import sys
sys.path.append("/usr/lib/python2.7/ina219/subfact_pi_ina219");
import RPi.GPIO as GPIO
import smbus
import time
from Subfact_ina219 import INA219

print("Hello, User.");
while True:
    for i2caddr in ['0x40', '0x41', '0x44']:
        ina = INA219(address=int(i2caddr,16));

        a=ina.getBusVoltage_V();
        b=ina.getShuntVoltage_mV();
        c=ina.getCurrent_mA();

        d=str(a);
        e=str(b);
        f=str(c);

        x = (ina.getBusVoltage_V() + ina.getShuntVoltage_mV() / 1000);

        z=str(x);

        g=i2caddr;

        fo=open('sol_data.dat', 'a');
        fo.write("==" +g + "\n");
        fo.write("Bus voltage: " +d +  " V \n");
        fo.write("Shunt Voltage: " +e + " mV \n");
        fo.write("Current: " +f + " mA \n"); 
        fo.write("Voltage: " +z + " V \n");
        fo.close(); 
time.sleep(.2);

-----------------------------------------EDIT ---------------------------------------

This is the new working code.

import sys
sys.path.append("/home/pi/subfact_pi_ina219");
import RPi.GPIO as GPIO
import smbus
import time
from Subfact_ina219 import INA219

while True:
    for i2caddr in ['0x40', '0x41', '0x44']:
        ina = INA219(address=int(i2caddr,16));

        a=ina.getBusVoltage_V();
        b=ina.getShuntVoltage_mV();
        c=ina.getCurrent_mA();

        d=str(a);
        e=str(b);
        f=str(c);

        x = (ina.getBusVoltage_V() + ina.getShuntVoltage_mV() / 1000);

        z=str(x);

        g=i2caddr;

        fo=open('/home/pi/sol_data.csv', 'a', 0);
        fo.write("/" +g +"/" +"\n");
        fo.write("Bus voltage: " +d +  " V \n");
        fo.write("Shunt Voltage: " +e + " mV \n");
        fo.write("Current: " +f + " mA \n"); 
        fo.write("Voltage: " +z + " V \n");
        os.fsync(fo);
        fo.close();

time.sleep(.2);
  • I'm assuming time.slepp(.2) should be time.sleep(.2) – Jacobm001 Nov 19 '15 at 0:24
  • yes, just noticed that. – mobious Nov 19 '15 at 0:29
  • A pi is really not the right choice for this, as it is heavy and fragile - in its state and reliance on an sdcard, as much so as physically. But assuming you are stuck with it for the moment, the best thing you could do would be to detect balloon breakage, finalize all writing to an even greater degree than you periodically are doing during flight, and then unmount the filesystems and halt the pi, to minimize the chance of a housekeeping write being in progress at ground impact. If the data is "expensive' consider using an additional miniature USB drive or small SPI flash for a 2nd copy. – Chris Stratton Nov 19 '15 at 6:04
  • Also, make sure to bring a fully configured and tested installation on a spare SD card to the launch - you don't want to have a balloon ready to go and suddenly find that your card needs to be re-imaged. – Chris Stratton Nov 19 '15 at 6:07
  • @Chris Stratton yes, pretty much stuck with the pi at this point, as we launch this Saturday. That being said, the payload is well under the weight limit so we are considering adding in cushioning for the landing. Also, it be close to impossible to measure when the balloon pops at this stage. And the second SD card is a good idea, I'll do that, thanks. – mobious Nov 20 '15 at 6:45
1

My question is, how can I make sure the data is saved to the file even if there is power loss?

The short answer is "you can't". RAM is a volatile storage medium, once it loses power, it loses data. A quick blip is enough to corrupt RAM, if not restart the device entirely. Remember, The loss of power isn't like a signal that you can catch (unless you can program the RPi to be psychic).

A few general guidlines to reduce data loss:

  1. Write early, write often. Log information as soon as you can. Don't hold onto things in RAM and plan on writing it later. It's a fairly common practice to append data to a file, and then process it later in a more secure environment.

  2. Write simply. Don't waste time formatting the output. So long as you can read it without data loss in the future, cleaning and pretty formatting can happen later

  3. Don't trust that your language is writing exactly as your expect. fo.write() uses a buffer. If the power gets pulled before fo.close(), you may not actually see anything get written. I would include a fo.flush() after each write, or disable the buffer storage entirely by changing your open() call to fo = open('sol_data.dat', 'a', 0).

  4. Don't constantly call open() and fo.close(). System calls are expensive. Open the file once before the loop, and close it after. The less time you spend opening the file, the more time you have to write to the disk.

Edit:

  1. I forgot to mention that you also need to consider the fact that the OS has buffers in addition to your file. Look into the os module. Specifically, calling os.fsync(fo) at the end of your loop should help to make sure that the OS is writing to the disk when you want it to.
  • the reason I was calling fopen() and fclose() often was in hopes that if power loss did occur, it would have saved all data to that point. Unfortunately, that doesn't seem to be working. – mobious Nov 19 '15 at 0:33
  • so the code should look like this? fo=open('sol_data.dat', 'a', 0); while True: for i2caddr in ['0x40', '0x41', '0x44']: ina = INA219(address=int(i2caddr,16)); a=ina.getBusVoltage_V(); b=ina.getShuntVoltage_mV(); c=ina.getCurrent_mA(); d=str(a); e=str(b); f=str(c); x = (ina.getBusVoltage_V() + ina.getShuntVoltage_mV() / 1000); z=str(x); g=i2caddr; fo.write("==" +g + "\n"); fo.write("Bus voltage: " +d + " V \n"); fo.write("Shunt Voltage: " +e + " mV \n"); fo.write("Current: " +f + " mA \n"); fo.write("Voltage: " +z + " V \n"); fo.close(); time.sleep(.2); – mobious Nov 19 '15 at 0:36
  • @mobious: I have added one more point I forgot to mention about the OS's cache. Your code is very difficult to read as a comment. A question edit, or pastebin link would be much easier to read. – Jacobm001 Nov 19 '15 at 0:39
  • I figured as much, I tried formatting it, to no avail. I'll post it as a answer. – mobious Nov 19 '15 at 0:41
  • got it work as needed by adding os.fsync(fo); after the fclose() in the infinite loop. I left the fopen() in the infinite loop as well. tested it and it works as wanted. THANK YOU. – mobious Nov 19 '15 at 1:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.