RobotReceiver.cpp
Go to the documentation of this file.
1/**
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @author Fabian Reister ( fabian dot reister at kit dot edu )
17 * @date 2022
18 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
19 * GNU General Public License
20 */
21
22#include "RobotReceiver.h"
23
24#include <Eigen/Core>
25
26#include <VirtualRobot/Robot.h>
27
30
32
34
36{
37 RobotReceiver::RobotReceiver(const std::string& humanTrackingId,
38 const VirtualRobot::RobotPtr& robot) :
39 HandoverTargetProvider(humanTrackingId, robot)
40 {
41 }
42
43 std::vector<gaze_targets::GazeTarget>
45 {
46 std::vector<gaze_targets::GazeTarget> targets;
47
48 switch (phase_)
49 {
52 break;
55 break;
56 }
57
58 return targets;
59 }
60
61 std::vector<gaze_targets::GazeTarget>
63 {
64
65 const auto headKpName = util::headKeypoint(human.poseModelId);
66 const auto pelvisKpName = util::pelvisKeypoint(human.poseModelId);
67 const auto leftWristKpName = util::leftWristKeypoint(human.poseModelId);
68 const auto rightWristKpName = util::rightWristKeypoint(human.poseModelId);
69
70 ARMARX_CHECK(headKpName.has_value());
71 ARMARX_CHECK(leftWristKpName.has_value());
72 ARMARX_CHECK(rightWristKpName.has_value());
73 ARMARX_CHECK(pelvisKpName.has_value());
74
75 std::vector<gaze_targets::GazeTarget> gazeTargets;
76
77 if (human.keypoints.count(headKpName.value()) == 0)
78 {
79 ARMARX_WARNING << deactivateSpam(1) << "Head keypoint `" << headKpName.value()
80 << "` not available!";
81 return {};
82 };
83
84 // head target
85 {
86 const armem::human::PoseKeypoint headKp = human.keypoints.at(headKpName.value());
87
88 const gaze_targets::TargetPriority targetPriority(
90
91 gaze_targets::GazeTarget headTarget(
92 "head", headKp.positionGlobal.value(), targetPriority, Duration::Seconds(1), false);
93 gazeTargets.push_back(headTarget);
94 }
95
96 const armem::human::PoseKeypoint pelvisKp = human.keypoints.at(pelvisKpName.value());
97
98 const float distanceHumanRobot =
99 (pelvisKp.positionGlobal.value().toEigen() - robot_->getGlobalPosition())
100 .head<2>()
101 .norm();
102 ARMARX_VERBOSE << VAROUT(distanceHumanRobot);
103
104 if (distanceHumanRobot > params.maxHandoverInitializationDistance)
105 {
106 return gazeTargets;
107 }
108
109
110 // the priority to look at the humans hands is defined by the distance to the pelvis (2d projection)
111
112 const auto handPriorityFromDistance =
113 [&](const float handBodyDistance, const float handRobotDistance)
114 {
115 // f = 1: highest priority
116 // f = 0: low prio
117 const float normalizedHandBodyPriority =
118 std::clamp((handBodyDistance - params.minHandReachoutDistance) /
119 (params.maxHandReachoutDistance - params.minHandReachoutDistance),
120 0.f,
121 1.f);
122
123 // f = 1: highest priority
124 // f = 0: low prio
125 const float normalizedHandRobotPriority = std::clamp(
126 (params.maxHandoverInitializationDistance - handRobotDistance) /
127 (params.maxHandoverInitializationDistance - params.minHandoverDistance),
128 0.f,
129 1.f);
130
131 return params.handPriorityScaling * normalizedHandBodyPriority *
132 normalizedHandRobotPriority;
133 };
134
135 const auto handsPriorityFromDistance = [&](const float handsRobotDistance)
136 {
137 return handsRobotDistance < params.maxHandsInitializationDistance
138 ? (params.headPriority + 1)
139 : 0;
140 };
141
142
143 // left wrist target
144 if (human.keypoints.count(leftWristKpName.value()) > 0)
145 {
146 const armem::human::PoseKeypoint leftWristKp =
147 human.keypoints.at(leftWristKpName.value());
148
149 const float distanceLeft =
150 (leftWristKp.positionGlobal->toEigen() - pelvisKp.positionGlobal->toEigen()).norm();
151
152 const float handRobotDistance = leftWristKp.positionRobot->toEigen().head<2>().norm();
153
154 const float priority = handPriorityFromDistance(distanceLeft, handRobotDistance);
155 const gaze_targets::TargetPriority targetPriority(
157
158 gaze_targets::GazeTarget handTarget("left_hand",
159 leftWristKp.positionGlobal.value(),
160 targetPriority,
162 false);
163 gazeTargets.push_back(handTarget);
164 }
165
166 // right wrist target
167 if (human.keypoints.count(rightWristKpName.value()) > 0)
168 {
169 const armem::human::PoseKeypoint rightWristKp =
170 human.keypoints.at(rightWristKpName.value());
171
172 const float distanceRight =
173 (rightWristKp.positionGlobal->toEigen() - pelvisKp.positionGlobal->toEigen())
174 .norm();
175
176 const float handRobotDistance = rightWristKp.positionRobot->toEigen().head<2>().norm();
177
178 const float priority = handPriorityFromDistance(distanceRight, handRobotDistance);
179
180 const gaze_targets::TargetPriority targetPriority(
182
183 gaze_targets::GazeTarget handTarget("right_hand",
184 rightWristKp.positionGlobal.value(),
185 targetPriority,
187 false);
188 gazeTargets.push_back(handTarget);
189 }
190
191 // In addition to the individual hand targets, we create one target for the center point of both hands
192 // This will lower the gaze target and the head won't need to move too much once an arm is streched out.
193 {
194 const armem::human::PoseKeypoint leftWristKp =
195 human.keypoints.at(leftWristKpName.value());
196 const armem::human::PoseKeypoint rightWristKp =
197 human.keypoints.at(rightWristKpName.value());
198
199 const float alpha = 0.5; // might be improved in the future
200
201 const Eigen::Vector3f centerHandsPosition =
202 leftWristKp.positionGlobal->toEigen() +
203 alpha * (rightWristKp.positionGlobal->toEigen() -
204 leftWristKp.positionGlobal->toEigen());
205
206 const float centerHandsRobotDistance =
207 (centerHandsPosition - robot_->getGlobalPosition()).head<2>().norm();
208
209 const float priority = handsPriorityFromDistance(centerHandsRobotDistance);
210
211 const gaze_targets::TargetPriority targetPriority(
213
214 const std::string& agent = leftWristKp.positionGlobal->agent;
215
216 gaze_targets::GazeTarget handsTarget(
217 "center_hands",
218 FramedPosition(centerHandsPosition, GlobalFrame, agent),
219 targetPriority,
221 false);
222 gazeTargets.push_back(handsTarget);
223 }
224
225 // combined wrist
226
227 // some debugging
228 {
229 for (const auto& target : gazeTargets)
230 {
231 ARMARX_VERBOSE << target.name << ": " << target.priority;
232 }
233 }
234
235 return gazeTargets;
236 }
237
238 std::vector<gaze_targets::GazeTarget>
240 {
241
242 const auto headKpName = util::headKeypoint(human.poseModelId);
243 const auto leftWristKpName = util::leftWristKeypoint(human.poseModelId);
244 const auto rightWristKpName = util::rightWristKeypoint(human.poseModelId);
245
246 ARMARX_CHECK(headKpName.has_value());
247 ARMARX_CHECK(leftWristKpName.has_value());
248 ARMARX_CHECK(rightWristKpName.has_value());
249
250 std::vector<gaze_targets::GazeTarget> gazeTargets;
251
252 if (human.keypoints.count(headKpName.value()) == 0)
253 {
254 ARMARX_WARNING << deactivateSpam(1) << "Head keypoint `" << headKpName.value()
255 << "` not available!";
256 return {};
257 };
258
259 // head target
260 {
261 const armem::human::PoseKeypoint headKp = human.keypoints.at(headKpName.value());
262
263 const gaze_targets::TargetPriority targetPriority(
265
266 gaze_targets::GazeTarget headTarget(
267 "head", headKp.positionGlobal.value(), targetPriority, Duration::Seconds(1), false);
268 gazeTargets.push_back(headTarget);
269 }
270
271 return gazeTargets;
272 }
273
274} // namespace armarx::view_selection::target_provider::handover
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
#define VAROUT(x)
static Duration Seconds(std::int64_t seconds)
Constructs a duration in seconds.
Definition Duration.cpp:72
The FramedPosition class.
Definition FramedPose.h:158
Business Object (BO) class of GazeTarget.
Definition GazeTarget.h:23
RobotReceiver(const std::string &humanTrackingId, const VirtualRobot::RobotPtr &robot)
std::vector< gaze_targets::GazeTarget > updateTargets(const armem::human::HumanPose &human) override
HandoverTargetProvider(const std::string &humanTrackingId, const VirtualRobot::RobotPtr &robot)
std::vector< gaze_targets::GazeTarget > updateTargetsPreHandover(const armem::human::HumanPose &human) const
std::vector< gaze_targets::GazeTarget > updateTargetsAfterHandover(const armem::human::HumanPose &human) const
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
std::string const GlobalFrame
Variable of the global coordinate system.
Definition FramedPose.h:65
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
@ TaskDriven
Task-Driven attention has highest priority.
std::optional< std::string > pelvisKeypoint(const std::string &poseModelId)
Definition util.cpp:73
std::optional< std::string > headKeypoint(const std::string &poseModelId)
Definition util.cpp:13
std::optional< std::string > rightWristKeypoint(const std::string &poseModelId)
Definition util.cpp:53
std::optional< std::string > leftWristKeypoint(const std::string &poseModelId)
Definition util.cpp:33
This file is part of ArmarX.
Definition Human.cpp:33
Eigen::Vector3f toEigen(const pcl::PointXYZ &pt)
double norm(const Point &a)
Definition point.hpp:102
std::optional< armarx::FramedPosition > positionRobot
Definition types.h:35
std::optional< armarx::FramedPosition > positionGlobal
Definition types.h:37