TinyCircuits

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - PioneeringStar

Pages: [1]
1
New Product Ideas / Butterfly
« on: October 11, 2018, 01:52:27 PM »
A simple tinyboard, nothing on it but bus connectors along the edge to connect other boards to. So instead of stacks, projects could be flat.

2
User Projects / Code Examples / Re: 9 Axis IMU + MicroSD
« on: September 18, 2018, 06:05:42 AM »
I'm currently developing a 9-axis data-logger. This uses a tinyscreen+, wifi, 9-axis imu and an sd-card. This currently works, but needs a change to manage file sizes.

The Arduino SD card writes to FAT32 only, and can only create files with 8 dot 3 filenames. File size is a concern to me as I'm trying to ensure I get at least 25 samples per second. This is going to create large file sizes, and the open-write data-close are going to get slower as the file get bigger.


#include <Wire.h>
#include <SPI.h>
#include <TinyScreen.h>
#include <WiFi101.h>
#include <RTCZero.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include "RTIMUSettings.h"
#include "RTIMU.h"
#include "RTFusionRTQF.h"
#include <SD.h>

//---------------------------------------------------------------

//Set up the WiFi
char ssid[] = "";        // your network SSID (Name)
char pass[] = "";          // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS;       // the WiFi radio's status
bool WifiShieldPresent = false;
bool CalculatingGyro = false;
bool FirstTimeThrough = true;      //This is so we can do a bunch of stuff on the initial run after turning on

//Set up the TinyScreen+
//Library must be passed the board type
//TinyScreenDefault for TinyScreen shields
//TinyScreenAlternate for alternate address TinyScreen shields
//TinyScreenPlus for TinyScreen+
TinyScreen display = TinyScreen(TinyScreenPlus);

//Create a file object for writing out data to the SD card
File myFile;

//Tell the SD card library that the SD card controller is on pin 10 of the Arduino
const int Chipselect = 10;

//Set up the Filename for storing X/Y/Z degree data
String MyFileName = "";
String OutputVal = "";

//Set up the IMU (Inertial Motion Unit) 9-axis chip
RTIMU *imu;                                           // the IMU object
RTFusionRTQF fusion;                                  // the fusion object
RTIMUSettings settings;                               // the settings object

// NTP (Network Time Protocol) Setup
// You can specify the time server pool and the offset, (in seconds)
// additionaly you can specify the update interval (in milliseconds).
// NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);
WiFiUDP ntpUDP;
NTPClient NTPtimeClient(ntpUDP);
NTPClient timeClient(ntpUDP, "0.uk.pool.ntp.org", 3600, 60000); //Change this to local network NTP server IP address if neeeded

//Create an RTCZero object to talk to the onboard clock
RTCZero rtc;

//  DISPLAY_INTERVAL sets the rate at which results are displayed
#define DISPLAY_INTERVAL  35                         // interval between pose displays - default was 300
unsigned long lastDisplay;
unsigned long lastRate;

int sampleCount;
//---------------------------------------------------------------

void setup() {
  //Start the Wire object. We need this in order to talk with the IMU and other devices on the bus.
  Wire.begin();

  //Initialise the TinyScreen+ Display
  display.begin();                        //Start the display object
  display.setBrightness(5);                  //Turn down the brightness so we don't burn the OLED
  display.setFont(thinPixel7_10ptFontInfo);      //Nice, readable, font size
  display.fontColor(TS_8b_White, TS_8b_Black);  //Set the font color, font background
  display.on();                                 //Turns TinyScreen display on
  display.clearScreen();                  //Clear the screen
  display.setCursor(1, 1);                  //Put the cursor in the top left. A line is about 10 pixels setCursor(X,Y)

  //Start the SD-Card
  pinMode(10, OUTPUT);                     //Set pin 10 to output
  display.println("Initializing");
  display.setCursor(1, 10);                  //Move the cursor down 1 line
  display.println("SD card...");
  delay(2000);
  display.clearScreen();

  SD.begin(10);

  int errcode;

  //Make DAMN sure that the filename is blank.
  MyFileName = "";
 
  //Set up the Wifi
  //-------------------------------------
  //Set up the WiFi pins, as the tinyduino wifi shield are different from the defaults
  WiFi.setPins(8, 2, A3, -1); // VERY IMPORTANT FOR TINYDUINO
 
  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
     display.setCursor(1, 1);
     display.print("WiFi shield");
     display.setCursor(1, 10);
     display.print("not present");
     // don't continue:
     //while (true);
  }
  else {
     WifiShieldPresent = true;
  }
 
  if (WifiShieldPresent == true) {
     // attempt to connect to WiFi network:
     while (status != WL_CONNECTED) {
      display.clearScreen();
      display.setCursor(1,1);
      display.println("Attempting");
      display.setCursor(1,10);
      display.println("to connect WIFI: ");
      display.setCursor(1,20);
      display.println(ssid);
      // Connect to WPA/WPA2 network:
      status = WiFi.begin(ssid, pass);

      // wait 10 seconds for connection:
      delay(10000);
  }
 
  //Get the assigned IP Address
  IPAddress ip = WiFi.localIP();

  // you're connected now, so show a message and the IP Address:
  display.clearScreen();
  display.setCursor(1,1);
  display.println("Connected!");
  display.setCursor(1,10);
  display.print("IP: ");
  display.println(ip);

  //Start the Onboard Realtime Clock
  rtc.begin();

  //Start the Network Time Protocol (NTP) Client
  //We need the WiFi for this to work, but we assume it has
  NTPtimeClient.begin();
  NTPtimeClient.forceUpdate();
  display.setCursor(1, 20);

  //Sync the time between the NTP server and the onboard Realtime Clock (RTC)
  //If the RTC is already configured, don't bother. The small battery doesn't last long,
  //so we can 'assume' that if the RTC is set, then it sync'd recently.
  while ((rtc.isConfigured() == false) || (rtc.getYear() == 00)) {
     display.clearScreen();
     display.setCursor(1, 1);
     display.print("NTP Sync");
     rtc.setTime(NTPtimeClient.getHours(), NTPtimeClient.getMinutes(), NTPtimeClient.getSeconds());
     rtc.setEpoch(NTPtimeClient.getEpochTime());
  }

  //Quickly show the time on-screen before Getting into the tracking
  display.clearScreen();
  display.print(NTPtimeClient.getFormattedTime());
  display.setCursor(1, 30);
  display.print(rtc.getDay());
  display.print("/");
  display.print(rtc.getMonth());
  display.print("/");
  display.print(rtc.getYear());

  //Assemble the first filename to use
  CreateFilename();
  display.setCursor(1, 40);
  display.println(MyFileName);


  delay(10000); //Wait 10 seconds
  display.clearScreen();
  }
 
  //Initialise the IMU
  display.clearScreen();
  display.setCursor(1, 1);
  imu = RTIMU::createIMU(&settings);                        // create the imu object
  display.print("ArduinoIMU");
  display.setCursor(1, 10);
  display.print("starting");
  if ((errcode = imu->IMUInit()) < 0) {
     display.clearScreen();
     display.setCursor(1, 1);
     display.print("Failed to init");
     display.setCursor(1, 20);
     display.print("IMU: ");
     display.println(errcode);
  }

  display.clearScreen();
  display.setCursor(1, 1);
  if (imu->getCalibrationValid()) {
     display.print("Using compass");
     display.setCursor(1, 20);
     display.print("calibration");
  }
  else {
     display.setCursor(1, 1);
     display.print("No valid ");
     display.setCursor(1, 10);
     display.print("compass calibration");
     display.setCursor(1, 20);
     display.print("data");
  }
  lastDisplay = lastRate = millis();
  sampleCount = 0;
  delay(5000); //Wait 5 seconds
  display.clearScreen();

  // Slerp power controls the fusion and can be between 0 and 1
  // 0 means that only gyros are used, 1 means that only accels/compass are used
  // In-between gives the fusion mix.

  fusion.setSlerpPower(0.02);

  // use of sensors in the fusion algorithm can be controlled here
  // change any of these to false to disable that sensor

  fusion.setGyroEnable(true);
  fusion.setAccelEnable(true);
  fusion.setCompassEnable(true);

}

void loop() {
  // put your main code here, to run repeatedly:
   unsigned long now = millis();
   unsigned long delta;

   //Start reading the IMU (Inertial Motion Unit)
  if (imu->IMURead()) {                                // get the latest data if ready yet
     fusion.newIMUData(imu->getGyro(), imu->getAccel(), imu->getCompass(), imu->getTimestamp());
     sampleCount++;
     if ((delta = now - lastRate) >= 1000) {
        if (imu->IMUGyroBiasValid())
        {
           display.clearScreen();
           display.setCursor(1, 15);
           if (FirstTimeThrough == true) {
            display.print("Gyro Calibrated");
           }
           CalculatingGyro = false;
        }
        else
        {
           display.setCursor(1, 15);
           display.print("Calculating gyro");
           display.setCursor(1, 25);
           display.print("Don't move IMU!!");
           CalculatingGyro = true;
        }
        sampleCount = 0;
        lastRate = now;
     }
    
     if (CalculatingGyro == false) {
        if (FirstTimeThrough == true) {
         display.clearScreen();
         FirstTimeThrough = false;
        }
        if ((now - lastDisplay) >= DISPLAY_INTERVAL) {
           lastDisplay = now;
           RTVector3 accelData = imu->getAccel();
           RTVector3 gyroData = imu->getGyro();
           RTVector3 compassData = imu->getCompass();
           RTVector3 fusionData = fusion.getFusionPose();
           //displayAxis("Accel:", accelData.x(), accelData.y(), accelData.z());        // accel data
           //displayAxis("Gyro:", gyroData.x(), gyroData.y(), gyroData.z());            // gyro data
           //displayAxis("Mag:", compassData.x(), compassData.y(), compassData.z());    // compass data
           //displayDegrees("Fusion Position:", fusionData.x(), fusionData.y(), fusionData.z());   // fused output
           WriteToFile(fusionData.x(), fusionData.y(), fusionData.z(), accelData.x(), accelData.y(), accelData.z(), gyroData.x(), gyroData.y(), gyroData.z(), compassData.x(), compassData.y(), compassData.z());
        }
     }
  }


}

void displayAxis(const char *label, float x, float y, float z)
{
   OutputVal = "";
   OutputVal = label;
   OutputVal = OutputVal + (",X:");
   OutputVal = OutputVal + (x);
   OutputVal = OutputVal + (",Y:");
   OutputVal = OutputVal + (y);
   OutputVal = OutputVal + (",Z:");
   OutputVal = OutputVal + (z);
   OutputVal = OutputVal + (",T:" + NTPtimeClient.getFormattedTime());
   OutputVal = OutputVal + ":";
   OutputVal = OutputVal + ((int(millis() / 10) % 100));

   // open the file. note that only one file can be open at a time,
   // so you have to close this one before opening another.
   myFile = SD.open(MyFileName, FILE_WRITE);

   //If the file was opened properly
   if (myFile) {
      //Write the data out
      myFile.println(OutputVal);
      //Close the file
      myFile.close();
   }
   else {
      display.setCursor(30, 15);
      display.print("Error writing to file");
   }

}

void WriteToFile(const float Fusionx, float Fusiony, float Fusionz, float Accelx, float Accely, float Accelz, float Gyrox, float Gyroy, float Gyroz, float Compassx, float Compassy, float Compassz)
{
   OutputVal = "";
   OutputVal = "Fusion Position:";
   OutputVal = OutputVal + (",X:");
   OutputVal = OutputVal + (Fusionx * RTMATH_RAD_TO_DEGREE);
   OutputVal = OutputVal + (",Y:");
   OutputVal = OutputVal + (Fusiony * RTMATH_RAD_TO_DEGREE);
   OutputVal = OutputVal + (",Z:");
   OutputVal = OutputVal + (Fusionz * RTMATH_RAD_TO_DEGREE);
   OutputVal = OutputVal + ",Accelerometer:";
   OutputVal = OutputVal + (",X:");
   OutputVal = OutputVal + (Accelx);
   OutputVal = OutputVal + (",Y:");
   OutputVal = OutputVal + (Accely);
   OutputVal = OutputVal + (",Z:");
   OutputVal = OutputVal + (Accelz);
   OutputVal = OutputVal + ",Gyroscope:";
   OutputVal = OutputVal + (",X:");
   OutputVal = OutputVal + (Gyrox);
   OutputVal = OutputVal + (",Y:");
   OutputVal = OutputVal + (Gyroy);
   OutputVal = OutputVal + (",Z:");
   OutputVal = OutputVal + (Gyroz);
   OutputVal = OutputVal + ",Compass:";
   OutputVal = OutputVal + (",X:");
   OutputVal = OutputVal + (Compassx);
   OutputVal = OutputVal + (",Y:");
   OutputVal = OutputVal + (Compassy);
   OutputVal = OutputVal + (",Z:");
   OutputVal = OutputVal + (Compassz);
   OutputVal = OutputVal + (",Timestamp:" + NTPtimeClient.getFormattedTime());
   OutputVal = OutputVal + ":";
   OutputVal = OutputVal + ((int(millis() / 10) % 100));

   // open the file. note that only one file can be open at a time,
   // so you have to close this one before opening another.
   myFile = SD.open(MyFileName, FILE_WRITE);

   //If the file was opened properly
   if (myFile) {
      //Write the data out
      myFile.println(OutputVal);
      //Close the file
      myFile.close();
   }
   else {
      display.setCursor(30, 15);
      display.print("Error writing to file");
   }


}

void CreateFilename()
{
   int Day = rtc.getDay();
   int Hours = rtc.getHours();
   int Minutes = rtc.getAlarmMinutes();

   //Note. Filenames CANNOT be more than 8.3 characters
   MyFileName = "";
   //MyFileName = MyFileName + rtc.getMonth();
   MyFileName = MyFileName + Day;
   MyFileName = MyFileName + "_" + Hours;
   
   //We need to add a zero to bring it to 24hr format
   if (Minutes < 10) {
      MyFileName = MyFileName + "0";
   }

   MyFileName = MyFileName + Minutes;
   MyFileName = MyFileName + ".csv";
}

Pages: [1]