End of day 07 Mar. commit

CLI is now back to normal, updated DataSaving to be better.
Logging now stores camera names.
This commit is contained in:
Blizzard Finnegan 2023-03-07 15:41:10 -05:00
parent 7708d1359a
commit 3167df3192
No known key found for this signature in database
GPG key ID: DE547EDF547DDA49
4 changed files with 200 additions and 184 deletions

View file

@ -83,99 +83,73 @@ public class Cli
try{
inputScanner = new Scanner(System.in);
//ConfigFacade.init();
ConfigFacade.init();
int userInput = 0;
MovementFacade.resetArm();
MovementFacade.goDown();
MovementFacade.goUp();
ErrorLogging.logError("Calibrating motor movement. This may take several minutes...");
MovementFacade.calibrate();
prompt("Did the motor move successfully? (Y/n): ");
String successfulMovement = inputScanner.next().trim().toLowerCase();
ErrorLogging.logError("DEBUG: user report of motor movement = " + successfulMovement);
if(successfulMovement == "" || successfulMovement.charAt(0) != 'y')
do
{
ErrorLogging.logError("DEBUG: User reported failed movement of the motor! Allowing reset of frequency...");
print("As the default frequency did not work successfully, a new frequency value is required.");
print("Higher frequency: Faster motor movement, not guaranteed to work, may cause damage to motor.");
print(" Lower frequency: Slower motor movement, safer, but longer iteration time.");
boolean frequencyReset = false;
while(true)
printMainMenu();
userInput = (int)inputFiltering(inputScanner.nextLine());
switch (userInput)
{
prompt("Please enter a new frequency value (Default: 50kHz): ");
userInput = (int)inputFiltering(inputScanner.next());
frequencyReset = MovementFacade.setFrequency(userInput);
if(!frequencyReset) continue;
MovementFacade.resetArm();
MovementFacade.goDown();
MovementFacade.goUp();
prompt("Did the motor move successfully? (Y/n): ");
successfulMovement = inputScanner.next();
if(successfulMovement != "" || successfulMovement.toLowerCase().charAt(0) != 'n') break;
case 1:
println("Setting up cameras...");
println("This may take a moment...");
configureCameras();
camerasConfigured = true;
break;
case 2:
setDUTSerials();
break;
case 3:
setIterationCount();
break;
case 4:
setActiveCameras();
break;
case 5:
if(!camerasConfigured)
{
prompt("You have not configured the cameras yet! Are you sure you would like to continue? (y/N): ");
String input = inputScanner.nextLine().toLowerCase().trim();
if( input.isBlank() || input.charAt(0) != 'y' ) break;
else
ErrorLogging.logError("DEBUG: Potential for error: Un-initialised cameras.");
}
serialsSet = true;
for(String cameraName : OpenCVFacade.getCameraNames())
{
if(ConfigFacade.getValue(cameraName,ConfigProperties.ACTIVE) != 0 &&
ConfigFacade.getSerial(cameraName) == null )
serialsSet = false;
}
if(!serialsSet)
{
prompt("You have not set the serial numbers for your DUTs yet! Are you sure you would like to continue? (y/N): ");
String input = inputScanner.nextLine().toLowerCase().trim();
if( input.isBlank() || input.charAt(0) != 'y' ) break;
else
ErrorLogging.logError("DEBUG: Potential for error: Un-initialised DUT Serial numbers.");
}
runTests();
break;
case 6:
printHelp();
break;
case 8:
break;
default:
//Input handling already done by inputFiltering()
}
}
//do
//{
// printMainMenu();
// userInput = (int)inputFiltering(inputScanner.nextLine());
// switch (userInput)
// {
// case 1:
// println("Setting up cameras...");
// println("This may take a moment...");
// configureCameras();
// camerasConfigured = true;
// break;
// case 2:
// setDUTSerials();
// break;
// case 3:
// setIterationCount();
// break;
// case 4:
// setActiveCameras();
// break;
// case 5:
// if(!camerasConfigured)
// {
// prompt("You have not configured the cameras yet! Are you sure you would like to continue? (y/N): ");
// String input = inputScanner.nextLine().toLowerCase().trim();
// if( input.isBlank() || input.charAt(0) != 'y' ) break;
// else
// ErrorLogging.logError("DEBUG: Potential for error: Un-initialised cameras.");
// }
// serialsSet = true;
// for(String cameraName : OpenCVFacade.getCameraNames())
// {
// if(ConfigFacade.getValue(cameraName,ConfigProperties.ACTIVE) != 0 &&
// ConfigFacade.getSerial(cameraName) == null )
// serialsSet = false;
// }
// if(!serialsSet)
// {
// prompt("You have not set the serial numbers for your DUTs yet! Are you sure you would like to continue? (y/N): ");
// String input = inputScanner.nextLine().toLowerCase().trim();
// if( input.isBlank() || input.charAt(0) != 'y' ) break;
// else
// ErrorLogging.logError("DEBUG: Potential for error: Un-initialised DUT Serial numbers.");
// }
// runTests();
// break;
// case 6:
// printHelp();
// break;
// case 8:
// break;
// default:
// //Input handling already done by inputFiltering()
// }
//} while (userInput != mainMenuOptionCount);
} while (userInput != mainMenuOptionCount);
}
//If anything ever goes wrong, catch the error and exit
@ -693,8 +667,6 @@ public class Cli
//DO NOT CLEAR camera to file Map. This will change the order of the objects within it
resultMap.clear();
}
//Close the Excel workbook
DataSaving.closeWorkbook(cameraList.size());
//Alert the user to testing being complete
println("=======================================");
println("Testing complete!");

View file

@ -32,7 +32,7 @@ import static org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
* Facade for saving data out to a file.
*
* @author Blizzard Finnegan
* @version 4.1.0, 24 Feb. 2023
* @version 5.0.0, 07 Mar. 2023
*/
public class DataSaving
{
@ -148,6 +148,10 @@ public class DataSaving
cell = row.createCell(cellnum++);
cell.setCellValue("");
}
HSSFCell serialTitleCell = row.createCell(cellnum++);
serialTitleCell.setCellValue("Serial");
HSSFCell passPercentCell = row.createCell(cellnum++);
passPercentCell.setCellValue("Pass %");
//Save to file
try (FileOutputStream outputStream = new FileOutputStream(outputFile))
@ -163,44 +167,44 @@ public class DataSaving
*
* @param cameraCount The number of cameras that were used.
*/
public static void closeWorkbook(int cameraCount)
private static void updateFormulas(int cameraCount)
{
int rowIndex = 0;
FormulaEvaluator formulaEvaluator = outputWorkbook.getCreationHelper().createFormulaEvaluator();
int lastColumnOfData = outputSheet.getRow(rowIndex).getLastCellNum();
int serialColumn = lastColumnOfData + 1;
int percentColumn = lastColumnOfData + 2;
//Get the last row, add another row below it, and name the first cell "Totals:"
int lastRowOfData = outputSheet.getLastRowNum();
HSSFRow finalRow = outputSheet.createRow(++lastRowOfData);
HSSFCell titleCell = finalRow.createCell(0);
titleCell.setCellValue("Totals:");
//ErrorLogging.logError("DEBUG: 3 ?= " + (cameraCount*3));
//For each camera, create a unique total line
for(int column = 3; column <= (cameraCount*3); column+=3)
{
//Create a cell in the right column
HSSFCell cell = finalRow.createCell(column);
FormulaEvaluator formulaEvaluator = outputWorkbook.getCreationHelper().createFormulaEvaluator();
String columnName = CellReference.convertNumToColString(column);
HSSFRow row = outputSheet.getRow(++rowIndex);
HSSFCell serialCell = row.createCell(serialColumn);
String formula = "$" + columnName + "$" + rowIndex;
serialCell.setCellFormula(formula);
formulaEvaluator.evaluate(serialCell);
//Intermediate variable to store the array of possible values
//Dollar signs in use here indicate that if the cell is copied and pasted,
//the same cells will be referenced
HSSFCell percentCell = row.createCell(percentColumn);
String verticalArray = String.format("$%s$2:$%s$%s",columnName,columnName,lastRowOfData);
ErrorLogging.logError("DEBUG: Vertical Array: " + verticalArray);
//Create the error formula, then set it as the cell's formula.
String formula = String.format(
"(COUNT(%s)-COUNTIF(%s,{\"<%s\",\">%s\"}))/(COUNT(%s))",
formula = String.format(
"(COUNT(%s)-(COUNTIF(%s,\"<%s\")+COUNTIF(%s,\">%s\",))/(COUNT(%s))",
verticalArray,
verticalArray, (targetTemp - failRange), (targetTemp + failRange),
verticalArray, (targetTemp - failRange),
verticalArray, (targetTemp + failRange),
verticalArray);
cell.setCellFormula(formula);
percentCell.setCellFormula(formula);
//Make the percentage human-readable
cell.setCellStyle(finalValuesStyle);
percentCell.setCellStyle(finalValuesStyle);
//To make the cell be a readable value, you need to
//evaluate the formula within the cell.
formulaEvaluator.evaluate(cell);
//To make the percentCell be a readable value, you need to
//evaluate the formula within the percentCell.
formulaEvaluator.evaluate(percentCell);
ErrorLogging.logError("DEBUG: Formula: " + formula);
}
@ -282,44 +286,8 @@ public class DataSaving
//Create a blank cell as a spacer
row.createCell(cellnum++);
//ErrorLogging.logError("DEBUG: " + cameraName);
//objectArray.add(serialNumber);
//objectArray.add(file.getPath());
//objectArray.add(inputMap.get(file));
//objectArray.add(" ");
}
//for(Object cellObject : objectArray)
//{
// HSSFCell cell = row.createCell(cellnum++);
// if(cellObject instanceof Double)
// {
// Double cellValue = (Double)cellObject;
// ErrorLogging.logError("DEBUG: " + cellValue + " ?= " + targetTemp + " +- " + failRange);
// if(cellValue.equals(Double.NEGATIVE_INFINITY))
// {
// cell.setCellValue("ERROR!");
// cell.setCellStyle(errorStyle);
// }
// else
// {
// cell.setCellValue(cellValue);
// if( cellValue.doubleValue() > (targetTemp + failRange) ||
// cellValue.doubleValue() < (targetTemp - failRange) )
// {
// ErrorLogging.logError("DEBUG: Cell value " + cellValue.doubleValue() + " is outside the allowed range! (" + (targetTemp -failRange) + "-" + (targetTemp + failRange) + "). Setting cell to fail colouring.");
// cell.setCellStyle(failStyle);
// }
// }
// }
// else if(cellObject instanceof String) cell.setCellValue((String) cellObject);
// else
// {
// ErrorLogging.logError("XLSX Write Error!!! - Invalid input.");
// ErrorLogging.logError("\t" + cellObject.toString());
// }
//}
updateFormulas(cameraNames.size());
try (FileOutputStream outputStream = new FileOutputStream(outputFile))
{ outputWorkbook.write(outputStream); output = true; }
catch(Exception e) {ErrorLogging.logError(e);}

View file

@ -52,35 +52,44 @@ public class MovementFacade
* Max allowed speed by current fixture design.
* Motor appears to start acting erratically over 192kHz.
*/
private static final double MAX_FREQUENCY = 192000;
private static final int MAX_FREQUENCY = 192000;
/**
* Amount of buffer between the found absolute speed, and used speed.
*/
private static final int SPEED_BUFFER = 4000;
/**
* Minimum allowed speed of the fixture arm; also used for reset travels.
*/
private static final double MIN_FREQUENCY = 20000;
private static final int MIN_FREQUENCY = 10000;
/**
* Distance in cm the fixture needs to travel.
*
* Distance between limit switches: ~80cm.
* Thickness of fixture arm: ~50cm.
* *** ABOVE MATH IS WRONG ***
* I don't know what I did wrong, but this value doesn't work
* properly if straight calculated.
* I will look into this more at some point.
*/
private static final int TRAVEL_DIST = 10;
private static final int TRAVEL_DIST = 12;
/**
* What percentage of the travel to slow down the motor.
*/
private static final double STEP_1 = 1.0 / 2.0;
private static final double STEP_1 = 2.0/3.0;
/**
* What percentage of the travel to slow down the motor farther.
*/
private static final double STEP_2 = 3.0 / 4.0;
private static final double STEP_2 = 5.0/6.0;
/**
* Default frequency fed to the PWM pin, which the motor controller converts into movement speed.
* Frequency fed to the PWM pin, which the motor controller converts into movement speed.
*/
private static int FREQUENCY = 70000;
private static int FREQUENCY = MIN_FREQUENCY;
/**
* PWM Duty Cycle.
@ -341,9 +350,10 @@ public class MovementFacade
*/
public static int resetArm()
{
ErrorLogging.logError("DEBUG: --------------------------------------");
int counter = 0;
ErrorLogging.logError("DEBUG: Setting minimum frequency of PWM...");
pwm.on(DUTY_CYCLE, (int)MIN_FREQUENCY);
pwm.on(DUTY_CYCLE, MIN_FREQUENCY);
if(upperLimit.isHigh())
{
ErrorLogging.logError("DEBUG: Motor at highest point! Lowering to reset.");
@ -370,21 +380,94 @@ public class MovementFacade
}
motorEnable.off();
ErrorLogging.logError("DEBUG: Motor returned after " + counter + " polls.");
ErrorLogging.logError("DEBUG: --------------------------------------");
return counter;
}
/**
* Used to set the motor's max speed.
*/
public static void calibrate()
{
ErrorLogging.logError("Initial Calibration reset.");
resetArm();
ErrorLogging.logError("Coarse calibrating...");
FREQUENCY = calib(MIN_FREQUENCY, MAX_FREQUENCY, 10000);
ErrorLogging.logError("Fine calibrating...");
FREQUENCY = calib(FREQUENCY,(FREQUENCY+10000),1000);
ErrorLogging.logError("Calibration complete!");
ErrorLogging.logError("DEBUG: Speed set to " + (FREQUENCY - SPEED_BUFFER));
setFrequency(FREQUENCY - SPEED_BUFFER);
}
/**
* Find the max speed of the fixure between two points.
*
* @param start Lowest speed to check
* @param max Highest speed to check
* @param iterate How much to iterate by
*
* @return The largest safe value between start and max.
*/
private static int calib(int start, int max, int iterate)
{
//start -= iterate;
for(int i = start; i < max; i+=iterate)
{
if(!setFrequency(i))
{
ErrorLogging.logError("DEBUG: Speed set unsuccessfully! returning " + MIN_FREQUENCY + "...");
return MIN_FREQUENCY;
}
ErrorLogging.logError("DEBUG: Motor travelling down.");
motorDirection.low();
ErrorLogging.logError("DEBUG: Motor Frequency: " + FREQUENCY);
ErrorLogging.logError("DEBUG: Motor calibrate on.");
motorEnable.on();
for(int j = 0; j < 20; j++)
{
try{ Thread.sleep(100); }
catch (Exception e){ ErrorLogging.logError(e); }
if(lowerLimit.isHigh())
{
ErrorLogging.logError("DEBUG: Breaking loop early!");
break;
}
}
motorEnable.off();
ErrorLogging.logError("DEBUG: Motor calibrate off.");
if(upperLimit.isHigh())
{
ErrorLogging.logError("DEBUG: Upper limit is high = " + upperLimit.isHigh());
ErrorLogging.logError("DEBUG: Motor failed to move! Returning " + (i - iterate));
return i-iterate;
}
else
{
ErrorLogging.logError("DEBUG: Motor moved at speed " + i + ". Checking for errors.");
if(resetArm() < 10 && i > 3.0)
{
ErrorLogging.logError("DEBUG: Motor failed to move! Returning " + (i - iterate));
return i - iterate;
}
}
}
return max-iterate;
}
/**
* Safely set the speed of the motor and fixture.
*
* @return true if set successfully, else false
*/
public static boolean setFrequency(int newFrequency)
private static boolean setFrequency(int newFrequency)
{
boolean output;
if(newFrequency < MIN_FREQUENCY || newFrequency > MAX_FREQUENCY)
{
ErrorLogging.logError("Movement control error!!! - Invalid frequency input.");
FREQUENCY = (int)MIN_FREQUENCY;
ErrorLogging.logError("DEBUG: Invalid MovementFacade.setFrequency() value, setting to minfrequency!");
FREQUENCY = MIN_FREQUENCY;
output = false;
}
else
@ -414,13 +497,13 @@ public class MovementFacade
{
motorDirection.high();
limitSense = upperLimit;
ErrorLogging.logError("DEBUG: Sending fixture up...");
ErrorLogging.logError("Sending fixture up...");
}
else
{
motorDirection.low();
limitSense = lowerLimit;
ErrorLogging.logError("DEBUG: Sending fixture down...");
ErrorLogging.logError("Sending fixture down...");
}
if(limitSense.isHigh()) return FinalState.SAFE;
@ -431,57 +514,49 @@ public class MovementFacade
int VEL_STEP_1 = (int)(STEP_1 * POLL_COUNT);
int VEL_STEP_2 = (int)(STEP_2 * POLL_COUNT);
ErrorLogging.logError("DEBUG: ========================================");
ErrorLogging.logError("DEBUG: =================================");
ErrorLogging.logError("DEBUG: Total Poll count: " + POLL_COUNT);
ErrorLogging.logError("DEBUG: Transition 1: " + VEL_STEP_1);
ErrorLogging.logError("DEBUG: Transition 2: " + VEL_STEP_2);
ErrorLogging.logError("DEBUG: Travel time: " + TRAVEL_TIME);
ErrorLogging.logError("DEBUG: Travel speed: " + (FREQUENCY/PWM_FREQ_CONVERT));
ErrorLogging.logError("DEBUG: ========================================");
ErrorLogging.logError("DEBUG: Motor on.");
ErrorLogging.logError("DEBUG: STEP_1: " + STEP_1);
ErrorLogging.logError("DEBUG: STEP_2: " + STEP_2);
ErrorLogging.logError("DEBUG: =================================");
motorEnable.on();
boolean slow = false;
boolean slower = false;
for(int i = 0; i < (POLL_COUNT);i++)
{
try{ Thread.sleep(POLL_WAIT); } catch(Exception e){ ErrorLogging.logError(e); }
if(limitSense.isOn())
{
ErrorLogging.logError("DEBUG: Exiting early due to limit switch activation!");
ErrorLogging.logError("DEBUG: Exiting on poll " + i);
break;
}
if(i >= VEL_STEP_1 && i < VEL_STEP_2)
{
output = FinalState.UNSAFE;
if(slow)
if(output != FinalState.UNSAFE)
{
output = FinalState.UNSAFE;
ErrorLogging.logError("DEBUG: Slowing down.");
slow = true;
pwm.on(DUTY_CYCLE, (int)(FREQUENCY / 1.25));
}
pwm.on(DUTY_CYCLE, (int)(FREQUENCY / 1.25));
}
else if(i >= VEL_STEP_2)
{
output = FinalState.SAFE;
if(slower)
if(output != FinalState.SAFE)
{
ErrorLogging.logError("DEBUG: Slowing down more.");
slower = true;
pwm.on(DUTY_CYCLE, FREQUENCY / 2);
output = FinalState.SAFE;
}
pwm.on(DUTY_CYCLE, FREQUENCY / 2);
}
}
motorEnable.off();
ErrorLogging.logError("DEBUG: Motor off.");
if(output == FinalState.FAILED)
ErrorLogging.logError("DEBUG: Motor movement exited early.");
ErrorLogging.logError("Motor moved too fast!");
else if(output == FinalState.UNSAFE)
ErrorLogging.logError("DEBUG: Motor movement slowed down, but not fully.");
ErrorLogging.logError("DEBUG: Motor only slowed down partially.");
else if(output == FinalState.SAFE)
ErrorLogging.logError("DEBUG: Motor movement successfully slowed fully.");
{
if(limitSense.isOn()) ErrorLogging.logError("DEBUG: Motor slowed down successfully.");
else ErrorLogging.logError("DEBUG: Motor did not reach limit switch successfully.");
}
pwm.on(DUTY_CYCLE, FREQUENCY);
return output;
}

View file

@ -84,6 +84,7 @@ public class OpenCVFacade
{
String cameraName = cameraFile.getName().
substring(CAMERA_FILE_PREFIX.length());
ErrorLogging.logError("DEBUG: Camera name: " + cameraName);
newCamera(cameraName, cameraFile.getAbsolutePath());
}
}