ShapeHand.cpp
Go to the documentation of this file.
1#include "ShapeHand.h"
2
3#include <cstdlib>
4#include <string>
5
6#include <range/v3/algorithm/contains.hpp>
7
8#include <SimoxUtility/algorithm/string/string_tools.h>
9
17
18#include <RobotAPI/interface/core/NameValueMap.h>
23
24#include <armarx/control/skills/aron/HandParam.aron.generated.h>
25#include <armarx/control/skills/aron/ShapeHandParams.aron.generated.h>
28
30{
31 namespace
32 {
34 removePrefixFromKeys(const NameValueMap& map, const std::string& prefix)
35 {
36 NameValueMap result;
37 for (const auto& [key, value] : map)
38 {
39 if (simox::alg::starts_with(key, prefix))
40 {
41 result[key.substr(prefix.size())] = value;
42 }
43 else
44 {
45 result[key] = value;
46 }
47 }
48 return result;
49 }
50 } // namespace
51
53 ::armarx::skills::SpecializedSkill<ParamType>(GetSkillDescription()), srv_(srv), p_(p)
54 {
55 }
56
58 ShapeHand::main()
59 {
60 const arondto::ShapeHandParams params = getParameters();
61
62 // verify exactly one of the parameters 'shapeName' and 'jointAngles' is set
63 if ((not params.shapeName) and (not params.jointAngles))
64 {
65 ARMARX_ERROR << "Exactly one of the parameters 'shapeName' and 'jointAngles' must be "
66 "set. However, neither has been set.";
67 return MakeFailedResult();
68 }
69
70 if (params.shapeName and params.jointAngles)
71 {
72 ARMARX_ERROR << "Exactly one of the parameters 'shapeName' and 'jointAngles' must be "
73 "set. However, both have been set.";
74 return MakeFailedResult();
75 }
76
77 // set shape/joinAngles
78
79 auto& handUnit = srv_.getHandUnit(params.hand);
80
81 if (params.shapeName)
82 {
83 const auto shape = params.shapeName.value();
84 ARMARX_INFO << VAROUT(shape);
85
86 // check that the shape is defined
87 // const auto defShapes =
88 // ::armarx::SingleTypeVariantListPtr::dynamicCast(handUnit->getShapeNames())
89 // ->toStdVector<std::string>();
90
91 // if (not ranges::contains(defShapes, shape))
92 // {
93 // ARMARX_ERROR << "Shape with name '" << shape
94 // << "' not defined. Defined shapes: " << defShapes;
95 // return MakeFailedResult();
96 // }
97
98 // set shape
99 ARMARX_INFO << "Setting shape of hand '" << handUnit->getHandName() << "' to '" << shape
100 << "'.";
101
102 handUnit->setShape(shape);
103
104 if (params.waitUntilFinished)
105 {
106 return waitUntilFinished(handUnit->getShapeJointValues(shape));
107 }
108 }
109
110 else // params.jointAngles
111 {
112 const auto jointAngles = params.jointAngles.value();
113
114 ARMARX_INFO << "Setting joint angles of hand '" << handUnit->getHandName()
115 << "' to: " << jointAngles;
116
117 handUnit->setJointAngles(jointAngles);
118
119 if (params.waitUntilFinished)
120 {
121 return waitUntilFinished(jointAngles);
122 }
123 }
124 return MakeSucceededResult();
125 }
126
127 armarx::skills::Skill::MainResult
128 ShapeHand::waitUntilFinished(const NameValueMap& targetAnglesRaw)
129 {
130 if (p_.disableWaitUntilFinished)
131 {
132 return MakeSucceededResult();
133 }
134
135 const arondto::ShapeHandParams params = getParameters();
136
137 auto& handUnit = srv_.getHandUnit(params.hand);
138 const auto movementTimeout = params.waitUntilFinished->movementTimeout;
139
140 ARMARX_INFO << "Waiting until target position is reached"
141 << (movementTimeout ? " or movement times out" : "");
142
143 const std::string handPrefix = params.hand == ::armarx::control::skills::arondto::Hand::Left
144 ? "LeftHand"
145 : "RightHand";
146
147 const NameValueMap targetAngles = removePrefixFromKeys(targetAnglesRaw, handPrefix);
148
149 struct
150 {
151 NameValueMap angles;
152 ::armarx::DateTime time;
153 } pastJointAngles{.angles = handUnit->getCurrentJointValues(), .time = DateTime::Now()};
154
155 const Clock clock;
156 const auto sleepTime = Duration::MilliSeconds(20);
157
158 bool reached = false;
159 bool movementTimedOut = false;
160
161
162 while (not shouldSkillTerminate() and not reached and not movementTimedOut)
163 {
164 // get current angles without hand prefix, e.g. "LeftHand" (depending on simulation or real robot, this might be inconsistent)
165 const auto currentAngles =
166 removePrefixFromKeys(handUnit->getCurrentJointValues(), handPrefix);
167
168 // check if target reached
169 reached = true;
170 for (const auto& [jointName, targetAngle] : targetAngles)
171 {
172 ARMARX_CHECK(currentAngles.count(jointName) > 0)
173 << "Joint '" << jointName << "' not found in current joint angles.";
174 if (std::abs(targetAngle - currentAngles.at(jointName)) > getAccuracy(jointName))
175 {
176 reached = false;
178 << deactivateSpam(1) << "Delta for joint '" << jointName
179 << "' is: " << std::abs(targetAngle - currentAngles.at(jointName)) << " > "
180 << getAccuracy(jointName) << "(accuracy)";
181 break;
182 }
183 }
184
185 // check if movement timed out
186 if (movementTimeout and (DateTime::Now() - pastJointAngles.time).toSecondsDouble() >=
187 movementTimeout.value())
188 {
189 movementTimedOut = true;
190 for (const auto& [jointName, targetAngle] : targetAngles)
191 {
192 if (std::abs(currentAngles.at(jointName) -
193 pastJointAngles.angles.at(jointName)) > getAccuracy(jointName))
194 {
195 movementTimedOut = false;
197 << deactivateSpam(1) << "Joint '" << jointName << "' still moving: "
198 << std::abs(currentAngles.at(jointName) -
199 pastJointAngles.angles.at(jointName))
200 << " > " << getAccuracy(jointName) << "(accuracy)"
201 << "in the last " << movementTimeout.value() << "s (movement timeout)";
202 break;
203 }
204 }
205 pastJointAngles = {.angles = currentAngles, .time = DateTime::Now()};
206 }
207
208 clock.waitFor(sleepTime);
209 }
210
211 if (reached)
212 {
213 ARMARX_INFO << "Target position reached!";
214 }
215 else if (movementTimedOut)
216 {
217 ARMARX_INFO << "Movement timed out! Joints stopped moving. Not waiting anymore until "
218 "target postion is reached";
219 }
220 else if (shouldSkillTerminate())
221 {
223 << "Skill aborted. Not waiting anymore until target position is reached";
224 return MakeAbortedResult();
225 }
226
227 return MakeSucceededResult();
228 }
229
230 float
231 ShapeHand::getAccuracy(const std::string& jointName)
232 {
233 const arondto::ShapeHandParams params = getParameters();
234
235 const auto accuracy = params.waitUntilFinished->accuracy;
236 const auto accuracyOverride = params.waitUntilFinished->accuracyOverride;
237
238 return accuracyOverride.count(jointName) > 0 ? accuracyOverride.at(jointName) : accuracy;
239 }
240
242 {
243 }
244
246 OpenHand::main()
247 {
248 // call ShapeHand-skill
251 id.providerId = getSkillId().providerId;
252
253 using Parameters = arondto::ShapeHandParams;
254 const auto inParams = getParameters();
255
256
258 [inParams](Parameters& params)
259 {
260 params.hand = inParams.hand;
261 params.shapeName = "Open";
262 params.waitUntilFinished =
263 inParams.waitUntilFinished;
264 });
265
267 {
268 return MakeFailedResult();
269 }
270
271 return MakeSucceededResult();
272 }
273
275 {
276 }
277
279 CloseHand::main()
280 {
281 // call ShapeHand-skill
284 id.providerId = getSkillId().providerId;
285
286 using Parameters = arondto::ShapeHandParams;
287
288 const auto inParams = getParameters();
289
291 [&inParams](Parameters& params)
292 {
293 params.hand = inParams.hand;
294 params.shapeName = "Close";
295 params.waitUntilFinished =
296 params.waitUntilFinished;
297 });
298
300 {
301 return MakeFailedResult();
302 }
303
304 return MakeSucceededResult();
305 }
306
307} // 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()
Definition ShapeHand.h:77
::armarx::skills::SkillDescription GetSkillDescription()
Definition ShapeHand.h:55
ShapeHand(const HandUnitServices &, Properties p)
Definition ShapeHand.cpp:52
::armarx::skills::SkillDescription GetSkillDescription()
Definition ShapeHand.h:23
std::optional< ProviderID > providerId
Definition SkillID.h:40
std::string skillName
Definition SkillID.h:41
std::optional< TerminatedSkillStatusUpdate > callSubskill(const SkillID &skillId)
Call a subskill with the given ID and its default parameters.
Definition Skill.cpp:119
static MainResult MakeSucceededResult(aron::data::DictPtr data=nullptr)
Definition Skill.cpp:413
static MainResult MakeAbortedResult(aron::data::DictPtr data=nullptr)
Definition Skill.cpp:431
bool shouldSkillTerminate() const override
Returns whether the skill should terminate as soon as possible.
Definition Skill.cpp:469
SkillID getSkillId() const
Get the id of the skill.
Definition Skill.cpp:587
static MainResult MakeFailedResult(aron::data::DictPtr data=nullptr)
Definition Skill.cpp:422
#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_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
bool skillExecutionFailed(const std::optional< armarx::skills::TerminatedSkillStatusUpdate > &update)
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
::armarx::HandUnitInterfacePrx & getHandUnit(const arondto::Hand hand)
A result struct for th main method of a skill.
Definition Skill.h:62