ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question

Keyboard key pressed

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

s_bot gravatar image

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

ngrennan gravatar image


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

4 Answers

Sort by ยป oldest newest most voted

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

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


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

s_bot gravatar image s_bot  ( 2013-05-25 22:31:43 -0500 )edit

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

Equanox gravatar image Equanox  ( 2014-02-21 03:19:10 -0500 )edit

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

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

See for more details.

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

einrob gravatar image einrob  ( 2014-11-21 07:30:24 -0500 )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 image Adnan Munawar  ( 2016-06-17 14:51:05 -0500 )edit

Note that if you don't want your input to be displayed in the terminal, then you have to modify the line newt.c_lflag &= ~(ICANON); to newt.c_lflag &= ~(ICANON | ECHO);. It is written in one of the link provided in the main answer, but maybe it is worth to highlight that.

ROS_user gravatar image ROS_user  ( 2021-09-17 16:24:42 -0500 )edit

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

lucasw gravatar image

updated 2018-07-06 10:55:28 -0500

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

edit flag offensive delete link more

answered 2018-07-06 11:41:07 -0500

AndyZe gravatar image

There is a package to read keyboard events straight from /dev:

A problem is that RViz also listens for hotkeys. For example, pressing 'g' will cause your robot to take off towards a goal if RViz is the active window. There's a PR to fix this but it hasn't been accepted yet. Pressing 'm' will toggle interactive markers, which is pretty confusing for new users. "Where did my markers go!?"

edit flag offensive delete link more

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

Dipendra Singh gravatar image

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_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)
    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)
    else if(rv == 0)
        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:

I Hope This Helps!!!!!

edit flag offensive delete link more

Question Tools



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

Seen: 31,598 times

Last updated: Jul 06 '18