Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge CubVision into main #32

Merged
merged 4 commits into from
Feb 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import java.util.function.Supplier;

import com.team1701.lib.alerts.Alert;
import com.team1701.lib.drivers.cameras.AprilTagCameraIO.PhotonCameraInputs;
import com.team1701.lib.drivers.cameras.AprilTagCameraIO.AprilTagInputs;
import edu.wpi.first.apriltag.AprilTagFieldLayout;
import edu.wpi.first.math.geometry.Pose2d;
import edu.wpi.first.math.geometry.Pose3d;
Expand All @@ -22,7 +22,7 @@

public class AprilTagCamera {
private final AprilTagCameraIO mCameraIO;
private final PhotonCameraInputs mCameraInputs;
private final AprilTagInputs mCameraInputs;
private final String mLoggingPrefix;
private final PhotonPoseEstimator mPoseEstimator;
private final Transform3d mRobotToCamPose;
Expand All @@ -42,7 +42,7 @@ public AprilTagCamera(
Supplier<AprilTagFieldLayout> fieldLayoutSupplier,
Supplier<Pose3d> robotPoseSupplier) {
mCameraIO = cameraIO;
mCameraInputs = new PhotonCameraInputs();
mCameraInputs = new AprilTagInputs();
mLoggingPrefix = "Camera/" + cameraName + "/";
mPoseEstimator = new PhotonPoseEstimator(fieldLayoutSupplier.get(), poseStrategy, null, robotToCamPose);
mPoseEstimator.setMultiTagFallbackStrategy(fallbackPoseStrategy);
Expand All @@ -69,6 +69,7 @@ public void periodic() {
return;
}

// TODO: Make field pub/sub
mPoseEstimator.setFieldTags(mFieldLayoutSupplier.get());
var estimatedRobotPose = mPoseEstimator.update(filteredPipelineResult);
if (estimatedRobotPose.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import org.photonvision.targeting.TargetCorner;

public interface AprilTagCameraIO {
public class PhotonCameraInputs implements LoggableInputs {
public class AprilTagInputs implements LoggableInputs {
public PhotonPipelineResult pipelineResult = new PhotonPipelineResult();
public boolean isConnected;

Expand Down Expand Up @@ -132,7 +132,7 @@ public void fromLog(LogTable table) {
}
}

public default void updateInputs(PhotonCameraInputs inputs) {}
public default void updateInputs(AprilTagInputs inputs) {}

public default void addToVisionSim(
VisionSystemSim visionSim, SimCameraProperties cameraProperties, Transform3d robotToCamPose) {}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package com.team1701.lib.drivers.cameras;

import java.util.ArrayList;
import java.util.Collections;

import com.team1701.robot.Constants;
import edu.wpi.first.math.geometry.Transform3d;
import edu.wpi.first.networktables.IntegerSubscriber;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.networktables.PubSubOption;
import edu.wpi.first.networktables.RawSubscriber;
import edu.wpi.first.networktables.TimestampedRaw;
import edu.wpi.first.wpilibj.RobotController;
import org.photonvision.common.dataflow.structures.Packet;
import org.photonvision.simulation.SimCameraProperties;
import org.photonvision.simulation.VisionSystemSim;
import org.photonvision.targeting.MultiTargetPNPResult;
import org.photonvision.targeting.PNPResult;
import org.photonvision.targeting.PhotonPipelineResult;
import org.photonvision.targeting.PhotonTrackedTarget;
import org.photonvision.utils.PacketUtils;

public class AprilTagCameraIOCubVision implements AprilTagCameraIO {
private static final PhotonPipelineResult kEmptyResult = new PhotonPipelineResult();
private static final MultiTargetPNPResult kEmptyPnpResult = new MultiTargetPNPResult();

private final RawSubscriber mObservationSubscriber;
private final IntegerSubscriber mFpsSubscriber;

public AprilTagCameraIOCubVision(String cameraName, int cameraId) {
var CubVisionTable = NetworkTableInstance.getDefault().getTable("CubVision/" + cameraName);

var configTable = CubVisionTable.getSubTable("config");
configTable.getIntegerTopic("camera_id").publish().set(cameraId);
configTable.getIntegerTopic("camera_resolution_width").publish().set(Constants.Vision.cameraResolutionWidth);
configTable.getIntegerTopic("camera_resolution_height").publish().set(Constants.Vision.cameraResolutionHeight);
configTable.getIntegerTopic("camera_auto_exposure").publish().set(Constants.Vision.cameraAutoExposure);
configTable.getIntegerTopic("camera_exposure").publish().set(Constants.Vision.cameraExposure);
configTable.getIntegerTopic("camera_gain").publish().set(Constants.Vision.cameraGain);
configTable.getDoubleTopic("fiducial_size_m").publish().set(Constants.Vision.kAprilTagWidth);

var outputTable = CubVisionTable.getSubTable("output");
mObservationSubscriber = outputTable
.getRawTopic("observations")
.subscribe(
"ObservationsPacket",
new byte[] {},
PubSubOption.keepDuplicates(true),
PubSubOption.sendAll(true));

mFpsSubscriber = outputTable.getIntegerTopic("fps").subscribe(0);
}

@Override
public void updateInputs(AprilTagInputs inputs) {
// Use fps to determine if the camera is connected
// FPS should always be non-zero and will update at least once every 2 + latency seconds
var timestampedFps = mFpsSubscriber.getAtomic();
inputs.isConnected = timestampedFps.value > 0
&& RobotController.getFPGATime() - mFpsSubscriber.getAtomic().timestamp < 2500000; // 2.5 seconds
inputs.pipelineResult = readPhotonPipelineResult(mObservationSubscriber.getAtomic());
}

private PhotonPipelineResult readPhotonPipelineResult(TimestampedRaw timestampedPacket) {
if (timestampedPacket.value.length == 0) {
return kEmptyResult;
}

var packet = new Packet(timestampedPacket.value);
var latency = packet.decodeDouble();

var targets = new ArrayList<PhotonTrackedTarget>();
var numTargets = packet.decodeByte();
for (var i = 0; i < numTargets; i++) {
var targetId = packet.decodeByte();
var bestCameraToTargetError = packet.decodeDouble();
var bestCameraToTarget = PacketUtils.unpackTransform3d(packet);
var altCameraToTargetError = packet.decodeDouble();
var altCameratoTarget = PacketUtils.unpackTransform3d(packet);
var ambiguity = altCameraToTargetError > 0 ? bestCameraToTargetError / altCameraToTargetError : 1.0;

// The packet only includes data needed for pose estimation
targets.add(new PhotonTrackedTarget(
0.0,
0.0,
0.0,
0.0,
(int) targetId,
bestCameraToTarget,
altCameratoTarget,
ambiguity,
Collections.emptyList(),
Collections.emptyList()));
}

var pnpResult = kEmptyPnpResult;
var numTagsUsedForCameraPose = packet.decodeByte();
if (numTagsUsedForCameraPose > 1) {
var tags = new ArrayList<Integer>();
for (var i = 0; i < numTagsUsedForCameraPose; i++) {
tags.add((int) packet.decodeByte());
}
var error = packet.decodeDouble();
var pose = PacketUtils.unpackTransform3d(packet);

pnpResult = new MultiTargetPNPResult(new PNPResult(pose, error), tags);
}

var result = new PhotonPipelineResult(latency, targets, pnpResult);
result.setTimestampSeconds(timestampedPacket.timestamp / 1000000.0 - latency / 1000.0);
return result;
}

@Override
public void addToVisionSim(
VisionSystemSim visionSim, SimCameraProperties cameraProperties, Transform3d robotToCamPose) {}
}

This file was deleted.

Loading
Loading