Rio not receiving NetworkTable updates from Raspberry Pi

Hello, and greetings from team 4119!

I am the programmer in charge of our vision programming, which we have never done before, so this is new to everyone on our team.

We’ve decided to go with running our vision on a pi and communicating results through NetworkTables. This has been working wonderfully, but the last part of the code, where the robot checks and listens for changes has not been working. When the co-processor (client) changes the value, the variables view of the FRC dashboard (and the outline viewer) update with the correct value, but the rio (server) does not notice a change.

Just as a warning, I have been writing extremely rough code to learn about the systems I am working with.

Here is the relevant coprocessor code, written in C++ (a language I like more than Java, just as a matter of personal preference). I am using the frcvision raspbian image. This code is working- this sample is more intended to show the architecture of my system and how I am configuring my networktable. I removed a lot of irrelevant things and cleaned up parts of the code for the purposes of this post.

#include "cameraserver/CameraServer.h"

#include <cscore.h>
#include <cscore_cv.h>

#include <iostream>
#include <vector>
#include <string>

#include "networktables/NetworkTable.h"
#include "networktables/NetworkTableEntry.h"
#include "networktables/NetworkTableInstance.h"
#include "networktables/EntryListenerFlags.h"

#define CAMERA_WIDTH  160
#define CAMERA_HEIGHT 120

 bool outerPort_paused = true;

void OuterPortFinder(cv::Mat& image) {
    /** removed the code to find the outer port- it works and is beyond the scope of this post */
    nt::NetworkTableInstance::GetDefault().GetEntry("Vision/OuterPortAngle").SetDouble(angle);
    return;
}

void getFrame(cs::CvSink& sink) {
    cv::Mat image;
    sink.GrabFrame(image);
    if (image.empty()) {
        return;
    }

    if (!outerPort_paused) {
        OuterPortFinder(image);
    }
}

int main() {
    cs::UsbCamera camera = frc::CameraServer::GetInstance()->StartAutomaticCapture();
    camera.SetResolution(CAMERA_WIDTH, CAMERA_HEIGHT);
    camera.SetExposureManual(0);
    
    cs::CvSink sink = frc::CameraServer::GetInstance()->GetVideo();
    
    nt::NetworkTableInstance inst = nt::NetworkTableInstance::GetDefault();
    std::shared_ptr<nt::NetworkTable> vision = inst.GetTable("Vision");

    inst.StartClientTeam(4119);
    
    vision->AddEntryListener([vision](nt::NetworkTable* table, std::string name, nt::NetworkTableEntry entry, std::shared_ptr<nt::Value> value, int flags) {
        if (name == "OuterPortFinder") {
            outerPort_paused = !value; // this works
        }
    }, nt::EntryListenerFlags::kNew | nt::EntryListenerFlags::kUpdate);
    
    while (true) {
        getFrame(sink);
    }
}

Here is the relevant part of my robot code, written in Java (because it’s what my team uses for its robot code- more people on my team need to be able to understand this code). I’m using the TimedRobot Skeleton template because there wasn’t really a motivation for me to use the whole command-based structure here for this simple test.

I have tried using listeners here, but they suffered from the same problem of not registering changes. I believe it is because the robot is not receiving the changes from the pi.

package frc.robot;
 
import edu.wpi.first.wpilibj.TimedRobot;
import edu.wpi.first.wpilibj.XboxController;

import edu.wpi.first.networktables.EntryListenerFlags;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;

public class Robot extends TimedRobot {
  XboxController xbox = new XboxController(0);
  NetworkTableEntry outerPortFinder;
  NetworkTableEntry outerPortAngle;

  boolean outerPortFinderActive = false;
  NetworkTableInstance inst;

  double visionAngle;
  @Override
  public void robotInit() {
    inst = NetworkTableInstance.getDefault();
    outerPortFinder = inst.getEntry("/Vision/OuterPortFinder");
    outerPortAngle = inst.getEntry("/Vision/OuterPortAngle");
  }
 
  @Override
  public void autonomousInit() {
  }
 
  @Override
  public void autonomousPeriodic() {
  }
 
  @Override
  public void teleopInit() {
  }
 
  @Override
  public void teleopPeriodic() {
    boolean pressed = xbox.getAButton();
    if (outerPortFinderActive != pressed) {
      outerPortFinderActive = pressed;
      System.out.println("Camera State Changed.");
      outerPortFinder.setBoolean(outerPortFinderActive); // tell coprocessor to turn on/off- this works!
    }

    if (outerPortFinderActive) {
      double currentAngle = outerPortAngle.getDouble(visionAngle);
      // <--------------- Code not working here
      // this always prints 0.0, no matter what the value is in OutlineViewer etc
      System.out.println(currentAngle);
      if (currentAngle != visionAngle) {
        visionAngle = currentAngle;
        // code is never executed
      }
    }
  }
 
  @Override
  public void testInit() {
  }
 
  @Override
  public void testPeriodic() {
  }
}

I have the correct team number entered in both the raspberry PI console and in driverstation.

What exactly am I doing wrong here, or what should I check for next? Thank you.

This is the issue. When using NetworkTableInstance.getEntry() to get an entry (rather than e.g. getTable() to get a NetworkTable, then NetworkTable.getEntry() to get an entry), the string used must exactly match. NetworkTableInstance.getEntry() has no concept of tables/subtables, so it doesn’t prepend a leading “/” if the passed-in string doesn’t have one.

1 Like

Thank you very much, that worked :smiley:

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.