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