I generated a GRIP pipeline to use for gear auton in an off season competition, and I wrote what I think should work. Long story short, it didn’t work the way I wanted it to. The robot’s movements were jittery and it was starting and stopping. My thought was that there was a delay between when it was getting values from the calculations to when it was setting the motor speeds, so I rewrote the command. I dded in a thread to calculate the values I’d need, and then it would just set the motor speeds in the execute function, hopefully removing that delay. After working through tons of errors, I finally got it to a point where it builds and uploads; and then does nothing. It does, however, give an exception. I’ll put the pipeline, the command, and the exception down below, but I am very very confused!! (Also, ignore the while(true), one weird problem was that it was just skipping the inside of the run function, so that’s just a placeholder for now.) If you need me to explain any of the code so you can understand why we did some really odd stuff to throw it together, just let me know! Whatever I can do to help you help me
Command:
package org.usfirst.frc.team4750.robot.commands;
import org.opencv.core.Mat;
import org.usfirst.frc.team4750.robot.Robot;
import org.usfirst.frc.team4750.robot.GripPipeline;
import edu.wpi.cscore.CvSink;
import edu.wpi.cscore.UsbCamera;
import edu.wpi.first.wpilibj.CameraServer;
import edu.wpi.first.wpilibj.command.Command;
import edu.wpi.first.wpilibj.networktables.NetworkTable;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
/**
*
*/
public class TrackGear extends Command {
// Creates double arrays
double] defaultValue = new double[0];
boolean isFinished = false;
// Network Tables
NetworkTable table;
public VisionThread calculateSpeed;
// Create variables
double xOffset;
double offsetMotorSpeed;
// Vision Thread
class VisionThread extends Thread {
boolean keepgoing = true;
double] area;
double] centerX;
double] centerY;
// Declare pipeline
public GripPipeline gearPipe;
double goalCenterX;
double goalCenterY;
// Create instance of camera, cvsink, mat
public UsbCamera camera;
public CvSink cvsink;
public Mat mat;
public VisionThread() {
keepgoing=true;
camera = CameraServer.getInstance().startAutomaticCapture();
cvsink = CameraServer.getInstance().getVideo(camera);
mat = new Mat();
gearPipe = new GripPipeline();
table = NetworkTable.getTable("GRIP/gearReport");
}
@Override
public void run() {
System.out.println("VisionThread Started...");
while (true) {
System.out.println("In Visionthread run!!!");
// Process mat
gearPipe.process(mat);
// Set double arrays to NetworkTable values
area = table.getNumberArray("area", defaultValue);
centerX = table.getNumberArray("centerX", defaultValue);
centerY = table.getNumberArray("centerY", defaultValue);
// If 2 or more contours are shown
if (area.length >= 2) {
// Average of centerX and centerY (average of goal)
goalCenterX = (centerX[0] + centerX[1]) / 2;
goalCenterY = (centerY[0] + centerY[1]) / 2;
xOffset = 320 - goalCenterX;
offsetMotorSpeed = (Math.abs(xOffset) * 1.64) + 60;
SmartDashboard.putNumber("ThreadxOffset", xOffset);
SmartDashboard.putNumber("Thread offsetMotorSpeed", offsetMotorSpeed);
} else { // If less than 2 contours
// Stop drive
offsetMotorSpeed = 0;
}
if(keepgoing==false)
break;
}
System.out.println("VisionThread Done!!!");
}
public void stopThread() {
keepgoing = false;
}
}
public TrackGear() {
// Use requires() here to declare subsystem dependencies
// eg. requires(chassis);
}
// Called just before this Command runs the first time
protected void initialize() {
System.out.println("TrackGear initialize()");
calculateSpeed = new VisionThread();
// Start vision thread
calculateSpeed.start();
System.out.println("TrackGear initialize done!");
}
// Called repeatedly when this Command is scheduled to run
protected void execute() {
//Create new local variables
double offset = xOffset;
double motorSpeed = offsetMotorSpeed;
SmartDashboard.putNumber("Local xoffset", offset);
SmartDashboard.putNumber("motorSpeed", motorSpeed);
// If the offset is less than 5px
if (Math.abs(offset) < 5) {
// Stop motors
Robot.driveTrain.visionDrive(0);
// Stop command
isFinished = true;
} else {
// If the offset is positive
if (offset > 0) {
// Strafe left
Robot.driveTrain.visionDrive(-motorSpeed);
} else { // If the offset is negative
// Strafe right
Robot.driveTrain.visionDrive(motorSpeed);
}
}
}
// Make this return true when this Command no longer needs to run execute()
protected boolean isFinished() {
if (isFinished = false) {
return false;
} else {
calculateSpeed.stopThread();
return true;
}
}
// Called once after isFinished returns true
protected void end() {
}
// Called when another command which requires one or more of the same
// subsystems is scheduled to run
protected void interrupted() {
}
}
Error:
OpenCV Error: Assertion failed ((scn == 3 || scn == 4) && (depth == CV_8U || depth == CV_32F)) in cvtColor, file /var/lib/jenkins/workspace/OpenCV-roborio/modules/imgproc/src/color.cpp, line 8141
Exception in thread "Thread-0" CvException [org.opencv.core.CvException: cv::Exception: /var/lib/jenkins/workspace/OpenCV-roborio/modules/imgproc/src/color.cpp:8141: error: (-215) (scn == 3 || scn == 4) && (depth == CV_8U || depth == CV_32F) in function cvtColor
]
at org.opencv.imgproc.Imgproc.cvtColor_1(Native Method)
at org.opencv.imgproc.Imgproc.cvtColor(Unknown Source)
at org.usfirst.frc.team4750.robot.GripPipe.hslThreshold(GripPipe.java:106)
at org.usfirst.frc.team4750.robot.GripPipe.process(GripPipe.java:46)
at org.usfirst.frc.team4750.robot.commands.TrackGear$VisionThread.run(TrackGear.java:66)
NT: server: client CONNECTED: 10.47.50.46 port 57978
Pipeline:
package org.usfirst.frc.team4750.robot;
import java.util.ArrayList;
import java.util.List;
import org.opencv.core.*;
import org.opencv.imgproc.*;
/**
* GripPipeline class.
*
* <p>An OpenCV pipeline generated by GRIP.
*
* @author GRIP
*/
public class GripPipeline {
//Outputs
private Mat resizeImageOutput = new Mat();
private Mat hslThresholdOutput = new Mat();
private ArrayList<MatOfPoint> findContoursOutput = new ArrayList<MatOfPoint>();
private ArrayList<MatOfPoint> filterContoursOutput = new ArrayList<MatOfPoint>();
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
/**
* This is the primary method that runs the entire pipeline and updates the outputs.
*/
public void process(Mat source0) {
// Step Resize_Image0:
Mat resizeImageInput = source0;
double resizeImageWidth = 640.0;
double resizeImageHeight = 480.0;
int resizeImageInterpolation = Imgproc.INTER_CUBIC;
resizeImage(resizeImageInput, resizeImageWidth, resizeImageHeight, resizeImageInterpolation, resizeImageOutput);
// Step HSL_Threshold0:
Mat hslThresholdInput = resizeImageOutput;
double] hslThresholdHue = {38.84892086330935, 98.3059261557555};
double] hslThresholdSaturation = {36.954348510643435, 255.0};
double] hslThresholdLuminance = {80.26079136690647, 255.0};
hslThreshold(hslThresholdInput, hslThresholdHue, hslThresholdSaturation, hslThresholdLuminance, hslThresholdOutput);
// Step Find_Contours0:
Mat findContoursInput = hslThresholdOutput;
boolean findContoursExternalOnly = false;
findContours(findContoursInput, findContoursExternalOnly, findContoursOutput);
// Step Filter_Contours0:
ArrayList<MatOfPoint> filterContoursContours = findContoursOutput;
double filterContoursMinArea = 200.0;
double filterContoursMinPerimeter = 0.0;
double filterContoursMinWidth = 0.0;
double filterContoursMaxWidth = 1000.0;
double filterContoursMinHeight = 0.0;
double filterContoursMaxHeight = 1000.0;
double] filterContoursSolidity = {0, 100};
double filterContoursMaxVertices = 1000000.0;
double filterContoursMinVertices = 0.0;
double filterContoursMinRatio = 0.0;
double filterContoursMaxRatio = 1000.0;
filterContours(filterContoursContours, filterContoursMinArea, filterContoursMinPerimeter, filterContoursMinWidth, filterContoursMaxWidth, filterContoursMinHeight, filterContoursMaxHeight, filterContoursSolidity, filterContoursMaxVertices, filterContoursMinVertices, filterContoursMinRatio, filterContoursMaxRatio, filterContoursOutput);
}
/**
* This method is a generated getter for the output of a Resize_Image.
* @return Mat output from Resize_Image.
*/
public Mat resizeImageOutput() {
return resizeImageOutput;
}
/**
* This method is a generated getter for the output of a HSL_Threshold.
* @return Mat output from HSL_Threshold.
*/
public Mat hslThresholdOutput() {
return hslThresholdOutput;
}
/**
* This method is a generated getter for the output of a Find_Contours.
* @return ArrayList<MatOfPoint> output from Find_Contours.
*/
public ArrayList<MatOfPoint> findContoursOutput() {
return findContoursOutput;
}
/**
* This method is a generated getter for the output of a Filter_Contours.
* @return ArrayList<MatOfPoint> output from Filter_Contours.
*/
public ArrayList<MatOfPoint> filterContoursOutput() {
return filterContoursOutput;
}
/**
* Scales and image to an exact size.
* @param input The image on which to perform the Resize.
* @param width The width of the output in pixels.
* @param height The height of the output in pixels.
* @param interpolation The type of interpolation.
* @param output The image in which to store the output.
*/
private void resizeImage(Mat input, double width, double height,
int interpolation, Mat output) {
Imgproc.resize(input, output, new Size(width, height), 0.0, 0.0, interpolation);
}
/**
* Segment an image based on hue, saturation, and luminance ranges.
*
* @param input The image on which to perform the HSL threshold.
* @param hue The min and max hue
* @param sat The min and max saturation
* @param lum The min and max luminance
* @param output The image in which to store the output.
*/
private void hslThreshold(Mat input, double] hue, double] sat, double] lum,
Mat out) {
Imgproc.cvtColor(input, out, Imgproc.COLOR_BGR2HLS);
Core.inRange(out, new Scalar(hue[0], lum[0], sat[0]),
new Scalar(hue[1], lum[1], sat[1]), out);
}
/**
* Sets the values of pixels in a binary image to their distance to the nearest black pixel.
* @param input The image on which to perform the Distance Transform.
* @param type The Transform.
* @param maskSize the size of the mask.
* @param output The image in which to store the output.
*/
private void findContours(Mat input, boolean externalOnly,
List<MatOfPoint> contours) {
Mat hierarchy = new Mat();
contours.clear();
int mode;
if (externalOnly) {
mode = Imgproc.RETR_EXTERNAL;
}
else {
mode = Imgproc.RETR_LIST;
}
int method = Imgproc.CHAIN_APPROX_SIMPLE;
Imgproc.findContours(input, contours, hierarchy, mode, method);
}
/**
* Filters out contours that do not meet certain criteria.
* @param inputContours is the input list of contours
* @param output is the the output list of contours
* @param minArea is the minimum area of a contour that will be kept
* @param minPerimeter is the minimum perimeter of a contour that will be kept
* @param minWidth minimum width of a contour
* @param maxWidth maximum width
* @param minHeight minimum height
* @param maxHeight maximimum height
* @param Solidity the minimum and maximum solidity of a contour
* @param minVertexCount minimum vertex Count of the contours
* @param maxVertexCount maximum vertex Count
* @param minRatio minimum ratio of width to height
* @param maxRatio maximum ratio of width to height
*/
private void filterContours(List<MatOfPoint> inputContours, double minArea,
double minPerimeter, double minWidth, double maxWidth, double minHeight, double
maxHeight, double] solidity, double maxVertexCount, double minVertexCount, double
minRatio, double maxRatio, List<MatOfPoint> output) {
final MatOfInt hull = new MatOfInt();
output.clear();
//operation
for (int i = 0; i < inputContours.size(); i++) {
final MatOfPoint contour = inputContours.get(i);
final Rect bb = Imgproc.boundingRect(contour);
if (bb.width < minWidth || bb.width > maxWidth) continue;
if (bb.height < minHeight || bb.height > maxHeight) continue;
final double area = Imgproc.contourArea(contour);
if (area < minArea) continue;
if (Imgproc.arcLength(new MatOfPoint2f(contour.toArray()), true) < minPerimeter) continue;
Imgproc.convexHull(contour, hull);
MatOfPoint mopHull = new MatOfPoint();
mopHull.create((int) hull.size().height, 1, CvType.CV_32SC2);
for (int j = 0; j < hull.size().height; j++) {
int index = (int)hull.get(j, 0)[0];
double] point = new double] { contour.get(index, 0)[0], contour.get(index, 0)[1]};
mopHull.put(j, 0, point);
}
final double solid = 100 * area / Imgproc.contourArea(mopHull);
if (solid < solidity[0] || solid > solidity[1]) continue;
if (contour.rows() < minVertexCount || contour.rows() > maxVertexCount) continue;
final double ratio = bb.width / (double)bb.height;
if (ratio < minRatio || ratio > maxRatio) continue;
output.add(contour);
}
}
}