Robotics StackExchange | Archived questions

Launch Node from code spawns node 2 times and breaks output

Hi,

I'm a bit confused. When I try to launch my navstack.lauch from my benchmarking code for evaluation purposes and trying to parse the output of it, the output stops. I launch the node via execl and redirect the output to a file that gets later parsed. My call to start the node boils down to:

execl("/bin/bash", "/bin/bash", "-c", "/usr/bin/python /opt/ros/hydro/bin/roslaunch gki3dnavbenchmark nonenavstack.launch 2>&1 > navstackoutput.txt", NULL);
When I call the makeplan service from the same code I do get a valid response. But when I take look at the navstackoutput.txt there's no trace of a request getting handled. Here the ouput of ps ax | grep navstack:
24328 ?  S  0:00 /bin/bash -c /usr/bin/python /opt/ros/hydro/bin/roslaunch gki3dnavbenchmark nonenavstack.launch 2>&1 > navstackoutput.txt
24329 ?  Sl 0:00 /usr/bin/python /opt/ros/hydro/bin/roslaunch gki3dnavbenchmark nonenav_stack.launch
It seems to me the node starts but another gets started too, which actually handle the requests. Does anyone know how to prevent this? Or do I do something wrong in my execlcall?

PS: I know it's kind of hacky but still the behaviour confuses me. You can find the benchmark project here. As for why I'm doing it this way is that the sbpl outputs some information to stdout that I want to dump in my evaluation database which are not getting published.

Update: Seems the output gets cutoff too when trying the same thing from the shell

roslaunch gki3dnavbenchmark nonenavstack.launch > test.txt
The result of the txt where you can see the cutoff:
[ INFO] [1441555720.539266930, 9773.525000000]: Tolerance rot: 0.200000
[ INFO] [1441555720.539284357, 9773.525000000]: Tolerance time: 0.500000
[ INFO] [1441555721.024403188, 9773.861000000]: pluginlib WARNING: In file /tmp/buildd/ros-hydro-clear-costmap-recovery-1.11.16-0precise-20150501-0923/src/clearcostmaprecovery.cpp PLUGINLIBDECLARECLASS is deprecated, please use PLUGINLIBEXPORTCLASS instead. You can run the script 'pluginmacroupdate' provided with pluginlib in your package source folder to automatically and recursively update legacy macros.  Base = baseclasstype, Derived = derivedclass_type
[ INFO] [1441555721.025830108, 9

Asked by PhiPhiper on 2015-09-06 09:40:48 UTC

Comments

stdout usually buffers a bunch of data when writing to a file; try checking the output file again after your node has exited and actually written all of its output to disk.

Asked by ahendrix on 2015-09-06 11:50:14 UTC

Would be odd if that's the reason, when executing "sudo find / > test.txt" I got my results in seconds without a hitch. Btw it's a navstack that runs "indefinitely". I do fork the call and the new pipe doesn receive any new data too.

Asked by PhiPhiper on 2015-09-06 12:11:22 UTC

A tool like find terminates, and flushes the output buffer when it exits; hence a complete file in that case. Since the navstack doesn't exit and isn't constantly writing, it never fills up the log output buffer, and never needs to flush it to disk.

Asked by ahendrix on 2015-09-06 21:24:07 UTC

I moved on not parsing the output anymore. I deleted the results where you could have seen, that after the cutoff, the killing notification of the node got written. As far as my understanding goes, redirecting stdout to file should always flush the current output, at least when the process exits.

Asked by PhiPhiper on 2015-09-07 05:35:23 UTC

Answers

As far as I'm aware, you can't redirect files like that with execl. Here's a complete example with redirection written in C (should also compile in C++, but change NULL to nullptr).

Also be sure to source your ROS environment before you execute this.

#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>

int main(int argc, char ** argv)
{
  int pid = fork();
  if (-1 == pid) {
    /* fork failed */
    perror("fork");
    return 1;
  } else if (0 == pid) {
    /* child process */
    FILE * fp = fopen("navstackoutput.txt", "w");
    if (NULL == fp) {
      perror("fopen");
      return 1;
    }
    /* get descriptor for the file */
    int fd = fileno(fp);
    /* redirect stderr to stdout */
    dup2(fd, 1);
    /* redirect stdout (and stderr) to the file */
    dup2(fd, 2);
    close(fd);  /* close redundant fd */
    execlp("roslaunch", "roslaunch", "gazebo_ros", "willowgarage_world.launch", NULL);
    perror("execlp");  /* should never get here */
  } else {
    /* parent process */
    printf("Waiting for pid '%d' to exit...\n", pid);
    int status;
    int ret = waitpid(pid, &status, WUNTRACED);
    if (0 > ret) {
      perror("waitpid");
      return 1;
    }
    printf("Child exited with return code '%d'\n", status);
  }

  return 0;
}

I should also note that the process will probably hang until you manually kill it, so you should do a kill -SIGINT [pid] where pid is the number output in the line "Waiting for pid '%d' to exit...".

Asked by allenh1 on 2020-09-22 07:35:50 UTC

Comments