0
$\begingroup$

Rosanswers logo

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!


Originally posted by s_bot on ROS Answers with karma: 53 on 2013-05-25

Post score: 5

$\endgroup$

4 Answers 4

0
$\begingroup$

Rosanswers logo

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

Originally posted by Jeremy Zoss with karma: 4976 on 2013-05-25

This answer was ACCEPTED on the original site

Post score: 16


Original comments

Comment by s_bot on 2013-05-25:
I tried your suggestion and it works very well. Thank you :)

Comment by Equanox on 2014-02-21:
Don't forget to add #include <termios.h>

Comment by einrob on 2014-11-21:
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/termios-vmin-vtime.html for more details.

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

Comment by Adnan Munawar on 2016-06-17:
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.

Comment by ROS_user on 2021-09-17:
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.

$\endgroup$
0
$\begingroup$

Rosanswers logo

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.

http://docs.opencv.org/modules/highgui/doc/user_interface.html#waitkey


Originally posted by lucasw with karma: 8729 on 2015-06-15

This answer was NOT ACCEPTED on the original site

Post score: 2

$\endgroup$
0
$\begingroup$

Rosanswers logo

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) &lt 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) &lt 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) &lt 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!!!!!


Originally posted by Dipendra Singh with karma: 11 on 2015-10-07

This answer was NOT ACCEPTED on the original site

Post score: 1

$\endgroup$
0
$\begingroup$

Rosanswers logo

There is a package to read keyboard events straight from /dev: https://github.com/UTNuclearRoboticsPublic/keyboard_reader

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!?" https://github.com/ros-visualization/rviz/pull/1243


Originally posted by AndyZe with karma: 2331 on 2018-07-06

This answer was NOT ACCEPTED on the original site

Post score: 2

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.