Hi,
Thanks for the reply. Unfortunately I’m at home now and I don’t have a call stack with me but I remember it was down in the call to get the value of one of the keys (e.g. table.getValue()). Let me layout some details about how the code is structured and perhaps someone might be able to spot what is going wrong. There are three pieces to the vision solution, a RoboRealm script, a Java application running on a PC (called the RobotVisionTargetServer), and a command based Robot program running on the Robot. The RobotVisionTargetServer communicates with RoboRealm using the a TCP socket connection in order to request image data. That part is working correctly. The communication between the Robot and the RobotVisionServer is where the NetworkTable comes into play.
On the Robot the interaction begins as follows with the Robot requesting that targeting of a specific goal type begin:
table = NetworkTable.getTable("SmartDashboard");
this.goalType = goalType;
table.addTableListener(this);
requestId = System.currentTimeMillis();
table.putNumber("TARGET_TYPE_REQUEST_ID", (double)requestId);
table.putNumber("TARGET_TYPE_REQUEST", (double)goalType);
System.out.println("Published requestId");
Notice that it registers a listener which is how it picks up the response that is supposed to be written by the RobotVisionServer application. However, it never gets that far because of the problem that we run into with the RobotVisionServer. The RobotVisionServer initializes interaction with the NetworkTable as follows. Note that address is “10.39.50.2” which is the address of our Robot. (Is the Robot address the correct one to use?)
public RobotVisionServer(String address) {
NetworkTable.setClientMode();
NetworkTable.setIPAddress(address);
NetworkTable table = NetworkTable.getTable(“SmartDashboard”);
if (table == null) {
// TBD: What to do if we can't get the table
// Does getTable return null or throw an exception.
}
table.addTableListener(this);
}
The RobotVersionServer instance also adds itself as a table listener so that it can act on the requests passed over by the Robot. One of the issues that we’re running into is when a request from the Robot is detected by the RobotVisionServer and we’re trying to read one of the keys as is indicated in the code snippet below…
public void valueChanged(ITable source, String key, Object value, boolean isNew) {
System.out.println("ValueChanged: " + key + " Value: " + value + " new: " + isNew);
// Is this a key we care about?
if (key.equals("TARGET_TYPE_REQUEST")) {
// Expecting a double value.
if (value instanceof Double) {
double reqGoal = ((Double)value).doubleValue();
// *** This line causes an exception to be thrown
Object v = table.getValue("TARGET_TYPE_REQUEST_ID");
.
.
.
}
else {
System.out.println("Received goal targeting request but value is not a Double as expected.");
}
}
}
I tried changing the table.getValue(…) to something simpler: table.getNumber(“TARGET_TYPE_REQUEST_ID”) but the same exception occurs. I’m not sure what the issue is but one of the assumptions I made is that because the Robot is writing the key “TARGET_TYPE_REQUEST_ID” first followed by the key “TARGET_TYPE_REQUEST” that when the RobotVisionServer application is notified of the change to “TARGET_TYPE_REQUEST” that the “TARGET_TYPE_REQUEST_ID” change would have already arrived and been made available. If this isn’t correct how can I ensure both values are available together since transactions have been removed?
If I comment out the getValue of the “TARGET_TYPE_REQUEST_ID” the code will run further but runs into trouble when it then tries to publish the resulting angle of the target it has detected. A similar exception occurs except this time it on writing a result out to the NetworkTable. Here’s a snippet showing the write code. All the types passed to putNumber are double primitives. The very first putNumber causes an exception:
// Exception is thrown when the line below is executed.
table.putNumber("TARGET_TYPE_RESULT", mapGoalTypeToDouble(goalType));
table.putNumber("TARGET_TYPE_RESULT_ID", currRequestId);
table.putNumber(TARGET_AVG_DISTANCE_RESULT , avgDistance);
table.putNumber("TARGET_ANGLE_RESULT", angle);
Note that these put calls are called from a Java Thread that my program creates. I have a lock object which is used for synchronization and is acquired when either the change notification performs the getValue key calls or the putNumber calls are made. (I didn’t show the synchronization here to keep the code simple). Are there any threading issues to be aware of when using the NetworkTable from multiple threads?
I’m at my wits end since the clock is running out. Any help is greatly appreciated in trying to shoot down this issue. Would we better off not using the “SmartDashboard” table?
Regards,
Rob Saccone
Mentor Team 3950