computer_vision_and_shooter_targeting
Differences
This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| computer_vision_and_shooter_targeting [2022/08/14 23:38] – created rfhuang | computer_vision_and_shooter_targeting [2022/08/15 00:00] (current) – rfhuang | ||
|---|---|---|---|
| Line 7: | Line 7: | ||
| ---- | ---- | ||
| + | |||
| + | ==== Detection Pipeline ==== | ||
| For this game in particular, it is advantageous to be able to reliably shoot from variable distances. To accomplish this, we needed to figure out a reliable method of targeting the goal and choosing the right shooter speeds. When we saw that there were retro reflective tape strips that lined the goals, we immediately looked into using CV. \\ | For this game in particular, it is advantageous to be able to reliably shoot from variable distances. To accomplish this, we needed to figure out a reliable method of targeting the goal and choosing the right shooter speeds. When we saw that there were retro reflective tape strips that lined the goals, we immediately looked into using CV. \\ | ||
| Line 12: | Line 14: | ||
| In 2020, we attempted to develop in-house CV solutions for ball detection. However, this exposed many issues in our design, development, | In 2020, we attempted to develop in-house CV solutions for ball detection. However, this exposed many issues in our design, development, | ||
| - | Our main use of CV was to detect the distance from the robot from the base of the goal and to calculate the angle offset between the robot and the center of the goal. We use the angle offset to align ourselves with the goal, through the use of PID, and we use the distance | + | {{ :: |
| + | |||
| + | ---- | ||
| + | |||
| + | ==== Shooter RPM Interpolation ==== | ||
| + | |||
| + | {{ :: | ||
| + | Our main use of CV was to detect the distance from the robot from the base of the goal and to calculate the angle offset between the robot and the center of the goal. We use the angle offset to align ourselves with the goal, through the use of PID, and we interpolate | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== Other Notable Structures ==== | ||
| + | |||
| + | |||
| + | === Turn to Goal === | ||
| + | <code java> | ||
| + | if (useCV && vision.hasTarget() && System.currentTimeMillis() - start < 3000) { | ||
| + | double distance = vision.getTargetDistance(); | ||
| + | double angle = vision.getTargetAngle(); | ||
| + | double turnSpeed = angle / 50.0; | ||
| + | |||
| + | preset = interpolate(distance); | ||
| + | |||
| + | turnSpeed = MathUtil.clamp(Math.copySign(Math.max(Math.abs(turnSpeed), | ||
| + | |||
| + | if (useAlignment && Math.abs(angle) > 2) { | ||
| + | isAligned = false; | ||
| + | } else { | ||
| + | var goalPose = drivebase.getGoalPose(); | ||
| + | double centerDistance = Units.feetToMeters(vision.getTargetDistance() + 1.5 + 2); | ||
| + | double poseAngle = drivebase.getPose().getRotation().getDegrees(); | ||
| + | double transformRotation = 0; | ||
| + | if (angle < 0 && poseAngle > 0) { | ||
| + | transformRotation = angle + poseAngle; | ||
| + | } else if (angle > 0 && poseAngle > 0) { | ||
| + | transformRotation = angle + poseAngle + 90; | ||
| + | } else if (angle < 0 && poseAngle < 0) { | ||
| + | transformRotation = angle + poseAngle + 90; | ||
| + | } else if (angle > 0 && poseAngle < 0) { | ||
| + | transformRotation = angle + poseAngle + 90; | ||
| + | } | ||
| + | double newX = goalPose.getX() - centerDistance * Math.sin(Math.toRadians(transformRotation)); | ||
| + | double newY = goalPose.getY() + centerDistance * Math.cos(Math.toRadians(transformRotation)); | ||
| + | |||
| + | drivebase.resetOdometry(new Pose2d(newX, | ||
| + | } | ||
| + | |||
| + | drivebase.curvatureDrive(0, | ||
| + | } else { | ||
| + | drivebase.curvatureDrive(0, | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | === Interpolate Algorithm === | ||
| + | |||
| + | <code java> | ||
| + | public static ShooterPreset interpolate(double distance) { | ||
| + | ArrayList< | ||
| + | |||
| + | distance -= 0.5; | ||
| + | |||
| + | presets.add(new ShooterPreset(900, | ||
| + | presets.add(new ShooterPreset(1950, | ||
| + | presets.add(new ShooterPreset(2150, | ||
| + | presets.add(new ShooterPreset(2500, | ||
| + | presets.add(new ShooterPreset(2950, | ||
| + | presets.add(new ShooterPreset(3350, | ||
| + | presets.add(new ShooterPreset(4100, | ||
| + | presets.add(new ShooterPreset(4600, | ||
| + | |||
| + | ShooterPreset bottomPreset = presets.get(presets.size() - 1); | ||
| + | ShooterPreset upperPreset; | ||
| + | |||
| + | for (ShooterPreset p : presets) { | ||
| + | if (distance - p.distance < 0) { | ||
| + | bottomPreset = p; | ||
| + | break; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | try { | ||
| + | bottomPreset = presets.get(presets.indexOf(bottomPreset) - 1); | ||
| + | upperPreset = presets.get(presets.indexOf(bottomPreset) + 1); | ||
| + | } catch (IndexOutOfBoundsException e) { | ||
| + | if (distance > presets.get(presets.size() - 1).distance) { | ||
| + | bottomPreset = presets.get(presets.size() - 1); | ||
| + | } | ||
| + | upperPreset = bottomPreset; | ||
| + | } | ||
| + | |||
| + | double topRPMDifference = upperPreset.topRPM - bottomPreset.topRPM; | ||
| + | double mainRPMDifference = upperPreset.mainRPM - bottomPreset.mainRPM; | ||
| + | double dist = upperPreset.distance - bottomPreset.distance; | ||
| + | |||
| + | if (dist == 0) dist = bottomPreset.distance; | ||
| + | |||
| + | double percentage = (distance - bottomPreset.distance) / dist; | ||
| + | double topRPM = percentage * topRPMDifference + bottomPreset.topRPM; | ||
| + | double mainRPM = percentage * mainRPMDifference + bottomPreset.mainRPM; | ||
| + | | ||
| + | return new ShooterPreset(topRPM, | ||
| + | } | ||
| + | </ | ||
computer_vision_and_shooter_targeting.1660534721.txt.gz · Last modified: 2022/08/14 23:38 by rfhuang
