NASA Astrobee Robot Software  0.19.1
Flight software for the Astrobee robots operating inside the International Space Station.
planner.h
Go to the documentation of this file.
1 /* Copyright (c) 2017, United States Government, as represented by the
2  * Administrator of the National Aeronautics and Space Administration.
3  *
4  * All rights reserved.
5  *
6  * The Astrobee platform is licensed under the Apache License, Version 2.0
7  * (the "License"); you may not use this file except in compliance with the
8  * License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15  * License for the specific language governing permissions and limitations
16  * under the License.
17  */
18 
19 #ifndef CHOREOGRAPHER_PLANNER_H_
20 #define CHOREOGRAPHER_PLANNER_H_
21 
22 // Standard includes
23 #include <ros/ros.h>
24 #include <pcl/point_types.h>
25 
26 // FSW libraries
27 #include <ff_util/ff_nodelet.h>
28 #include <ff_common/ff_names.h>
29 #include <ff_util/ff_action.h>
30 #include <ff_util/ff_service.h>
31 #include <ff_util/ff_flight.h>
32 #include <ff_util/config_server.h>
33 #include <ff_util/config_client.h>
34 #include <ff_util/conversion.h>
35 #include <jsonloader/keepout.h>
36 #include <mapper/point_cloud.h>
37 
38 // FSW messages
39 #include <ff_msgs/PlanAction.h>
40 #include <ff_msgs/ControlState.h>
41 #include <ff_msgs/Zone.h>
42 #include <ff_msgs/RegisterPlanner.h>
43 #include <ff_msgs/GetZones.h>
44 #include <ff_msgs/GetOccupancyMap.h>
45 #include <ff_msgs/GetMap.h>
46 
47 // Voxel map
48 #include <jps3d/planner/jps_3d_util.h>
49 
50 #include <memory>
51 #include <string>
52 #include <vector>
53 
57 namespace planner {
58 
59 // Convenience declarations
60 using RESPONSE = ff_msgs::PlanResult;
61 
62 // Abstract class for implementing planners
64  private:
65  enum State {
66  INITIALIZING,
67  WAITING,
68  PLANNING
69  };
70 
71  public:
72  // The constructor takes the planner name and a brief description of it
73  explicit PlannerImplementation(std::string const& name, std::string const& description) :
75  state_(INITIALIZING) {
76  // Configure the registration details
77  registration_.request.name = name;
78  registration_.request.description = description;
79  registration_.request.unregister = false;
80  }
81 
82  // Destructor deregisters with choreographer
84  // registration_.request.unregister = true;
85  // client_r_.Call(registration_);
86  }
87 
88  protected:
89  // Derived classes must implement these functions
90  virtual bool InitializePlanner(ros::NodeHandle *nh) = 0;
91  virtual void PlanCallback(ff_msgs::PlanGoal const& goal) = 0;
92 
93  // Send the planner result
94  void PlanResult(ff_msgs::PlanResult const& result) {
95  switch (state_) {
96  case PLANNING:
97  NODELET_DEBUG_STREAM("Plan result received");
98  NODELET_DEBUG_STREAM(result);
99  Complete(result.response, result);
100  break;
101  default:
102  NODELET_WARN_STREAM("Plan result received in non-planning state");
103  break;
104  }
105  }
106 
107  // Send some planner feedback
108  void PlanFeedback(ff_msgs::PlanFeedback const& feedback) {
109  switch (state_) {
110  case PLANNING:
111  server_p_.SendFeedback(feedback);
112  break;
113  default:
114  NODELET_WARN_STREAM("Plan feedback received in non-planning state");
115  break;
116  }
117  }
118 
119  // Get the keepin and keepout zones
120  bool GetZones(std::vector < ff_msgs::Zone > & zones) {
121  ff_msgs::GetZones srv;
122  if (client_z_.Call(srv)) {
123  zones = srv.response.zones;
124  return true;
125  }
126  return false;
127  }
128  // Get the keepin and keepout zones
129  bool GetZonesMap(std::vector<signed char> &map, Vec3f &origin, Vec3i &dim, double &map_res) {
130  ff_msgs::GetOccupancyMap srv;
131  if (client_z_m_.Call(srv)) {
132  map.resize(srv.response.map.size());
133  map = srv.response.map;
134  origin[0] = srv.response.origin.x;
135  origin[1] = srv.response.origin.y;
136  origin[2] = srv.response.origin.z;
137  dim[0] = srv.response.dim.x;
138  dim[1] = srv.response.dim.y;
139  dim[2] = srv.response.dim.z;
140  map_res = srv.response.resolution;
141  return true;
142  }
143  return false;
144  }
145  bool GetFreeMap(pcl::PointCloud<pcl::PointXYZ> *points, float *resolution) {
146  ff_msgs::GetMap srv;
147  if (client_f_.Call(srv)) {
148  pcl::fromROSMsg(srv.response.points, *points);
149  *resolution = srv.response.resolution;
150  return true;
151  }
152  return false;
153  }
154  bool GetObstacleMap(pcl::PointCloud<pcl::PointXYZ> *points, float *resolution) {
155  ff_msgs::GetMap srv;
156  if (client_o_.Call(srv)) {
157  pcl::fromROSMsg(srv.response.points, *points);
158  *resolution = srv.response.resolution;
159  return true;
160  }
161  return false;
162  }
163 
164  private:
165  void Initialize(ros::NodeHandle *nh) {
166  cfg_fm_.AddFile("flight.config");
167  cfg_fm_.ReadFiles();
168  // Listen for plan requests
169  server_p_.SetGoalCallback(std::bind(&PlannerImplementation::GoalCallback, this, std::placeholders::_1));
170  server_p_.SetPreemptCallback(std::bind(&PlannerImplementation::PreemptCallback, this));
171  server_p_.SetCancelCallback(std::bind(&PlannerImplementation::CancelCallback, this));
172  std::string topic = std::string(PREFIX_MOBILITY_PLANNER)
173  + registration_.request.name
174  + std::string(SUFFIX_MOBILITY_PLANNER);
175  server_p_.Create(nh, topic);
176  // Initialize the get zone call
177  client_z_.SetConnectedCallback(std::bind(&PlannerImplementation::ConnectedCallback, this));
178  client_z_.SetTimeoutCallback(std::bind(&PlannerImplementation::GetZonesTimeoutCallback, this));
179  client_z_.Create(nh, SERVICE_MOBILITY_GET_ZONES);
180  // Initialize the get zone map call
181  client_z_m_.SetConnectedCallback(std::bind(&PlannerImplementation::ConnectedCallback, this));
182  client_z_m_.SetTimeoutCallback(std::bind(&PlannerImplementation::GetZonesMapTimeoutCallback, this));
183  client_z_m_.Create(nh, SERVICE_MOBILITY_GET_ZONES_MAP);
184  // Initialize the register planner call
185  client_r_.SetConnectedCallback(std::bind(&PlannerImplementation::ConnectedCallback, this));
186  client_r_.SetTimeoutCallback(std::bind(&PlannerImplementation::RegisterTimeoutCallback, this));
188  // Initialize the free map call
189  client_f_.SetConnectedCallback(std::bind(&PlannerImplementation::ConnectedCallback, this));
190  client_f_.SetTimeoutCallback(std::bind(&PlannerImplementation::GetFreeMapTimeoutCallback, this));
191  client_f_.Create(nh, SERVICE_MOBILITY_GET_FREE_MAP);
192  // Initialize the obstacle map call
193  client_o_.SetConnectedCallback(std::bind(&PlannerImplementation::ConnectedCallback, this));
194  client_o_.SetTimeoutCallback(std::bind(&PlannerImplementation::GetObstacleMapTimeoutCallback, this));
196  // Initialize the planner itself
197  if (!InitializePlanner(nh))
198  InitFault("Planner could not be initialized");
199  }
200 
201  // Deal with a fault in a responsible manner - note that this may also be
202  // called if action and service servers timeout on conenction.
203  void InitFault(std::string const& msg ) {
204  NODELET_ERROR_STREAM(msg);
206  return;
207  }
208 
209  // Finish this action
210  void Complete(int32_t response_code, ff_msgs::PlanResult result = ff_msgs::PlanResult()) {
211  switch (state_) {
212  case PLANNING:
213  result.response = response_code;
214  if (result.response > 0)
216  else if (result.response < 0)
218  else
220  break;
221  default:
222  NODELET_WARN_STREAM("Plan result received in non-planning state");
223  break;
224  }
225  // We are now back to waiting
226  state_ = WAITING;
227  }
228 
229  // Ensure all clients are connected
230  void ConnectedCallback(void) {
231  NODELET_DEBUG_STREAM("ConnectedCallback()");
232  if (!client_z_.IsConnected()) return; // Zones
233  if (!client_z_m_.IsConnected()) return; // Zones Map
234  if (!client_r_.IsConnected()) return; // Register
235  if (!client_o_.IsConnected()) return; // Register
236  if (!client_f_.IsConnected()) return; // Register
237  if (state_ != INITIALIZING) return; // Don't initialize twice
238  // Register this planner
239  NODELET_DEBUG_STREAM("Registering planner");
240  client_r_.Call(registration_);
241  // Move to waiting state
242  state_ = WAITING;
243  }
244 
245  // Timeout on a trajectory generation request
246  void RegisterTimeoutCallback(void) {
247  return InitFault("Timeout connecting to register service");
248  }
249 
250  // Timeout on a trajectory generation request
251  void GetZonesTimeoutCallback(void) {
252  return InitFault("Timeout connecting to the get zones service");
253  }
254 
255  // Timeout on a trajectory generation request
256  void GetZonesMapTimeoutCallback(void) {
257  return InitFault("Timeout connecting to the get zones map service");
258  }
259 
260  // Timeout on a free map request
261  void GetFreeMapTimeoutCallback(void) {
262  return InitFault("Timeout connecting to the get free map service");
263  }
264 
265  // Timeout on a obstacle map request
266  void GetObstacleMapTimeoutCallback(void) {
267  return InitFault("Timeout connecting to the get obstacle map service");
268  }
269 
270  // Check that the value is less than the given bound
271  bool CheckBound(double candidate, double upper_bound) {
272  return (candidate <= upper_bound);
273  }
274 
275  // Get the value
276  double GetValue(double candidate, double upper_bound) {
277  if (candidate > 0.0 && candidate <= upper_bound)
278  return candidate;
279  return upper_bound;
280  }
281 
282  // Called when a new planning goal arrives
283  void GoalCallback(ff_msgs::PlanGoalConstPtr const& old_goal) {
284  NODELET_DEBUG_STREAM("A new plan request was just received");
285  NODELET_DEBUG_STREAM(*old_goal);
286  switch (state_) {
287  default:
288  case INITIALIZING:
289  return Complete(RESPONSE::PROBLEM_CONNECTING_TO_SERVICES);
290  case PLANNING:
291  Complete(RESPONSE::PREEMPTED);
292  case WAITING:
293  break;
294  }
295  // We are now planning
296  state_ = PLANNING;
297  // Call the implementation with the plan goal
298  return PlanCallback(*old_goal);
299  }
300 
301  // Cancel the current operation
302  void PreemptCallback(void) {
303  return Complete(RESPONSE::PREEMPTED);
304  }
305 
306  // Cancel the current operation
307  void CancelCallback(void) {
308  return Complete(RESPONSE::CANCELLED);
309  }
310 
311  private:
312  State state_; // Planner state
318  ff_msgs::RegisterPlanner registration_; // Registration info
319  config_reader::ConfigReader cfg_fm_; // Configuration
320 };
321 
322 } // namespace planner
323 
324 #endif // CHOREOGRAPHER_PLANNER_H_
ff_util::FreeFlyerActionServer< ff_msgs::PlanAction >
SERVICE_MOBILITY_GET_OBSTACLE_MAP
#define SERVICE_MOBILITY_GET_OBSTACLE_MAP
Definition: ff_names.h:246
planner
Definition: planner.h:57
planner::PlannerImplementation::GetFreeMap
bool GetFreeMap(pcl::PointCloud< pcl::PointXYZ > *points, float *resolution)
Definition: planner.h:145
keepout.h
ff_util::FreeFlyerServiceClient::SetConnectedCallback
void SetConnectedCallback(ConnectedCallbackType cb_connected)
Definition: ff_service.h:56
ff_util::FreeFlyerNodelet::FreeFlyerNodelet
FreeFlyerNodelet(bool autostart_hb_timer=true)
Definition: ff_nodelet.cc:46
config_reader::ConfigReader::ReadFiles
bool ReadFiles()
Definition: config_reader.cc:530
ff_util::FreeFlyerActionServer::SetPreemptCallback
void SetPreemptCallback(PreemptCallbackType cb_preempt)
Definition: ff_action.h:72
ff_util::FreeFlyerActionServer::SendFeedback
void SendFeedback(Feedback const &feedback)
Definition: ff_action.h:85
ff_util::FreeFlyerActionState::PREEMPTED
@ PREEMPTED
Definition: ff_action.h:43
point_cloud.h
ff_util::FreeFlyerServiceClient< ff_msgs::GetZones >
planner::RESPONSE
ff_msgs::PlanResult RESPONSE
Definition: planner.h:60
ff_flight.h
PREFIX_MOBILITY_PLANNER
#define PREFIX_MOBILITY_PLANNER
Definition: ff_names.h:258
ff_nodelet.h
pcl::fromROSMsg
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
Definition: pcl_conversions.h:242
planner::PlannerImplementation::~PlannerImplementation
virtual ~PlannerImplementation()
Definition: planner.h:83
ff_util::FreeFlyerServiceClient::IsConnected
bool IsConnected()
Definition: ff_service.h:86
planner::PlannerImplementation::GetObstacleMap
bool GetObstacleMap(pcl::PointCloud< pcl::PointXYZ > *points, float *resolution)
Definition: planner.h:154
config_server.h
planner::PlannerImplementation::PlannerImplementation
PlannerImplementation(std::string const &name, std::string const &description)
Definition: planner.h:73
config_reader::ConfigReader::AddFile
void AddFile(const char *filename, unsigned flags=0)
Definition: config_reader.cc:517
ff_util::FreeFlyerActionServer::SetGoalCallback
void SetGoalCallback(GoalCallbackType cb_goal)
Definition: ff_action.h:71
name
std::string name
Definition: eps_simulator.cc:48
ff_util::FreeFlyerNodelet
Definition: ff_nodelet.h:57
ff_names.h
SERVICE_MOBILITY_GET_FREE_MAP
#define SERVICE_MOBILITY_GET_FREE_MAP
Definition: ff_names.h:245
planner::PlannerImplementation::PlanResult
void PlanResult(ff_msgs::PlanResult const &result)
Definition: planner.h:94
ff_service.h
ff_util::FreeFlyerActionServer::Create
void Create(ros::NodeHandle *nh, std::string const &topic)
Definition: ff_action.h:76
planner::PlannerImplementation::InitializePlanner
virtual bool InitializePlanner(ros::NodeHandle *nh)=0
ff_util::FreeFlyerActionState::ABORTED
@ ABORTED
Definition: ff_action.h:44
config_reader::ConfigReader
Definition: config_reader.h:48
conversion.h
config_client.h
SERVICE_MOBILITY_PLANNER_REGISTER
#define SERVICE_MOBILITY_PLANNER_REGISTER
Definition: ff_names.h:255
ff_action.h
ff_util::INITIALIZATION_FAILED
@ INITIALIZATION_FAILED
Definition: ff_faults.h:32
PREFIX_MOBILITY_PLANNER_PRIVATE
#define PREFIX_MOBILITY_PLANNER_PRIVATE
Definition: ff_names.h:257
std
Definition: tensor.h:39
ff_util::FreeFlyerActionServer::SetCancelCallback
void SetCancelCallback(CancelCallbackType cb_cancel)
Definition: ff_action.h:73
ff_util::FreeFlyerActionState::SUCCESS
@ SUCCESS
Definition: ff_action.h:42
ff_util
Definition: config_client.h:31
SUFFIX_MOBILITY_PLANNER
#define SUFFIX_MOBILITY_PLANNER
Definition: ff_names.h:259
planner::PlannerImplementation::PlanFeedback
void PlanFeedback(ff_msgs::PlanFeedback const &feedback)
Definition: planner.h:108
ff_util::FreeFlyerNodelet::AssertFault
void AssertFault(FaultKeys enum_key, std::string const &message, ros::Time time_fault_occurred=ros::Time::now())
Definition: ff_nodelet.cc:199
ff_util::FreeFlyerServiceClient::Call
bool Call(ServiceSpec &service)
Definition: ff_service.h:94
ff_util::FreeFlyerActionServer::SendResult
void SendResult(FreeFlyerActionState::Enum result_code, Result const &result)
Definition: ff_action.h:91
planner::PlannerImplementation
Definition: planner.h:63
SERVICE_MOBILITY_GET_ZONES
#define SERVICE_MOBILITY_GET_ZONES
Definition: ff_names.h:235
ff_util::FreeFlyerServiceClient::Create
bool Create(ros::NodeHandle *nh, std::string const &topic)
Definition: ff_service.h:72
planner::PlannerImplementation::GetZones
bool GetZones(std::vector< ff_msgs::Zone > &zones)
Definition: planner.h:120
planner::PlannerImplementation::GetZonesMap
bool GetZonesMap(std::vector< signed char > &map, Vec3f &origin, Vec3i &dim, double &map_res)
Definition: planner.h:129
SERVICE_MOBILITY_GET_ZONES_MAP
#define SERVICE_MOBILITY_GET_ZONES_MAP
Definition: ff_names.h:236
planner::PlannerImplementation::PlanCallback
virtual void PlanCallback(ff_msgs::PlanGoal const &goal)=0
ff_util::FreeFlyerServiceClient::SetTimeoutCallback
void SetTimeoutCallback(TimeoutCallbackType cb_timeout)
Definition: ff_service.h:55