MoveJointsToPosition.cpp
Go to the documentation of this file.
2
5
8
10{
11
13 ::armarx::skills::SimpleSpecializedSkill<ParamType>(GetSkillDescription()), srv_(srv)
14 {
15 }
16
17 std::map<std::string, float>
18 MoveJointsToPosition::filterJointTargetValues(
19 const NameValueMap& jointsTargetValues,
20 const std::vector<std::string>& disabledJoints) const
21 {
22 std::map<std::string, float> filtered;
23 for (const auto& [jointName, v] : jointsTargetValues)
24 {
25 if (std::find(disabledJoints.begin(), disabledJoints.end(), jointName) !=
26 disabledJoints.end())
27 {
28 ARMARX_INFO << "Disable joint " << jointName
29 << " because it was explictly disabled in skill params.";
30 continue;
31 }
32 filtered[jointName] = v;
33 }
34 return filtered;
35 }
36
38 MoveJointsToPosition::exit(const SpecializedExitInput& in)
39 {
40 auto filtered = this->filterJointTargetValues(in.parameters.jointsTargetValues,
41 in.parameters.disabledJoints);
42
43 auto jointNames = simox::alg::get_keys(filtered);
44
45 srv_.kinematicUnit->releaseJoints(jointNames);
47 }
48
49 ::armarx::skills::Skill::MainResult
50 MoveJointsToPosition::main(const SpecializedMainInput& in)
51 {
52 auto filtered = this->filterJointTargetValues(in.parameters.jointsTargetValues,
53 in.parameters.disabledJoints);
54
55 auto jointNames = simox::alg::get_keys(filtered);
56
57 // get VirtualRobot
58 const VirtualRobot::RobotPtr virtualRobot =
59 srv_.virtualRobotReader.getRobot(srv_.robotName);
60 if (not virtualRobot)
61 {
62 ARMARX_ERROR << "Could not get robot '" << srv_.robotName << "'";
63 return MakeFailedResult();
64 }
65
66 // check jointsTargetValues are valid (joints exist, target values are within limits)
67 if (not checkJointsTargetValuesValid(in.parameters.jointsTargetValues, virtualRobot))
68 {
69 return MakeFailedResult();
70 }
71
72 // request joints
73 ARMARX_INFO << "Requesting joints";
74 try
75 {
76 srv_.kinematicUnit->requestJoints(jointNames);
77 }
78 catch (const armarx::KinematicUnitUnavailable& e)
79 {
80 ARMARX_IMPORTANT << "Failed to request joints. Terminating. Joints unavailable:"
81 << e.nodeOwners;
82 return MakeFailedResult();
83 }
84
85 // move joints
86 ARMARX_INFO << "Moving joints to " << filtered;
87
88 switchControlMode(filtered, ePositionControl);
89
90 if (in.parameters.inSimulation)
91 {
92 // trajectories from joint value updates through the KinematicUnit are not simulated
93 // -> simulate manually
94 moveJointsSimulation(filtered,
95 in.parameters.simulationJointSpeed,
96 in.parameters.simulationJointSpeedOverride,
97 virtualRobot);
98 }
99 else
100 {
101 NameValueMap test = in.parameters.timeoutOverrideMS;
102
103 moveJoints(filtered,
104 in.parameters.accuracy,
105 in.parameters.accuracyOverride,
106 in.parameters.timeoutMS,
107 in.parameters.timeoutOverrideMS,
108 virtualRobot);
109 }
110 return MakeSucceededResult();
111 }
112
113 bool
114 MoveJointsToPosition::checkJointsTargetValuesValid(const NameValueMap& jointsTargetValues,
115 const VirtualRobot::RobotPtr& virtualRobot)
116 {
117 for (const auto& [jointName, targetValue] : jointsTargetValues)
118 {
119 if (not virtualRobot->hasRobotNode(jointName))
120 {
121 ARMARX_ERROR << "Robot has no joint '" << jointName << "'";
122 return false;
123 }
124 const VirtualRobot::RobotNodePtr robotNode = virtualRobot->getRobotNode(jointName);
125 if (not robotNode->checkJointLimits(targetValue))
126 {
127 ARMARX_ERROR << "Target value '" << targetValue << "' for joint '" << jointName
128 << "' out of limits (" << robotNode->getJointLimitLo() << " - "
129 << robotNode->getJointLimitHi() << ")";
130 return false;
131 }
132 }
133 return true;
134 }
135
136 void
137 MoveJointsToPosition::switchControlMode(const NameValueMap& jointsTargetValues,
138 const ControlMode controlMode)
139 {
140 armarx::NameControlModeMap modeMap;
141 for (const auto& [jointName, _] : jointsTargetValues)
142 {
143 modeMap[jointName] = controlMode;
144 }
145 srv_.kinematicUnit->switchControlMode(modeMap);
146 }
147
148 void
149 MoveJointsToPosition::moveJoints(const NameValueMap& jointsTargetValues,
150 const float accuracyDefault,
151 const NameValueMap& accuracyOverride,
152 const float timeoutDefault,
153 NameValueMap timeoutOverride,
154 const VirtualRobot::RobotPtr& virtualRobot)
155 {
156 srv_.kinematicUnit->setJointAngles(jointsTargetValues);
157
158 // wait until target values are reached
159 ARMARX_INFO << "Waiting until target values are reached";
160
161 const Clock clock;
162 const Duration sleepTime = Duration::MilliSeconds(50);
163
164 auto do_if_terminate_and_not_reached = [&]()
165 {
166 ARMARX_INFO << "Skill got aborted, stopping movement";
167 ARMARX_CHECK(srv_.virtualRobotReader.synchronizeRobotJoints(*virtualRobot,
169 << "Robot state synchronization failed";
170
171 // stop movement
172 switchControlMode(jointsTargetValues, eVelocityControl);
173
174 NameValueMap targetJointVelocities;
175 for (auto& [jointName, _] : jointsTargetValues)
176 {
177 targetJointVelocities[jointName] = 0;
178 }
179 srv_.kinematicUnit->setJointVelocities(targetJointVelocities);
180
181 throwIfSkillShouldTerminate(); // throws exception
182
183 ARMARX_INFO << "Target values reached";
184 };
185
186 bool reachedOrTimedOut = false;
187
188
189 // fill map with default value, if joint has no specific timeout
190 for (const auto& [jointName, _] : jointsTargetValues)
191 {
192 if (timeoutOverride.find(jointName) == timeoutOverride.end())
193 {
194 timeoutOverride[jointName] = timeoutDefault;
195 }
196 }
197
198 // store if joint has reached its timeout
199 std::map<std::string, bool> timeoutedJoints;
200 for (const auto& [jointName, _] : jointsTargetValues)
201 {
202 timeoutedJoints[jointName] = false;
203 }
204
205 // hold last joint angle
206 NameValueMap pastJointAngles = srv_.kinematicUnit->getJointAngles();
207
208 // store the last time where joint moved significantly
209 std::map<std::string, armarx::DateTime> lastMotion;
210 for (const auto& [jointName, _] : jointsTargetValues)
211 {
212 lastMotion[jointName] = DateTime::Now();
213 }
214
215 while (not reachedOrTimedOut)
216 {
217 throwIfSkillShouldTerminate(do_if_terminate_and_not_reached);
218 ARMARX_CHECK(srv_.virtualRobotReader.synchronizeRobotJoints(*virtualRobot,
220 << "Robot state synchronization failed";
221
222 reachedOrTimedOut = true;
223 for (const auto& [jointName, targetValue] : jointsTargetValues)
224 {
225 if (not timeoutedJoints[jointName])
226 {
227
228 const float currentValue =
229 virtualRobot->getRobotNode(jointName)->getJointValue();
230 const float accuracy = accuracyOverride.count(jointName) > 0
231 ? accuracyOverride.at(jointName)
232 : accuracyDefault;
233
234 ARMARX_INFO << deactivateSpam(1) << "Delta for joint '" << jointName
235 << "' is: " << std::abs(targetValue - currentValue);
236
237 // check if joint still moves significantly
238 if (std::abs(currentValue - pastJointAngles[jointName]) > accuracy)
239 {
240 // update last joint angles and timestamp
241 pastJointAngles[jointName] = currentValue;
242 lastMotion[jointName] = DateTime::Now();
243 }
244
245 // check if joint reaches its timeout
246 if ((timeoutOverride[jointName] >= 0) &&
247 ((DateTime::Now() - lastMotion[jointName]).toMilliSecondsDouble() >=
248 timeoutOverride[jointName]))
249 {
250 timeoutedJoints[jointName] = true;
251 ARMARX_INFO << "Joint " << jointName << " has reached its timeout.";
252 }
253
254 if (std::abs(targetValue - currentValue) > accuracy)
255 {
257 << deactivateSpam(1) << "Delta for joint '" << jointName
258 << "' is higer than accuracy: " << std::abs(targetValue - currentValue)
259 << " > " << accuracy << "(accuracy)";
260 reachedOrTimedOut = false;
261
262 break;
263 }
264 }
265 }
266 clock.waitFor(sleepTime);
267 }
268 }
269
270 void
271 MoveJointsToPosition::moveJointsSimulation(const NameValueMap& jointsTargetValues,
272 const float speedDefault,
273 const NameValueMap& speedOverride,
274 const VirtualRobot::RobotPtr& virtualRobot)
275 {
277 srv_.virtualRobotReader.synchronizeRobotJoints(*virtualRobot, armarx::DateTime::Now()))
278 << "Robot state synchronization failed";
279
280 //build trajectory
281 armarx::trajectory::Trajectory trajectory;
282 double maxDuration = 0;
283
284 for (const auto& [jointName, targetValue] : jointsTargetValues)
285 {
286 const float speed =
287 speedOverride.count(jointName) > 0 ? speedOverride.at(jointName) : speedDefault;
288
289 const float currentValue = virtualRobot->getRobotNode(jointName)->getJointValue();
290 const double duration = std::abs(targetValue - currentValue) / speed;
291
292 ARMARX_DEBUG << VAROUT(jointName) << VAROUT(duration);
293
294 armarx::trajectory::VariantTrack& track = trajectory.addTrack(jointName);
295 track[0] = currentValue;
296 track[duration] = targetValue;
297
298 maxDuration = std::max(maxDuration, duration);
299 }
300
301 ARMARX_INFO << "Simulating trajectory (duration: " << maxDuration << "s)";
302
303 // run trajectory
304 const Clock clock;
305 const Duration sleepTime = Duration::MilliSeconds(10);
306
307 const armarx::DateTime start = armarx::DateTime::Now();
308 double t = 0;
309 while (t < maxDuration)
310 {
312 t = std::min((armarx::DateTime::Now() - start).toSecondsDouble(), maxDuration);
313
314 NameValueMap nextValues;
315 for (const auto& [name, _] : jointsTargetValues)
316 {
317 const float value = std::get<float>(trajectory[name].at(t));
318 nextValues[name] = value;
319 }
320
321 srv_.kinematicUnit->setJointAngles(nextValues);
322
323 clock.waitFor(sleepTime);
324 }
325 ARMARX_INFO << "Target values reached";
326 }
327
328} // namespace armarx::control::skills::skills
#define VAROUT(x)
static DateTime Now()
Definition DateTime.cpp:51
static Duration MilliSeconds(std::int64_t milliSeconds)
Constructs a duration in milliseconds.
Definition Duration.cpp:48
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
Definition Logging.cpp:99
::armarx::skills::SkillDescription GetSkillDescription()
static MainResult MakeSucceededResult(aron::data::DictPtr data=nullptr)
Definition Skill.cpp:413
virtual MainResult main()
Override this method with the actual implementation.
Definition Skill.cpp:542
void throwIfSkillShouldTerminate(const std::string &abortedMessage="") const
Definition Skill.cpp:389
virtual ExitResult exit()
Override this method with the actual implementation.
Definition Skill.cpp:535
static MainResult MakeFailedResult(aron::data::DictPtr data=nullptr)
Definition Skill.cpp:422
VariantTrack & addTrack(const TrackID &id)
Add track with the given ID (and no update function).
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
armarx::core::time::Duration Duration
Track< VariantValue > VariantTrack
A track with value type TValue.
Definition Track.h:129
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::shared_ptr< Value > value()
Definition cxxopts.hpp:855
This file is part of ArmarX.
std::chrono::system_clock Clock
Definition Stopwatch.h:10
A result struct for skill exit function.
Definition Skill.h:69