How to Set Up a Limelight on Your FRC Robot (Wiring, Pipelines, AprilTags)
Set up a Limelight on your FRC robot: wiring, power, static IP networking, the web UI, building pipelines, AprilTag botpose, and NetworkTables in Java.
- to read
- 11 min
- words
- 2,438
- sections
- 11
to read
words
sections
A Limelight is the fastest way to give an FRC robot eyes. It is a self-contained smart camera: an image sensor, a small Linux computer, and LEDs in one housing that runs vision pipelines on-board and publishes results to your robot over NetworkTables. You do not process pixels in your roboRIO code — you read a handful of numbers like "how far left is the target" and "where am I on the field," and act on them. That trade of flexibility for speed is exactly why so many teams reach for one when they need aiming or AprilTag localization working before their next event.
This guide walks the whole setup end to end: choosing and mounting the camera, powering and networking it, first configuration in the web UI, building a pipeline, standing up AprilTag pose estimation with MegaTag, and finally reading the values in your Java code. Everything here is checked against the current Limelight documentation as of the 2026 season. Where a detail is model- or firmware-specific, it is called out so you can confirm against the docs for your exact hardware.
Pick the right model
Limelight has shipped several generations — Limelight 1, 2/2+, 3, 3A, 3G, and 4. For AprilTag-heavy games the meaningful split is between the color-capable models and the monochrome long-range models:
- Limelight 3 / 4 use a color sensor, which you need for any color- or game-piece detection pipeline as well as AprilTags.
- Limelight 3G uses an OV9281 global-shutter monochrome sensor with a narrower 82° horizontal field of view and a replaceable M12 lens, tuned for accurate long-range AprilTag tracking (up to 50 fps at 640x480). Being monochrome, it is a poor choice if you also want color pipelines.
The exact FOV, sensor, and on-board IMU details differ per model and are version-specific — check the hardware comparison page in the Limelight docs before you buy. If you are still deciding between platforms entirely, our Limelight vs PhotonVision comparison breaks down the trade-offs.
Mounting
Mounting quality determines how much you can trust the numbers coming back. A camera that flexes or vibrates produces noisy tx/ty readings and, worse, unstable pose estimates.
Mounting tips: Bolt the Limelight to a rigid part of the frame or superstructure, not to thin sheet metal or anything that oscillates when the robot drives. Aim it so your primary targets sit in the center third of the frame at typical scoring range. A slight upward tilt often helps see AprilTags on field walls without catching ceiling glare.
For AprilTag localization, the physical position of the camera relative to your robot's center matters just as much as rigidity, because the Limelight uses it to convert what the camera sees into where the robot is. Measure that offset carefully in meters and degrees — you will enter it in the web UI later. Getting it wrong by a few centimeters shifts every pose estimate by the same amount.
Power and wiring
Limelights run on your robot's 12V system, but not directly off an unprotected battery lead. The documented method is to run two 18-20 AWG wires from the camera's power leads to an open slot on your PDP/PDH, protected by a 5A breaker in that slot.
The input range is 4.1V-16V on current models (the 2025 "red button" variant accepts 4.1V-24V, with a 30V absolute maximum). That range comfortably covers a normal FRC battery, but it is why you should never feed it through a boost regulator or an unfused tap.
Limelights can also be powered over Ethernet using a passive PoE injector on the network run — support and connectors vary by model, so confirm the exact scheme for your unit on the Limelight wiring page before cutting anything.
Wiring tip: Keep the Ethernet run to the radio short and strain-relieved. A flaky Ethernet connection is the single most common cause of "the Limelight disappears mid-match." Note that the Limelight talks over Ethernet, not the CAN bus — it does not share the CAN chain with your motor controllers.
Networking: team number and static IP
The Limelight joins your robot's network and speaks NetworkTables. Limelight OS runs a NetworkTables 4 client that auto-connects to the NT4 server on your robot based on the team number you set in the web UI's Settings tab. All of its data is published to a table named after the device (default: limelight).
Set a static IP rather than relying on DHCP. The docs recommend this because a static IP shaves several seconds off boot time and sidesteps DHCP/mDNS problems that teams have historically hit on real FRC fields with event radio firmware. Configure it in Settings as:
- IP:
10.TE.AM.11— replaceTE.AMwith your team number (team 916 →10.9.16.11) - Netmask:
255.255.255.0 - Gateway:
10.TE.AM.1
The .11 is a convention that keeps the Limelight clear of the roboRIO (.2) and radio (.1); if you run multiple Limelights, give each its own address and its own device name.
First boot: the web interface
Power the robot, connect to the same network, and open the Limelight dashboard at http://limelight.local:5801, or at http://<your-static-ip>:5801 once you have set one. You can also launch the Limelight Hardware Manager to scan for devices on the network. If the camera is brand new, use the Hardware Manager's Flash OS tab over a USB-C cable to image it with the latest Limelight OS before anything else.
The dashboard shows a live camera feed, the current pipeline's tuning controls on the side panels, and the live NetworkTables values at the bottom. This is where you will spend most of your setup time. A second stream is available at http://<ip>:5800 for putting the feed on a driver-station dashboard like Shuffleboard or Elastic.
Build your first pipeline
A pipeline is a saved set of vision settings. The Limelight stores up to 10 (indices 0-9), and you switch between them at runtime by writing the pipeline key. Each pipeline has a type, and the two you will use most are:
- Color / retroreflective — HSV thresholding to find a colored blob or a retroreflective strip lit by the LEDs. You tune hue/saturation/value ranges until only the target is highlighted, then filter by area, aspect ratio, and fullness to reject noise. Output is
tx,ty,ta, andtv. - AprilTag / fiducial — detects the field's AprilTags by ID. This is the modern default for most tasks: tags give you
tx/tyto a specific ID and full 3D field localization.
To build a color pipeline, put a target in view, drop the exposure until the image is dark except for your lit target, then widen the HSV thresholds just enough to cover the target under match lighting. Lower exposure is your friend — it cuts ambient light and makes thresholding stable. Save it to a pipeline index and note that index for your code.
AprilTags and botpose
For AprilTag work, set pipeline 0 to the AprilTag type and enable its 3D/localization functionality. Then do two things in the web UI:
- Upload the field map (the season's
.fmap) so the Limelight knows where every tag lives on the field. - Enter the camera's pose relative to robot center — the offset you measured while mounting. This is what lets the camera report the robot's location instead of just the camera's.
With both set, the Limelight computes botpose: your robot's position and rotation in field space, published as an array of x, y, z (meters) and roll, pitch, yaw (degrees) plus latency data. For 2024 and later, always use the blue-origin variant — botpose_wpiblue — because WPILib and path-planning tools standardize on a blue-corner field origin regardless of alliance. Our AprilTags explainer covers the tag families and field layout in more depth.
MegaTag vs MegaTag2
Limelight offers two localization solvers:
- MegaTag (MT1) derives the full pose — including heading — from the tag geometry alone. It works, but a single tag viewed head-on can be ambiguous, producing two plausible poses that flip back and forth.
- MegaTag2 (MT2) assumes you already know your heading and feeds it in from your gyro. Because yaw is fixed, MT2 resolves the ambiguity, stays accurate from a single tag at any distance, and tolerates image noise and slight tag-placement error far better. It is the recommended solver for 2024+.
MT2's cost is one obligation: you must call SetRobotOrientation(name, yaw, 0,0,0,0,0) every loop before you read the estimate, so the camera has a current heading. Read the result from botpose_orb_wpiblue (or getBotPoseEstimate_wpiBlue_MegaTag2() in code). The 3G and 4 can fuse an external/on-board IMU for even steadier MT2 headings.
NetworkTables values you will read
Everything the Limelight knows shows up as keys in its NetworkTables table. These are the ones you will actually use:
| Key | Meaning | Notes |
|---|---|---|
tv | Valid target? | 1 if a target exists, 0 if not |
tx | Horizontal offset to target | Degrees, negative = target is left of crosshair (~±29.8° on LL2-class lenses) |
ty | Vertical offset to target | Degrees; pair with a known height to estimate distance |
ta | Target area | Percent of the image, 0-100; a rough distance proxy |
tl | Pipeline latency | Milliseconds; add capture latency cl for the total |
tid | Primary AprilTag ID | The in-view tag the solver is keyed on |
getpipe | Active pipeline index | 0-9, the pipeline currently running |
botpose_wpiblue | Robot pose, blue origin | [x, y, z, roll, pitch, yaw, latency, …]; MegaTag1 |
botpose_orb_wpiblue | Robot pose, blue origin | MegaTag2 estimate; requires SetRobotOrientation |
pipeline | Set active pipeline | Write 0-9 to switch pipelines |
ledMode | LED control | Force on/off/blink or let the pipeline decide |
snapshot | Capture a still | Increment to trigger a snapshot for later tuning |
Reading the values in code
You can read these keys straight from the NetworkTable, but the official LimelightHelpers class (a single Java file you drop into your project) wraps all of them cleanly. Here is a minimal proportional-aim example that turns the robot until the target is centered:
import frc.robot.LimelightHelpers;
public void teleopPeriodic() {
boolean hasTarget = LimelightHelpers.getTV("limelight"); // valid target?
double tx = LimelightHelpers.getTX("limelight"); // degrees left/right of crosshair
double ty = LimelightHelpers.getTY("limelight"); // degrees up/down
double ta = LimelightHelpers.getTA("limelight"); // % of image filled
if (hasTarget) {
double kP = 0.02; // tune this
double turn = -tx * kP; // drive tx toward 0
drivetrain.arcadeDrive(0.0, turn);
}
}
Pass the device name ("limelight", or whatever you named it) to every call so the code works even with multiple cameras. For per-tag detail, LimelightHelpers.getRawFiducials("limelight") returns a RawFiducial[], each with id, txnc, tync, ta, distToCamera, distToRobot, and ambiguity.
Feeding pose into your estimator
For localization you do not aim — you fuse the Limelight's field pose into your drivetrain's pose estimator. The MT2 pattern each loop is: call LimelightHelpers.SetRobotOrientation("limelight", gyro.getYaw(), 0,0,0,0,0), then grab LimelightHelpers.PoseEstimate mt = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2("limelight"). The PoseEstimate gives you mt.pose (a Pose2d), mt.timestampSeconds, and mt.tagCount. Reject bad frames — skip when mt.tagCount == 0 or when your gyro's angular velocity exceeds 360°/s — then hand the rest to WPILib:
m_poseEstimator.addVisionMeasurement(mt.pose, mt.timestampSeconds);
That single call blends vision into your odometry, correcting drift while your wheel encoders and gyro carry you between tag sightings.
Calibration and tuning tips
- Verify the crosshair. For aiming, a small mechanical offset between camera and shooter is normal. Rather than fudge it in code, dual-calibrate the crosshair in the web UI so
tx = 0means "on target" for your mechanism. - Trust
tyovertafor distance. Target area changes with pipeline settings and lighting;tycombined with a fixed mounting angle and known target height gives a much steadier distance estimate. - Lower exposure until it hurts, then back off. For both retroreflective and AprilTag pipelines, the darkest usable image is the most reliable one. AprilTag detection wants sharp black-white edges, not brightness.
- Watch latency. Always use the timestamp from the
PoseEstimate(ortl+cl) when feeding the estimator, so WPILib knows the measurement describes where you were, not where you are. - Log and replay. Use the
snapshotkey to capture frames during a real match, then re-tune against them in the pit instead of guessing.
Frequently asked questions
Do I need a static IP, or will DHCP work?
DHCP usually works on the bench, but the docs recommend a static IP (10.TE.AM.11, netmask 255.255.255.0) for competition. It boots faster and avoids DHCP/mDNS issues that have historically bitten teams on real fields with event radio firmware.
Why is my botpose always zero or empty?
Almost always one of three things: no AprilTag is in view, you have not uploaded the season field map, or the pipeline is not set to the AprilTag type with 3D enabled. Confirm a valid tid first, then check that botpose_wpiblue populates.
MegaTag1 or MegaTag2 — which should I use?
MegaTag2 for nearly everyone. It resolves the single-tag ambiguity that makes MT1 jittery, but it requires feeding your gyro heading via SetRobotOrientation every loop. If you have a reliable gyro, MT2 is more accurate and more stable.
Can I aim and localize with one Limelight at the same time?
You can switch a single camera between an aiming pipeline and an AprilTag pipeline by writing the pipeline key, but you cannot do both simultaneously on one unit. Teams that need both at once typically run two Limelights with different device names.
How do I read Limelight values without LimelightHelpers?
Grab the table with NetworkTableInstance.getDefault().getTable("limelight") and read entries like getEntry("tx").getDouble(0.0). LimelightHelpers just wraps this and adds typed pose parsing, so it is worth using, but the raw keys are always available.
Does the Limelight use up a CAN or PWM channel?
No. It communicates entirely over Ethernet/NetworkTables and draws power from a PDP/PDH slot behind a 5A breaker. It does not occupy a CAN ID, a PWM port, or a roboRIO DIO.
Once the camera is mounted rigidly, powered through a 5A breaker, addressed statically, and publishing a clean botpose, the hard part is over — the rest is tuning kP values and deciding which vision measurements to trust. Start with a single AprilTag pipeline and MegaTag2 into your pose estimator, get that solid, and add aiming pipelines from there. For more programming and hardware walkthroughs, browse the rest of our guides.
Keep reading
More from the pit
Start learning FRC — free
Structured lessons and quizzes across every department. Create a free account to save your progress, track your team, and earn a certificate.