基础参考:
1.C 编程中的system终端命令与thread并行基础和进阶(含ROS2 CLI)
2.FTXUI基础笔记(botton按钮组件基础)
如何编写一个终端用户接口,实现打开turtlesim仿真和teleop遥控呢?
需要参考程序1:
代码语言:javascript复制#include <memory> // for shared_ptr, __shared_ptr_access
#include <string> // for operator , to_string
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Button, Horizontal, Renderer
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for separator, gauge, text, Element, operator|, vbox, border
using namespace ftxui;
int main(int argc, const char* argv[]) {
int value = 50;
// The tree of components. This defines how to navigate using the keyboard.
auto buttons = Container::Horizontal({
Button("计数加1", [&] { value--; }),
Button("计数减1", [&] { value ; }),
});
// Modify the way to render them on screen:
auto component = Renderer(buttons, [&] {
return vbox({
text(" 数值 = " std::to_string(value)),
separator(),
gauge(value * 0.01f),
separator(),
buttons->Render(),
}) |
border;
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(component);
return 0;
}
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
程序2:
代码语言:javascript复制#include <iostream>
#include <thread>
using namespace std;
void turtlesim_node()
{
system("ros2 run turtlesim turtlesim_node");
}
void turtle_teleop_key()
{
system("ros2 run turtlesim turtle_teleop_key");
}
int main ()
{
cout << "Hello ros2 turtlesim!" << endl;
thread th1(turtlesim_node);
thread th2(turtle_teleop_key);
th1.join();
th2.join();
return 0;
}
拼到一起试试看?
代码语言:javascript复制#include <memory> // for shared_ptr, __shared_ptr_access
#include <string> // for operator , to_string
#include <iostream>
#include <thread>
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Button, Horizontal, Renderer
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for separator, gauge, text, Element, operator|, vbox, border
using namespace ftxui;
void turtlesim_node()
{
std::system("ros2 run turtlesim turtlesim_node");
}
void turtle_teleop_key()
{
std::system("ros2 run turtlesim turtle_teleop_key");
}
int main(int argc, const char* argv[]) {
int value = 50;
std::thread th1(turtlesim_node);
std::thread th2(turtle_teleop_key);
// The tree of components. This defines how to navigate using the keyboard.
auto buttons = Container::Horizontal({
Button("turtlesim", [&] { th1.join(); }),
Button("teleop", [&] { th2.join(); }),
});
// Modify the way to render them on screen:
auto component = Renderer(buttons, [&] {
return vbox({
text(" cmd = " std::to_string(value)),
separator(),
gauge(value * 0.01f),
separator(),
buttons->Render(),
}) |
border;
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(component);
return 0;
}
程序运行效果很不好哦。
怎么办?留着作为思考题?
参考下面程序:
代码语言:javascript复制#include <memory> // for shared_ptr, __shared_ptr_access
#include <string> // for operator , to_string
#include <iostream>
#include <thread>
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Button, Horizontal, Renderer
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for separator, gauge, text, Element, operator|, vbox, border
using namespace ftxui;
void turtlesim_node()
{
std::system("terminator -e 'ros2 run turtlesim turtlesim_node'");
}
void turtle_teleop_key()
{
std::system("terminator -e 'ros2 run turtlesim turtle_teleop_key'");
}
int main(int argc, const char* argv[]) {
int value = 50;
std::thread th1(turtlesim_node);
std::thread th2(turtle_teleop_key);
// The tree of components. This defines how to navigate using the keyboard.
auto buttons = Container::Horizontal({
Button("turtlesim", [&] { th1.join(); }),
Button("teleop", [&] { th2.join(); }),
});
// Modify the way to render them on screen:
auto component = Renderer(buttons, [&] {
return vbox({
text(" cmd = " std::to_string(value)),
separator(),
gauge(value * 0.01f),
separator(),
buttons->Render(),
}) |
border;
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(component);
return 0;
}
void turtlesim_node()
{
std::system("terminator -e 'ros2 run turtlesim turtlesim_node'");
}
void turtle_teleop_key()
{
std::system("terminator -e 'ros2 run turtlesim turtle_teleop_key'");
}
效果依然惊悚啊^_^
ConfigBase::load: Unable to open /etc/xdg/terminator/config (Errno 2 No such file or directory: '/etc/xdg/terminator/config')
运行terminator ,给出如上提示。
介绍
各种规范指定文件和文件格式。该规范通过定义一个或多个相对于哪些文件应位于的基本目录来定义应在何处查找这些文件。
基本
XDG 基本目录规范基于以下概念:
有一个相对于应该写入用户特定数据文件的基本目录。该目录由环境变量定义$XDG_DATA_HOME。
有一个相对于应该写入用户特定配置文件的基本目录。该目录由环境变量定义$XDG_CONFIG_HOME。
有一个相对于应该写入用户特定状态数据的基本目录。该目录由环境变量定义$XDG_STATE_HOME。
有一个相对于其可以写入用户特定可执行文件的基本目录。
有一组与应搜索的数据文件相关的优先排序基本目录。这组目录由环境变量定义$XDG_DATA_DIRS。
有一组优先排序的基本目录相对于应该搜索的配置文件。这组目录由环境变量定义$XDG_CONFIG_DIRS。
有一个相对于应该写入用户特定的非必要(缓存)数据的基本目录。该目录由环境变量定义$XDG_CACHE_HOME。
有一个相对于应该放置用户特定运行时文件和其他文件对象的基本目录。该目录由环境变量定义$XDG_RUNTIME_DIR。
在这些环境变量中设置的所有路径都必须是绝对的。如果实现在任何这些变量中遇到相对路径,它应该认为路径无效并忽略它。
环境变量 XDG_DATA_HOME定义相对于应存储用户特定数据文件的基本目录。如果 未设置或为空,则应使用 XDG_DATA_HOME等于 /.local/share 的默认值 。
XDG_CONFIG_HOME定义相对于应存储用户特定配置文件的基本目录。如果 未设置或为空,则应使用 XDG_CONFIG_HOME等于 /.config 的默认值 。
XDG_STATE_HOME定义相对应存储用户特定状态文件的基本目录。如果 未设置或为空,则应使用 XDG_STATE_HOME等于 /.local/state 的默认值 。
包含应该在(应用程序)重新启动之间保持的XDG_STATE_HOME状态数据,但对于用户来说,它应该存储在 XDG_DATA_HOME. 它可能包含:
操作历史记录(日志、历史记录、最近使用的文件……)
可以在重新启动时重用的应用程序的当前状态(视图、布局、打开的文件、撤消历史记录……)
用户特定的可执行文件可能存储在 HOME/.local/bin 中。发行版应确保此目录显示在 UNIX PATH 环境变量中的适当位置。
由于HOME可能在不同架构的系统之间共享,将编译后的二进制文件安装到 HOME/.local/bin 可能会在不同架构的系统上使用时导致问题。这通常不是问题,但
XDG_DATA_DIRS定义优先顺序的基本目录集以搜索除 XDG_DATA_HOME基本目录之外的数据文件。中的目录
如果$XDG_DATA_DIRS未设置或为空,则应使用等于 /usr/local/share/:/usr/share/ 的值。
XDG_CONFIG_DIRS定义优先顺序的基本目录集以搜索除 XDG_CONFIG_HOME基本目录之外的配置文件。中的目录
如果$XDG_CONFIG_DIRS未设置或为空,则应使用等于 /etc/xdg 的值。
基本目录的顺序表示它们的重要性;列出的第一个目录是最重要的。当在多个位置定义相同的信息时,相对于更重要的基本目录定义的信息优先。由 定义的基本目录XDG_DATA_HOME被认为比由 定义的任何基本目录更重要 XDG_DATA_DIRS。由 定义的基本目录XDG_CONFIG_HOME被认为比由 定义的任何基本目录更重要 XDG_CONFIG_DIRS。
XDG_CACHE_HOME定义相对于应该存储用户特定的非必要数据文件的基本目录。如果 未设置或为空,则应使用 XDG_CACHE_HOME等于 /.cache 的默认值 。
$XDG_RUNTIME_DIR定义相对于用户特定的非必要运行时文件和其他文件对象(如套接字、命名管道等)应该存储的基本目录。该目录必须由用户拥有,并且他必须是唯一拥有对该目录的读写权限的人。它的 Unix 访问模式必须是 0700。
目录的生命周期必须与正在登录的用户绑定。它必须在用户首次登录时创建,如果用户完全注销,则必须删除目录。如果用户多次登录,他应该被指向同一个目录,并且从他第一次登录到他最后一次注销系统,该目录必须继续存在,并且在这期间不能被删除。目录中的文件必须不能在重新启动或完整的注销/登录周期后继续存在。
该目录必须位于本地文件系统上,并且不与任何其他系统共享。该目录必须完全符合操作系统的标准。更具体地说,在类 Unix 操作系统上 AF_UNIX 套接字、符号链接、硬链接、适当的权限、文件锁定、稀疏文件、内存映射、文件更改通知,必须支持可靠的硬链接计数,并且对文件名没有限制字符集应该被强加。此目录中的文件可能会受到定期清理。为确保您的文件不会被删除,它们的访问时间时间戳应至少每 6 小时单调时间修改一次,或者应在文件上设置“粘性”位。
如果$XDG_RUNTIME_DIR未设置,应用程序应退回到具有类似功能的替换目录并打印警告消息。应用程序应该使用这个目录进行通信和同步,并且不应该在其中放置较大的文件,因为它可能驻留在运行时内存中并且不一定被换出到磁盘。
参考本规范
其他规范可以通过将数据文件的位置指定为 $XDG_DATA_DIRS/subdir/filename 来引用此规范。这意味着:
此类文件应安装到datadir/subdir/filename, datadir默认为 /usr/share。
可以在 XDG_DATA_HOME/subdir/filename 中创建用户特定版本的数据文件,同时考虑 XDG_DATA_HOMEif
数据文件的查找应搜索 ./subdir/filename 相对于XDG_DATA_HOME和 指定的所有基本目录 XDG_DATA_DIRS。如果环境变量未设置或为空,则应使用本规范定义的默认值。
规范可以通过将配置文件的位置指定为 $XDG_CONFIG_DIRS/subdir/filename 来引用此规范。这意味着:
默认配置文件应安装到sysconfdir/xdg/subdir/filename, sysconfdir默认为 /etc。
可以在 XDG_CONFIG_HOME/subdir/filename 中创建用户特定版本的配置文件,同时考虑 XDG_CONFIG_HOMEif
配置文件的查找应搜索 ./subdir/filename 相对于XDG_CONFIG_HOME和 指示的所有基本目录 XDG_CONFIG_DIRS。如果环境变量未设置或为空,则应使用本规范定义的默认值。
如果在尝试写入文件时,目标目录不存在,则应尝试使用权限创建它0700。如果目标目录已经存在,则不应更改权限。应用程序应准备好处理无法写入文件的情况,因为目录不存在且无法创建,或者出于任何其他原因。在这种情况下,它可以选择向用户显示错误消息。
尝试读取文件时,如果由于某种原因无法访问某个目录中的文件,例如因为目录不存在、文件不存在或用户无权打开文件,则处理应该跳过该目录中的文件。如果因此根本找不到所需的文件,则应用程序可能会选择向用户显示错误消息。
当文件位于多个基本目录下时 ,引用XDG_DATA_DIRS或 应该定义行为必须是什么的规范。 XDG_CONFIG_DIRS例如,它可以定义只应使用最重要的基本目录下的文件,或者作为另一个示例,它可以定义用于合并来自不同文件的信息的规则。
terminator -u
<window.Window object at 0x************(terminatorlib window Window at 0x*************)> is not in registered window list