NASA Astrobee Robot Software  Astrobee Version:
Flight software for the Astrobee robots operating inside the International Space Station.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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