ROS Resources: Documentation | Support | Discussion Forum | Service Status | Q&A answers.ros.org
Ask Your Question
3

Keyboard key pressed

asked 2013-05-25 13:43:25 -0600

s_bot gravatar image

updated 2014-04-20 14:09:44 -0600

ngrennan gravatar image

Hello

I created a robot model in gazebo, and also a plugin through which I can control the model. There is also a ROS application which communicates with plugin by messages. In that application, I should catch the keyboard input, send the masseges based on input, and finally, control the model. I dont know how to catch keyboard input. Is there something like "isPressed("key")" function?

Ubuntu 12.04, ROS Groovy, c++

EDIT: Now I have another problem. Is there a way to find out that there is no key pressed? Something like timeout for getch() function? In the example explained in the post bellow, the while() loop stops on the int c = getch(); line and waits for inupt.

Thank you!

edit retag flag offensive close merge delete

3 Answers

Sort by ยป oldest newest most voted
13

answered 2013-05-25 16:10:05 -0600

As far as I know, there's no ROS (or Boost) built-in function for this.

You can look at the method used in the turtlesim teleop_turtle_key. This node is used in the Understanding Topics tutorial.

All the default built-in functions (cin >>, getchar, etc.) block until the user presses "enter". Which is probably not the behavior you want. So, you'll need to use some sort of OS-specific hack to read the keys as they are pressed.

See this thread for suggestions on how to implement a non-blocking getchar() in linux. It boils down to modifying the terminal settings to disable input buffering. You'll want to make sure and restore the original settings when your program exits, or else the terminal will behave oddly. Basically, you need something like:

int getch()
{
  static struct termios oldt, newt;
  tcgetattr( STDIN_FILENO, &oldt);           // save old settings
  newt = oldt;
  newt.c_lflag &= ~(ICANON);                 // disable buffering      
  tcsetattr( STDIN_FILENO, TCSANOW, &newt);  // apply new settings

  int c = getchar();  // read character (non-blocking)

  tcsetattr( STDIN_FILENO, TCSANOW, &oldt);  // restore old settings
  return c;
}

Once you've got that function written, you can do something like:

while (ros::ok())
{
  int c = getch();   // call your non-blocking input function
  if (c == 'a')
    send message 'A'
  else if (c == 'b')
    send message 'B'

  << do other processing >>
}
edit flag offensive delete link more

Comments

I tried your suggestion and it works very well. Thank you :)

s_bot gravatar images_bot ( 2013-05-25 22:31:43 -0600 )edit
1

Don't forget to add #include <termios.h>

Equanox gravatar imageEquanox ( 2014-02-21 03:19:10 -0600 )edit
2

This didn't worked for me till I set the following:

newt.c_cc[VMIN] = 0; newt.c_cc[VTIME] = 0;

See http://www.unixwiz.net/techtips/termi... for more details.

This is a nice and easy way catching some basic Inputs! Thank you!

einrob gravatar imageeinrob ( 2014-11-21 07:30:24 -0600 )edit

Very helpful. I wanted to handle the program termination using ctrl-c and it wasn't clean. Using your method and suggestion the edit by @einrob I can.

Adnan Munawar gravatar imageAdnan Munawar ( 2016-06-17 14:51:05 -0600 )edit
1

answered 2015-06-15 08:31:15 -0600

lucasw gravatar image

updated 2015-06-15 08:31:24 -0600

I usually use opencv waitKey (Which requires imshow to have run, could be blank mat, and then the keys pressed with the imshow window in focus can be caught or it can time out after so many milliseconds.

http://docs.opencv.org/modules/highgu...

edit flag offensive delete link more
0

answered 2015-10-07 16:59:02 -0600

In the above answers the getchar() function blocks the ros's while loop, If you want the loop to run at a particular rate and to get inputs when it's available replace the getch() function definition with the below.

You can change the timeout.tv_sec, timeout.tv_sec to change the time to wait for user input. filedesc is 0 for taking input from keyboard, most probably it's similar to stdin but not sure.


char getch()
{
    fd_set set;
    struct timeval timeout;
    int rv;
    char buff = 0;
    int len = 1;
    int filedesc = 0;
    FD_ZERO(&set);
    FD_SET(filedesc, &set);

    timeout.tv_sec = 0;
    timeout.tv_usec = 1000;

    rv = select(filedesc + 1, &set, NULL, NULL, &timeout);

    struct termios old = {0};
    if (tcgetattr(filedesc, &old) < 0)
        ROS_ERROR("tcsetattr()");
    old.c_lflag &= ~ICANON;
    old.c_lflag &= ~ECHO;
    old.c_cc[VMIN] = 1;
    old.c_cc[VTIME] = 0;
    if (tcsetattr(filedesc, TCSANOW, &old) < 0)
        ROS_ERROR("tcsetattr ICANON");

    if(rv == -1)
        ROS_ERROR("select");
    else if(rv == 0)
        ROS_INFO("no_key_pressed");
    else
        read(filedesc, &buff, len );

    old.c_lflag |= ICANON;
    old.c_lflag |= ECHO;
    if (tcsetattr(filedesc, TCSADRAIN, &old) < 0)
        ROS_ERROR ("tcsetattr ~ICANON");
    return (buff);
}

If you require an example code visit here: keyboard_non_blocking_input_node.cpp

This link helped in implementing this: http://stackoverflow.com/a/2918709

I Hope This Helps!!!!!

edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

4 followers

Stats

Asked: 2013-05-25 13:43:25 -0600

Seen: 11,192 times

Last updated: Jun 15 '15