NCurses getch始终返回ERR(-1),ROS键盘节点无法发布消息求助
嘿,我之前在ROS节点里用ncurses时也踩过这个坑!getch()一直返回ERR(-1),大概率和终端控制权、ncurses的初始化流程或者ROS的终端重定向有关,咱们一步步来排查解决:
1. 先确保ncurses的基础流程完全正确
很多时候问题出在初始化步骤漏了关键配置,ncurses默认是行缓冲模式,必须按回车才会传递输入,而且需要明确开启按键的即时读取:
#include <ncurses.h> #include <ros/ros.h> #include <std_msgs/String.h> int main(int argc, char** argv) { // 先初始化ROS,再初始化ncurses(顺序很重要!) ros::init(argc, argv, "key_publisher"); ros::NodeHandle nh; ros::Publisher key_pub = nh.advertise<std_msgs::String>("/keys", 10); // 初始化ncurses核心配置 initscr(); // 启动ncurses环境 cbreak(); // 禁用行缓冲,按键立即被读取 noecho(); // 不回显按下的按键 keypad(stdscr, TRUE); // 支持功能键(方向键、F键等) // 如果需要非阻塞读取(不卡主ROS循环),加上这句;如果要阻塞等按键就注释掉 // nodelay(stdscr, TRUE); printw("Press keys to publish to /keys (press 'q' to exit)\n"); refresh(); // 刷新屏幕,让输出显示 ros::Rate loop_rate(10); while (ros::ok()) { int ch = getch(); if (ch != ERR) { std_msgs::String msg; msg.data = std::string(1, static_cast<char>(ch)); key_pub.publish(msg); printw("Published key: %c\n", ch); refresh(); if (ch == 'q') break; } ros::spinOnce(); loop_rate.sleep(); } // 退出前必须清理ncurses endwin(); return 0; }
重点检查:有没有调用cbreak()?有没有在输出后调用refresh()?退出时有没有endwin()?
2. 确保ROS节点关联到正确的终端
用rosrun运行节点时,ROS有时候会悄悄修改终端的输入输出关联,导致ncurses拿不到终端控制权:
- 先试试直接运行节点的可执行文件:cd到
devel/lib/你的包名,然后执行./你的节点名,如果这时候getch()正常,那就是rosrun的锅。 - 解决rosrun的问题:用
--prefix "exec"参数强制节点直接关联当前终端:rosrun --prefix "exec" 你的包名 你的节点名
3. 区分“无按键”和“读取失败”
如果你用了nodelay(stdscr, TRUE)开启非阻塞模式,getch()在没有按键时会返回ERR(-1),这是正常现象!你需要在代码里判断:只有当ch不等于ERR时,才处理按键并发布消息,否则继续循环即可(别把ERR当成错误)。
4. 先修复纯ncurses程序的问题
你说简化的ncurses小程序也无输出,先解决这个基础问题:
- 写一个最极简的测试程序,编译时一定要链接ncurses库:
g++ test.cpp -o test -lncurses - 如果运行还是没反应,重置终端设置:执行
stty sane后再运行测试程序 - 再不行就重新安装ncurses依赖:
sudo apt-get install libncurses5-dev libncursesw5-dev - 另外,别用IDE的内置终端(比如CLion、VS Code的终端),换原生的gnome-terminal或xterm试试,很多IDE终端对ncurses支持不好。
最后再整合到ROS节点
等纯ncurses程序能正常读取按键后,再把代码整合到ROS节点里,注意ROS初始化和ncurses初始化的顺序(先ROS,后ncurses),确保退出时调用endwin()清理终端。
内容的提问来源于stack exchange,提问作者VansFannel
相关产品推荐
相关产品推荐

