mimic_node.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <ros/ros.h>
17 #include <ros/package.h>
20 
21 #include <cob_mimic/SetMimicAction.h>
22 #include <cob_mimic/SetMimicGoal.h>
23 #include <cob_mimic/SetMimicFeedback.h>
24 #include <cob_mimic/SetMimicResult.h>
25 
26 #include <cob_mimic/SetMimic.h>
27 #include <cob_mimic/SetMimicRequest.h>
28 #include <cob_mimic/SetMimicResponse.h>
29 
30 #include <vlc/vlc.h>
31 #include <unistd.h>
32 
33 #include <boost/thread.hpp>
34 #include <boost/filesystem.hpp>
35 #include <boost/format.hpp>
36 #include <boost/random/mersenne_twister.hpp>
37 #include <boost/random/uniform_real_distribution.hpp>
38 #include <boost/random/uniform_int_distribution.hpp>
39 
40 class Mimic
41 {
42 public:
43  Mimic():
44  as_mimic_(nh_, ros::this_node::getName() + "/set_mimic", boost::bind(&Mimic::as_cb_mimic_, this, _1), false),
45  new_mimic_request_(false), sim_enabled_(false), blocking_(true), default_mimic_("default"),
46  real_dist_(2,10), int_dist_(0,6)
47  {
48  nh_ = ros::NodeHandle("~");
49  }
50 
51  ~Mimic(void)
52  {
53  libvlc_media_player_stop(vlc_player_);
54  libvlc_media_player_release(vlc_player_);
55  libvlc_release(vlc_inst_);
56  }
57 
58  bool init()
59  {
60  if(!copy_mimic_files())
61  return false;
62 
63  sim_enabled_ = nh_.param<bool>("sim", false);
64  blocking_ = nh_.param<bool>("blocking", true);
65  default_mimic_ = nh_.param<std::string>("default_mimic", "default");
67  action_active_ = false;
68  service_active_ = false;
69 
70  random_mimics_.push_back("blinking");
71  random_mimics_.push_back("blinking");
72  random_mimics_.push_back("blinking");
73  random_mimics_.push_back("blinking_left");
74  random_mimics_.push_back("blinking_right");
75  random_mimics_ = nh_.param<std::vector< std::string> >("random_mimics", random_mimics_);
76 
80 
81  int_dist_ = boost::random::uniform_int_distribution<>(0,static_cast<int>(random_mimics_.size())-1);
82 
83  char const *argv[] =
84  {
85  "--ignore-config",
86  "--mouse-hide-timeout=0",
87  "-q",
88  "--no-osd",
89  "-L",
90  "--one-instance",
91  "--playlist-enqueue",
92  "--no-video-title-show",
93  "--no-skip-frames",
94  "--no-audio",
95  "--vout=glx,none"
96  };
97  int argc = sizeof( argv ) / sizeof( *argv );
98 
99  vlc_inst_ = libvlc_new(argc, argv);
100  if(!vlc_inst_){ROS_ERROR("failed to create libvlc instance"); return false;}
101  vlc_player_ = libvlc_media_player_new(vlc_inst_);
102  if(!vlc_player_){ROS_ERROR("failed to create vlc media player object"); return false;}
103 
104  if(sim_enabled_){libvlc_set_fullscreen(vlc_player_, 0);}
105  else{libvlc_set_fullscreen(vlc_player_, 1);}
106  set_mimic(default_mimic_, 1, 1.0, false);
108  as_mimic_.start();
109  return true;
110  }
111 
112 private:
117  std::string mimic_folder_;
118 
121  std::string active_mimic_;
123  boost::thread diagnostic_thread_;
124 
125  libvlc_instance_t* vlc_inst_;
126  libvlc_media_player_t* vlc_player_;
127  libvlc_media_t* vlc_media_;
128 
130  bool blocking_;
132  boost::mutex mutex_;
133 
134  boost::random::mt19937 gen_;
135  boost::random::uniform_real_distribution<> real_dist_;
136  boost::random::uniform_int_distribution<> int_dist_;
137 
138  std::string default_mimic_;
139  std::vector<std::string> random_mimics_;
140 
142  {
143  char *lgn;
144  if((lgn = getlogin()) == NULL)
145  {
146  lgn = getenv("USER");
147  if(lgn == NULL || std::string(lgn) == "")
148  {
149  ROS_ERROR("unable to get user name");
150  return false;
151  }
152  }
153  std::string username(lgn);
154  mimic_folder_ = "/tmp/mimic_" + username;
155  ROS_INFO("copying all mimic files to %s...", mimic_folder_.c_str());
156  std::string pkg_path = ros::package::getPath("cob_mimic");
157  std::string mimics_path = pkg_path + "/common";
158 
159  try{
160  if(boost::filesystem::exists(mimic_folder_))
161  {
162  boost::filesystem::remove_all(mimic_folder_);
163  }
164  }
165  catch(boost::filesystem::filesystem_error const & e)
166  {
167  ROS_ERROR_STREAM(std::string(e.what()));
168  return false;
169  }
170 
171  if(copy_dir(boost::filesystem::path(mimics_path), boost::filesystem::path(mimic_folder_)) )
172  {
173  ROS_INFO("...copied all mimic files to %s", mimic_folder_.c_str());
174  return true;
175  }
176  else
177  {
178  ROS_ERROR("...could not copy mimic files to %s", mimic_folder_.c_str());
179  return false;
180  }
181  }
182 
183  void as_cb_mimic_(const cob_mimic::SetMimicGoalConstPtr &goal)
184  {
185  random_timer_.stop();
186  action_active_ = true;
187 
188  if(set_mimic(goal->mimic, goal->repeat, goal->speed, blocking_))
189  as_mimic_.setSucceeded();
190  else
191  if(as_mimic_.isPreemptRequested())
192  as_mimic_.setPreempted();
193  else
194  as_mimic_.setAborted();
195  action_active_ = false;
196 
197  if(goal->mimic != "falling_asleep" && goal->mimic != "sleeping")
198  random_timer_ = nh_.createTimer(ros::Duration(real_dist_(gen_)), &Mimic::random_cb, this, true);
199  }
200 
201  bool service_cb_mimic(cob_mimic::SetMimic::Request &req,
202  cob_mimic::SetMimic::Response &res )
203  {
204  service_active_ = true;
205  random_timer_.stop();
206 
207  res.success = set_mimic(req.mimic, req.repeat, req.speed, blocking_);
208  res.message = "";
209 
210  if(req.mimic != "falling_asleep" && req.mimic != "sleeping")
211  random_timer_ = nh_.createTimer(ros::Duration(real_dist_(gen_)), &Mimic::random_cb, this, true);
212  service_active_ = false;
213  return true;
214  }
215 
216  bool set_mimic(std::string mimic, int repeat, float speed, bool blocking)
217  {
218  new_mimic_request_=true;
219  ROS_INFO("New mimic request with: %s", mimic.c_str());
220  mutex_.lock();
221  active_mimic_= (boost::format("Mimic: %1%, repeat: %2%, speed: %3%, blocking: %4%")% mimic % repeat % speed % blocking).str();
222  new_mimic_request_=false;
223  ROS_INFO("Mimic: %s (speed: %f, repeat: %d)", mimic.c_str(), speed, repeat);
224 
225  std::string filename = mimic_folder_ + "/" + mimic + ".mp4";
226 
227  // check if mimic exists
228  if ( !boost::filesystem::exists(filename) )
229  {
230  if ( !boost::filesystem::exists(mimic) )
231  {
232  ROS_ERROR("File not found: %s", filename.c_str());
233  active_mimic_ = "None";
234  mutex_.unlock();
235  return false;
236  }
237  else
238  {
239  ROS_INFO("Playing mimic from non-default file: %s", mimic.c_str());
240  filename = mimic;
241  }
242  }
243 
244  // repeat cannot be 0
245  repeat = std::max(1, repeat);
246  if(repeat > 1 && !blocking)
247  {
248  ROS_WARN_STREAM("Mimic repeat ("<<repeat<<") is overwritten by blocking ("<<blocking<<"). Will only play once.");
249  repeat = 1;
250  }
251 
252  // speed cannot be 0 or negative
253  if(speed <= 0)
254  {
255  ROS_WARN_STREAM("Mimic speed ("<<speed<<") cannot be 0 or negative. Setting Speed to 1.0");
256  speed = 1.0;
257  }
258 
259  // returns -1 if an error was detected, 0 otherwise (but even then, it might not actually work depending on the underlying media protocol)
260  if(libvlc_media_player_set_rate(vlc_player_, speed)!=0){ROS_ERROR("failed to set movie play rate");}
261 
262  while(repeat > 0)
263  {
264  if(action_active_ && as_mimic_.isPreemptRequested())
265  {
266  ROS_WARN("mimic %s preempted between repetitions", mimic.c_str());
267  active_mimic_ = "None";
268  mutex_.unlock();
269  return false;
270  }
271 
272  vlc_media_ = libvlc_media_new_path(vlc_inst_, filename.c_str());
273  if(!vlc_media_)
274  {
275  ROS_ERROR("failed to create media for filepath %s", filename.c_str());
276  active_mimic_ = "None";
277  mutex_.unlock();
278  return false;
279  }
280 
281  libvlc_media_player_set_media(vlc_player_, vlc_media_);
282  libvlc_media_release(vlc_media_);
283 
284  // returns 0 if playback started (and was already started), or -1 on error.
285  if(libvlc_media_player_play(vlc_player_)!=0)
286  {
287  ROS_ERROR("failed to play");
288  active_mimic_ = "None";
289  mutex_.unlock();
290  return false;
291  }
292 
293  ros::Duration(0.1).sleep();
294  while(blocking && (libvlc_media_player_is_playing(vlc_player_) == 1))
295  {
296  ros::Duration(0.1).sleep();
297  ROS_DEBUG("still playing %s", mimic.c_str());
298  if(new_mimic_request_)
299  {
300  ROS_WARN("mimic %s preempted while playing", mimic.c_str());
301  active_mimic_ = "None";
302  mutex_.unlock();
303  return false;
304  }
305  }
306  repeat --;
307  }
308  active_mimic_ = "None";
309  mutex_.unlock();
310  return true;
311  }
312 
314  {
315  int rand = int_dist_(gen_);
316  set_mimic(random_mimics_[rand], 1, 1.5, blocking_);
317  random_timer_ = nh_.createTimer(ros::Duration(real_dist_(gen_)), &Mimic::random_cb, this, true);
318  }
319 
320  bool copy_dir( boost::filesystem::path const & source,
321  boost::filesystem::path const & mimic_folder )
322  {
323  namespace fs = boost::filesystem;
324  try
325  {
326  // Check whether the function call is valid
327  if(!fs::exists(source) || !fs::is_directory(source))
328  {
329  ROS_ERROR_STREAM("Source directory " << source.string() << " does not exist or is not a directory.");
330  return false;
331  }
332  if(fs::exists(mimic_folder))
333  {
334  ROS_INFO_STREAM("Destination directory " << mimic_folder.string() << " already exists.");
335  return false;
336  }
337  // Create the mimic_folder directory
338  if(!fs::create_directory(mimic_folder))
339  {
340  ROS_ERROR_STREAM( "Unable to create mimic_folder directory" << mimic_folder.string());
341  return false;
342  }
343  }
344  catch(fs::filesystem_error const & e)
345  {
346  ROS_ERROR_STREAM(std::string(e.what()));
347  return false;
348  }
349  // Iterate through the source directory
350  for(fs::directory_iterator file(source); file != fs::directory_iterator(); ++file)
351  {
352  try
353  {
354  fs::path current(file->path());
355  if(fs::is_directory(current))
356  {
357  // Found directory: Recursion
358  if( !copy_dir(current, mimic_folder / current.filename()) )
359  return false;
360  }
361  else
362  {
363  // Found file: Copy
364  fs::copy_file(current, mimic_folder / current.filename() );
365  }
366  }
367  catch(fs::filesystem_error const & e)
368  {
369  ROS_ERROR_STREAM(std::string(e.what()));
370  }
371  }
372  return true;
373  }
374 
376  {
377  while(ros::ok())
378  {
379  ros::Duration(1.0).sleep();
380  diagnostic_updater_.update();
381  }
382  }
383 
385  {
386  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Mimic running");
387  stat.add("Action is active", action_active_);
388  stat.add("Service is active", service_active_);
389  stat.add("Active mimic", active_mimic_);
390  }
391 };
392 
393 
394 int main(int argc, char** argv)
395 {
396  ros::init(argc, argv, "mimic");
397 
398  Mimic mimic;
399  if(!mimic.init())
400  {
401  ROS_ERROR("mimic init failed");
402  return 1;
403  }
404  else
405  {
406  ROS_INFO("mimic node started");
407  ros::spin();
408  return 0;
409  }
410 }
boost::thread diagnostic_thread_
Definition: mimic_node.cpp:123
~Mimic(void)
Definition: mimic_node.cpp:51
filename
void diagnostics_timer_thread()
Definition: mimic_node.cpp:375
void as_cb_mimic_(const cob_mimic::SetMimicGoalConstPtr &goal)
Definition: mimic_node.cpp:183
bool set_mimic(std::string mimic, int repeat, float speed, bool blocking)
Definition: mimic_node.cpp:216
void summary(unsigned char lvl, const std::string s)
bool new_mimic_request_
Definition: mimic_node.cpp:131
std::string default_mimic_
Definition: mimic_node.cpp:138
boost::random::uniform_int_distribution int_dist_
Definition: mimic_node.cpp:136
void setHardwareID(const std::string &hwid)
bool blocking_
Definition: mimic_node.cpp:130
bool sleep() const
diagnostic_updater::Updater diagnostic_updater_
Definition: mimic_node.cpp:122
void stop()
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
bool sim_enabled_
Definition: mimic_node.cpp:129
std::string getName(void *handle)
void add(const std::string &name, TaskFunction f)
std::string mimic_folder_
Definition: mimic_node.cpp:117
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
#define ROS_WARN(...)
void setSucceeded(const Result &result=Result(), const std::string &text=std::string(""))
libvlc_media_t * vlc_media_
Definition: mimic_node.cpp:127
boost::mutex mutex_
Definition: mimic_node.cpp:132
void produce_diagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: mimic_node.cpp:384
void setPreempted(const Result &result=Result(), const std::string &text=std::string(""))
ros::ServiceServer srvServer_mimic_
Definition: mimic_node.cpp:115
bool init()
Definition: mimic_node.cpp:58
bool copy_mimic_files()
Definition: mimic_node.cpp:141
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
libvlc_media_player_t * vlc_player_
Definition: mimic_node.cpp:126
ROSCPP_DECL bool ok()
bool action_active_
Definition: mimic_node.cpp:119
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
int main(int argc, char **argv)
Definition: mimic_node.cpp:394
boost::random::mt19937 gen_
Definition: mimic_node.cpp:134
std::string active_mimic_
Definition: mimic_node.cpp:121
ROSCPP_DECL void spin()
ros::Timer random_timer_
Definition: mimic_node.cpp:116
#define ROS_WARN_STREAM(args)
ROSLIB_DECL std::string getPath(const std::string &package_name)
bool service_active_
Definition: mimic_node.cpp:120
void setAborted(const Result &result=Result(), const std::string &text=std::string(""))
bool service_cb_mimic(cob_mimic::SetMimic::Request &req, cob_mimic::SetMimic::Response &res)
Definition: mimic_node.cpp:201
#define ROS_INFO_STREAM(args)
std::vector< std::string > random_mimics_
Definition: mimic_node.cpp:139
void random_cb(const ros::TimerEvent &)
Definition: mimic_node.cpp:313
void add(const std::string &key, const T &val)
#define ROS_ERROR_STREAM(args)
ros::NodeHandle nh_
Definition: mimic_node.cpp:113
boost::random::uniform_real_distribution real_dist_
Definition: mimic_node.cpp:135
bool copy_dir(boost::filesystem::path const &source, boost::filesystem::path const &mimic_folder)
Definition: mimic_node.cpp:320
#define ROS_ERROR(...)
libvlc_instance_t * vlc_inst_
Definition: mimic_node.cpp:125
#define ROS_DEBUG(...)
actionlib::SimpleActionServer< cob_mimic::SetMimicAction > as_mimic_
Definition: mimic_node.cpp:114


cob_mimic
Author(s): Nadia Hammoudeh Garcia , Benjamin Maidel
autogenerated on Wed Apr 7 2021 02:11:42