You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Patch #2841 introduced a check in YARP 3.7.0 that, under certain circumstances, prevents controlBoard_nws_yarp from broadcasting state (ports /state:o and /stateExt:o) to clients (namely its NWC counterpart, i.e. remote_controlboard). This encompasses encoder data as well as torques, currents, control modes, etc. The check itself consists of a comparison of timestamps as returned by IEncodersTimed::getEncodersTimed. If any of these timestamps (each corresponding to one wrapped joint) is more than one second apart from the others, the check claims this situation is inconsistent and prevents from dispatching the port write further down in the code:
// Check if the encoders timestamps are consistent.
for (double tt : times)
{
if (std::abs(times[0] - tt) > 1.0)
{
yCError(CONTROLBOARD, "Encoder Timestamps are not consistent! Data will not be published.");
yarp::sig::Vector _data(subdevice_joints);
return;
}
}
As I observed in #2862 (comment), this consistency checking can break some workflows:
In our hardware setup, there is one physical motion controller per joint, connected via CAN bus to a CPU where our centralized control board implementation resides. Often, we observe communication issues on specific (not all) controllers, but we are prepared to deal with that: relying on a heartbeat signal, the conflicting device is restarted when a reasonable timeout elapses. We are able to command working joints while some others are still trying to restart, i.e. in our case robot joints are somewhat independent from each other.
The first point I'd like to bring up in this issue is: what was the rationale behind the introduction of this consistency check and what problems does it aim to solve?
In my opinion, disabling state broadcasting is a bit draconian (clients can no longer attend to robot state just because one single joint is off sync) and inconsistency could be handled differently, i.e. through return codes. These are already broadcast through the same port along with proper data (see Boolean fields here).
The times vector as it appears in the previous snippet is only used as the envelope of both state ports after averaging:
This envelope is read by the NWC counterpart, RemoteControlBoard, and stored in a class variable named lastStamphere. Clients that want to retrieve certain data (broadcast by said state ports, such as current torques) will trigger a local save of the timestamp enveloping the last state message: ref.
Although this operation (retrieve time envelope) is repeated in several places throughout the NWC's code, lastStamp is only consumed (read from) in two situations:
Interface calls to IEncodersTimed::{getEncoderTimed,getEncodersTimed} and IMotorEncoders::{getMotorEncoderTimed,getMotorEncodersTimed}. Please note the timestamps we get here are the average of all timestamps, contrary to the interface contract which says "stamps: pointer to the array that will contain individual timestamps".
An interface call to IPreciselyTimed::getLastInputStamphere. The contract specifies that this is the "time stamp relative to the last acquisition", which seems correct, but...
...I believe lastStamp is still being misused in both situations. In the former, since we don't expect an average stamp according to the documentation. In the latter, because lastStamp is also set whenever the client performs an RPC call that contains timestamp information, see getTimestamp. Example: if a client calls getRefTorque(), the NWC will internally update lastStamp (for further use as an average stamp of encoder data and last acquisition stamp; see the two points explained earlier) despite not having received any data through the state ports for a while. As far as I can guess the purpose behind the consistency checker, I believe this behavior invalidates it. Interestingly, the stamp returned by RPC calls, generated on the NWS side, is simply the current timestamp at the time said RPC call was performed: ref.
Proposed course of action (depending on the first point: what was the purpose of the consistency checker)
Revert CB_NWS encoder check #2841 per the above reasons (draconian solution, we lose information about current state, a single faulty joint invalidates the whole robot part). Detect inconsistency through return codes instead, e.g. let consumers deduce it from the boolean returned by getEncoder and similar. This might require action on the implementor's side: if my joint is not responding, return false and let it flow through the NWS/NWC pair down to remote callers.
Make /state:o and /stateExt:o use the current stamp as the port envelope instead of averaging anything, consistently with the behavior of current RPC calls.
(probably a protocol breaker, then to be considered for YARP 4) Include proper per-joint timestamps in the joint data message, i.e. add a VectorOfDouble stamps field in the jointData struct and populate it with the return values of the second out array parameter in getEncodersTimed.
Regarding IPreciselyTimed::getLastInputStamp: in order to be consistent with the contract, use the most recent stamp obtained in the previous point (assuming "time stamp relative to the last acquisition" means "the last time we got a response from the real hardware", not "the last time we called the raw subdevice").
Patch #2841 introduced a check in YARP 3.7.0 that, under certain circumstances, prevents controlBoard_nws_yarp from broadcasting state (ports
/state:oand/stateExt:o) to clients (namely its NWC counterpart, i.e. remote_controlboard). This encompasses encoder data as well as torques, currents, control modes, etc. The check itself consists of a comparison of timestamps as returned byIEncodersTimed::getEncodersTimed. If any of these timestamps (each corresponding to one wrapped joint) is more than one second apart from the others, the check claims this situation is inconsistent and prevents from dispatching the port write further down in the code:yarp/src/devices/controlBoard_nws_yarp/ControlBoard_nws_yarp.cpp
Lines 511 to 520 in 920ecde
As I observed in #2862 (comment), this consistency checking can break some workflows:
The first point I'd like to bring up in this issue is: what was the rationale behind the introduction of this consistency check and what problems does it aim to solve?
In my opinion, disabling state broadcasting is a bit draconian (clients can no longer attend to robot state just because one single joint is off sync) and inconsistency could be handled differently, i.e. through return codes. These are already broadcast through the same port along with proper data (see Boolean fields here).
The
timesvector as it appears in the previous snippet is only used as the envelope of both state ports after averaging:yarp/src/devices/controlBoard_nws_yarp/ControlBoard_nws_yarp.cpp
Lines 522 to 527 in 920ecde
This envelope is read by the NWC counterpart, RemoteControlBoard, and stored in a class variable named
lastStamphere. Clients that want to retrieve certain data (broadcast by said state ports, such as current torques) will trigger a local save of the timestamp enveloping the last state message: ref.Although this operation (retrieve time envelope) is repeated in several places throughout the NWC's code,
lastStampis only consumed (read from) in two situations:IEncodersTimed::{getEncoderTimed,getEncodersTimed}andIMotorEncoders::{getMotorEncoderTimed,getMotorEncodersTimed}. Please note the timestamps we get here are the average of all timestamps, contrary to the interface contract which says "stamps: pointer to the array that will contain individual timestamps".IPreciselyTimed::getLastInputStamphere. The contract specifies that this is the "time stamp relative to the last acquisition", which seems correct, but......I believe
lastStampis still being misused in both situations. In the former, since we don't expect an average stamp according to the documentation. In the latter, becauselastStampis also set whenever the client performs an RPC call that contains timestamp information, seegetTimestamp. Example: if a client callsgetRefTorque(), the NWC will internally updatelastStamp(for further use as an average stamp of encoder data and last acquisition stamp; see the two points explained earlier) despite not having received any data through the state ports for a while. As far as I can guess the purpose behind the consistency checker, I believe this behavior invalidates it. Interestingly, the stamp returned by RPC calls, generated on the NWS side, is simply the current timestamp at the time said RPC call was performed: ref.Proposed course of action (depending on the first point: what was the purpose of the consistency checker)
getEncoderand similar. This might require action on the implementor's side: if my joint is not responding, returnfalseand let it flow through the NWS/NWC pair down to remote callers./state:oand/stateExt:ouse the current stamp as the port envelope instead of averaging anything, consistently with the behavior of current RPC calls.VectorOfDouble stampsfield in thejointDatastruct and populate it with the return values of the second out array parameter ingetEncodersTimed.IPreciselyTimed::getLastInputStamp: in order to be consistent with the contract, use the most recent stamp obtained in the previous point (assuming "time stamp relative to the last acquisition" means "the last time we got a response from the real hardware", not "the last time we called the raw subdevice").cc @randaz81