Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 0 additions & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ sphinx-autobuild==2024.10.3
sphinx-basic-ng==1.0.0b2
sphinx-notfound-page==1.1.0
sphinx-rtd-theme==3.0.2
sphinx-tabs==3.4.7
sphinx_design==0.6.1
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
Expand Down
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With more LED support added to these hardware configuration files, I'm not sure hidden in the documentation is the best spot for them anymore. It feels more appropriate to install them in the images available for download, like is done for Luma P1. However, I'm also not sure if I like the sqlite database being committed for just hardware config, since it is a lot harder to view the contents of a sqlite than it is for JSON.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely agree. Maybe for 27. Let's talk about committing Jason files but converting them using some sort of Java tool?

Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
"ledPins" : [ 13, 18 ],
"ledsCanDim" : true,
"ledPWMFrequency" : 30000,
"statusLEDType": "Green-Yellow",
"statusLEDPins": [ 5, 4 ],
"statusLEDActiveHigh": false,
"vendorFOV" : 75.76079874010732
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
"supportURL" : "https://limelightvision.io",
"ledPins" : [ 17, 18 ],
"ledsCanDim" : false,
"statusLEDType": "Green-Yellow",
"statusLEDPins": [ 5, 4 ],
"statusLEDActiveHigh": false,
"vendorFOV" : 75.76079874010732
}
19 changes: 12 additions & 7 deletions docs/source/docs/hardware/customhardware.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@ When running on Linux, PhotonVision can use [diozero](https://www.diozero.com) t
"ledsCanDim" : true,
"ledBrightnessRange" : [ 0, 100 ],
"ledPWMFrequency" : 0,
"statusRGBPins" : [ ],
"statusRGBActiveHigh" : false,
"statusLEDType": "RGB",
"statusLEDPins" : [ ],
"statusLEDActiveHigh" : false,
}
```

:::{note}
No hardware boards with status RGB LED pins or non-dimming LED's have been tested yet. Please reach out to the development team if these features are desired, they can assist with configuration and testing.
:::
There are currently two types of status LEDs supported:

* `RGB` (default): A singular LED mixing separate red, green, and blue inputs
* `GY`/`Green-Yellow`: A pair of independent green and yellow LEDs

For an explanation of the colors used for status LEDs, see {ref}`Status LEDs<docs/troubleshooting/status-leds:Status LEDs>`

### GPIO Pinout

Expand Down Expand Up @@ -144,8 +148,9 @@ Here is a complete example `hardwareConfig.json`:
"ledsCanDim" : true,
"ledBrightnessRange" : [ 0, 100 ],
"ledPWMFrequency" : 0,
"statusRGBPins" : [ ],
"statusRGBActiveHigh" : false,
"statusLEDType": "RGB",
"statusLEDPins" : [ ],
"statusLEDActiveHigh" : false,
"getGPIOCommand" : "getGPIO {p}",
"setGPIOCommand" : "setGPIO {p} {s}",
"setPWMCommand" : "setPWM {p} {v}",
Expand Down
15 changes: 15 additions & 0 deletions docs/source/docs/troubleshooting/images/led.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/source/docs/troubleshooting/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
common-errors
logging
status-leds
camera-troubleshooting
networking-troubleshooting
unix-commands
Expand Down
92 changes: 92 additions & 0 deletions docs/source/docs/troubleshooting/status-leds.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
myst:
substitutions:
led_loader: |
```{image} images/led.svg
:height: 0
```
led_green: |
```{raw} html
<object data="../../_images/led.svg">
<param name="onColor" value="limegreen"/>
</object>
```
led_solid_blue: |
```{raw} html
<object data="../../_images/led.svg">
<param name="onColor" value="blue"/>
<param name="onTime" value="indefinite"/>
</object>
```
led_yellow: |
```{raw} html
<object data="../../_images/led.svg">
<param name="onColor" value="yellow"/>
</object>
```
led_blue: |
```{raw} html
<object data="../../_images/led.svg">
<param name="onColor" value="blue"/>
</object>
```
led_red: |
```{raw} html
<object data="../../_images/led.svg">
<param name="onColor" value="red"/>
</object>
```
led_off: |
```{raw} html
<object data="../../_images/led.svg">
<param name="onColor" value="transparent"/>
<param name="onTime" value="indefinite"/>
</object>
```
led_fast_green: |
```{raw} html
<object data="../../_images/led.svg">
<param name="onColor" value="limegreen"/>
<param name="onTime" value="75ms"/>
<param name="offTime" value="75ms"/>
</object>
```
led_solid_yellow: |
```{raw} html
<object data="../../_images/led.svg">
<param name="onColor" value="yellow"/>
<param name="onTime" value="indefinite"/>
</object>
```
---

# Status LEDs

PhotonVision has support for multiple kinds of status LEDs. Make sure you reference the correct table for the type present on your hardware.

## RGB LED

Color | Flashing | Preview | Status
--------|----------|:--------------------:|-----------------------------------------------
Green | Yes | {{ led_green }} | Running normally, no targets visible
Blue | No | {{ led_solid_blue }} | Running normally, targets visible
Yellow | Yes | {{ led_yellow }} | NT Disconnected, no targets visible
Blue | Yes | {{ led_blue }} | NT Disconnected, targets visible
Red | Yes | {{ led_red }} | Initializing or faulted, not running
Off | No | {{ led_off }} | No power or initialization fault, not running

## Green and Yellow LEDs

Used on Limelight 1, 2, 2+, 3, 3G, and 3A

Green and Yellow LED patterns may be active at the same time

Color | Pattern | Preview | Status
--------|----------------|:------------------------------------:|-------------------------------------------------
Green | Slow Flashing | {{ led_green }} {{ led_off }} | No targets visible
Green | Quick Flashing | {{ led_fast_green }} {{ led_off }} | Targets visible
Yellow | Flashing | {{ led_off }} {{ led_yellow }} | NT Disconnected
Yellow | Solid | {{ led_off }} {{ led_solid_yellow }} | NT Connected
Both | Off | {{ led_off }} {{ led_off }} | No power, initializing, or faulted, not running

{{ led_loader }}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@

package org.photonvision.common.configuration;

import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.ArrayList;
import org.photonvision.common.hardware.statusLED.StatusLEDType;

@JsonIgnoreProperties(ignoreUnknown = true)
public class HardwareConfig {
Expand All @@ -31,8 +33,13 @@ public class HardwareConfig {
public final boolean ledsCanDim;
public final ArrayList<Integer> ledBrightnessRange;
public final int ledPWMFrequency;
public final ArrayList<Integer> statusRGBPins;
public final boolean statusRGBActiveHigh;
public final StatusLEDType statusLEDType;

@JsonAlias("statusRGBPins")
public final ArrayList<Integer> statusLEDPins;

@JsonAlias("statusRGBActiveHigh")
public final boolean statusLEDActiveHigh;

// Custom GPIO
public final String getGPIOCommand;
Expand All @@ -53,8 +60,9 @@ public HardwareConfig(
boolean ledsCanDim,
ArrayList<Integer> ledBrightnessRange,
int ledPwmFrequency,
ArrayList<Integer> statusRGBPins,
boolean statusRGBActiveHigh,
StatusLEDType statusLEDType,
ArrayList<Integer> statusLEDPins,
boolean statusLEDActiveHigh,
String getGPIOCommand,
String setGPIOCommand,
String setPWMCommand,
Expand All @@ -69,8 +77,9 @@ public HardwareConfig(
this.ledsCanDim = ledsCanDim;
this.ledBrightnessRange = ledBrightnessRange;
this.ledPWMFrequency = ledPwmFrequency;
this.statusRGBPins = statusRGBPins;
this.statusRGBActiveHigh = statusRGBActiveHigh;
this.statusLEDType = statusLEDType;
this.statusLEDPins = statusLEDPins;
this.statusLEDActiveHigh = statusLEDActiveHigh;
this.getGPIOCommand = getGPIOCommand;
this.setGPIOCommand = setGPIOCommand;
this.setPWMCommand = setPWMCommand;
Expand All @@ -88,8 +97,9 @@ public HardwareConfig() {
ledsCanDim = false;
ledBrightnessRange = new ArrayList<>();
ledPWMFrequency = 0;
statusRGBPins = new ArrayList<>();
statusRGBActiveHigh = false;
statusLEDType = StatusLEDType.RGB;
statusLEDPins = new ArrayList<>();
statusLEDActiveHigh = false;
getGPIOCommand = "";
setGPIOCommand = "";
setPWMCommand = "";
Expand Down Expand Up @@ -133,10 +143,12 @@ public String toString() {
+ ledBrightnessRange
+ ", ledPWMFrequency="
+ ledPWMFrequency
+ ", statusRGBPins="
+ statusRGBPins
+ ", statusRGBActiveHigh"
+ statusRGBActiveHigh
+ ", statusLEDType="
+ statusLEDType
+ ", statusLEDPins="
+ statusLEDPins
+ ", statusLEDActiveHigh"
+ statusLEDActiveHigh
+ ", getGPIOCommand="
+ getGPIOCommand
+ ", setGPIOCommand="
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.photonvision.common.dataflow.networktables.NetworkTablesManager;
import org.photonvision.common.hardware.gpio.CustomAdapter;
import org.photonvision.common.hardware.gpio.CustomDeviceFactory;
import org.photonvision.common.hardware.statusLED.StatusLED;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
import org.photonvision.common.util.ShellExec;
Expand Down Expand Up @@ -102,12 +103,11 @@ public NativeDeviceFactoryInterface get() {
};

statusLED =
hardwareConfig.statusRGBPins.size() == 3
? new StatusLED(
lazyDeviceFactory.get(),
hardwareConfig.statusRGBPins,
hardwareConfig.statusRGBActiveHigh)
: null;
StatusLED.ofType(
hardwareConfig.statusLEDType,
lazyDeviceFactory,
hardwareConfig.statusLEDPins,
hardwareConfig.statusLEDActiveHigh);

var hasBrightnessRange = hardwareConfig.ledBrightnessRange.size() == 2;
visionLED =
Expand Down Expand Up @@ -161,7 +161,7 @@ public static NativeDeviceFactoryInterface configureCustomGPIO(HardwareConfig ha
pinInfo.addGpioPinInfo(pin, pin, List.of(DeviceMode.DIGITAL_OUTPUT));
}
}
for (int pin : hardwareConfig.statusRGBPins) {
for (int pin : hardwareConfig.statusLEDPins) {
pinInfo.addGpioPinInfo(pin, pin, List.of(DeviceMode.DIGITAL_OUTPUT));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (C) Photon Vision.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package org.photonvision.common.hardware.statusLED;

import com.diozero.devices.LED;
import com.diozero.internal.spi.NativeDeviceFactoryInterface;
import java.util.List;
import org.photonvision.common.hardware.PhotonStatus;
import org.photonvision.common.util.TimedTaskManager;

/** A pair of green and yellow LEDs, as used on the Limelight cameras */
public class GYStatusLED implements StatusLED {
public final LED greenLED;
public final LED yellowLED;
protected int blinkCounter;

protected PhotonStatus status = PhotonStatus.GENERIC_ERROR;

public GYStatusLED(
NativeDeviceFactoryInterface deviceFactory, List<Integer> statusLedPins, boolean activeHigh) {
// fill unassigned pins with -1 to disable
if (statusLedPins.size() != 3) {
for (int i = 0; i < 3 - statusLedPins.size(); i++) {
statusLedPins.add(-1);
}
}

// Outputs are active-low for a common-anode RGB LED
greenLED = new LED(deviceFactory, statusLedPins.get(0), activeHigh, false);
yellowLED = new LED(deviceFactory, statusLedPins.get(1), activeHigh, false);

TimedTaskManager.getInstance().addTask("StatusLEDUpdate", this::updateLED, 75);
}

protected void setLEDs(boolean green, boolean yellow) {
greenLED.setOn(green);
yellowLED.setOn(yellow);
}

@Override
public void setStatus(PhotonStatus status) {
this.status = status;
}

protected void updateLED() {
boolean slowBlink = blinkCounter > 1;
boolean fastBlink = (blinkCounter % 2) > 0;

switch (status) {
case NT_CONNECTED_TARGETS_VISIBLE ->
// Green fast, yellow on
setLEDs(fastBlink, true);
case NT_CONNECTED_TARGETS_MISSING ->
// Green slow, yellow on
setLEDs(slowBlink, true);
case NT_DISCONNECTED_TARGETS_VISIBLE ->
// Green fast, yellow slow
setLEDs(fastBlink, slowBlink);
case NT_DISCONNECTED_TARGETS_MISSING ->
// Green slow, yellow slow
setLEDs(slowBlink, slowBlink);
case GENERIC_ERROR ->
// No lights
setLEDs(false, false);
Comment on lines +77 to +79
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am debating between no lights and a slow green blink with no yellow. There is no precedent from Limelight on this case.

}

blinkCounter++;
blinkCounter %= 6;
}

@Override
public void close() throws Exception {
greenLED.close();
yellowLED.close();
}
}
Loading
Loading