Threading overhaul + Updated datasaving
Data-saving at high cycle count takes too long, causing the DUT to fall asleep. Data-saving has been extracted into its own thread. Additionally, Run/pause switch has been re-threaded using synchronized statements, rather than lock statements, making the run switch work properly (finally). Data is now saved in the new Cycle object, rather than passing around multiple maps, hopefully improving memory footprint.
This commit is contained in:
parent
52fe20fba5
commit
e37f7b71f9
9 changed files with 246 additions and 108 deletions
|
@ -4,7 +4,7 @@
|
||||||
<groupId>org.baxter.disco</groupId>
|
<groupId>org.baxter.disco</groupId>
|
||||||
<artifactId>ocr</artifactId>
|
<artifactId>ocr</artifactId>
|
||||||
<name>Disco OCR Accuracy Over Life Testing</name>
|
<name>Disco OCR Accuracy Over Life Testing</name>
|
||||||
<version>4.3.8</version>
|
<version>4.3.9</version>
|
||||||
<description>Testing Discos for long-term accuracy, using automated optical character recognition.</description>
|
<description>Testing Discos for long-term accuracy, using automated optical character recognition.</description>
|
||||||
<organization>
|
<organization>
|
||||||
<name>Baxter International</name>
|
<name>Baxter International</name>
|
||||||
|
@ -95,9 +95,6 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
<version>3.4.1</version>
|
<version>3.4.1</version>
|
||||||
<configuration>
|
|
||||||
<show>private</show>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</reporting>
|
</reporting>
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -3,7 +3,7 @@
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.baxter.disco</groupId>
|
<groupId>org.baxter.disco</groupId>
|
||||||
<artifactId>ocr</artifactId>
|
<artifactId>ocr</artifactId>
|
||||||
<version>4.3.8</version>
|
<version>4.3.9</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<name>Disco OCR Accuracy Over Life Testing</name>
|
<name>Disco OCR Accuracy Over Life Testing</name>
|
||||||
<description>Testing Discos for long-term accuracy, using automated optical character recognition.</description>
|
<description>Testing Discos for long-term accuracy, using automated optical character recognition.</description>
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#! /usr/bin/env sh
|
#! /usr/bin/env sh
|
||||||
sudo java -jar discoTesting-4.3.8.jar 2>/dev/null
|
sudo java -jar discoTesting-4.3.9.jar 2>/dev/null
|
||||||
|
|
|
@ -3,12 +3,11 @@ package org.baxter.disco.ocr;
|
||||||
//Standard imports
|
//Standard imports
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CLI for the Fixture.
|
* CLI for the Fixture.
|
||||||
|
@ -18,20 +17,22 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||||
* classes).
|
* classes).
|
||||||
*
|
*
|
||||||
* @author Blizzard Finnegan
|
* @author Blizzard Finnegan
|
||||||
* @version 1.8.0, 16 Mar. 2023
|
* @version 1.9.0, 20 Mar. 2023
|
||||||
*/
|
*/
|
||||||
public class Cli
|
public class Cli
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Complete build version number
|
* Complete build version number
|
||||||
*/
|
*/
|
||||||
private static final String version = "4.3.8";
|
private static final String version = "4.3.9";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Currently saved iteration count.
|
* Currently saved iteration count.
|
||||||
*/
|
*/
|
||||||
private static int iterationCount = 10;
|
private static int iterationCount = 10;
|
||||||
|
|
||||||
|
private static boolean endOfCycles = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scanner used for monitoring user input.
|
* Scanner used for monitoring user input.
|
||||||
* This is a global object, so that functions
|
* This is a global object, so that functions
|
||||||
|
@ -65,11 +66,6 @@ public class Cli
|
||||||
*/
|
*/
|
||||||
private static final int cameraMenuOptionCount = 7;
|
private static final int cameraMenuOptionCount = 7;
|
||||||
|
|
||||||
/**
|
|
||||||
* Lock object, used for temporary interruption of {@link #runTests()}
|
|
||||||
*/
|
|
||||||
public static final Lock LOCK = new ReentrantLock();
|
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
|
@ -139,6 +135,7 @@ public class Cli
|
||||||
setActiveCameras();
|
setActiveCameras();
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
|
endOfCycles = false;
|
||||||
if(!camerasConfigured)
|
if(!camerasConfigured)
|
||||||
{
|
{
|
||||||
prompt("You have not configured the cameras yet! Are you sure you would like to continue? (y/N): ");
|
prompt("You have not configured the cameras yet! Are you sure you would like to continue? (y/N): ");
|
||||||
|
@ -647,21 +644,34 @@ public class Cli
|
||||||
try{ Thread.sleep(2000); } catch(Exception e){ ErrorLogging.logError(e); }
|
try{ Thread.sleep(2000); } catch(Exception e){ ErrorLogging.logError(e); }
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<File,Double> resultMap = new HashMap<>();
|
final Map<String,String> serials = ConfigFacade.getSerials();
|
||||||
Map<String,File> cameraToFile = new HashMap<>();
|
|
||||||
|
|
||||||
//Initialise cameraToFile, so keys don't shuffle.
|
|
||||||
for(String cameraName : cameraList)
|
|
||||||
{
|
|
||||||
cameraToFile.put(cameraName,new File("/dev/null"));
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorLogging.logError("DEBUG: Starting tests...");
|
ErrorLogging.logError("DEBUG: Starting tests...");
|
||||||
|
|
||||||
//All portions of the test check with the GPIO Run/Pause switch before
|
|
||||||
//continuing, using the Lock object.
|
final LinkedBlockingQueue<Cycle> dataEntryQueue = new LinkedBlockingQueue<>();
|
||||||
|
|
||||||
|
Thread writeThread = new Thread( () -> {
|
||||||
|
while(dataEntryQueue.size() > 0 && !endOfCycles)
|
||||||
|
{
|
||||||
|
Cycle cycle = null;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try{ cycle = dataEntryQueue.poll(Long.MAX_VALUE,TimeUnit.SECONDS); }
|
||||||
|
catch(Exception e){ ErrorLogging.logError(e); }
|
||||||
|
}
|
||||||
|
while(cycle == null);
|
||||||
|
|
||||||
|
DataSaving.writeValues(cycle,serials);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
writeThread.start();
|
||||||
|
|
||||||
for(int i = 0; i < localIterations; i++)
|
for(int i = 0; i < localIterations; i++)
|
||||||
{
|
{
|
||||||
|
Cycle cycle = new Cycle(i);
|
||||||
println("");
|
println("");
|
||||||
ErrorLogging.logError("====================================");
|
ErrorLogging.logError("====================================");
|
||||||
ErrorLogging.logError("Starting iteration " + (i+1) + " of " + localIterations + "...");
|
ErrorLogging.logError("Starting iteration " + (i+1) + " of " + localIterations + "...");
|
||||||
|
@ -675,9 +685,7 @@ public class Cli
|
||||||
fail = false;
|
fail = false;
|
||||||
if(safeGPIO)
|
if(safeGPIO)
|
||||||
{
|
{
|
||||||
while(!LOCK.tryLock()) {}
|
|
||||||
MovementFacade.iterationMovement(prime);
|
MovementFacade.iterationMovement(prime);
|
||||||
LOCK.unlock();
|
|
||||||
|
|
||||||
//Wait for the DUT to display an image
|
//Wait for the DUT to display an image
|
||||||
try{ Thread.sleep(2000); } catch(Exception e){ ErrorLogging.logError(e); }
|
try{ Thread.sleep(2000); } catch(Exception e){ ErrorLogging.logError(e); }
|
||||||
|
@ -685,27 +693,19 @@ public class Cli
|
||||||
|
|
||||||
for(String cameraName : cameraList)
|
for(String cameraName : cameraList)
|
||||||
{
|
{
|
||||||
while(!LOCK.tryLock()) {}
|
Thread cameraThread = new Thread(() -> {
|
||||||
File file = OpenCVFacade.completeProcess(cameraName);
|
File file = OpenCVFacade.completeProcess(cameraName);
|
||||||
LOCK.unlock();
|
Double result = TesseractFacade.imageToDouble(file);
|
||||||
|
ErrorLogging.logError("Parsed value from camera " + cameraName +": " + result);
|
||||||
while(!LOCK.tryLock()) {}
|
synchronized(cycle) { cycle.addCamera(cameraName,file,result); }
|
||||||
cameraToFile.replace(cameraName,file);
|
});
|
||||||
LOCK.unlock();
|
cameraThread.start();
|
||||||
|
try{ cameraThread.join(); } catch(Exception e){ ErrorLogging.logError(e); }
|
||||||
}
|
}
|
||||||
|
|
||||||
for(String cameraName : cameraList)
|
for(String cameraName : cameraList)
|
||||||
{
|
{
|
||||||
while(!LOCK.tryLock()) {}
|
double result = cycle.getValue(cameraName);
|
||||||
File file = cameraToFile.get(cameraName);
|
|
||||||
LOCK.unlock();
|
|
||||||
while(!LOCK.tryLock()) {}
|
|
||||||
Double result = TesseractFacade.imageToDouble(file);
|
|
||||||
LOCK.unlock();
|
|
||||||
while(!LOCK.tryLock()) {}
|
|
||||||
resultMap.put(file,result);
|
|
||||||
ErrorLogging.logError("Parsed value from camera " + cameraName +": " + result);
|
|
||||||
LOCK.unlock();
|
|
||||||
if(result <= 10 ||
|
if(result <= 10 ||
|
||||||
result >= 100 ||
|
result >= 100 ||
|
||||||
result == Double.NEGATIVE_INFINITY)
|
result == Double.NEGATIVE_INFINITY)
|
||||||
|
@ -723,14 +723,9 @@ public class Cli
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(fail);
|
while(fail);
|
||||||
|
dataEntryQueue.add(cycle);
|
||||||
while(!LOCK.tryLock()) {}
|
|
||||||
DataSaving.writeValues(i,resultMap,cameraToFile);
|
|
||||||
LOCK.unlock();
|
|
||||||
|
|
||||||
//DO NOT CLEAR camera to file Map. This will change the order of the objects within it
|
|
||||||
resultMap.clear();
|
|
||||||
}
|
}
|
||||||
|
endOfCycles = true;
|
||||||
println("=======================================");
|
println("=======================================");
|
||||||
println("Testing complete!");
|
println("Testing complete!");
|
||||||
}
|
}
|
||||||
|
|
84
src/main/java/org/baxter/disco/ocr/Cycle.java
Normal file
84
src/main/java/org/baxter/disco/ocr/Cycle.java
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
package org.baxter.disco.ocr;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single cycle in a test.
|
||||||
|
*
|
||||||
|
* @author Blizzard Finnegan
|
||||||
|
* @version 1.0.0, 20 Mar. 2023
|
||||||
|
*/
|
||||||
|
public class Cycle
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Current cycle number.
|
||||||
|
*/
|
||||||
|
private final int cycleNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of values, paired to their camera.
|
||||||
|
*
|
||||||
|
* Key: String of the name of the camera
|
||||||
|
* Value: Pair[File,Double] of the information for this cycle.
|
||||||
|
*
|
||||||
|
* Pair[File,Double]:
|
||||||
|
* First: File of the location of the image from the camera.
|
||||||
|
* Second: Double generated by Tesseract parsing the above image.
|
||||||
|
*/
|
||||||
|
private final Map<String,Pair<File,Double>> cycleValues = new TreeMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
public Cycle(int cycleNumber)
|
||||||
|
{ this.cycleNumber = cycleNumber; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for this object's cycle number.
|
||||||
|
*
|
||||||
|
* @return int of the current cycle number.
|
||||||
|
*/
|
||||||
|
public int getcycleNumber() { return this.cycleNumber; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all cameras contained within this object.
|
||||||
|
*
|
||||||
|
* @return Set of Strings of all cameras available in this object.
|
||||||
|
*/
|
||||||
|
public Set<String> getCameras() { return this.cycleValues.keySet(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for the given camera's associated image File.
|
||||||
|
*
|
||||||
|
* @param cameraName name of the camera to get the image from
|
||||||
|
*
|
||||||
|
* @return File of the image from the camera
|
||||||
|
*/
|
||||||
|
public File getImage(String cameraName)
|
||||||
|
{ return this.cycleValues.get(cameraName).first(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Tesseract parsed value of the image from the given camera.
|
||||||
|
*
|
||||||
|
* @param cameraName name of the camera to get the image from
|
||||||
|
*
|
||||||
|
* @return Double of the Tesseract-parsed value of the image.
|
||||||
|
*/
|
||||||
|
public Double getValue(String cameraName)
|
||||||
|
{ return this.cycleValues.get(cameraName).second(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a camera to the object, with its accociated image and value.
|
||||||
|
*
|
||||||
|
* @param cameraName Name of the camera associated with the image and value
|
||||||
|
* @param image File object denoting the location of the image from the camera
|
||||||
|
* @param parsedValue Double of the value generated by Tesseract from the image
|
||||||
|
*
|
||||||
|
* @return true if saved successfully, else false.
|
||||||
|
*/
|
||||||
|
public void addCamera(String cameraName, File image, Double parsedValue)
|
||||||
|
{ this.cycleValues.put(cameraName,new Pair<File,Double>(image, parsedValue)); }
|
||||||
|
}
|
|
@ -32,7 +32,7 @@ import static org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
|
||||||
* Facade for saving data out to a file.
|
* Facade for saving data out to a file.
|
||||||
*
|
*
|
||||||
* @author Blizzard Finnegan
|
* @author Blizzard Finnegan
|
||||||
* @version 5.0.1, 10 Mar. 2023
|
* @version 6.0.0, 10 Mar. 2023
|
||||||
*/
|
*/
|
||||||
public class DataSaving
|
public class DataSaving
|
||||||
{
|
{
|
||||||
|
@ -167,7 +167,7 @@ public class DataSaving
|
||||||
*
|
*
|
||||||
* @param cameraCount The number of cameras that were used.
|
* @param cameraCount The number of cameras that were used.
|
||||||
*/
|
*/
|
||||||
private static void updateFormulas(int cameraCount)
|
private static synchronized void updateFormulas(int cameraCount)
|
||||||
{
|
{
|
||||||
ErrorLogging.logError("DEBUG: Updating formulas in Excel sheet...");
|
ErrorLogging.logError("DEBUG: Updating formulas in Excel sheet...");
|
||||||
int rowIndex = 0;
|
int rowIndex = 0;
|
||||||
|
@ -227,30 +227,29 @@ public class DataSaving
|
||||||
* Writes line to XLSX file.
|
* Writes line to XLSX file.
|
||||||
*
|
*
|
||||||
* @param cycle What test cycle is being saved to the file
|
* @param cycle What test cycle is being saved to the file
|
||||||
* @param inputMap Map[String,Double] list of inputs
|
* @param serials Map[String,String] list of camera serials
|
||||||
*
|
*
|
||||||
* @return Returns whether values were saved successfully.
|
* @return Returns whether values were saved successfully.
|
||||||
*/
|
*/
|
||||||
public static boolean writeValues(int cycle, Map<File,Double> inputMap, Map<String,File> cameraToFile)
|
public static synchronized boolean writeValues(Cycle cycle, Map<String,String> serials)
|
||||||
{
|
{
|
||||||
ErrorLogging.logError("DEBUG: Writing values for " + (cycle + 1) + " cycle to worksheet.");
|
int cycleNumber = cycle.getcycleNumber() + 1;
|
||||||
|
ErrorLogging.logError("DEBUG: Writing values for " + (cycleNumber) + " cycle to worksheet.");
|
||||||
boolean output = false;
|
boolean output = false;
|
||||||
int cellnum = 0;
|
int cellnum = 0;
|
||||||
int startingRow = outputSheet.getLastRowNum();
|
int startingRow = outputSheet.getLastRowNum();
|
||||||
HSSFRow row = (cycle == 1) ? outputSheet.getRow(startingRow) : outputSheet.createRow(++startingRow);
|
HSSFRow row = (cycle.getcycleNumber() == 1) ? outputSheet.getRow(startingRow) : outputSheet.createRow(++startingRow);
|
||||||
List<String> cameraNames = new ArrayList<>(cameraToFile.keySet());
|
List<String> cameraNames = new ArrayList<>(cycle.getCameras());
|
||||||
|
|
||||||
cycle++;
|
|
||||||
|
|
||||||
HSSFCell indexCell = row.createCell(cellnum++);
|
HSSFCell indexCell = row.createCell(cellnum++);
|
||||||
indexCell.setCellValue(cycle);
|
indexCell.setCellValue(cycleNumber);
|
||||||
for(String cameraName : cameraNames)
|
for(String cameraName : cameraNames)
|
||||||
{
|
{
|
||||||
String serialNumber = ConfigFacade.getSerial(cameraName);
|
String serialNumber = serials.get(cameraName);
|
||||||
HSSFCell serialCell = row.createCell(cellnum++);
|
HSSFCell serialCell = row.createCell(cellnum++);
|
||||||
serialCell.setCellValue(serialNumber);
|
serialCell.setCellValue(serialNumber);
|
||||||
|
|
||||||
File file = cameraToFile.get(cameraName);
|
File file = cycle.getImage(cameraName);
|
||||||
HSSFCell imageCell = row.createCell(cellnum++);
|
HSSFCell imageCell = row.createCell(cellnum++);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -275,7 +274,7 @@ public class DataSaving
|
||||||
|
|
||||||
//Put the OCR value into the sheet
|
//Put the OCR value into the sheet
|
||||||
HSSFCell ocrCell = row.createCell(cellnum++);
|
HSSFCell ocrCell = row.createCell(cellnum++);
|
||||||
Double ocrRead = inputMap.get(file);
|
Double ocrRead = cycle.getValue(cameraName);
|
||||||
if(ocrRead.equals(Double.NEGATIVE_INFINITY))
|
if(ocrRead.equals(Double.NEGATIVE_INFINITY))
|
||||||
{
|
{
|
||||||
ocrCell.setCellValue("ERROR!");
|
ocrCell.setCellValue("ERROR!");
|
||||||
|
|
|
@ -87,7 +87,7 @@ public class ErrorLogging
|
||||||
*
|
*
|
||||||
* @param error Any error being thrown to be logged.
|
* @param error Any error being thrown to be logged.
|
||||||
*/
|
*/
|
||||||
public static void logError(Throwable error)
|
public static synchronized void logError(Throwable error)
|
||||||
{
|
{
|
||||||
String errorStackTrace = ExceptionUtils.getStackTrace(error);
|
String errorStackTrace = ExceptionUtils.getStackTrace(error);
|
||||||
String errorMessage = datetime.format(LocalDateTime.now()) + " - " + errorStackTrace;
|
String errorMessage = datetime.format(LocalDateTime.now()) + " - " + errorStackTrace;
|
||||||
|
@ -100,7 +100,7 @@ public class ErrorLogging
|
||||||
*
|
*
|
||||||
* @param error Any information to save to the log file.
|
* @param error Any information to save to the log file.
|
||||||
*/
|
*/
|
||||||
public static void logError(String error)
|
public static synchronized void logError(String error)
|
||||||
{
|
{
|
||||||
String errorMessage = datetime.format(LocalDateTime.now()) + "\t- " + error;
|
String errorMessage = datetime.format(LocalDateTime.now()) + "\t- " + error;
|
||||||
fileOut.println(errorMessage);
|
fileOut.println(errorMessage);
|
||||||
|
|
|
@ -17,7 +17,7 @@ import com.pi4j.io.gpio.digital.PullResistance;
|
||||||
* Currently missing Run switch compatibility.
|
* Currently missing Run switch compatibility.
|
||||||
*
|
*
|
||||||
* @author Blizzard Finnegan
|
* @author Blizzard Finnegan
|
||||||
* @version 3.1.0, 16 Mar. 2023
|
* @version 3.3.0, 20 Mar. 2023
|
||||||
*/
|
*/
|
||||||
public class MovementFacade
|
public class MovementFacade
|
||||||
{
|
{
|
||||||
|
@ -32,6 +32,11 @@ public class MovementFacade
|
||||||
*/
|
*/
|
||||||
private static Thread runSwitchThread;
|
private static Thread runSwitchThread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock object for multithreading/run switch.
|
||||||
|
*/
|
||||||
|
private static final Object lockObject = new Object();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fraction of the total travel time, so the arm won't push through the limit switch.
|
* Fraction of the total travel time, so the arm won't push through the limit switch.
|
||||||
*/
|
*/
|
||||||
|
@ -185,23 +190,27 @@ public class MovementFacade
|
||||||
ErrorLogging.logError("DEBUG: Starting lock thread...");
|
ErrorLogging.logError("DEBUG: Starting lock thread...");
|
||||||
runSwitchThread = new Thread(() ->
|
runSwitchThread = new Thread(() ->
|
||||||
{
|
{
|
||||||
boolean unlock = false;
|
|
||||||
while(!exit)
|
while(!exit)
|
||||||
{
|
{
|
||||||
if(runSwitch.isOn())
|
if(runSwitch.isOn())
|
||||||
{
|
{
|
||||||
ErrorLogging.logError("DEBUG: Run switch turned off!");
|
synchronized(lockObject)
|
||||||
while(!Cli.LOCK.tryLock())
|
{
|
||||||
{}
|
while(runSwitch.isOn())
|
||||||
unlock = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
//ErrorLogging.logError("Run switch on!");
|
|
||||||
if(unlock)
|
|
||||||
{ Cli.LOCK.unlock(); unlock = false; }
|
|
||||||
}
|
|
||||||
try{ Thread.sleep(100); } catch(Exception e){ErrorLogging.logError(e);}
|
try{ Thread.sleep(100); } catch(Exception e){ErrorLogging.logError(e);}
|
||||||
|
if(runSwitch.isOff())
|
||||||
|
{
|
||||||
|
try{ Thread.sleep(100); } catch(Exception e){ErrorLogging.logError(e);}
|
||||||
|
if(runSwitch.isOff())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try{ Thread.sleep(1); } catch(Exception e){ErrorLogging.logError(e);}
|
||||||
}
|
}
|
||||||
}, "Run switch monitor.");
|
}, "Run switch monitor.");
|
||||||
runSwitchThread.start();
|
runSwitchThread.start();
|
||||||
|
@ -255,15 +264,20 @@ public class MovementFacade
|
||||||
if(upperLimit.isHigh())
|
if(upperLimit.isHigh())
|
||||||
{
|
{
|
||||||
ErrorLogging.logError("DEBUG: Motor at highest point! Lowering to reset.");
|
ErrorLogging.logError("DEBUG: Motor at highest point! Lowering to reset.");
|
||||||
|
synchronized(lockObject)
|
||||||
|
{
|
||||||
motorDirectionDown();
|
motorDirectionDown();
|
||||||
motorOn();
|
motorOn();
|
||||||
try{ Thread.sleep(500); }
|
try{ Thread.sleep(500); }
|
||||||
catch (Exception e){ ErrorLogging.logError(e); }
|
catch (Exception e){ ErrorLogging.logError(e); }
|
||||||
motorOff();
|
motorOff();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ErrorLogging.logError("DEBUG: Moving motor to highest point.");
|
ErrorLogging.logError("DEBUG: Moving motor to highest point.");
|
||||||
motorDirectionUp();
|
motorDirectionUp();
|
||||||
|
|
||||||
|
synchronized(lockObject)
|
||||||
|
{
|
||||||
motorOn();
|
motorOn();
|
||||||
|
|
||||||
for(counter = 0; counter < TIMEOUT; counter++)
|
for(counter = 0; counter < TIMEOUT; counter++)
|
||||||
|
@ -276,12 +290,15 @@ public class MovementFacade
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
motorOff();
|
motorOff();
|
||||||
|
}
|
||||||
|
|
||||||
if(counter < TIMEOUT)
|
if(counter < TIMEOUT)
|
||||||
{
|
{
|
||||||
ErrorLogging.logError("DEBUG: Motor returned after " + counter + " polls.");
|
ErrorLogging.logError("DEBUG: Motor returned after " + counter + " polls.");
|
||||||
ErrorLogging.logError("DEBUG: --------------------------------------");
|
ErrorLogging.logError("DEBUG: --------------------------------------");
|
||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ErrorLogging.logError("DEBUG: No motor return after 3 seconds.");
|
ErrorLogging.logError("DEBUG: No motor return after 3 seconds.");
|
||||||
|
@ -372,6 +389,9 @@ public class MovementFacade
|
||||||
ErrorLogging.logError("DEBUG: Travel time: " + totalPollCount);
|
ErrorLogging.logError("DEBUG: Travel time: " + totalPollCount);
|
||||||
ErrorLogging.logError("DEBUG: High speed poll count: " + highSpeedPolls);
|
ErrorLogging.logError("DEBUG: High speed poll count: " + highSpeedPolls);
|
||||||
ErrorLogging.logError("DEBUG: =============================");
|
ErrorLogging.logError("DEBUG: =============================");
|
||||||
|
|
||||||
|
synchronized(lockObject)
|
||||||
|
{
|
||||||
motorOn();
|
motorOn();
|
||||||
for(int i = 0; i < highSpeedPolls; i++)
|
for(int i = 0; i < highSpeedPolls; i++)
|
||||||
{
|
{
|
||||||
|
@ -387,6 +407,7 @@ public class MovementFacade
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
motorOff();
|
motorOff();
|
||||||
|
}
|
||||||
|
|
||||||
output = (limitSense.isOn() ? FinalState.UNSAFE : FinalState.SAFE);
|
output = (limitSense.isOn() ? FinalState.UNSAFE : FinalState.SAFE);
|
||||||
|
|
||||||
|
@ -411,6 +432,8 @@ public class MovementFacade
|
||||||
* Extends the piston for 1 second, pushing the button on the DUT.
|
* Extends the piston for 1 second, pushing the button on the DUT.
|
||||||
*/
|
*/
|
||||||
public static void pressButton()
|
public static void pressButton()
|
||||||
|
{
|
||||||
|
synchronized(lockObject)
|
||||||
{
|
{
|
||||||
ErrorLogging.logError("DEBUG: Pressing button...");
|
ErrorLogging.logError("DEBUG: Pressing button...");
|
||||||
pistonActivate.on();
|
pistonActivate.on();
|
||||||
|
@ -418,6 +441,7 @@ public class MovementFacade
|
||||||
ErrorLogging.logError("DEBUG: Releasing button...");
|
ErrorLogging.logError("DEBUG: Releasing button...");
|
||||||
pistonActivate.off();
|
pistonActivate.off();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes connections to all GPIO pins.
|
* Closes connections to all GPIO pins.
|
||||||
|
|
39
src/main/java/org/baxter/disco/ocr/Pair.java
Normal file
39
src/main/java/org/baxter/disco/ocr/Pair.java
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package org.baxter.disco.ocr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard read-only pair object.
|
||||||
|
*
|
||||||
|
* @author Blizzard Finnegan
|
||||||
|
* @version 1.0.0, 20 Mar. 2023
|
||||||
|
*/
|
||||||
|
public class Pair<E,F>
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The first object in the pair.
|
||||||
|
*/
|
||||||
|
private final E first;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The second object in the pair.
|
||||||
|
*/
|
||||||
|
private final F second;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
public Pair(E first, F second)
|
||||||
|
{
|
||||||
|
this.first = first;
|
||||||
|
this.second = second;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for the first value.
|
||||||
|
*/
|
||||||
|
public E first() { return first; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for the second value.
|
||||||
|
*/
|
||||||
|
public F second() { return second; }
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue