Segment.cpp
Go to the documentation of this file.
1 #include "Segment.h"
2 
3 #include <SimoxUtility/math/regression/linear.hpp>
4 
11 
15 #include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h>
17 
18 #include "SensorValues.h"
19 
21 
23 {
24 
26  Base(memoryToIceAdapter,
27  armem::robot_state::proprioceptionSegmentID.coreSegmentName,
28  arondto::Proprioception::ToAronType(),
29  1024)
30  {
31  }
32 
33  Segment::~Segment() = default;
34 
35  void
37  {
38  Base::defineProperties(defs, prefix);
39 
40  defs->optional(properties.predictionTimeWindow,
41  "prediction.TimeWindow",
42  "Duration of time window into the past to use for predictions"
43  " when requested via the PredictingMemoryInterface (in seconds).");
44  }
45 
47  {
48  Base::init();
49 
51  armem::PredictionEngine{.engineID = "Linear"},
52  [this](const PredictionRequest& request) { return this->predictLinear(request); });
53  }
54 
56  {
57  this->robotUnit = robotUnitPrx;
58 
59  std::string providerSegmentName = "Robot";
60 
61  KinematicUnitInterfacePrx kinematicUnit = robotUnit->getKinematicUnit();
62  if (kinematicUnit)
63  {
64  providerSegmentName = kinematicUnit->getRobotName();
65  }
66  else
67  {
68  ARMARX_WARNING << "Robot unit '" << robotUnit->ice_getIdentity().name << "' does not have a kinematic unit."
69  << "\n Falling back to provider segment name '" << providerSegmentName << "'.";
70  }
71  this->robotUnitProviderID = segmentPtr->id().withProviderSegmentName(providerSegmentName);
72  }
73 
74 
75 
77  const armem::Time& timestamp,
78  DebugObserverHelper* debugObserver) const
79  {
80  return doLocked([this, &timestamp, &debugObserver]()
81  {
82  return getSensorValues(timestamp, debugObserver);
83  });
84  }
85 
86 
87  static
89  getDictElement(const aron::data::Dict& dict, const std::string& key)
90  {
91  if (dict.hasElement(key))
92  {
94  }
95  return nullptr;
96  }
97 
98 
101  const armem::Time& timestamp,
102  DebugObserverHelper* debugObserver) const
103  {
104  namespace adn = aron::data;
106 
107  SensorValuesMap sensorValues;
108  int i = 0;
109 
110  Duration tFindData = Duration::MilliSeconds(0), tReadSensorValues = Duration::MilliSeconds(0);
111  TIMING_START(tProcessEntities)
112  segmentPtr->forEachEntity([&](const wm::Entity & entity)
113  {
115  {
116  TIMING_START(_tFindData)
117 
118  const wm::EntitySnapshot* snapshot = entity.findLatestSnapshotBeforeOrAt(timestamp);
119  if (not snapshot)
120  {
121  // Got no snapshot <= timestamp. Take latest instead (if present).
122  snapshot = entity.findLatestSnapshot();
123  }
124  if (snapshot)
125  {
126  data = snapshot->findInstanceData();
127  }
128 
129  TIMING_END_COMMENT_STREAM(_tFindData, "tFindData " + std::to_string(i), ARMARX_DEBUG);
130  tFindData += Duration::MicroSeconds(_tFindData.toMicroSeconds());
131  }
132  if (data)
133  {
134  TIMING_START(_tReadSensorValues)
135 
136  sensorValues.emplace(entity.id().providerSegmentName, readSensorValues(*data));
137 
138  TIMING_END_COMMENT_STREAM(_tReadSensorValues, "tReadSensorValues " + std::to_string(i), ARMARX_DEBUG)
139  tReadSensorValues += Duration::MicroSeconds(_tReadSensorValues.toMicroSeconds());
140  }
141  ++i;
142  });
143  TIMING_END_STREAM(tProcessEntities, ARMARX_DEBUG)
144 
145  if (debugObserver)
146  {
147  debugObserver->setDebugObserverDatafield(dp + "t 1.1 Process Entities (ms)", tProcessEntities.toMilliSecondsDouble());
148  debugObserver->setDebugObserverDatafield(dp + "t 1.1.1 FindData (ms)", tFindData.toMilliSecondsDouble());
149  debugObserver->setDebugObserverDatafield(dp + "t 1.1.2 ReadSensorValues (ms)", tReadSensorValues.toMilliSecondsDouble());
150  }
151 
152  return sensorValues;
153  }
154 
155 
157  {
158  return robotUnitProviderID;
159  }
160 
161  Eigen::VectorXd readJointData(const wm::EntityInstanceData& data)
162  {
163  namespace adn = aron::data;
164 
165  std::vector<double> values;
166 
167  auto addData =
168  [&](adn::DictPtr dict) // NOLINT
169  {
170  for (const auto& [name, value] : dict->getElements())
171  {
172  values.push_back(
173  static_cast<double>(adn::Float::DynamicCastAndCheck(value)->getValue()));
174  }
175  };
176 
177  if (adn::DictPtr joints = getDictElement(data, "joints"))
178  {
179  if (adn::DictPtr jointsPosition = getDictElement(*joints, "position"))
180  {
181  addData(jointsPosition);
182  }
183  if (adn::DictPtr jointsVelocity = getDictElement(*joints, "velocity"))
184  {
185  addData(jointsVelocity);
186  }
187  if (adn::DictPtr jointsTorque = getDictElement(*joints, "torque"))
188  {
189  addData(jointsTorque);
190  }
191  }
192  Eigen::VectorXd vec =
193  Eigen::Map<Eigen::VectorXd>(values.data(), static_cast<Eigen::Index>(values.size()));
194  return vec;
195  }
196 
197  void
198  emplaceJointData(const Eigen::VectorXd& jointData,
199  arondto::Proprioception& dataTemplate)
200  {
201  Eigen::Index row = 0;
202  for (auto& [joint, value] : dataTemplate.joints.position)
203  {
204  value = static_cast<float>(jointData(row++));
205  }
206  for (auto& [joint, value] : dataTemplate.joints.velocity)
207  {
208  value = static_cast<float>(jointData(row++));
209  }
210  for (auto& [joint, value] : dataTemplate.joints.torque)
211  {
212  value = static_cast<float>(jointData(row++));
213  }
214  }
215 
218  {
219  PredictionResult result;
220  result.snapshotID = request.snapshotID;
221  if (request.predictionSettings.predictionEngineID != "Linear")
222  {
223  result.success = false;
224  result.errorMessage = "Prediction engine " +
226  " is not supported in Proprioception.";
227  return result;
228  }
229 
230  const DateTime timeOrigin = DateTime::Now();
231  const armarx::Duration timeWindow = Duration::SecondsDouble(properties.predictionTimeWindow);
233 
234  doLocked(
235  // Default capture because the number of variables was getting out of hand
236  [&, this]()
237  {
239  Eigen::VectorXd,
241  segmentPtr,
242  request.snapshotID,
243  timeOrigin - timeWindow,
244  timeOrigin,
245  [](const aron::data::DictPtr& data) { return readJointData(*data); },
246  [](const aron::data::DictPtr& data) { return data; });
247  });
248 
249  if (info.success)
250  {
251  Eigen::VectorXd latestJoints = readJointData(*info.latestValue);
252  Eigen::VectorXd prediction(latestJoints.size());
253  if (info.timestampsSec.size() <= 1)
254  {
255  prediction = latestJoints;
256  }
257  else
258  {
259  using simox::math::LinearRegression;
260  const bool inputOffset = false;
261  const LinearRegression model = LinearRegression<Eigen::Dynamic>::Fit(
262  info.timestampsSec, info.values, inputOffset);
263  const auto predictionTime = request.snapshotID.timestamp;
264  prediction = model.predict((predictionTime - timeOrigin).toSecondsDouble());
265  }
266 
267  arondto::Proprioception templateData =
268  arondto::Proprioception::FromAron(info.latestValue);
269  emplaceJointData(prediction, templateData);
270  result.success = true;
271  result.prediction = templateData.toAron();
272  }
273  else
274  {
275  result.success = false;
276  result.errorMessage = info.errorMessage;
277  }
278 
279  return result;
280  }
281 
282 
284  Segment::readSensorValues(const wm::EntityInstanceData& data)
285  {
286  namespace adn = aron::data;
287 
288  // Just get what we need without casting the whole data.
289  SensorValues sensorValues;
290  auto checkJVM = [&sensorValues](const std::string& name)
291  {
292  if (sensorValues.jointValueMap.find(name) == sensorValues.jointValueMap.end())
293  {
294  sensorValues.jointValueMap[name] = JointValues();
295  }
296  };
297  if (adn::DictPtr joints = getDictElement(data, "joints"))
298  {
299  if (adn::DictPtr values = getDictElement(*joints, "position"))
300  {
301  for (const auto& [name, value] : values->getElements())
302  {
303  checkJVM(name);
304  sensorValues.jointValueMap[name].position
305  = adn::Float::DynamicCastAndCheck(value)->getValue();
306  }
307  }
308  if (adn::DictPtr values = getDictElement(*joints, "velocity"))
309  {
310  for (const auto& [name, value] : values->getElements())
311  {
312  checkJVM(name);
313  sensorValues.jointValueMap[name].velocity
314  = adn::Float::DynamicCastAndCheck(value)->getValue();
315  }
316  }
317  if (adn::DictPtr values = getDictElement(*joints, "torque"))
318  {
319  for (const auto& [name, value] : values->getElements())
320  {
321  checkJVM(name);
322  sensorValues.jointValueMap[name].velocity
323  = adn::Float::DynamicCastAndCheck(value)->getValue();
324  }
325  }
326  }
327  if (adn::DictPtr forceTorqueMap = getDictElement(data, "forceTorque"))
328  {
329  for (const auto& [name, value] : forceTorqueMap->getElements())
330  {
332  {
333  const Eigen::Vector3f torque
335  adn::NDArray::DynamicCastAndCheck(forceTorqueValues->getElement("torque")));
336 
337  const Eigen::Vector3f force
339  adn::NDArray::DynamicCastAndCheck(forceTorqueValues->getElement("force")));
340 
341  sensorValues.forceTorqueValuesMap[name] = ForceTorqueValues
342  {
343  .force = force,
344  .torque = torque
345  };
346  }
347  }
348  }
349  return sensorValues;
350  }
351 
352 } // namespace armarx::armem::server::robot_state::proprioception
armarx::armem::MemoryID::timestamp
Time timestamp
Definition: MemoryID.h:54
TIMING_START
#define TIMING_START(name)
Definition: TimeUtil.h:280
armarx::armem::PredictionRequest
Definition: Prediction.h:49
armarx::armem::PredictionResult::snapshotID
armem::MemoryID snapshotID
Definition: Prediction.h:63
armarx::armem::PredictionEngine::engineID
std::string engineID
Definition: Prediction.h:35
armarx::armem::SnapshotRangeInfo::timestampsSec
std::vector< double > timestampsSec
Definition: prediction_helpers.h:45
armarx::armem::server::robot_state::proprioception::Segment::getSensorValues
SensorValuesMap getSensorValues(const armem::Time &timestamp, DebugObserverHelper *debugObserver=nullptr) const
Definition: Segment.cpp:100
prediction_helpers.h
armarx::armem::MemoryID::providerSegmentName
std::string providerSegmentName
Definition: MemoryID.h:52
armarx::armem::server::robot_state::proprioception::readJointData
Eigen::VectorXd readJointData(const wm::EntityInstanceData &data)
Definition: Segment.cpp:161
armarx::armem::server::MemoryToIceAdapter
Helps connecting a Memory server to the Ice interface.
Definition: MemoryToIceAdapter.h:19
armarx::core::time::DateTime::Now
static DateTime Now()
Definition: DateTime.cpp:55
MemoryID.h
ARMARX_CHECK_NOT_NULL
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
Definition: ExpressionException.h:206
armarx::armem::PredictionRequest::predictionSettings
PredictionSettings predictionSettings
Definition: Prediction.h:52
armarx::aron::data::Dict::getElement
VariantPtr getElement(const std::string &) const
Definition: Dict.cpp:233
armarx::armem::server::robot_state::proprioception
Definition: forward_declarations.h:75
armarx::armem
Definition: LegacyRobotStateMemoryAdapter.cpp:31
ProsthesisInterface.values
values
Definition: ProsthesisInterface.py:190
armarx::armem::server::robot_state::proprioception::Segment::init
void init() override
Definition: Segment.cpp:46
armarx::armem::server::robot_state::proprioception::SensorValues::jointValueMap
JointValuesMap jointValueMap
Definition: SensorValues.h:45
armarx::core::time::Duration::toMilliSecondsDouble
double toMilliSecondsDouble() const
Returns the amount of milliseconds.
Definition: Duration.cpp:76
armarx::armem::server::robot_state::proprioception::emplaceJointData
void emplaceJointData(const Eigen::VectorXd &jointData, arondto::Proprioception &dataTemplate)
Definition: Segment.cpp:198
armarx::armem::server::robot_state::proprioception::SensorValues
Definition: SensorValues.h:43
armarx::aron::data::detail::SpecializedVariantBase< data::dto::Dict, Dict >::DynamicCastAndCheck
static PointerType DynamicCastAndCheck(const VariantPtr &n)
Definition: SpecializedVariant.h:135
armarx::armem::PredictionResult
Definition: Prediction.h:58
armarx::armem::server::wm::Entity
Definition: memory_definitions.h:30
armarx::armem::server::robot_state::proprioception::JointValues
Definition: SensorValues.h:29
armarx::armem::base::detail::ForEachEntityMixin::forEachEntity
bool forEachEntity(FunctionT &&func)
Definition: iteration_mixins.h:258
TIMING_END_STREAM
#define TIMING_END_STREAM(name, os)
Definition: TimeUtil.h:300
armarx::armem::server::robot_state::proprioception::Segment::predictLinear
armem::PredictionResult predictLinear(const armem::PredictionRequest &request) const
Definition: Segment.cpp:217
armarx::armem::SnapshotRangeInfo::success
bool success
Definition: prediction_helpers.h:42
ObserverObjectFactories.h
armarx::armem::server::segment::detail::SegmentBase< server::wm::CoreSegment >::segmentPtr
server::wm::CoreSegment * segmentPtr
Definition: SpecializedSegment.h:54
armarx::armem::MemoryID::withProviderSegmentName
MemoryID withProviderSegmentName(const std::string &name) const
Definition: MemoryID.cpp:412
cxxopts::value
std::shared_ptr< Value > value()
Definition: cxxopts.hpp:926
armarx::armem::MemoryID
A memory ID.
Definition: MemoryID.h:47
armarx::armem::PredictionResult::prediction
aron::data::DictPtr prediction
Definition: Prediction.h:64
armarx::armem::base::EntityBase::findLatestSnapshot
EntitySnapshotT * findLatestSnapshot()
Return the snapshot with the most recent timestamp.
Definition: EntityBase.h:228
armarx::armem::server::segment::detail::SegmentBase< server::wm::CoreSegment >
armarx::armem::server::segment::SpecializedCoreSegment::init
virtual void init() override
Definition: SpecializedCoreSegment.cpp:49
data
uint8_t data[1]
Definition: EtherCATFrame.h:68
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:177
armarx::armem::server::segment::SpecializedCoreSegment::doLocked
auto doLocked(FunctionT &&function) const
Definition: SpecializedCoreSegment.h:39
armarx::core::time::Duration::SecondsDouble
static Duration SecondsDouble(double seconds)
Constructs a duration in seconds.
Definition: Duration.cpp:90
All.h
armarx::armem::SnapshotRangeInfo::latestValue
LatestType latestValue
Definition: prediction_helpers.h:47
armarx::aron::data::Dict::hasElement
bool hasElement(const std::string &) const
Definition: Dict.cpp:227
armarx::armem::server::robot_state::proprioception::Segment::getRobotUnitProviderID
const armem::MemoryID & getRobotUnitProviderID() const
Definition: Segment.cpp:156
EigenConverter.h
armarx::armem::getSnapshotsInRange
SnapshotRangeInfo< DataType, LatestType > getSnapshotsInRange(const SegmentType *segment, const MemoryID &entityID, const DateTime &startTime, const DateTime &endTime, std::function< DataType(const aron::data::DictPtr &)> dictToData, std::function< LatestType(const aron::data::DictPtr &)> dictToLatest)
Get data points for the snapshots of an entity in a given time range.
Definition: prediction_helpers.h:72
armarx::armem::wm::EntitySnapshot
Client-side working memory entity snapshot.
Definition: memory_definitions.h:80
armarx::armem::SnapshotRangeInfo::values
std::vector< DataType > values
Definition: prediction_helpers.h:46
armarx::armem::base::detail::MemoryItem::id
MemoryID & id()
Definition: MemoryItem.h:27
armarx::armem::server::wm::detail::Prediction::addPredictor
void addPredictor(const PredictionEngine &engine, Predictor &&predictor)
Definition: Prediction.h:68
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:40
armarx::armem::server::robot_state::proprioception::SensorValuesMap
std::unordered_map< std::string, SensorValues > SensorValuesMap
Definition: forward_declarations.h:82
armarx::armem::PredictionEngine
Definition: Prediction.h:33
TIMING_END_COMMENT_STREAM
#define TIMING_END_COMMENT_STREAM(name, comment, os)
Definition: TimeUtil.h:284
ExpressionException.h
armarx::armem::server::wm::CoreSegment
base::CoreSegmentBase
Definition: memory_definitions.h:86
armarx::core::time::DateTime
Represents a point in time.
Definition: DateTime.h:24
armarx::aron::data::DictPtr
std::shared_ptr< Dict > DictPtr
Definition: Dict.h:41
DebugObserverHelper.h
Segment.h
armarx::armem::PredictionResult::errorMessage
std::string errorMessage
Definition: Prediction.h:61
TimeUtil.h
armarx::armem::robot_state::proprioceptionSegmentID
const MemoryID proprioceptionSegmentID
Definition: memory_ids.cpp:32
armarx::DebugObserverHelper::setDebugObserverDatafield
void setDebugObserverDatafield(const std::string &channelName, const std::string &datafieldName, const TimedVariantPtr &value) const
Definition: DebugObserverHelper.cpp:74
armarx::aron::data::Dict::getElements
std::map< std::string, VariantPtr > getElements() const
Definition: Dict.cpp:249
PropertyDefinitionContainer.h
IceUtil::Handle< class PropertyDefinitionContainer >
armarx::core::time::Duration
Represents a duration.
Definition: Duration.h:17
IceInternal::ProxyHandle<::IceProxy::armarx::RobotUnitInterface >
armarx::armem::base::EntityBase::findLatestSnapshotBeforeOrAt
const EntitySnapshotT * findLatestSnapshotBeforeOrAt(const Time &time) const
Return the latest snapshot before or at time.
Definition: EntityBase.h:319
armarx::armem::SnapshotRangeInfo::errorMessage
std::string errorMessage
Definition: prediction_helpers.h:43
armarx::armem::server::robot_state::proprioception::Segment::~Segment
virtual ~Segment() override
armarx::armem::SnapshotRangeInfo
Holds info on snapshot data extracted from a time range.
Definition: prediction_helpers.h:40
armarx::armem::server::robot_state::proprioception::Segment::onConnect
void onConnect(RobotUnitInterfacePrx robotUnitPrx)
Definition: Segment.cpp:55
armarx::armem::server::robot_state::proprioception::Segment::getSensorValuesLocking
SensorValuesMap getSensorValuesLocking(const armem::Time &timestamp, DebugObserverHelper *debugObserver=nullptr) const
Definition: Segment.cpp:76
armarx::armem::server::robot_state::proprioception::SensorValues::forceTorqueValuesMap
ForceTorqueValuesMap forceTorqueValuesMap
Definition: SensorValues.h:46
armarx::armem::server::robot_state::proprioception::Segment::Segment
Segment(server::MemoryToIceAdapter &iceMemory)
Definition: Segment.cpp:25
Logging.h
armarx::armem::PredictionResult::success
bool success
Definition: Prediction.h:60
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:186
armarx::core::time::Duration::MicroSeconds
static Duration MicroSeconds(std::int64_t microSeconds)
Constructs a duration in microseconds.
Definition: Duration.cpp:27
armarx::DebugObserverHelper
Brief description of class DebugObserverHelper.
Definition: DebugObserverHelper.h:50
armarx::armem::PredictionRequest::snapshotID
armem::MemoryID snapshotID
Definition: Prediction.h:51
armarx::armem::server::segment::SpecializedCoreSegment::defineProperties
virtual void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string &prefix="") override
Definition: SpecializedCoreSegment.cpp:33
memory_ids.h
SensorValues.h
armarx::core::time::Duration::MilliSeconds
static Duration MilliSeconds(std::int64_t milliSeconds)
Constructs a duration in milliseconds.
Definition: Duration.cpp:55
armarx::aron::data::Dict
Definition: Dict.h:44
armarx::aron::data::converter::AronEigenConverter::ConvertToVector3f
static Eigen::Vector3f ConvertToVector3f(const data::NDArrayPtr &)
Definition: EigenConverter.cpp:45
armarx::armem::PredictionSettings::predictionEngineID
std::string predictionEngineID
Definition: Prediction.h:43
armarx::armem::server::robot_state::proprioception::Segment::defineProperties
void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string &prefix="") override
Definition: Segment.cpp:36