Bach05
Bach05

Reputation: 11

Sampling keyboard input at a certain rate in C++

What I want to do is sampling the keyboard input at a certain rate (e.g. 10-20 Hz). I use a while loop that read from stdin (I use read because I want to read asynchronously, e.i. I don't want to press enter every time) and then I have a pause before a new cycle starts to keep the sampling frequency stable.

The user press left/right arrow to give a command (to a robot). If nothing is pressed, the output is 0.

The problem is that, during the pause, the stdin buffer is written (I suppose), and so the read will return an old input. The final result is that the output is delayed. So if I press left the output immediately change to 1, but when I release it takes some seconds to return to 0. I want to remove this delay.

My aim is to sample just the more recent key pressed, in order to synchronize user input and output command without delays. Is there a way? Thank you in advance.

This is the method I'm using:

    void key_reader::keyLoop()
{
    char c;
    bool dirty = false;
    int read_flag;

// get the console in raw mode
tcgetattr(kfd, &cooked);
memcpy(&raw, &cooked, sizeof(struct termios));
raw.c_lflag &= ~(ICANON | ECHO);
// Setting a new line, then end of file
raw.c_cc[VEOL] = 1;
raw.c_cc[VEOF] = 2;
tcsetattr(kfd, TCSANOW, &raw);

//FD_ZERO(&set);     /* clear the set */
//FD_SET(kfd, &set); /* add our file descriptor to the set */

//timeout.tv_sec = 0;
//timeout.tv_usec = 10000;

if (fcntl(kfd, F_SETFL, O_NONBLOCK) == -1)
{
    perror("fcntl:"); // an error accured
    exit(-1);
}

puts("Reading from keyboard");
puts("---------------------------");
puts("Use arrow keys to move the turtle.");

ros::Rate r(10);
while (ros::ok())
{
    
    read_flag = read(kfd, &c, 1);
    switch (read_flag)
    {
    case -1:

        // case -1: is empty and errono
        // set EAGAIN
        if (errno == EAGAIN)
        {
            //no input yet
            direction = 0;
            break;
        }

        else
        {
            perror("read:");
            exit(2);
        }

    // case 0 means all bytes are read and EOF(end of conv.)
    case 0:

        //no input yet
        direction = 0;
        break;

    default:

        ROS_DEBUG("value: 0x%02X\n", c);

        switch (c)
        {
        case KEYCODE_L:
            ROS_DEBUG("LEFT");
            direction = 1;
            dirty = true;
            break;
        case KEYCODE_R:
            ROS_DEBUG("RIGHT");
            direction = -1;
            dirty = true;
            break;
        }
    }

    continuos_input::input_command cmd;
    cmd.type = "Keyboard";
    cmd.command = direction;
    cmd.stamp = ros::Time::now();
    key_pub.publish(cmd);
    r.sleep();
       
    }
}

Upvotes: 0

Views: 598

Answers (1)

Amal Pavithran
Amal Pavithran

Reputation: 1

I feel that the issue is with your subscriber rather than publisher. I can see that you have used rate to limit the publishing rate to 10Hz. Do confirm the publishing rate using Topic Monitor in rqt. Also setting a lower queue size for the publisher might help. Can't give a more definitive answer without referring to your subscriber node.

Upvotes: 0

Related Questions