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 <Ice/Current.h>
16#include <Ice/Object.h>
17
18#include <VirtualRobot/VirtualRobot.h>
19
20#include "RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedJSONConverter.h"
24#include <RobotAPI/interface/aron/Aron.h>
25#include <RobotAPI/interface/units/RobotUnit/NJointController.h>
26#include <RobotAPI/interface/visualization/DebugDrawerInterface.h>
29
37
38#include <nlohmann/json_fwd.hpp>
39#include <zenoh_constants.h>
40
42{
43 namespace base = armarx::control::njoint_controller::task_space;
44
45 armarx::NJointControllerRegistration<
50
56
62
68
70 base::NJointTaskspaceCollisionAvoidanceMixedImpedanceVelocityController>>
74
75 // Implement getClassName() method for templated NJointZenohTaskspaceController
76 template <>
77 std::string
84
85 template <>
86 std::string
93
94 template <>
95 std::string
102
103 template <>
104 std::string
106 class base::NJointTaskspaceCollisionAvoidanceImpedanceController>::
107 getClassName(const Ice::Current&) const
108 {
111 }
112
113 template <>
114 std::string
116 class base::NJointTaskspaceCollisionAvoidanceMixedImpedanceVelocityController>::
117 getClassName(const Ice::Current&) const
118 {
121 }
122
123 template <typename NJointTaskspaceController>
126 const armarx::NJointControllerConfigPtr& config,
127 const VirtualRobot::RobotPtr& robot) :
129 {
130 init();
131 }
132
133 template <>
135 class base::NJointTaskspaceCollisionAvoidanceImpedanceController>::
136 NJointZenohTaskspaceController(const armarx::RobotUnitPtr& robotUnit,
137 const armarx::NJointControllerConfigPtr& config,
138 const VirtualRobot::RobotPtr& robot) :
139 base::NJointTaskspaceImpedanceController{robotUnit, config, robot},
140 base::NJointTaskspaceCollisionAvoidanceImpedanceController{robotUnit, config, robot}
141 {
142 init();
143 }
144
145 template <>
146 NJointZenohTaskspaceController<
147 class base::NJointTaskspaceCollisionAvoidanceMixedImpedanceVelocityController>::
148 NJointZenohTaskspaceController(const armarx::RobotUnitPtr& robotUnit,
149 const armarx::NJointControllerConfigPtr& config,
150 const VirtualRobot::RobotPtr& robot) :
151 base::NJointTaskspaceMixedImpedanceVelocityController{robotUnit, config, robot},
152 base::NJointTaskspaceCollisionAvoidanceMixedImpedanceVelocityController{robotUnit,
153 config,
154 robot}
155 {
156 init();
157 }
158
159 // Method(s) of NJointZenohTaskspaceController in general
160 template <typename NJointTaskspaceController>
161 void
163 {
165 auto config = zenoh::Config::create_default();
166 // config.insert_json5(zenoh::Z_CONFIG_CONNECT_KEY, "[\"" + _connect_endpoint + "\"]");
167 config.insert_json5("connect/endpoints", "[\"" + _connect_endpoint + "\"]");
168
169
170 _session = std::make_unique<zenoh::Session>(zenoh::Session::open(std::move(config)));
171 ARMARX_CHECK(_session) << "Failed to create Zenoh session unique pointer";
172
173
175 ARMARX_INFO << "setting up publisher and subscriber";
176
177 _publisher = std::make_unique<zenoh::Publisher>(
178 _session->declare_publisher(zenoh::KeyExpr(_state_key)));
179
180 auto queryable_expr = zenoh::KeyExpr(_config_key);
181 auto on_drop_queryable = []() { ARMARX_INFO << "Destroying queryable"; };
182 zenoh::Session::QueryableOptions opts;
183 opts.complete = true;
184 auto queryable = _session->declare_queryable(
185 queryable_expr,
186 [&queryable_expr](const zenoh::Query& query)
187 {
188 ARMARX_INFO << "Received Query '" << query.get_keyexpr().as_string_view();
189 query.reply(queryable_expr, zenoh::Bytes("42"));
190 },
191 std::move(on_drop_queryable),
192 std::move(opts));
193 // _subscriber = std::make_unique<zenoh::Subscriber>(_session->declare_subscriber(
194 // _config_key, [this](const zenoh::Sample& s) { this->updateConfigZenoh(s); }));
195
196 ARMARX_INFO << "Zenoh session and endpoints initialized";
197 time_last_packet = std::chrono::steady_clock::now();
198 }
199
200 template <typename NJointTaskspaceController>
201 void
203 {
204 auto [rtTargetSafe, ftSafe] = this->additionalTaskUpdateStatus();
205
206 auto sendTime = std::chrono::duration_cast<std::chrono::microseconds>(
207 std::chrono::system_clock::now().time_since_epoch())
208 .count();
209 nlohmann::json j;
210
211 j["timestamp"] = static_cast<double>(sendTime) / 1e6;
212 j["msg"] = R"({"matrix":[[1,0],[0,1]],"float":3.14,"string":"hello","bool":true})";
213 // std::string msg = R"({"matrix":[[1,0],[0,1]],"float":3.14,"string":"hello","bool":true})";
214
215 for (auto& pair : this->limb)
216 {
217 this->userConfig.limbs.at(pair.first) = pair.second->nonRtConfig;
218 }
220 auto json_msg = this->userConfig.write(writer);
221
223 ARMARX_INFO << "convert json";
225 ARMARX_INFO << this->limb.at("LeftArm")->nonRtConfig.desiredNullspaceJointAngles.value();
226
227 try
228 {
230 this->limb.at("LeftArm")->nonRtConfig.toAron(),
231 this->limb.at("LeftArm")->nonRtConfig.ToAronType());
232 }
233 catch (const aron::error::AronException& e)
234 {
235 ARMARX_WARNING << "In controller additional task, failed to Aron data to JSON: "
236 << e.getReason();
237 }
238 ARMARX_INFO << "dump json";
239 _publisher->put(conv.getJSON().dump(2));
240
241 // std::string msg = j.dump();
242 // _publisher->put(json_msg.dump());
243
244 // Zenoh::message_t config_msg;
245 // bool received = socket.recv(&config_msg, Zenoh_DONTWAIT); // Try receive message, don't wait
246 // if (received)
247 // {
248 // // Measure time passed since last packet was received
249 // auto currentTime = std::chrono::steady_clock::now();
250 // std::chrono::duration<double> elapsed_seconds = currentTime - time_last_packet;
251 // frequency_ms = elapsed_seconds.count() * 1000;
252 // time_last_packet = currentTime;
253
254 // // Parse config message into nlohmann::json
255 // std::string config_json_str(static_cast<char*>(config_msg.data()), config_msg.size());
256 // nlohmann::json config_json = nlohmann::json::parse(config_json_str);
257
258 // // Calculate latency (might be imprecise due to clocks being not being synchronized?)
259 // if (config_json.contains("timestamp") && config_json["timestamp"].is_number())
260 // {
261 // auto arrival_time = std::chrono::duration<double>(
262 // std::chrono::system_clock::now().time_since_epoch())
263 // .count();
264 // double sender_time = config_json["timestamp"];
265 // latency_ms = (arrival_time - sender_time) * 1000; // Convert to milliseconds
266 // config_json.erase(
267 // "timestamp"); // Important! Remove any data that is not part of the config
268 // }
269
270 // // Read into config data structure
271 // armarx::aron::data::reader::NlohmannJSONReaderWithoutTypeCheck reader;
272 // typename NJointTaskspaceController::ConfigDict receivedConfig;
273 // receivedConfig.read(reader, config_json);
274 // for (auto& pair : this->limb)
275 // {
276 // auto limbName = pair.first;
277 // auto& arm = pair.second;
278
279 // auto limbConfigNew = receivedConfig.limbs.at(limbName);
280 // arm->nonRtConfig.desiredPose =
281 // limbConfigNew.desiredPose; // Update desiredPose with new configuration
282 // // TODO: Other config parameters can be updated here as needed
283 // arm->bufferConfigUserToNonRt.getWriteBuffer() =
284 // arm->nonRtConfig; // Overwrite user config
285 // arm->bufferConfigUserToNonRt.commitWrite();
286 // }
287
288 // // Update hands
289 // if (this->hands)
290 // {
291 // this->hands->updateConfig(receivedConfig.hands);
292 // }
293 // }
294
296 if (not rtTargetSafe)
297 {
299 }
300 }
301
302 template <typename NJointTaskspaceController>
303 void
305 const zenoh::Sample& sample)
306 {
307
308 std::string payload = sample.get_payload().as_string();
309 _config_json = payload;
310 ARMARX_INFO << "[CONFIG] Updated: " << _config_json;
311 }
312
313 template <typename NJointTaskspaceController>
314 void
316 const SensorAndControl&,
318 const DebugObserverInterfacePrx& debugObs)
319 {
320 // Log metrics
321 StringVariantBaseMap datafields;
322 datafields["frequency_ms"] = new Variant(frequency_ms);
323 datafields["latency_ms"] = new Variant(latency_ms);
324 debugObs->setDebugChannel(getClassName(), datafields);
325
326 // Do limb publish
327 for (auto& pair : this->limb)
328 {
329 if (not pair.second->rtReady.load())
330 continue;
331 this->limbPublish(pair.second, debugObs);
332 }
333 }
334} // 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:804
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:179
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:191
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:75