This is our first year of vision processing. I am trying to figure out what goes in for the “listener” portion for the VisionThread.
visionThread = new VisionThread(server, new GripPipeline(),?){
if (!gripPipeline.filterContoursOutput().isEmpty()) {
Rect r = Imgproc.boundingRect(gripPipeline.filterContoursOutput().get(0));
synchronized (imgLock){
centerX = r.x + (r.width / 2);
}
}
}
The listener in the example is a lambda expression, or an “anonymous function”. Basically, a method that’s defined where it’s used. It’s similar to an anonymous class, but is more succinct.
visionThread = new VisionThread(camera, new GripPipeline(), pipeline -> {
if (!gripPipeline.filterContoursOutput().isEmpty()) {
Rect r = Imgproc.boundingRect(gripPipeline.filterContoursOutput().get(0));
synchronized (imgLock){
centerX = r.x + (r.width / 2);
}
}
});
can also be written as
visionThread = new VisionThread(camera, new GripPipeline(), new VisionRunner.Listener<GripPipeline>() {
@Override
public void copyPipelineOutputs(GripPipeline pipeline) {
// same as the contents of the lambda above
}
});
Thank you for your reply the only thing that doesn’t work is my camera is a camera server of type CameraServer. What do I do? Here is my complete Robot.java class code.
// RobotBuilder Version: 2.0
//
// This file was generated by RobotBuilder. It contains sections of
// code that are automatically generated and assigned by robotbuilder.
// These sections will be updated in the future when you export to
// Java from RobotBuilder. Do not put any code or make any change in
// the blocks indicating autogenerated code or it will be lost on an
// update. Deleting the comments indicating the section will prevent
// it from being updated in the future.
package org.usfirst.frc3534.DriveTest;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.opencv.imgproc.Imgproc;
import edu.wpi.cscore.CvSink;
import edu.wpi.cscore.CvSource;
import edu.wpi.cscore.UsbCamera;
import edu.wpi.cscore.UsbCameraInfo;
import edu.wpi.first.wpilibj.CameraServer;
import edu.wpi.first.wpilibj.IterativeRobot;
import edu.wpi.first.wpilibj.RobotDrive;
import edu.wpi.first.wpilibj.command.Command;
import edu.wpi.first.wpilibj.command.Scheduler;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.wpilibj.vision.VisionPipeline;
import edu.wpi.first.wpilibj.vision.VisionRunner;
import edu.wpi.first.wpilibj.vision.VisionThread;
import org.usfirst.frc3534.DriveTest.commands.AutonomousCommand;
import org.usfirst.frc3534.DriveTest.commands.GripPipeline;
import org.usfirst.frc3534.DriveTest.subsystems.*;
/**
* The VM is configured to automatically run this class, and to call the
* functions corresponding to each mode, as described in the IterativeRobot
* documentation. If you change the name of this class or the package after
* creating this project, you must also update the manifest file in the resource
* directory.
*/
public class Robot extends IterativeRobot {
private VisionThread visionThread;
private GripPipeline gripPipeline;
private double centerX = 0.0;
private RobotDrive drive;
private final Object imgLock = new Object();
Command autonomousCommand;
public static OI oi;
public int counter;
public CameraServer server;
// BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS
public static DriveTrain driveTrain;
// END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS
/**
* This function is run when the robot is first started up and should be
* used for any initialization code.
*/
public void robotInit() {
visionThread = new VisionThread(camera, new GripPipeline(), pipeline -> {
if (!gripPipeline.filterContoursOutput().isEmpty()) {
Rect r = Imgproc.boundingRect(gripPipeline.filterContoursOutput().get(0));
synchronized (imgLock){
centerX = r.x + (r.width / 2);
}
}
});
visionThread.start();
drive = new RobotDrive(1, 2);
RobotMap.init();
// BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
driveTrain = new DriveTrain();
// END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
// OI must be constructed after subsystems. If the OI creates Commands
//(which it very likely will), subsystems are not guaranteed to be
// constructed yet. Thus, their requires() statements may grab null
// pointers. Bad news. Don't move it.
oi = new OI();
server = CameraServer.getInstance();
server.setSize(50);
//the camera name (ex "cam0") can be found through the roborio web interface
server.startAutomaticCapture();
// instantiate the command used for the autonomous period
// BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=AUTONOMOUS
autonomousCommand = new AutonomousCommand();
// END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=AUTONOMOUS
}
/**
* This function is called when the disabled button is hit.
* You can use it to reset subsystems before shutting down.
*/
public void disabledInit(){
}
public void disabledPeriodic() {
Scheduler.getInstance().run();
}
public void autonomousInit() {
// schedule the autonomous command (example)
if (autonomousCommand != null)autonomousCommand.start();
}
/**
* This function is called periodically during autonomous
*/
public void autonomousPeriodic() {
Scheduler.getInstance().run();
log();
}
public void teleopInit() {
// This makes sure that the autonomous stops running when
// teleop starts running. If you want the autonomous to
// continue until interrupted by another command, remove
// this line or comment it out.
if (autonomousCommand != null) autonomousCommand.cancel();
}
/**
* This function is called periodically during operator control
*/
public void teleopPeriodic() {
Scheduler.getInstance().run();
log();
}
/**
* This function is called periodically during test mode
*/
public void testPeriodic() {
LiveWindow.run();
log();
}
private void log(){
counter++;
if(counter >= 5){
SmartDashboard.putNumber("Left Encoder Count", driveTrain.getLtEncoderPosition());
SmartDashboard.putNumber("Right Encoder Count", driveTrain.getRtEncoderPosition());
SmartDashboard.putNumber("Encoder Difference", driveTrain.getEncoderDifference());
SmartDashboard.putNumber("Rt Value", driveTrain.getRtValue());
SmartDashboard.putNumber("Correction Value", driveTrain.getCorrection());
counter = 0;
}
}
}
Don’t copy-paste code that someone gives as an example and expect it to work.
And definitely don’t copy and paste it into a program and then ask someone if it works before you even try to run it. It’s lazy and very few people will be willing to help you.