David Bershadsky
Created August 3, 2021 © CC BY-SA

Open Tense

Open source universal tensile testing machine.

IntermediateWork in progress3 hours75
Open Tense

Things used in this project

Hardware components

Arduino Mega 2560
Arduino Mega 2560
×1
Stepper Motor, Mini Step
Stepper Motor, Mini Step
×1
TMC 2130 SPI STEPPER DRIVER
×1
Standard LCD - 16x2 White on Blue
Adafruit Standard LCD - 16x2 White on Blue
×1
Rotary Encoder
×1
Linear Motion Kit
×1
2040 extrusion 400mm
×1
12v power supply
×1
Micro SD Card
×1
Adafruit Micro Sd Card Reader
×1
XL6019 Step Up Voltage Converter
×1
Load Cell transmitter
×1
Load Cell
×1
Custom PCB
Custom PCB
×1
Relay
×1
Assorted Screws (M3-M5)
×1

Software apps and online services

Arduino IDE
Arduino IDE
Fusion
Autodesk Fusion

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

Load Cell Cover

Sample Clamp A

Sample Clamp B

Full Assembly

Full Assembly (Fusion 360 files)

Stepper Mount

Endcap2

Motion Carriage

Example Sample Mounting Plate

Example Load Cell Mounting Plate

Load Cell Slider

Schematics

testermainboard_Rev3.brd

testermainboard_Rev3.sch

Code

OpenTense Firmware

C/C++
#include <LiquidCrystal.h>
#include <TMCStepper.h>
#include <SPI.h>
#include <SDADA.h>
#include <movingAvg.h>

// SD /////////////////////////////////////////
const int chipSelect = 36;
const int Mosi = 35;
const int Miso = 34;
const int Sck = 33;
File dataFile;
// LCD /////////////////////////////////////////
#define RS 8
#define RW 3
#define EN 9
LiquidCrystal lcd(RS, RW, EN, 4, 5, 6, 7);

// Encoder /////////////////////////////////////
#define CLK 40
#define DT 39
#define SW 38

// LCR /////////////////////////////////////
#define LCRTrigger 31

//Input & Button Logic /////////////////////////////////////////
const int numOfInputs = 3;
const int inputPins[numOfInputs] = { DT, CLK, SW };
int inputState[numOfInputs];
int lastInputState[numOfInputs] = { LOW, LOW, LOW };
bool inputFlags[numOfInputs] = { LOW, LOW, LOW };
long lastDebounceTime[numOfInputs] = { 0, 0, 0 };
long debounceDelay = 1;

//Global Variables /////////////////////////////////////////
bool motorenablestate = false;
bool ishomed = false;
int testiterations = 0;
double sensorsize = 0;
double actualsensorlength = 0;
double testdistance = 0;
bool booted = false;
double currentposition = 0;
bool infunction = false;
long counter = 0;
long cyclecount = 0;
bool stoponfail = false;
bool paused = false;
bool intest = false;
int upperpositionlimit = 400; // need to measure and update value
double MMconstant = 400; // steps per mm
double MMPerSeconds = 7.8125;// seconds per mm: 0.128 // step delay = (((1/MMPerSeconds)/400)*1000000)/2
int step_delay = int((((1 / MMPerSeconds) / 400) * 1000000) / 2);
bool hasfailed = false;
double stepsize = 1;

//Emergency Stop /////////////////////////////////////////
bool Estop = false;
bool enableEstop = true; // change this if you have an estop connected
#define EstopPin 45


//LCD Menu Logic /////////////////////////////////////////
const int numOfScreens = 12; // to add screens increment this number. Also add the screen info to the screens string and update the number lables in the parameter change function
int currentScreen = 0;
String screens[numOfScreens][2] = { { "Home Machine", "Activate?" }, { "Move Machine", "Position" }, { "Sensor Position", "mm" } , { "Sensor Length", "mm" }, { "Number of Cycles", "#" }, { "Test Distance", "mm" }, { "Travel Speed", "mm/s" }, { "Stop on Fail?", "Y/N" }, { "Start Test", "Start?" }, { "Failure Test", "Start?" }, { "Toggle Motor", "On/Off" }, { "Step Size", "mm" }};
double parameters[numOfScreens];

// LoadCell /////////////////////////////////////////
int loadcellpin = A3;
int loadcellvalue = 0;
movingAvg loadcellave(40);
movingAvg loadcellave2(10);
double avevalue = 0;
double avevalue2 = 0;

// Limit /////////////////////////////////////////
int Limitpin = 42;
bool limitstate = false;

// Stepper Motor Parameters /////////////////////////////////////////
#define MAX_SPEED 40  // In timer value
#define MIN_SPEED 1000

#define STALL_VALUE 15  // [-64..63]
#define EN_PIN 27       // Enable
#define DIR_PIN 28      // Direction
#define STEP_PIN 29     // Step
#define CS_PIN 26       // Chip select
#define SW_MOSI 24      // Software Master Out Slave In (MOSI)
#define SW_MISO 23      // Software Master In Slave Out (MISO)
#define SW_SCK 25       // Software Slave Clock (SCK)

bool shaft = false;

#define R_SENSE 0.11f  // Match to your driver

TMC2130Stepper driver(CS_PIN, R_SENSE, SW_MOSI, SW_MISO, SW_SCK);  // Software SPI

using namespace TMC2130_n;

// Using direct register manipulation can reach faster stepping times
#define STEP_PORT PORTF  // Match with STEP_PIN
#define STEP_BIT_POS 0   // Match with STEP_PIN

ISR(TIMER1_COMPA_vect) {
  //STEP_PORT ^= 1 << STEP_BIT_POS;
  digitalWrite(STEP_PIN, !digitalRead(STEP_PIN));
}


void setup() {
  Serial.begin(115200);
  for (int i = 0; i < numOfInputs; i++) {
    pinMode(inputPins[i], INPUT);
    digitalWrite(inputPins[i], HIGH);  // pull-up 20k
  }
  lcd.begin(16, 2);

  // Emergency Stop
  if (enableEstop) {
    pinMode(EstopPin, INPUT_PULLUP);
  }

  // LCR
  pinMode(LCRTrigger, OUTPUT);

  // limit switch
  pinMode(Limitpin, INPUT_PULLUP);

  //SD
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(SS, OUTPUT);

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect, Mosi, Miso, Sck)) {  // chipSel, mosi, miso, sck
    Serial.println("Card failed, or not present");
    lcd.clear();
    lcd.print("Insert SD");
    lcd.setCursor(0, 1);
    lcd.print("then reboot");
    // don't do anything more:
    delay(2000);
    while (1);
  }
  Serial.println("card initialized.");

  //Stepper

  parameters[11] = 1;

  pinMode(EN_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);
  //  digitalWrite(EN_PIN, LOW);      // Enable driver in hardware

  driver.begin();  //  SPI: Init CS pins and possible SW SPI pins
  // UART: Init SW UART (if selected) with default 115200 baudrate
  driver.toff(5);           // Enables driver in software
  driver.rms_current(400);  // Set motor RMS current
  driver.microsteps(16);    // Set microsteps to 1/16th
  driver.blank_time(24);
  driver.TCOOLTHRS(0xFFFFF);  // 20bit max
  driver.THIGH(0);
  driver.semin(5);
  driver.semax(2);
  driver.sedn(0b01);

  driver.sgt(STALL_VALUE);



  driver.en_pwm_mode(true);  // Toggle stealthChop on TMC2130/2160/5130/5160
  //driver.en_spreadCycle(false);   // Toggle spreadCycle on TMC2208/2209/2224
  driver.pwm_autoscale(true);  // Needed for stealthChop


  // load cell
  loadcellave.begin();
  loadcellave2.begin();

}



void loop() {
  setInputFlags();
  resolveInputFlags();
  checkcanmove();
  infunction = false;
  intest = false;
  //Serial.println(digitalRead(Limitpin));
}

void setInputFlags() {
  if (digitalRead(EstopPin) == HIGH && millis() > 10000 && (enableEstop)) {
    Estop = true;
    digitalWrite(EN_PIN, HIGH);
    Serial.println("Emergency Stop");
    lcd.clear();
    lcd.print("Emergency Stop");
    lcd.setCursor(0, 1);
    lcd.print("Restart to Reset");
    dataFile.flush();
    while (1) {
      //do nothing in here
    }
  }
  for (int i = 0; i < numOfInputs; i++) {
    int reading = digitalRead(inputPins[i]);
    if (reading != lastInputState[i]) {
      lastDebounceTime[i] = millis();
    }
    if ((millis() - lastDebounceTime[i]) > debounceDelay) {
      if (reading != inputState[i]) {
        Serial.print("reading");
        Serial.print(i);
        Serial.print(":");
        Serial.println(reading);
        inputState[i] = reading;
        if (inputState[i] == HIGH && i == 2) {
          inputFlags[i] = HIGH;
        }
      }
    }
    lastInputState[i] = reading;
  }

  if (lastInputState[0] != inputState[0] && inputState[0] == HIGH) {
    if (inputState[0] != inputState[1]) {
      inputFlags[1] = HIGH;
    } else {
      inputFlags[0] = HIGH;
    }
  }
}

void resolveInputFlags() {
  for (int i = 0; i < numOfInputs; i++) {
    if (inputFlags[i] == HIGH) {
      inputAction(i);
      inputFlags[i] = LOW;
      printScreen();
    }
  }
}

void inputAction(int input) {
  if (!infunction) {
    Serial.print("input: ");
    Serial.println(input);
    if (input == 0) { // CCW rotation
      if (currentScreen == 0) {
        currentScreen = numOfScreens - 1;
      } else {
        currentScreen--;
      }
    } else if (input == 1) { // CC Roation
      if (currentScreen == numOfScreens - 1) {
        currentScreen = 0;
      } else {
        currentScreen++;
      }
    } else if (input == 2) { // Click
      cyclecount = 0;
      parameterChange();
    }
  } else {
    if (input == 0) {
      counter--;
    }
    else if (input == 1) {
      counter++;
    }
    else if (input == 2 && cyclecount > 1000 && intest == false) {
      Serial.println("Exiting Function");
      infunction = !infunction;
      lcd.noBlink();
    }
    else if (input == 2 && cyclecount > 1000 && intest == true) {
      Serial.println("pausing");
      paused = !paused;
    }
  }
}

void parameterChange() { // this section is used to trigger functions based on what menu was displayed during a click
  delay(100);
  Serial.println("Entering Function");
  if (millis() > 5000) {
    if (currentScreen == 0) {
      infunction = true;
      lcd.blink();
      home();
    }
    if (currentScreen == 1) { // the number coresponds to the index in the screens string
      //  Serial.print("infunction");
      //  Serial.println(infunction);
      infunction = true;
      lcd.blink();
      movetopos();
    }
    if (currentScreen == 2) {
      infunction = true;
      lcd.blink();
      setsensorsize();
    }
    if (currentScreen == 3) {
      infunction = true;
      lcd.blink();
      sensorlength();
    }
    if (currentScreen == 4) {
      infunction = true;
      lcd.blink();
      Testnum();
    }
    if (currentScreen == 5) {
      infunction = true;
      lcd.blink();
      Testdistance();
    }
    if (currentScreen == 6) {
      infunction = true;
      Setspeed();
    }
    if (currentScreen == 7) {
      infunction = true;
      testtofail();
    }
    if (currentScreen == 8) {
      infunction = true;
      starttest();
    }
    if (currentScreen == 9) {
      infunction = true;
      starttesttofailure();
    }
    if (currentScreen == 10) {
      infunction = true;
      togglemotor();
    }
    if (currentScreen == 11) {
      infunction = true;
      setstepsize();
    }
  }
}

// bellow are the various functions that are currently built into the testing rig

void home() { // homes machine
  Serial.println("homing machine");
  if (!motorenablestate) {
    togglemotor();
    Serial.println("MotorEnabled");
  }
  driver.shaft(false); // change motor direction
  while (!limitstate && !(Estop)) {
    checkcanmove();
    Serial.println("moving");
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(step_delay);
    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(step_delay);
    //Serial.print("Limit Switch state");
    //Serial.println(digitalRead(Limitpin));
    if (digitalRead(Limitpin) == HIGH) {
      limitstate = true;
      currentposition = 0;
    }
  }
  limitstate = false;
  ishomed = true;
}
void movetopos() { // moves machine to position as rotary encoder is rotated
  Serial.println("moving machine");
  if (!ishomed) {
    home();
  }
  if (!motorenablestate) {
    togglemotor();
  }
  counter = 0;
  delay(1000);
  while (infunction) {
    cyclecount++;
    setInputFlags();
    resolveInputFlags();
    if (counter * stepsize + currentposition != currentposition) {
      if (!(currentposition == 0 && counter * stepsize + currentposition < 0)) {
        double delta = counter * stepsize;
        Serial.print("Delta :");
        Serial.println(delta);
        Serial.print("Counter :");
        Serial.println(counter);
        Serial.print("Current Possition :");
        Serial.println(currentposition);
        Serial.print("stepsize :");
        Serial.println(stepsize);
        if (delta > 0) {
          shaft = true;
          currentposition += stepsize;
        } else if (delta < 0) {
          shaft = false;
          currentposition -= stepsize;
        }
        driver.shaft(shaft);

        for (uint16_t i = 0; i <= (abs(delta) * MMconstant); i++) {
          if (limitstate == false && (Estop == false) && currentposition <= upperpositionlimit) {
            digitalWrite(STEP_PIN, HIGH);
            delayMicroseconds(step_delay);
            digitalWrite(STEP_PIN, LOW);
            delayMicroseconds(step_delay);
          }
          else {
            home();
            return;
          }
        }
        counter = 0;
        delta = 0;
        printScreen();
      }
      else {
        counter = 0;
      }
    }
  }
}
void setsensorsize() { // sets the start position for the sample
  if (!ishomed) {
    home();
  }
  if (!motorenablestate) {
    togglemotor();
  }
  Serial.println("define length");
  counter = 0;
  delay(1000);
  while (infunction) {
    cyclecount++;
    setInputFlags();
    resolveInputFlags();
    if (counter * stepsize + currentposition != currentposition) {
      if (!(currentposition == 0 && counter * stepsize + currentposition < 0)) {
        double delta = counter * stepsize;
        Serial.print("Delta :");
        Serial.println(delta);
        Serial.print("Counter :");
        Serial.println(counter);
        Serial.print("Current Possition :");
        Serial.println(currentposition);
        if (delta > 0) {
          shaft = true;
          currentposition += stepsize;
        } else if (delta < 0) {
          shaft = false;
          currentposition -= stepsize;
        }
        driver.shaft(shaft);
        for (uint16_t i = 0; i <= (abs(delta) * MMconstant); i++) {
          checkcanmove();
          if (limitstate == false && (Estop == false)  && currentposition <= upperpositionlimit) {
            digitalWrite(STEP_PIN, HIGH);
            delayMicroseconds(step_delay);
            digitalWrite(STEP_PIN, LOW);
            delayMicroseconds(step_delay);
          }
          else {
            home();
            return;
          }
        }
        counter = 0;
        delta = 0;
        sensorsize = currentposition;
        parameters[2] = sensorsize;
        printScreen();
      } else {
        counter = 0;
      }
    }
  }
  actualsensorlength  = sensorsize;
  testdistance = currentposition;
}

void sensorlength() { // sets the length of the sample
  Serial.println("enter sensor size");
  counter = 0;
  delay(1000);
  while (infunction) {
    cyclecount++;
    actualsensorlength += counter * stepsize;
    parameters[3] = actualsensorlength;
    if (counter != 0) {
      printScreen();
    }
    counter = 0;
    setInputFlags();
    resolveInputFlags();
  }
}

void Testnum() { // sets the nubmer of cycles to do
  Serial.println("enter number of tests");
  counter = 0;
  delay(1000);
  while (infunction) {
    cyclecount++;
    testiterations += counter;
    parameters[4] = testiterations;
    if (counter != 0) {
      printScreen();
    }
    counter = 0;
    setInputFlags();
    resolveInputFlags();
  }

}
void Testdistance() { // sets the distance that the tester with strech the sample
  Serial.println("enter Test distance");
  delay(1000);
  while (infunction) {
    cyclecount++;
    testdistance += counter * stepsize;
    parameters[5] = testdistance;
    if (counter != 0) {
      printScreen();
    }
    counter = 0;
    setInputFlags();
    resolveInputFlags();
  }
}


void Setspeed() { // sets the travel speed
  Serial.println("Set speed (mm/s)");
  counter = 0;
  delay(1000);
  int mmPerS = 7;
  while (infunction) {
    cyclecount++;
    if (mmPerS + counter > 0) {
      mmPerS += counter;
      parameters[6] = mmPerS;
    }
    if (counter != 0) {
      printScreen();
    }
    counter = 0;
    setInputFlags();
    resolveInputFlags();
  }
  MMPerSeconds = mmPerS;
  step_delay = int((((1 / MMPerSeconds) / 400) * 1000000) / 2);
}


void testtofail() { // sets the length of the sample
  Serial.println("Stop on Fail Y/N");
  counter = 0;
  delay(1000);
  while (infunction) {
    cyclecount++;
    if (counter != 0) {
      stoponfail = !stoponfail;
      lcd.clear();
      lcd.print(screens[currentScreen][0]);
      lcd.setCursor(0, 1);
      if (stoponfail) {
        lcd.print("Yes");
        lcd.print(" ");
      }
      else {
        lcd.print("No");
        lcd.print(" ");
      }
      lcd.print(screens[currentScreen][1]);
      lcd.print(" ");
      lcd.print(currentposition);
      lcd.print(" mm");
    }
    counter = 0;
    setInputFlags();
    resolveInputFlags();
  }
}

void starttest() { // starts the automated testing cycle
   // load cell
  loadcellave.reset();
  loadcellave2.reset();
  
  intest = true;
  hasfailed = false;
  if (!ishomed) {
    home();
  }
  if (!motorenablestate) {
    togglemotor();
  }
  gotoposition(sensorsize);

  // Opens Datalogger File /////////////////////////////////////////
  bool havefile = false;
  int i = 0;
  String filename;
  //Serial.print("GOT here2");
  while (!havefile) {
    filename = "";
    filename.concat((int)actualsensorlength);
    filename.concat("_");
    filename.concat((int)i);
    filename.concat(".csv");
    Serial.println(filename);
    Serial.println(SD.exists(filename.c_str()));
    havefile = !SD.exists(filename.c_str());
    i++;
  }
  Serial.print("Filename is listed here: ");
  Serial.println(filename);
  // "data_output.csv"
  dataFile = SD.open(filename.c_str(), FILE_WRITE);
  if (!dataFile) {
    Serial.println("error opening file");
    lcd.clear();
    lcd.print("File Error");
    delay(2000);
    // see if the card is present and can be initialized:
    if (!SD.begin(chipSelect, Mosi, Miso, Sck)) {  // chipSel, mosi, miso, sck
      Serial.println("Card failed, or not present");
      lcd.clear();
      lcd.print("Insert SD");
      lcd.setCursor(0, 1);
      lcd.print("then reboot");
      // don't do anything more:
      delay(2000);
      return;
    }
    Serial.println("card initialized.");
    return;
  }
  String dataString = "";
  dataString += String("New Experiment");
  dataString += ",";
  dataString += String("Sensor_size(mm)");
  dataString += ",";
  dataString += String(actualsensorlength);
  dataString += ",";
  dataString += String("Test distance (how far from 1 length it will strain) (mm)");
  dataString += String(testdistance);
  dataString += ",";
  dataString += String("Sensor Postition");
  dataString += String(sensorsize);
  dataString += ",";
  dataString += String("Number of Cycles");
  dataString += String(testiterations);
  dataFile.println(dataString);

  dataString = "";
  dataString += String("Current_Position");
  dataString += ",";
  dataString += String("Load_Cell_Value");
  dataString += ",";
  dataString += String("MotorDiagnostic1");
  dataString += ",";
  dataString += String("MotorDiagnostic2");
  dataFile.println(dataString);
  dataFile.flush();
  //Serial.print("GOT here4");

  // Starts actual test /////////////////////////////////////////
  Serial.println("testing");
  for (int j = 0; j <= testiterations; j++) {
    //Serial.print("GOT her e5");
    driver.shaft(true);
    for (uint16_t z = 0; z <= int(testdistance / stepsize); z++) {
      currentposition += stepsize;
      for (uint16_t i = 0; i <= int(MMconstant * stepsize); i++) {
        checkcanmove();
        if (limitstate == false && !(stoponfail == true && hasfailed == true) && (Estop == false) && currentposition <= upperpositionlimit) {
          digitalWrite(STEP_PIN, HIGH);
          delayMicroseconds(step_delay);
          digitalWrite(STEP_PIN, LOW);
          delayMicroseconds(step_delay);
        }
        else {
          dataFile.flush();
          home();
          return;
        }
      }
      getdata(); // get sensor readings
      lcd.clear();
      lcd.print("Testing STR");
      lcd.print(int(((currentposition - sensorsize) / actualsensorlength) * 100 + 100));
      lcd.print("%");
      lcd.setCursor(0, 1);
      lcd.print("n: ");
      lcd.print(j);
      lcd.print("Pos: ");
      lcd.print(currentposition);
      lcd.print(" mm");

      bool tempbool = false;
      while (paused) {
        if (!tempbool) {
          dataFile.flush();
          tempbool = true;
        }
        setInputFlags();
        resolveInputFlags();
        lcd.clear();
        lcd.print("Test Paused");
      }
    }
    driver.shaft(false); // change motor direction
    for (uint16_t z = 0; z <= int(testdistance / stepsize); z++) {
      currentposition -= stepsize;
      for (uint16_t i = 0; i <= int(MMconstant * stepsize); i++) {
        checkcanmove();
        if (limitstate == false  && !(stoponfail == true && hasfailed == true) && (Estop == false)) {
          digitalWrite(STEP_PIN, HIGH);
          delayMicroseconds(step_delay);
          digitalWrite(STEP_PIN, LOW);
          delayMicroseconds(step_delay);
        }
        else {
          dataFile.flush();
          home();
          return;
        }
      }
      getdata(); // get sensor readings
      lcd.clear();
      lcd.print("Testing STR");
      lcd.print(int(((currentposition - sensorsize) / actualsensorlength) * 100));
      lcd.print("%");
      lcd.setCursor(0, 1);
      lcd.print("n: ");
      lcd.print(j);
      lcd.print("Pos: ");
      lcd.print(currentposition);
      lcd.print(" mm");
      bool tempbool = false;
      while (paused) {
        if (!tempbool) {
          dataFile.flush();
          tempbool = true;
        }
        setInputFlags();
        resolveInputFlags();
        lcd.clear();
        lcd.print("Test Paused");
      }
    }

    // log begining of new cycle to SD card
    String dataString = "";
    dataString += String("Current_Position");
    dataString += ",";
    dataString += String("Load_Cell_Value");
    dataString += ",";
    dataString += String(j);
    dataString += ",";
    dataString += String("Placeholder");
    dataFile.println(dataString);
    dataFile.flush(); // save data to sd
  }

  // at end of experiment
  dataFile.flush();  // save data to sd
}



void starttesttofailure() { // starts the automated test to failure or limit

  // load cell
  loadcellave.reset();
  loadcellave2.reset();
  
  intest = true;
  stoponfail = true;
  hasfailed = false;
  if (!ishomed) {
    home();
  }
  if (!motorenablestate) {
    togglemotor();
  }
  gotoposition(sensorsize);

  // Opens Datalogger File /////////////////////////////////////////
  bool havefile = false;
  int i = 0;
  String filename;
  //Serial.print("GOT here2");
  while (!havefile) {
    filename = "";
    filename.concat(((int)actualsensorlength));
    filename.concat("_");
    filename.concat((int)i);
    filename.concat(".csv");
    Serial.println(filename);
    Serial.println(SD.exists(filename.c_str()));
    havefile = !SD.exists(filename.c_str());
    i++;
  }
  Serial.print("Filename is listed here: ");
  Serial.println(filename);
  // "data_output.csv"
  dataFile = SD.open(filename.c_str(), FILE_WRITE);
  if (!dataFile) {
    Serial.println("error opening file");
    lcd.clear();
    lcd.print("File Error");
    delay(2000);
    // see if the card is present and can be initialized:
    if (!SD.begin(chipSelect, Mosi, Miso, Sck)) {  // chipSel, mosi, miso, sck
      Serial.println("Card failed, or not present");
      lcd.clear();
      lcd.print("Insert SD");
      lcd.setCursor(0, 1);
      lcd.print("then reboot");
      // don't do anything more:
      delay(2000);
      return;
    }
    Serial.println("card initialized.");
    return;
  }
  String dataString = "";
  dataString += String("New Experiment");
  dataString += ",";
  dataString += String("Sensor_size(mm)");
  dataString += ",";
  dataString += String(actualsensorlength);
  dataString += ",";
  dataString += String("Test distance (how far from 1 length it will strain) (mm)");
  dataString += String(testdistance);
  dataString += ",";
  dataString += String("Sensor Postition");
  dataString += String(sensorsize);
  dataString += ",";
  dataString += String("Number of Cycles");
  dataString += String(testiterations);
  dataFile.println(dataString);

  dataString = "";
  dataString += String("Current_Position");
  dataString += ",";
  dataString += String("Load_Cell_Value");
  dataString += ",";
  dataString += String("MotorDiagnostic1");
  dataString += ",";
  dataString += String("MotorDiagnostic2");
  dataFile.println(dataString);
  dataFile.flush();
  //Serial.print("GOT here4");

  // Starts actual test /////////////////////////////////////////
  Serial.println("testing");
  //Serial.print("GOT her e5");
  driver.shaft(true);
  for (uint16_t z = 0; z <= int(testdistance / stepsize); z++) {
    currentposition += stepsize;
    for (uint16_t i = 0; i <= int(MMconstant * stepsize); i++) {
      checkcanmove();
      if (limitstate == false && !(stoponfail == true && hasfailed == true) && (Estop == false) && currentposition <= upperpositionlimit) {
        digitalWrite(STEP_PIN, HIGH);
        delayMicroseconds(step_delay);
        digitalWrite(STEP_PIN, LOW);
        delayMicroseconds(step_delay);
      }
      else {
        dataFile.flush();
        home();
        return;
      }
    }
    getdata(); // get sensor readings
    lcd.clear();
    lcd.print("Testing STR");
    lcd.print(int(((currentposition - sensorsize) / actualsensorlength) * 100 + 100));
    lcd.print("%");
    lcd.setCursor(0, 1);
    lcd.print("n: ");
    lcd.print(1);
    lcd.print("Pos: ");
    lcd.print(currentposition);
    lcd.print(" mm");

    bool tempbool = false;
    while (paused) {
      if (!tempbool) {
        dataFile.flush();
        tempbool = true;
      }
      setInputFlags();
      resolveInputFlags();
      lcd.clear();
      lcd.print("Test Paused");
    }
  }
  // at end of experiment
  dataFile.flush();  // save data to sd
}

void checkcanmove() {
  // Estop Logic
  if (enableEstop) {
    if (digitalRead(EstopPin) == HIGH) {
      Estop = true;
      digitalWrite(EN_PIN, HIGH);
      Serial.println("Emergency Stop");
      lcd.clear();
      lcd.print("Emergency Stop");
      lcd.setCursor(0, 1);
      lcd.print("Restart to Reset");
      dataFile.flush();
      while (1) {
        //do nothing in here
      }
    }
  }
}

void gotoposition(int position) { // move actuator to an absolute postion
  cyclecount++;
  setInputFlags();
  resolveInputFlags();
  int delta = position - currentposition;
  Serial.print("Delta :");
  Serial.println(delta);
  Serial.print("Counter :");
  Serial.println(counter);
  Serial.print("Current Possition :");
  Serial.println(currentposition);
  if (delta > 0) {
    shaft = true;
    currentposition += delta;
  } else if (delta < 0) {
    shaft = false;
    currentposition += delta;
  }
  driver.shaft(shaft);
  for (uint16_t i = 0; i <= (abs(delta) * MMconstant); i++) {
    checkcanmove();
    if (limitstate == false && (Estop == false) && currentposition <= upperpositionlimit) {
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds(step_delay);
      digitalWrite(STEP_PIN, LOW);
      delayMicroseconds(step_delay);
    }
    else {
      home();
      return;
    }
  }
}

void togglemotor() { // enables/dissables stepper motor
  motorenablestate = !motorenablestate;
  if (motorenablestate) {
    digitalWrite(EN_PIN, LOW);  // Enable driver in hardware
  } else {
    digitalWrite(EN_PIN, HIGH);  //diable motor in hardware
  }
}


void setstepsize() { // sets movment increment
  Serial.println("Set movement increment (mm)");
  counter = 0;
  delay(1000);
  int tempcount = 0;
  while (infunction) {
    cyclecount++;
    tempcount += counter;
    parameters[11] = 1 * pow(10, tempcount);
    if (counter != 0) {
      printScreen();
    }
    counter = 0;
    setInputFlags();
    resolveInputFlags();
  }
  stepsize = 1 * pow(10, tempcount);
}


...

This file has been truncated, please download it to see its full contents.

Data Processing Python Notebook

Python
No preview (download only).

Credits

David Bershadsky
3 projects • 6 followers

Comments