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