从命令行read()返回EISDIR错误

时间:2017-03-18 08:42:45

标签: c++ ros

我尝试从终端读取箭头键字符并使用String类型的消息通过ROS。为此,我使用termios read()函数。

首先,我做了一个在C下使用gcc编译的小测试。这是代码:

#include <unistd.h>
#include <stdlib.h>
#include <termios.h> // for keyboard input
#include <string.h>
#include <stdio.h>

bool quit_requested = false;

void processKeyboardInput (char c)
{
   switch (c)
   {
     case 68:// Left arrow pressed
     {
       puts("Left pressed");
       break;
     }
     case 67://Right arrow pressed
     {
       puts("Right pressed");
       break;
     }
     case 65://Up arrow pressed
     {
       puts("Up pressed");
       break;
     }
     case 66://Down arrow pressed
     {
       puts("Down pressed");
       break;
     }
     case 'q'://Quit arrow pressed
     {
       quit_requested = true;
       puts("q pressed, quitting...");
     }
     default:
     {
       break;
     }
 }

}

int main(int argc, char const *argv[]) {
  int key_file_descriptor;
  struct termios raw;
  struct termios original_terminal_state;

  tcgetattr(key_file_descriptor, &original_terminal_state); // get       terminal properties
  memcpy(&raw, &original_terminal_state, sizeof(struct termios));

  raw.c_lflag &= ~(ICANON | ECHO);//local modes, enable canonical mode and echo
  // Setting a new line, then end of file
  raw.c_cc[VEOL] = 1;//special characters
  raw.c_cc[VEOF] = 2;
  tcsetattr(key_file_descriptor, TCSANOW, &raw);

  puts("Reading from keyboard");
  puts("---------------------------");
  puts("Press the arrow keys to move and q to quit");

  char c;
  while (!quit_requested)
  {
    if (read(key_file_descriptor, &c, 1) < 0)
    {
      perror("read char failed():");
      exit(-1);
    }
    processKeyboardInput(c);
  }
      tcsetattr(key_file_descriptor, TCSANOW,      &original_terminal_state);
      puts("Exit");
    return 0;
    }

完成此操作后,我添加了ROS内容以使用String消息发送密钥:

#include <unistd.h>
#include <termios.h> // for keyboard input
#include <cstring>
#include <stdio.h>

#include "ros/ros.h"
#include "std_msgs/String.h"


bool quit_requested = false;


std::string processKeyboardInput (char c)
{

   switch (c)
   {
     case 68:// Left arrow pressed
     {
       puts("Left pressed");
       return ("left");
     }
     case 67://Right arrow pressed
     {
       puts("Right pressed");
       return ("right");
     }
     case 65://Up arrow pressed
     {
       puts("Up pressed");
       return ("forward");
     }
     case 66://Down arrow pressed
     {
       puts("Down pressed");
       return ("backward");
     }
     case 'q'://Quit arrow pressed
     {
       quit_requested = true;
       puts("q pressed, quitting...");
     }
     default:
     {
       return ("");
     }
 }

}

int main(int argc, char **argv) {

  std::string cmd;
  int key_file_descriptor;
  char c;
  int error;
  struct termios raw;
  struct termios original_terminal_state;
  //std::string name = "key_teleop";

  /**** INIT ROS STUFFS  *****/
  ros::init(argc, argv, "key_teleop");
  std_msgs::String msg;
  ros::NodeHandle n;
  ros::Publisher key_pub = n.advertise<std_msgs::String>("key_teleop", 1000);
  ros::Rate loop_rate(1);
  /***************************/

  tcgetattr(key_file_descriptor, &original_terminal_state); // get terminal properties
  memcpy(&raw, &original_terminal_state, sizeof(struct termios));

  raw.c_lflag &= ~(ICANON | ECHO);//local modes, enable canonical mode and echo
  // Setting a new line, then end of file
  raw.c_cc[VEOL] = 1;//special characters
  raw.c_cc[VEOF] = 2;
  tcsetattr(key_file_descriptor, TCSANOW, &raw);

  puts("Reading from keyboard");
  puts("---------------------------");
  puts("Press the arrow keys to move and q to quit");


  while (ros::ok() & (!quit_requested))
  {
  //if (read(key_file_descriptor, &c, 1) < 0)
    error = read(key_file_descriptor, &c, 1);
    if ( error < 0)//Process the error
    {//TODO I get errors, not ROSify code doesn't, C / C++ code mixture issue??
      if (error == EAGAIN)
        puts ("EAGAIN");
      else if (error == EBADF)
        puts ("EBADF");
      else if (error == EFAULT)
        puts ("EFAULT");
      else if (error == EINTR)
        puts ("EINTR");
      else if (error == EINVAL)
        puts ("EINVAL");
      else if (error == EIO)
        puts ("EIO");
      else if (error = EISDIR)
        puts ("EISDIR");
      perror("read char failed():");
      exit(-1);
    }
    cmd = processKeyboardInput(c);
    if (!cmd.empty())
    {
      msg.data = cmd;
      key_pub.publish(msg);
      ros::spinOnce();
      //loop_rate.sleep();
    }
  }
  tcsetattr(key_file_descriptor, TCSANOW, &original_terminal_state);
  puts("Exit");
return 0;
}

创建CMakeLists.txtpackage.xml后,我使用catkin_make进行了编译。测试它现在不起作用,大多数时候我在read()收到错误返回,它进入EISDIR案例并打印出来。知道为什么现在我收到这个错误,而前一个c例子正常工作?

提前致谢!

1 个答案:

答案 0 :(得分:0)

在@Jonathan的推荐之后,我将标志-Wall -Werror -Wextra添加到CMake编译标志中,并发现了编译器抛出的下一条消息:

error: ‘key_file_descriptor’ may be used uninitialized in this function [-Werror=maybe-uninitialized]

我找到了此nice article并更改了我int key_file_descriptor使用的STDIN_FILENO。所以我已经将它全部替换为代码,现在正在工作!我也删除了比较拼写错误。谢谢你们!