2017-03-18 1 views
0

私は、端末から矢印キー文字を読み込み、StringタイプのメッセージをROSを通して送信しようとしています。そのために私はtermiosread()の機能を使用しています。コマンドラインからread()がEISDIRエラーを返します

まず、gccを使用してコンパイルされたCの下で問題なく動作する小さなテストを実行しました。これはコードです:

#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; 
} 

はかつて私はcatkin_makeを使用してコンパイルしているCMakeLists.txtpackage.xmlを、作成した:

#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; 
    } 

は一度これを行って、私はStringメッセージを使用して、キーを送信するためにROSものを追加しています。テストして、今は動作しません、私はread()でエラーリターンを受信すると、それはEISDIRケースに入り、それを印刷します。以前のcの例がうまく動作している間、私はこのエラーを受け取っています。

ありがとうございます!

+1

EISDIRエラーを生成するのはどの行ですか? 2番目の例の 'main()'の 'read()'呼び出しは? 'errno'が何に設定されているかをテストする必要があります - ' error'ではなく。通常、 'error'は' -1'です。全て 'E *'マクロにはマッチしません。マクロはすべて正であるからです。 –

+1

はい、 'read()'は負の値を返します。そのため、私は 'case'を持っています。それは 'error = EISDIR'の場合に入ります。なぜ最初の例がうまくいくのか分からないのです。 – mugurumov

+1

等号の代わりに代入がある: 'else if(error = EISDIR) puts(" EISDIR ");'。この質問を削除し、コンパイラの警告レベルを上げることをお勧めします。 GCCを使用している場合は、少なくとも '-Wall -Werror -Wextra'を使用してください。私はそれ以上のものを使っていますが、私はC言語で30年以上のプログラミングしかしていませんでしたので、私はそれについてすべて知っていないことを知っています(そして、オプションによって、私は愚かな間違いを作ります。 'error'をテストするべきではないことに注意してください。 'E *'マクロの値を含む 'errno'をテストしているかもしれません。 –

答えて

0

@ジョナサンのreccomendation後、私はCMakeコンパイルフラグにフラグ-Wall -Werror -Wextraを追加して、コンパイラによってスローされた次のメッセージを発見した:私はこのnice articleを発見し、int key_file_descriptorを変更した

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

を私はSTDIN_FILENOのために使用していました。だから私はコード全体に置き換えて、今働いている!私も比較のタイプミスを削除しました。みんなありがとう!

関連する問題