私は、端末から矢印キー文字を読み込み、String
タイプのメッセージをROS
を通して送信しようとしています。そのために私はtermios
read()
の機能を使用しています。コマンドラインから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.txt
とpackage.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
の例がうまく動作している間、私はこのエラーを受け取っています。
ありがとうございます!
EISDIRエラーを生成するのはどの行ですか? 2番目の例の 'main()'の 'read()'呼び出しは? 'errno'が何に設定されているかをテストする必要があります - ' error'ではなく。通常、 'error'は' -1'です。全て 'E *'マクロにはマッチしません。マクロはすべて正であるからです。 –
はい、 'read()'は負の値を返します。そのため、私は 'case'を持っています。それは 'error = EISDIR'の場合に入ります。なぜ最初の例がうまくいくのか分からないのです。 – mugurumov
等号の代わりに代入がある: 'else if(error = EISDIR) puts(" EISDIR ");'。この質問を削除し、コンパイラの警告レベルを上げることをお勧めします。 GCCを使用している場合は、少なくとも '-Wall -Werror -Wextra'を使用してください。私はそれ以上のものを使っていますが、私はC言語で30年以上のプログラミングしかしていませんでしたので、私はそれについてすべて知っていないことを知っています(そして、オプションによって、私は愚かな間違いを作ります。 'error'をテストするべきではないことに注意してください。 'E *'マクロの値を含む 'errno'をテストしているかもしれません。 –