ZenohController.cpp
Go to the documentation of this file.
1#include "ZenohController.h"
2
3#include <Eigen/Dense>
4
7#include <ArmarXCore/interface/observers/ObserverInterface.h>
8#include <ArmarXCore/interface/observers/VariantBase.h>
10
11// for ARMARX_RT_LOGF_WARN
12#include <chrono>
13#include <string>
14
15#include <boost/date_time/posix_time/posix_time.hpp>
16
17#include <Ice/Current.h>
18#include <Ice/Object.h>
19
20#include <VirtualRobot/VirtualRobot.h>
21
22#include "RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedJSONConverter.h"
26#include <RobotAPI/interface/aron/Aron.h>
27#include <RobotAPI/interface/units/RobotUnit/NJointController.h>
28#include <RobotAPI/interface/visualization/DebugDrawerInterface.h>
31
39
40#include <nlohmann/json_fwd.hpp>
41#include <zenoh_constants.h>
42
44{
45 namespace base = armarx::control::njoint_controller::task_space;
46
47 armarx::NJointControllerRegistration<
52
58
64
70
72 base::NJointTaskspaceCollisionAvoidanceMixedImpedanceVelocityController>>
76
77 // Implement getClassName() method for templated NJointZenohTaskspaceController
78 template <>
79 std::string
86
87 template <>
88 std::string
95
96 template <>
97 std::string
104
105 template <>
106 std::string
108 class base::NJointTaskspaceCollisionAvoidanceImpedanceController>::
109 getClassName(const Ice::Current&) const
110 {
113 }
114
115 template <>
116 std::string
118 class base::NJointTaskspaceCollisionAvoidanceMixedImpedanceVelocityController>::
119 getClassName(const Ice::Current&) const
120 {
123 }
124
125 template <typename NJointTaskspaceController>
128 const armarx::NJointControllerConfigPtr& config,
129 const VirtualRobot::RobotPtr& robot) :
131 {
132 init();
133 }
134
135 template <>
137 class base::NJointTaskspaceCollisionAvoidanceImpedanceController>::
138 NJointZenohTaskspaceController(const armarx::RobotUnitPtr& robotUnit,
139 const armarx::NJointControllerConfigPtr& config,
140 const VirtualRobot::RobotPtr& robot) :
141 base::NJointTaskspaceImpedanceController{robotUnit, config, robot},
142 base::NJointTaskspaceCollisionAvoidanceImpedanceController{robotUnit, config, robot}
143 {
144 init();
145 }
146
147 template <>
148 NJointZenohTaskspaceController<
149 class base::NJointTaskspaceCollisionAvoidanceMixedImpedanceVelocityController>::
150 NJointZenohTaskspaceController(const armarx::RobotUnitPtr& robotUnit,
151 const armarx::NJointControllerConfigPtr& config,
152 const VirtualRobot::RobotPtr& robot) :
153 base::NJointTaskspaceMixedImpedanceVelocityController{robotUnit, config, robot},
154 base::NJointTaskspaceCollisionAvoidanceMixedImpedanceVelocityController{robotUnit,
155 config,
156 robot}
157 {
158 init();
159 }
160
161 // Method(s) of NJointZenohTaskspaceController in general
162 template <typename NJointTaskspaceController>
163 void
165 {
167 auto config = zenoh::Config::create_default();
168 // config.insert_json5(zenoh::Z_CONFIG_CONNECT_KEY, "[\"" + _connect_endpoint + "\"]");
169 config.insert_json5("connect/endpoints", "[\"" + _connect_endpoint + "\"]");
170
171
172 _session = std::make_unique<zenoh::Session>(zenoh::Session::open(std::move(config)));
173 ARMARX_CHECK(_session) << "Failed to create Zenoh session unique pointer";
174
175
177 ARMARX_INFO << "setting up publisher and subscriber";
178
179 _publisher = std::make_unique<zenoh::Publisher>(
180 _session->declare_publisher(zenoh::KeyExpr(_state_key)));
181
182 auto queryable_expr = zenoh::KeyExpr(_config_key);
183 auto on_drop_queryable = []() { ARMARX_INFO << "Destroying queryable"; };
184 zenoh::Session::QueryableOptions opts;
185 opts.complete = true;
186 auto queryable = _session->declare_queryable(
187 queryable_expr,
188 [&queryable_expr](const zenoh::Query& query)
189 {
190 ARMARX_INFO << "Received Query '" << query.get_keyexpr().as_string_view();
191 query.reply(queryable_expr, zenoh::Bytes("42"));
192 },
193 std::move(on_drop_queryable),
194 std::move(opts));
195 // _subscriber = std::make_unique<zenoh::Subscriber>(_session->declare_subscriber(
196 // _config_key, [this](const zenoh::Sample& s) { this->updateConfigZenoh(s); }));
197
198 ARMARX_INFO << "Zenoh session and endpoints initialized";
199 time_last_packet = std::chrono::steady_clock::now();
200 }
201
202 template <typename NJointTaskspaceController>
203 void
205 {
206 auto [rtTargetSafe, ftSafe] = this->additionalTaskUpdateStatus();
207
208 auto sendTime = std::chrono::duration_cast<std::chrono::microseconds>(
209 std::chrono::system_clock::now().time_since_epoch())
210 .count();
211 nlohmann::json j;
212
213 j["timestamp"] = static_cast<double>(sendTime) / 1e6;
214 j["msg"] = R"({"matrix":[[1,0],[0,1]],"float":3.14,"string":"hello","bool":true})";
215 // std::string msg = R"({"matrix":[[1,0],[0,1]],"float":3.14,"string":"hello","bool":true})";
216
217 for (auto& pair : this->limb)
218 {
219 this->userConfig.limbs.at(pair.first) = pair.second->nonRtConfig;
220 }
222 auto json_msg = this->userConfig.write(writer);
223
225 ARMARX_INFO << "convert json";
227 ARMARX_INFO << this->limb.at("LeftArm")->nonRtConfig.desiredNullspaceJointAngles.value();
228
229 try
230 {
232 this->limb.at("LeftArm")->nonRtConfig.toAron(),
233 this->limb.at("LeftArm")->nonRtConfig.ToAronType());
234 }
235 catch (const aron::error::AronException& e)
236 {
237 ARMARX_WARNING << "In controller additional task, failed to Aron data to JSON: "
238 << e.getReason();
239 }
240 ARMARX_INFO << "dump json";
241 _publisher->put(conv.getJSON().dump(2));
242
243 // std::string msg = j.dump();
244 // _publisher->put(json_msg.dump());
245
246 // Zenoh::message_t config_msg;
247 // bool received = socket.recv(&config_msg, Zenoh_DONTWAIT); // Try receive message, don't wait
248 // if (received)
249 // {
250 // // Measure time passed since last packet was received
251 // auto currentTime = std::chrono::steady_clock::now();
252 // std::chrono::duration<double> elapsed_seconds = currentTime - time_last_packet;
253 // frequency_ms = elapsed_seconds.count() * 1000;
254 // time_last_packet = currentTime;
255
256 // // Parse config message into nlohmann::json
257 // std::string config_json_str(static_cast<char*>(config_msg.data()), config_msg.size());
258 // nlohmann::json config_json = nlohmann::json::parse(config_json_str);
259
260 // // Calculate latency (might be imprecise due to clocks being not being synchronized?)
261 // if (config_json.contains("timestamp") && config_json["timestamp"].is_number())
262 // {
263 // auto arrival_time = std::chrono::duration<double>(
264 // std::chrono::system_clock::now().time_since_epoch())
265 // .count();
266 // double sender_time = config_json["timestamp"];
267 // latency_ms = (arrival_time - sender_time) * 1000; // Convert to milliseconds
268 // config_json.erase(
269 // "timestamp"); // Important! Remove any data that is not part of the config
270 // }
271
272 // // Read into config data structure
273 // armarx::aron::data::reader::NlohmannJSONReaderWithoutTypeCheck reader;
274 // typename NJointTaskspaceController::ConfigDict receivedConfig;
275 // receivedConfig.read(reader, config_json);
276 // for (auto& pair : this->limb)
277 // {
278 // auto limbName = pair.first;
279 // auto& arm = pair.second;
280
281 // auto limbConfigNew = receivedConfig.limbs.at(limbName);
282 // arm->nonRtConfig.desiredPose =
283 // limbConfigNew.desiredPose; // Update desiredPose with new configuration
284 // // TODO: Other config parameters can be updated here as needed
285 // arm->bufferConfigUserToNonRt.getWriteBuffer() =
286 // arm->nonRtConfig; // Overwrite user config
287 // arm->bufferConfigUserToNonRt.commitWrite();
288 // }
289
290 // // Update hands
291 // if (this->hands)
292 // {
293 // this->hands->updateConfig(receivedConfig.hands);
294 // }
295 // }
296
298 if (not rtTargetSafe)
299 {
301 }
302 }
303
304 template <typename NJointTaskspaceController>
305 void
307 const zenoh::Sample& sample)
308 {
309
310 std::string payload = sample.get_payload().as_string();
311 _config_json = payload;
312 ARMARX_INFO << "[CONFIG] Updated: " << _config_json;
313 }
314
315 template <typename NJointTaskspaceController>
316 void
318 const SensorAndControl&,
320 const DebugObserverInterfacePrx& debugObs)
321 {
322 // Log metrics
323 StringVariantBaseMap datafields;
324 datafields["frequency_ms"] = new Variant(frequency_ms);
325 datafields["latency_ms"] = new Variant(latency_ms);
326 debugObs->setDebugChannel(getClassName(), datafields);
327
328 // Do limb publish
329 for (auto& pair : this->limb)
330 {
331 if (not pair.second->rtReady.load())
332 continue;
333 this->limbPublish(pair.second, debugObs);
334 }
335 }
336} // namespace armarx::control::njoint_controller::task_space
The Variant class is described here: Variants.
Definition Variant.h:224
A base class for aron exceptions.
Definition Exception.h:37
NJointTaskspaceController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &)
Definition Base.cpp:138
void limbPublish(ArmPtr &arm, const DebugObserverInterfacePrx &debugObs)
Definition Base.cpp:819
void onPublish(const SensorAndControl &, const DebugDrawerInterfacePrx &, const DebugObserverInterfacePrx &) override
std::string getClassName(const Ice::Current &=Ice::emptyCurrent) const final
NJointZenohTaskspaceController(const armarx::RobotUnitPtr &robotUnit, const armarx::NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &robot)
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
void visitRecursive(RecursiveVisitorImplementation &v, typename RecursiveVisitorImplementation::Input &o)
const simox::meta::EnumNames< ControllerType > ControllerTypeNames
Definition type.h:170
armarx::NJointControllerRegistration< NJointSharedMemoryTaskspaceController< base::NJointTSMixImpVelColController > > registrationControllerNJointCollisionAvoidanceTSMixedImpedanceVelocityController(armarx::control::common::ControllerTypeNames.to_name(armarx::control::common::ControllerType::SharedMemoryTSMixImpVelCol))
armarx::NJointControllerRegistration< NJointSharedMemoryTaskspaceController< base::NJointTSMixImpVelController > > registrationControllerNJointTSMixedImpedanceVelocityController(armarx::control::common::ControllerTypeNames.to_name(armarx::control::common::ControllerType::SharedMemoryTSMixImpVel))
armarx::NJointControllerRegistration< NJointSharedMemoryTaskspaceController< base::NJointTSImpController > > registrationControllerNJointTSImpedanceController(armarx::control::common::ControllerTypeNames.to_name(armarx::control::common::ControllerType::SharedMemoryTSImp))
armarx::NJointControllerRegistration< NJointSharedMemoryTaskspaceController< base::NJointTSVelController > > registrationControllerNJointTSVelocityController(armarx::control::common::ControllerTypeNames.to_name(armarx::control::common::ControllerType::SharedMemoryTSVel))
armarx::NJointControllerRegistration< NJointSharedMemoryTaskspaceController< base::NJointTSImpColController > > registrationControllerNJointCollisionAvoidanceTSImpedanceController(armarx::control::common::ControllerTypeNames.to_name(armarx::control::common::ControllerType::SharedMemoryTSImpCol))
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugObserverInterface > DebugObserverInterfacePrx
std::map< std::string, VariantBasePtr > StringVariantBaseMap
IceUtil::Handle< class RobotUnit > RobotUnitPtr
Definition FTSensor.h:34
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugDrawerInterface > DebugDrawerInterfacePrx
detail::ControlThreadOutputBufferEntry SensorAndControl
#define ARMARX_TRACE
Definition trace.h:77