Metrics and lighting implementation (#116)

Implements metrics and lighting control.
This commit is contained in:
Matt
2020-09-15 11:19:36 -07:00
committed by GitHub
parent b73c698e4d
commit 71fc8a7017
23 changed files with 345 additions and 182 deletions

View File

@@ -47,7 +47,7 @@ public class HardwareManager {
@SuppressWarnings("FieldCanBeLocal")
private final NTDataChangeListener ledModeListener;
public final VisionLED visionLED;
public final VisionLED visionLED; // May be null if no LED is specified
public static HardwareManager getInstance() {
if (instance == null) {
@@ -61,28 +61,47 @@ public class HardwareManager {
CustomGPIO.setConfig(hardwareConfig);
MetricsBase.setConfig(hardwareConfig);
statusLED = new StatusLED(hardwareConfig.statusRGBPins);
statusLED =
hardwareConfig.statusRGBPins.size() == 3
? new StatusLED(hardwareConfig.statusRGBPins)
: null;
visionLED =
new VisionLED(
hardwareConfig.ledPins,
hardwareConfig.ledPWMFrequency,
(hardwareConfig.ledPWMRange != null && hardwareConfig.ledPWMRange.size() == 2)
? hardwareConfig.ledPWMRange.get(1)
: 0);
hardwareConfig.ledPins.isEmpty()
? null
: new VisionLED(
hardwareConfig.ledPins,
hardwareConfig.ledPWMFrequency,
(hardwareConfig.ledPWMRange != null && hardwareConfig.ledPWMRange.size() == 2)
? hardwareConfig.ledPWMRange.get(1)
: 0);
ledModeEntry = NetworkTablesManager.getInstance().kRootTable.getEntry("ledMode");
ledModeEntry.setNumber(VisionLEDMode.VLM_DEFAULT.value);
ledModeListener = new NTDataChangeListener(ledModeEntry, visionLED::onLedModeChange);
ledModeListener =
visionLED == null
? null
: new NTDataChangeListener(ledModeEntry, visionLED::onLedModeChange);
Runtime.getRuntime().addShutdownHook(new Thread(this::onJvmExit));
if (visionLED != null)
visionLED.setBrightness(
ConfigManager.getInstance().getConfig().getHardwareSettings().ledBrightnessPercentage);
// Start hardware metrics thread (Disabled until implemented)
// if (Platform.isLinux()) MetricsPublisher.getInstance().startTask();
}
public void setBrightnessPercent(int percent) {
ConfigManager.getInstance().getConfig().getHardwareSettings().ledBrightnessPercentage = percent;
if (visionLED != null) visionLED.setBrightness(percent);
ConfigManager.getInstance().requestSave();
logger.info("Setting led brightness to " + percent + "%");
}
private void onJvmExit() {
logger.info("Shutting down...");
visionLED.setState(false);
logger.info("Shutting down LEDs...");
if (visionLED != null) visionLED.setState(false);
}
public boolean restartDevice() {

View File

@@ -19,17 +19,23 @@ package org.photonvision.common.hardware.metrics;
public class CPUMetrics extends MetricsBase {
public CPUMetrics() {}
private String cpuMemSplit = null;
public String getMemory() {
if (cpuMemoryCommand.isEmpty()) return "";
return execute(cpuMemoryCommand);
if (cpuMemSplit == null) {
cpuMemSplit = execute(cpuMemoryCommand);
}
return cpuMemSplit;
}
// TODO: Command should return in Celsius
public String getTemp() {
if (cpuTemperatureCommand.isEmpty()) return "";
return execute(cpuTemperatureCommand);
try {
return execute(cpuTemperatureCommand);
} catch (Exception e) {
return "N/A";
}
}
public String getUtilization() {

View File

@@ -18,11 +18,16 @@
package org.photonvision.common.hardware.metrics;
public class GPUMetrics extends MetricsBase {
public String getMemory() {
return execute(gpuMemoryCommand);
private String gpuMemSplit = null;
public String getGPUMemorySplit() {
if (gpuMemSplit == null) {
gpuMemSplit = execute(gpuMemoryCommand);
}
return gpuMemSplit;
}
public String getTemp() {
return execute(gpuTemperatureCommand);
public String getMallocedMemory() {
return execute(gpuMemUsageCommand);
}
}

View File

@@ -26,18 +26,18 @@ import org.photonvision.common.util.ShellExec;
public abstract class MetricsBase {
private static final Logger logger = new Logger(MetricsBase.class, LogGroup.General);
// CPU
public static String cpuMemoryCommand = "sudo vcgencmd get_mem arm | grep -Eo '[0-9]+'";
public static String cpuMemoryCommand = "vcgencmd get_mem arm | grep -Eo '[0-9]+'";
public static String cpuTemperatureCommand =
"sudo cat /sys/class/thermal/thermal_zone0/temp | grep -x -E '[0-9]+'";
"sed 's/.\\{3\\}$/.&/' <<< cat /sys/class/thermal/thermal_zone0/temp";
public static String cpuUtilizationCommand =
"sudo top -bn1 | grep \"Cpu(s)\" | sed \"s/.*, *\\([0-9.]*\\)%* id.*/\\1/\" | awk '{print 100 - $1}'";
"top -bn1 | grep \"Cpu(s)\" | sed \"s/.*, *\\([0-9.]*\\)%* id.*/\\1/\" | awk '{print 100 - $1}'";
// GPU
public static String gpuMemoryCommand = "sudo vcgencmd get_mem gpu | grep -Eo '[0-9]+'";
public static String gpuTemperatureCommand = "sudo vcgencmd measure_temp | sed 's/[^0-9]*//g'\n";
public static String gpuMemoryCommand = "vcgencmd get_mem gpu | grep -Eo '[0-9]+'";
public static String gpuMemUsageCommand = "vcgencmd get_mem malloc | grep -Eo '[0-9]+'";
// RAM
public static String ramUsageCommand = "sudo free | awk -v i=2 -v j=3 'FNR == i {print $j}'";
public static String ramUsageCommand = "free --mega | awk -v i=2 -v j=3 'FNR == i {print $j}'";
private static ShellExec runCommand = new ShellExec(true, true);
@@ -48,7 +48,7 @@ public abstract class MetricsBase {
cpuUtilizationCommand = config.cpuUtilCommand;
gpuMemoryCommand = config.gpuMemoryCommand;
gpuTemperatureCommand = config.gpuTempCommand;
gpuMemUsageCommand = config.gpuMemUsageCommand;
ramUsageCommand = config.ramUtilCommand;
}

View File

@@ -17,15 +17,15 @@
package org.photonvision.common.hardware.metrics;
import com.fasterxml.jackson.core.JsonProcessingException;
import java.util.HashMap;
import org.photonvision.common.dataflow.DataChangeService;
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
import org.photonvision.common.hardware.Platform;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
import org.photonvision.common.util.TimedTaskManager;
import org.photonvision.server.SocketHandler;
public class MetricsPublisher {
private final HashMap<String, String> metrics;
private static final Logger logger = new Logger(MetricsPublisher.class, LogGroup.General);
private static CPUMetrics cpuMetrics;
private static GPUMetrics gpuMetrics;
@@ -39,26 +39,6 @@ public class MetricsPublisher {
cpuMetrics = new CPUMetrics();
gpuMetrics = new GPUMetrics();
ramMetrics = new RAMMetrics();
metrics = new HashMap<>();
}
public void startTask() {
TimedTaskManager.getInstance()
.addTask(
"Metrics",
() -> {
metrics.put("cpuTemp", cpuMetrics.getTemp());
metrics.put("cpuUtil", cpuMetrics.getUtilization());
metrics.put("cpuMem", cpuMetrics.getMemory());
metrics.put("gpuTemp", gpuMetrics.getTemp());
metrics.put("gpuMem", gpuMetrics.getMemory());
metrics.put("ramUtil", ramMetrics.getUsedRam());
DataChangeService.getInstance()
.publishEvent(new OutgoingUIEvent<>("metrics", metrics));
},
1000);
}
public void stopTask() {
@@ -66,6 +46,32 @@ public class MetricsPublisher {
logger.info("This device does not support running bash commands. Stopped metrics thread.");
}
public void publish() {
if (!Platform.isRaspberryPi()) {
logger.debug("Ignoring metrics on non-Pi devices");
return;
}
logger.debug("Publishing Metrics...");
final var metrics = new HashMap<String, String>();
metrics.put("cpuTemp", cpuMetrics.getTemp());
metrics.put("cpuUtil", cpuMetrics.getUtilization());
metrics.put("cpuMem", cpuMetrics.getMemory());
metrics.put("gpuMem", gpuMetrics.getGPUMemorySplit());
metrics.put("ramUtil", ramMetrics.getUsedRam());
metrics.put("gpuMemUtil", gpuMetrics.getMallocedMemory());
var retMap = new HashMap<String, Object>();
retMap.put("metrics", metrics);
try {
SocketHandler.getInstance().broadcastMessage(retMap, null);
} catch (JsonProcessingException e) {
logger.error("Exception while sending metrics!", e);
}
}
private static class Singleton {
public static final MetricsPublisher INSTANCE = new MetricsPublisher();
}