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)
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 const arondto::ShapeHandParams params = getParameters();
131
132 auto& handUnit = srv_.getHandUnit(params.hand);
133 const auto movementTimeout = params.waitUntilFinished->movementTimeout;
134
135 ARMARX_INFO << "Waiting until target position is reached"
136 << (movementTimeout ? " or movement times out" : "");
137
138 const std::string handPrefix = params.hand == ::armarx::control::skills::arondto::Hand::Left
139 ? "LeftHand"
140 : "RightHand";
141
142 const NameValueMap targetAngles = removePrefixFromKeys(targetAnglesRaw, handPrefix);
143
144 struct
145 {
146 NameValueMap angles;
147 ::armarx::DateTime time;
148 } pastJointAngles{handUnit->getCurrentJointValues(), DateTime::Now()};
149
150 const Clock clock;
151 const auto sleepTime = Duration::MilliSeconds(20);
152
153 bool reached = false;
154 bool movementTimedOut = false;
155
156
157 while (not shouldSkillTerminate() and not reached and not movementTimedOut)
158 {
159 // get current angles without hand prefix, e.g. "LeftHand" (depending on simulation or real robot, this might be inconsistent)
160 const auto currentAngles =
161 removePrefixFromKeys(handUnit->getCurrentJointValues(), handPrefix);
162
163 // check if target reached
164 reached = true;
165 for (const auto& [jointName, targetAngle] : targetAngles)
166 {
167 ARMARX_CHECK(currentAngles.count(jointName) > 0)
168 << "Joint '" << jointName << "' not found in current joint angles.";
169 if (std::abs(targetAngle - currentAngles.at(jointName)) > getAccuracy(jointName))
170 {
171 reached = false;
173 << deactivateSpam(1) << "Delta for joint '" << jointName
174 << "' is: " << std::abs(targetAngle - currentAngles.at(jointName)) << " > "
175 << getAccuracy(jointName) << "(accuracy)";
176 break;
177 }
178 }
179
180 // check if movement timed out
181 if (movementTimeout and (DateTime::Now() - pastJointAngles.time).toSecondsDouble() >=
182 movementTimeout.value())
183 {
184 movementTimedOut = true;
185 for (const auto& [jointName, targetAngle] : targetAngles)
186 {
187 if (std::abs(currentAngles.at(jointName) -
188 pastJointAngles.angles.at(jointName)) > getAccuracy(jointName))
189 {
190 movementTimedOut = false;
192 << deactivateSpam(1) << "Joint '" << jointName << "' still moving: "
193 << std::abs(currentAngles.at(jointName) -
194 pastJointAngles.angles.at(jointName))
195 << " > " << getAccuracy(jointName) << "(accuracy)"
196 << "in the last " << movementTimeout.value() << "s (movement timeout)";
197 break;
198 }
199 }
200 pastJointAngles = {.angles = currentAngles, .time = DateTime::Now()};
201 }
202
203 clock.waitFor(sleepTime);
204 }
205
206 if (reached)
207 {
208 ARMARX_INFO << "Target position reached!";
209 }
210 else if (movementTimedOut)
211 {
212 ARMARX_INFO << "Movement timed out! Joints stopped moving. Not waiting anymore until "
213 "target postion is reached";
214 }
215 else if (shouldSkillTerminate())
216 {
218 << "Skill aborted. Not waiting anymore until target position is reached";
219 return MakeAbortedResult();
220 }
221
222 return MakeSucceededResult();
223 }
224
225 float
226 ShapeHand::getAccuracy(const std::string& jointName)
227 {
228 const arondto::ShapeHandParams params = getParameters();
229
230 const auto accuracy = params.waitUntilFinished->accuracy;
231 const auto accuracyOverride = params.waitUntilFinished->accuracyOverride;
232
233 return accuracyOverride.count(jointName) > 0 ? accuracyOverride.at(jointName) : accuracy;
234 }
235
237 {
238 }
239
241 OpenHand::main()
242 {
243 // call ShapeHand-skill
246 id.providerId = getSkillId().providerId;
247
248 using Parameters = arondto::ShapeHandParams;
249 const auto inParams = getParameters();
250
251
253 [inParams](Parameters& params)
254 {
255 params.hand = inParams.hand;
256 params.shapeName = "Open";
257 params.waitUntilFinished =
258 inParams.waitUntilFinished;
259 });
260
262 {
263 return MakeFailedResult();
264 }
265
266 return MakeSucceededResult();
267 }
268
270 {
271 }
272
274 CloseHand::main()
275 {
276 // call ShapeHand-skill
279 id.providerId = getSkillId().providerId;
280
281 using Parameters = arondto::ShapeHandParams;
282
283 const auto inParams = getParameters();
284
286 [&inParams](Parameters& params)
287 {
288 params.hand = inParams.hand;
289 params.shapeName = "Close";
290 params.waitUntilFinished =
291 params.waitUntilFinished;
292 });
293
295 {
296 return MakeFailedResult();
297 }
298
299 return MakeSucceededResult();
300 }
301
302} // 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:70
::armarx::skills::SkillDescription GetSkillDescription()
Definition ShapeHand.h:48
ShapeHand(const HandUnitServices &)
Definition ShapeHand.cpp:52
::armarx::skills::SkillDescription GetSkillDescription()
Definition ShapeHand.h:18
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