SimulatedHuman.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 "SimulatedHuman.h"
23
24#include <algorithm>
25#include <optional>
26
30
42
44{
45
46
49 {
50 switch (state_)
51 {
52 case State::Idle:
53 ARMARX_DEBUG << "State:Idle";
54 initialize();
55 state_ = State::Walking;
56 break;
57 case State::Walking:
58 {
59 ARMARX_DEBUG << "State:Walking";
60
61 step();
62
63 if (goalReached())
64 {
65 ARMARX_INFO << "Human reached goal";
66 state_ = State::GoalReached;
67 }
68
69 break;
70 }
72 ARMARX_DEBUG << "State:GoalReached";
73
74 // TODO(fabian.reister): simulate "perform action at goal": wait a while until movement is started again.
75 state_ = State::Idle;
76 break;
77 }
78
79 return human_;
80 }
81
82 bool
84 {
85 const Eigen::Vector2f goal =
86 conv::to2D(globalTrajectory_.points().back().waypoint.pose.translation());
87
88 return ((goal - human_.pose.translation()).norm() < params_.goalDistanceThreshold);
89 }
90
91 void
93 {
94 human_.pose = pose;
95
96 if (goalReached())
97 {
98 ARMARX_VERBOSE << "Goal reached";
99 state_ = State::Idle;
100 }
101
102 initialize();
103 update();
104 }
105
106 void
108 {
109 core::GeneralConfig generalConfig;
110 generalConfig.maxVel.linear = this->params_.maxLinearVelocity;
111
113 params.algo.obstacleDistanceWeight = 1.1F;
114
115 core::Scene scene;
116
117 scene.staticScene.emplace(core::StaticScene{.objects = nullptr,
118 .objectMap = {},
119 .objectInfo = {},
120 .distanceToObstaclesCostmap = std::nullopt,
121 .orientationAwareCostmap = {},
122 .locations = {}});
123 scene.staticScene->distanceToObstaclesCostmap.emplace(distanceField_);
124
125 global_planning::SPFA planner(params, generalConfig, scene);
126
127 const core::Pose2D start = human_.pose;
128
129 if (state_ == State::Idle) // human reached goal and needs a new one
130 {
131 while (true)
132 {
133 const auto sampledPose = algorithms::sampleValidPositionInMap(distanceField_);
134 ARMARX_CHECK(sampledPose.has_value());
135 const core::Pose2D& goal = sampledPose.value();
136
137
138 const auto plan = planner.plan(conv::to3D(start), conv::to3D(goal));
139
140 // check if plan could be created. otherwise try another goal
141 if (plan.has_value())
142 {
143 globalTrajectory_ = plan->trajectory;
144
145 human_ = human::Human{.pose = start,
146 .linearVelocity = Eigen::Vector2f::Zero(),
147 .detectionTime = Clock::Now()};
148 return;
149 }
150 }
151 }
152 else if (state_ == State::Walking) // human is walking and replans to existing goal
153 {
154 const auto goal = conv::to2D(globalTrajectory_.poses().back());
155 const auto plan = planner.plan(conv::to3D(start), conv::to3D(goal));
156
157 // check if plan could be created. otherwise try another goal
158 if (plan.has_value())
159 {
160 globalTrajectory_ = plan->trajectory;
161
162 human_ = human::Human{.pose = start,
163 .linearVelocity = Eigen::Vector2f::Zero(),
164 .detectionTime = Clock::Now()};
165 return;
166 }
167 }
168 }
169
170 void
172 {
173 const auto updateTime = Clock::Now();
174
175 const auto duration = updateTime - human_.detectionTime;
176
177 // move according to old state
178 human_.pose.translation() += duration.toSecondsDouble() * human_.linearVelocity;
179
180 const auto projection =
181 globalTrajectory_.getProjection(conv::to3D(human_.pose.translation()),
183
184 human_.pose = conv::to2D(projection.projection.waypoint.pose);
185
186 const auto wpBefore = projection.wayPointBefore.waypoint.pose.translation();
187 const auto wpAfter = projection.wayPointAfter.waypoint.pose.translation();
188
189 human_.linearVelocity =
190 (wpAfter - wpBefore).head<2>().normalized() * projection.projection.velocity;
191
192 human_.linearVelocity =
193 human_.linearVelocity.normalized() * std::clamp(human_.linearVelocity.norm(),
194 params_.minLinearVelocity,
195 params_.maxLinearVelocity);
196
197 human_.detectionTime = updateTime;
198 }
199
200 SimulatedHuman::SimulatedHuman(const algorithms::Costmap& distanceField, const Params& params) :
201 distanceField_(distanceField), params_(params)
202 {
203 const auto sampledPose = algorithms::sampleValidPositionInMap(distanceField_);
204 ARMARX_CHECK(sampledPose.has_value());
205 human_.pose = sampledPose.value();
206
207 update(); // should bring the robot into walking state
208 }
209} // namespace armarx::navigation::human::simulation
static DateTime Now()
Current time on the virtual clock.
Definition Clock.cpp:93
std::optional< GlobalPlannerResult > plan(const core::Pose &goal) override
Definition SPFA.cpp:95
void reinitialize(const core::Pose2D &pose)
resets the human to the given pose and replans the global optimal trajectory
SimulatedHuman(const algorithms::Costmap &distanceField, const Params &params=Params())
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
std::optional< core::Pose2D > sampleValidPositionInMap(const algorithms::Costmap &costmap)
Definition util.cpp:431
std::vector< Eigen::Vector2f > to2D(const std::vector< Eigen::Vector3f > &v)
Definition eigen.cpp:29
std::vector< Eigen::Vector3f > to3D(const std::vector< Eigen::Vector2f > &v)
Definition eigen.cpp:14
Eigen::Isometry2f Pose2D
Definition basic_types.h:34
This file is part of ArmarX.
std::optional< core::StaticScene > staticScene
Definition types.h:70
algorithms::spfa::ShortestPathFasterAlgorithm::Parameters algo
Definition SPFA.h:52