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


cob_mimic
Author(s): Nadia Hammoudeh Garcia , Benjamin Maidel
autogenerated on Wed Nov 8 2023 03:47:40