Linux下开发C++ ROS节点:如何实时获取Unix控制台按键输入?
嘿,针对你在Ubuntu 16.04下开发ROS C++节点时需要实时捕获按键输入的需求,咱们直接通过修改终端属性就能搞定——默认终端是规范模式,会把输入缓冲到整行才处理,咱们把它改成非规范模式,就能让按键一按下就被程序读取到。
实现思路
Linux终端的输入行为由termios结构体控制,我们需要修改它的核心参数:关闭规范模式,调整读取的超时和最小字符数,实现单按键实时响应。特别注意:操作完成后一定要恢复原终端设置,不然退出程序后你的终端会变得异常(比如输入不回显、不缓冲)。
完整ROS节点代码示例
下面是一个可直接运行的ROS节点代码,包含终端模式切换、实时按键读取和退出恢复的完整逻辑:
#include <ros/ros.h> #include <termios.h> #include <unistd.h> #include <fcntl.h> // 保存终端原始属性,用于退出时恢复 struct termios original_termios; // 将终端设置为非规范模式(实时读取按键) void set_non_canonical_mode() { tcgetattr(STDIN_FILENO, &original_termios); struct termios new_termios = original_termios; // 关闭规范模式(取消整行缓冲),关闭回显(可选,不想看到按键时启用) new_termios.c_lflag &= ~(ICANON | ECHO); // 设置:至少读取1个字符,超时时间0(阻塞直到有按键按下) // 若要非阻塞读取(循环检查不等待),可将VMIN设为0、VTIME设为0,同时打开非阻塞标志(见注释) new_termios.c_cc[VMIN] = 1; new_termios.c_cc[VTIME] = 0; tcsetattr(STDIN_FILENO, TCSANOW, &new_termios); // 非阻塞读取开关(取消注释启用) // int flags = fcntl(STDIN_FILENO, F_GETFL, 0); // fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); } // 恢复终端原始属性 void restore_terminal_mode() { tcsetattr(STDIN_FILENO, TCSANOW, &original_termios); // 若启用了非阻塞,这里恢复原状态 // int flags = fcntl(STDIN_FILENO, F_GETFL, 0); // fcntl(STDIN_FILENO, F_SETFL, flags & ~O_NONBLOCK); } int main(int argc, char** argv) { ros::init(argc, argv, "keyboard_input_node"); ros::NodeHandle nh; // 设置终端模式,并注册退出时的恢复函数(异常退出也能生效) set_non_canonical_mode(); atexit(restore_terminal_mode); ros::Rate loop_rate(100); // 100Hz循环保证实时性 char key; while (ros::ok()) { // 读取单个按键 ssize_t bytes_read = read(STDIN_FILENO, &key, 1); if (bytes_read > 0) { ROS_INFO("Pressed key: %c (ASCII code: %d)", key, key); // 这里可以添加你的业务逻辑,比如发布ROS控制消息 if (key == 'q') { ROS_INFO("Exit command received, quitting..."); break; } } ros::spinOnce(); loop_rate.sleep(); } return 0; }
代码细节说明
set_non_canonical_mode:核心是修改termios的c_lflag和c_cc参数,关闭规范模式后,终端不再缓冲整行输入。restore_terminal_mode:通过atexit注册,确保程序无论正常还是异常退出,都能把终端恢复到原来的状态。- 主循环:用
read读取单个字符,捕获到按键后可直接执行你的ROS节点逻辑(比如发布话题、控制机器人)。
编译配置参考
在你的CMakeLists.txt中添加以下配置,确保能正常编译ROS节点:
cmake_minimum_required(VERSION 2.8.3) project(keyboard_input_node) find_package(catkin REQUIRED COMPONENTS roscpp std_msgs ) catkin_package( CATKIN_DEPENDS roscpp std_msgs ) include_directories( ${catkin_INCLUDE_DIRS} ) add_executable(keyboard_input_node src/keyboard_input_node.cpp) target_link_libraries(keyboard_input_node ${catkin_LIBRARIES} )
这样编译运行后,按下任意按键都会被程序立即捕获,完全满足你的课程作业需求~
内容的提问来源于stack exchange,提问作者VansFannel
相关产品推荐
相关产品推荐

