I’m the lead (and only) programmer of team 3603. Last season I was asked to learn how to do vision processing. The way that I found worked best (as in with the highest accuracy) was with a Kangaroo running GRIP. The Kangaroo ran on the robot, did all of the processing in GRIP, and published the data to NetworkTables for the roboRio to use.
The accuracy was perfect. However, this system wasn’t reliable enough. Every once in a while there would be no communication between the Kangaroo and the roboRio. In the beginning stages whenever this occurred, the robot code would completely crash. It had no consistency with when it worked. I made it so the code wouldn’t crash by adding in a try/catch statement. It caught the “TableKeyNotDefinedException”. I found that one when reading through the libraries trying to find some exception I could use.
It caught the exception so the code didn’t crash, but I want to know why sometimes the network table key wasn’t defined. I’ve tried various combinations of kangaroo on first, robot second, putting time between each one, etc., but no one system had more consistency than the other.
Why was the table key defined sometimes and not others?
Is something wrong with NetworkTables itself?
If so, how can I get around it?
Is there something better than NetworkTables?
I am not willing to change the system to something completely different, such as using raspberry pi’s, unless there is a step by step guide where I can also ask someone questions along the way.
What you’re experiencing is a race condition between the code running on your robot and the Kangaroo successfully establishing a connection to the robot and setting the table keys. The NetworkTable server is started just before your robot code; if the Kangaroo connected before your robot code read the value, the key existed, but sometimes your code was trying to read the value before the connection was established, in which case the key did not exist.
Naturally you don’t want your robot code to wait for the Kangaroo to connect; doing so would have even worse failure modes (what if the Kangaroo lost power, or the Ethernet connection to it came loose?). This race is fundamental to any network communication, not just NetworkTables.
What this means is you need to deal with this situation and determine what your code should do when the table value isn’t set. Your experience with TableKeyNotDefinedException is why we deprecated the exception-raising methods a couple of years ago (and in fact they’ve been removed entirely for 2018) in favor of getX() methods that take a default value–a value that is returned to your code if the table key does not exist. Generally that should be sufficient for most use cases (e.g. usually there’s a reasonable default), but there are other functions available for checking for the existence of a key and even getting a list of what clients are connected to the server–so your robot code could e.g. explicitly check whether or not the Kangaroo was connected and run a different autonomous routine entirely. But I would recommend first seeing if the default-returning getX() methods will meet your need.
No, your robot code just needs reasonable handling of the case when it boots before the kangaroo. For example, you could pass a very large, or very negative, value to the get () method, then have your auto do nothing until a real value is returned.
For our auto, we used a hybrid of dead-reckoning and vision. If we never got any tracking info, we proceeded using dead reckoning. Once tracking data started coming in, we’d use it. That way a vision failure wasn’t necessarily fatal.
In fact, our dead reckoning was so accurate that often our auto scored side gears even if the ringlight failed to turn on…or if our pi was left unplugged! Robot programming must anticipate failure modes!