Conversation
danielcastellarin
left a comment
There was a problem hiding this comment.
I'd like see full docstrings for your functions, but for now let's just address the individual comments I made
| inputs.targetIds = new int[multitagResult.fiducialIDsUsed.size()]; | ||
| for (int j = 0; j < inputs.targetIds.length; j++) { | ||
| inputs.targetIds[j] = multitagResult.fiducialIDsUsed.get(j).intValue(); | ||
| } |
There was a problem hiding this comment.
You could do this in one line. Potential learning opportunity
There was a problem hiding this comment.
I learned about java streams and was able to do it with this line in the update method:
inputs.targetIds = multitagResult.fiducialIDsUsed.stream().mapToInt(Short::toUnsignedInt).toArray();
| measurement.robotPose = | ||
| cameraPose.transformBy( | ||
| (new Transform2d( | ||
| robotToCamera.getTranslation().toTranslation2d(), | ||
| robotToCamera.getRotation().toRotation2d())) | ||
| .inverse()); | ||
| measurement.targetIds = inputs.targetIds; | ||
| measurement.timestamp = result.getTimestampSeconds(); | ||
|
|
||
| // robot to camera + camera to target = robot to target | ||
| measurement.robotToBestTargetDistanceInMeters = | ||
| robotToCamera | ||
| .plus(result.getBestTarget().getBestCameraToTarget()) | ||
| .getTranslation() | ||
| .getDistance(Translation3d.kZero); | ||
|
|
||
| inputs.cameraDistanceToTargetMeters = | ||
| result | ||
| .getBestTarget() | ||
| .getBestCameraToTarget() | ||
| .getTranslation() | ||
| .getDistance(Translation3d.kZero); | ||
| } |
There was a problem hiding this comment.
This feels repetitive from the previous else-if; let's see if we can consolidate them?
| if (VISION_LOGGING_DEBUG) { | ||
| for (int cameraIndex = 0; cameraIndex < cameras.size(); cameraIndex++) { | ||
| for (int i = 0; i < cameras.get(cameraIndex).getVisionPoseMeasurements().length; i++) { | ||
| VisionPoseMeasurement poseMeasurement = | ||
| cameras.get(cameraIndex).getVisionPoseMeasurements()[i]; | ||
| boolean isValid = validPoseMeasurements.contains(poseMeasurement); | ||
| String reason = ""; | ||
|
|
||
| if (poseMeasurement.targetIds.length >= 2) { | ||
| reason = "MultiTag with IDs:" + Arrays.toString(poseMeasurement.targetIds); | ||
| } else if (poseMeasurement.robotToBestTargetDistanceInMeters != -1 | ||
| && poseMeasurement.robotToBestTargetDistanceInMeters | ||
| <= MAXIMUM_SINGLE_TAG_DISTANCE_METERS) { | ||
| reason = | ||
| "Single tag with distance of : " | ||
| + poseMeasurement.robotToBestTargetDistanceInMeters; | ||
| } else if (isValid) { | ||
| reason = "Cross Tag Check, Same AprilTag as different camera"; | ||
|
|
||
| } else { | ||
| reason = | ||
| "Failed to have Single Tag with a match and is greater than min valid distance: " | ||
| + poseMeasurement.robotToBestTargetDistanceInMeters; | ||
| } | ||
|
|
||
| Logger.recordOutput( | ||
| "Vision/" | ||
| + cameras.get(cameraIndex).getName() | ||
| + "/PoseMeasurements/" | ||
| + String.valueOf(i) | ||
| + "/reason", | ||
| reason); | ||
| Logger.recordOutput( | ||
| "Vision/" | ||
| + cameras.get(cameraIndex).getName() | ||
| + "/PoseMeasurements/" | ||
| + String.valueOf(i) | ||
| + "/isValid", | ||
| isValid); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Would it make sense to consolidate the logging parts from earlier in this function into here?
| } | ||
|
|
||
| // add valid pose measurment to consumer | ||
| for (int i = 0; i < validPoseMeasurements.size(); i++) { |
There was a problem hiding this comment.
change this to a "for each" loop instead of a "for i". You don't really need the index for anything here
| double currentTime = Timer.getFPGATimestamp(); | ||
| for (int cameraIndex = 0; cameraIndex < cameraTagPoses.size(); cameraIndex++) { | ||
| // the time between one publish and the next | ||
| double oneMeasureDurationSeconds = 1.0 / cameras.get(cameraIndex).getCameraSettings().fps; | ||
|
|
||
| double measureLifespan = oneMeasureDurationSeconds * 5; // found 5 from testing in sim | ||
|
|
||
| Map<Integer, List<VisionPoseMeasurement>> tagMap = cameraTagPoses.get(cameraIndex); | ||
|
|
||
| for (List<VisionPoseMeasurement> posesAtSeenTag : tagMap.values()) { | ||
| posesAtSeenTag.removeIf( | ||
| measurement -> currentTime - measurement.timestamp > measureLifespan); | ||
| } | ||
| } |
There was a problem hiding this comment.
Reminder for Dan to look at this because I sleep
| Logger.processInputs("Vision/" + camera.getName(), inputs); | ||
| camera.update(inputs); | ||
|
|
||
| if (visionMeasurementConsumer.isPresent()) { |
There was a problem hiding this comment.
Do we need to do anything in updateCamera if the consumer doesn't exist?
There was a problem hiding this comment.
I think it depends on weather we want to use the camera with anything else that is not related to updating pose estimation. My thought was that information could still be gather weather or not we have a consumer.
There was a problem hiding this comment.
As it stands, the only other functionality photonvision enables is object detection/tracking. I think we can assume we won't be utilizing that (and if some reason we do need it, we can modify the code at that time)
| for (int i = 0; i < poseMeasurements.length; i++) { | ||
| for (int j = 0; j < poseMeasurements[i].targetIds.length; j++) { | ||
| if (cameraTagPoses.get(cameraIndex).containsKey(poseMeasurements[i].targetIds[j])) { | ||
| cameraTagPoses | ||
| .get(cameraIndex) | ||
| .get(poseMeasurements[i].targetIds[j]) | ||
| .add(poseMeasurements[i]); | ||
| } else { | ||
| // make new key if first time tag is being seen | ||
| List<VisionPoseMeasurement> poseMeasurementList = | ||
| new ArrayList<VisionPoseMeasurement>(); | ||
| poseMeasurementList.add(poseMeasurements[i]); | ||
| cameraTagPoses | ||
| .get(cameraIndex) | ||
| .put(poseMeasurements[i].targetIds[j], poseMeasurementList); | ||
| } | ||
| } |
There was a problem hiding this comment.
reminder for dan to reread
| public static class VisionPoseMeasurement { | ||
| public double timestamp = -1.0; | ||
| public Pose2d robotPose = new Pose2d(); | ||
| public int[] targetIds = new int[0]; | ||
| public double robotToBestTargetDistanceInMeters = -1.0; | ||
| } |
There was a problem hiding this comment.
Looking at this again: why does this class have to be static?
The Vision Subsystem.
Includes: