加粗样式@TOC
错误: 加载主类 com.intellij.idea.Main 时出现 LinkageError
java.lang.UnsupportedClassVersionError: com/intellij/idea/Main has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0
该传感器模块对环境光线适应能力强,其具有一对红外线发射与接收管,发射管发射出一定频率的红外线,当检测方向遇到障碍物(反射面)时,红外线反射回来被接收管接收,经过比较器电路处理之后,绿色指示灯会亮起,同时信号输出接回输出数字信号(一个低电平信号),可通过电位器旋钮调节检测距离,有效距离范围2~30cm,工作电压为3.3v-5v。该传感器的探测距离可以通过电位器调节、具有干扰小、便于装配、使用方便等特点,可以广泛应用于机器人避障、避障小车、流水线计数及黑白线循迹等众多场合。
模块参数
当模块检测到前方障碍物信号时,电路板上绿色指示灯点亮,同时OUT端口持续输出低电平信号
该模块测距离2~~30cm,检测角度35°,检测距离可以通过电位器进行调节,顺时针调电位器,检测距离增加;逆时针调电位器,检测距离减少。
传感器主动红外线反射探测,因此目标的反射率和形状是探测距离的关键。其中黑色探测距离小,白色大;小面积物体距离小,大面积距离大。
传感器模块输出端口OUT可直接与单片机IO口连接即可,也可以直接驱动一个5v继电器
比较器采用LM393,工作稳定;
可采用3-5v直流电源对模块进行供电。当电源接通时,红色电源指示灯点亮;
具有3mm的螺丝孔,便于固定、安装;
电路板尺寸:3.2CM*1.4CM
每个模块在发货已经将阈值比较电压通过电位器调节好,非特殊情况,请勿随意调节电位器。
接口说明
1.VCC外接3.3v-5v电压(可以直接与5v单片机和3.3v单片机相连)
2、GND 外接GND
3、OUT小板数字量输出接口(0和1)
手册说明
TCRT5000传感器的红外发射二极管不断发射红外线 ,当发射出的红外线没有被反射回来或被反射回来但强度不够大时, 红外接收管一直处于关断状态,此时模块的输出端为高电平,指示二极管一直处于熄灭状态, 被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,红外接收管饱和, 此时模块的输出端为低电平,指示二极管被点亮
总结就是一句话
没反射——D0输出高电平——灭灯
反射——D0输出低电平——亮灯
原文链接
├── bin -> usr/bin # 用于存放二进制命令
├── boot # 内核及引导系统程序所在的目录
├── dev # 所有设备文件的目录(如磁盘、光驱等)
├── etc # 配置文件默认路径、服务启动命令存放目录
├── home # 用户家目录,root用户为/root
├── lib -> usr/lib # 32位库文件存放目录
├── lib64 -> usr/lib64 # 64位库文件存放目录
├── media # 媒体文件存放目录
├── mnt # 临时挂载设备目录
├── opt # 自定义软件安装存放目录
├── proc # 进程及内核信息存放目录
├── root # Root用户家目录
├── run # 系统运行时产生临时文件,存放目录
├── sbin -> usr/sbin # 系统管理命令存放目录
├── srv # 服务启动之后需要访问的数据目录
├── sys # 系统使用目录
├── tmp # 临时文件目录
├── usr # 系统命令和帮助文件目录
└── var # 存放内容易变的文件的目录
pwd 查看当前工作目录
clear 清除屏幕
cd ~ 当前用户目录
cd / 根目录
cd - 上一次访问的目录
cd .. 上一级目录
ll 查看当前目录下内容(LL的小写)
mkdir aaa 在当前目录下创建aaa目录,相对路径;
mkdir ./bbb 在当前目录下创建bbb目录,相对路径;
mkdir /ccc 在根目录下创建ccc目录,绝对路径;
mkdir -p temp/nginx
find / -name 'b' 查询根目录下(包括子目录),名以b的目录和文件;
find / -name 'b*' 查询根目录下(包括子目录),名以b开头的目录和文件;
find . -name 'b' 查询当前目录下(包括子目录),名以b的目录和文件;
mv 原先目录 文件的名称 mv tomcat001 tomcat
mv /aaa /bbb 将根目录下的aaa目录,移动到bbb目录下(假如没有bbb目录,则重命名为bbb);
mv bbbb usr/bbb 将当前目录下的bbbb目录,移动到usr目录下,并且修改名称为bbb;
mv bbb usr/aaa 将当前目录下的bbbb目录,移动到usr目录下,并且修改名称为aaa;
cp -r /aaa /bbb 将/目录下的aaa目录复制到/bbb目录下,在/bbb目录下的名称为aaa
cp -r /aaa /bbb/aaa 将/目录下的aa目录复制到/bbb目录下,且修改名为aaa;
rm -rf /bbb 强制删除/目录下的bbb目录。如果bbb目录中还有子目录,也会被强制删除,不会提示;
rm -r /bbb 普通删除。会询问你是否删除每一个文件
rmdir test01 目录的删除
tree test01/
查看树状目录结构
mkdir -p ws/src
cd ws
catkin_make
code .//.是当前ws空间文件
//vscode编译
ctrl+shift+B
//启动节点,launch文件
rosrun pkg node
roslaunch pkg .launch
//查看节点之间关系
rqt_graph
#include "ros/ros.h"
#include "std_msgs/String.h" //普通文本类型的消息
#include
int main(int argc, char *argv[])
{
//设置编码
setlocale(LC_ALL,"");
//2.初始化 ROS 节点:命名(唯一)
// 参数1和参数2 后期为节点传值会使用
// 参数3 是节点名称,是一个标识符,需要保证运行后,在 ROS 网络拓扑中唯一
ros::init(argc,argv,"talker");
//3.实例化 ROS 句柄
ros::NodeHandle nh;//该类封装了 ROS 中的一些常用功能
//4.实例化 发布者 对象
//泛型: 发布的消息类型
//参数1: 要发布到的话题
//参数2: 队列中最大保存的消息数,超出此阀值时,先进的先销毁(时间早的先销毁)
ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10);
//5.组织被发布的数据,并编写逻辑发布数据
//数据(动态组织)
std_msgs::String msg;
// msg.data = "你好啊!!!";
std::string msg_front = "Hello 你好!"; //消息前缀
int count = 0; //消息计数器
//逻辑(一秒10次)
ros::Rate r(1);
//节点不死
while (ros::ok())
{
//使用 stringstream 拼接字符串与编号
std::stringstream ss;
ss << msg_front << count;
msg.data = ss.str();
//发布消息
pub.publish(msg);
//加入调试,打印发送的消息
ROS_INFO("发送的消息:%s",msg.data.c_str());
//根据前面制定的发送贫频率自动休眠 休眠时间 = 1/频率;
r.sleep();
count++;//循环结束前,让 count 自增
//暂无应用
ros::spinOnce();
}
return 0;
}
#include "ros/ros.h"
#include "std_msgs/String.h"
void doMsg(const std_msgs::String::ConstPtr& msg_p){
ROS_INFO("我听见:%s",msg_p->data.c_str());
// ROS_INFO("我听见:%s",(*msg_p).data.c_str());
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
//2.初始化 ROS 节点:命名(唯一)
ros::init(argc,argv,"listener");
//3.实例化 ROS 句柄
ros::NodeHandle nh;
//4.实例化 订阅者 对象
ros::Subscriber sub = nh.subscribe<std_msgs::String>("chatter",10,doMsg);
//5.处理订阅的消息(回调函数)
// 6.设置循环调用回调函数
ros::spin();//循环读取接收的数据,并调用回调函数处理
return 0;
}
1.定义msg文件:功能包下新建 msg 目录,添加文件 Person.msg
string name
uint16 age
float64 height
2.package.xml中添加编译依赖与执行依赖,CMakeLists.txt编辑 msg 相关配置
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
<!--
exce_depend 以前对应的是 run_depend 现在非法
-->
message_generation是一个ROS(机器人操作系统)软件,它提供了在ROS中生成自定义消息的工具。在ROS中,消息是指一组结构化数据,通过ROS话题(topic)进行传输。每个消息都有一个特定的格式(描述)和转换函数(注意,这里的“消息”不是网络通信协议中的“消息”)。
message_generation包包含了生成自定义消息的工具,主要是依据msg文件生成相应的源码和文件(例如,C++头和Python脚本)。当用户用户定义了新的消息结体时,使用此工具根据此结构体创建新的消息类型,并在ROS系统中使用它。
需要说明的是,如果想要使用自己创建的消息类型还需要安装message_runtime包因为发布节点和订阅节点需要能够解析新消息类型以接受和处理该消息。
3.CMakeLists.txt编辑 msg 相关配置
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
# 需要加入 message_generation,必须有 std_msgs
## 配置 msg 源文件
add_message_files(
FILES
Person.msg
)
# 生成消息时依赖于 std_msgs
generate_messages(
DEPENDENCIES
std_msgs
)
```c
#执行时依赖
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES demo02_talker_listener
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)
4.将前面生成的 head 文件路径配置进 c_cpp_properties.json 的 includepath属性:
{
"configurations": [
{
"browse": {
"databaseFilename": "${default}",
"limitSymbolsToIncludedHeaders": false
},
"includePath": [
"/opt/ros/melodic/include/**",
"/home/lzl/class_one_ws/src/class_one_pkg/include/**",
"/home/lzl/usb_cam_ws/src/usb_cam/include/**",
"/usr/include/**",
"/home/lzl/ros_ws/devel/include/**" //配置 head 文件的绝对路径
],
"name": "ROS",
"intelliSenseMode": "gcc-x64",
"compilerPath": "/usr/bin/gcc",
"cStandard": "gnu11",
"cppStandard": "c++14"
}
],
"version": 4
}
每个功能包的msg对应生成的.h消息文件只能在一个功能包下使用,跟路径有关
使用rosmsg package 包名
列出某个功能包下的msg
运行launch文件验证msg消息头文件的调用以及多个节点之间的通信
#include "ros/ros.h"
#include "demo03_server_client/AddInts.h"
// bool 返回值由于标志是否处理成功
bool doReq(demo03_server_client::AddInts::Request& req,
demo03_server_client::AddInts::Response& resp){
int num1 = req.num1;
int num2 = req.num2;
ROS_INFO("服务器接收到的请求数据为:num1 = %d, num2 = %d",num1, num2);
//逻辑处理
if (num1 < 0 || num2 < 0)
{
ROS_ERROR("提交的数据异常:数据不可以为负数");
return false;
}
//如果没有异常,那么相加并将结果赋值给 resp
resp.sum = num1 + num2;
return true;
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化 ROS 节点
ros::init(argc,argv,"AddInts_Server");
// 3.创建 ROS 句柄
ros::NodeHandle nh;
// 4.创建 服务 对象
ros::ServiceServer server = nh.advertiseService("AddInts",doReq);
ROS_INFO("服务已经启动....");
// 5.回调函数处理请求并产生响应
// 6.由于请求有多个,需要调用 ros::spin()
ros::spin();
return 0;
}
#include "ros/ros.h"
#include "demo03_server_client/AddInts.h"
// bool 返回值由于标志是否处理成功
bool doReq(demo03_server_client::AddInts::Request& req,
demo03_server_client::AddInts::Response& resp){
int num1 = req.num1;
int num2 = req.num2;
ROS_INFO("服务器接收到的请求数据为:num1 = %d, num2 = %d",num1, num2);
//逻辑处理
if (num1 < 0 || num2 < 0)
{
ROS_ERROR("提交的数据异常:数据不可以为负数");
return false;
}
//如果没有异常,那么相加并将结果赋值给 resp
resp.sum = num1 + num2;
return true;
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化 ROS 节点
ros::init(argc,argv,"AddInts_Server");
// 3.创建 ROS 句柄
ros::NodeHandle nh;
// 4.创建 服务 对象
ros::ServiceServer server = nh.advertiseService("AddInts",doReq);
ROS_INFO("服务已经启动....");
// 5.回调函数处理请求并产生响应
// 6.由于请求有多个,需要调用 ros::spin()
ros::spin();
return 0;
}
//定义srv文件
# 客户端请求时发送的两个数字
int32 num1
int32 num2
---
# 服务器响应发送的数据
int32 sum
//编辑配置文件
package.xml中添加编译依赖与执行依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
<!--
exce_depend 以前对应的是 run_depend 现在非法
-->
CMakeLists.txt编辑 srv 相关配置
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
# 需要加入 message_generation,必须有 std_msgs
add_service_files(
FILES
AddInts.srv
)
generate_messages(
DEPENDENCIES
std_msgs
)
<launch>
<!--启动的节点-->
<node pkg="topic_pkg" type="talker" name="talker_node1" output="screen" />
<!--键盘控制节点-->
<node pkg="topic_pkg" type="listener" name="listener_node1" output="screen" />
</launch>
常用的消息包消息:
geometry_msgs/TransformStamped消息类型包含了发送者与接收者之间的变换信息,包括变换的起点和终点、变换的旋转和平移矩阵等信息。
geometry_msgs/TransformStamped
std_msgs/Header header #头信息
uint32 seq #|-- 序列号
time stamp #|-- 时间戳
string frame_id #|-- 坐标 ID
string child_frame_id #子坐标系的 id
geometry_msgs/Transform transform #坐标信息
geometry_msgs/Vector3 translation #偏移量
float64 x #|-- X 方向的偏移量
float64 y #|-- Y 方向的偏移量
float64 z #|-- Z 方向上的偏移量
geometry_msgs/Quaternion rotation #四元数
float64 x
float64 y
float64 z
float64 w
geometry_msgs/PointStamped消息类型则表示在3D空间中的一个点的坐标信息,包含了这个点在XYZ三个方向上的坐标位置以及时间戳信息,常用于目标检测、位置识别等任务中。
geometry_msgs/PointStamped
std_msgs/Header header #头
uint32 seq #|-- 序号
time stamp #|-- 时间戳
string frame_id #|-- 所属坐标系的 id
geometry_msgs/Point point #点坐标
float64 x #|-- x y z 坐标
float64 y
float64 z
rosmsg info
坐标变换通过发布订阅模型
功能包的依赖
find_package(catkin REQUIRED COMPONENTS
geometry_msgs
roscpp
rospy
std_msgs
tf2
tf2_geometry_msgs
tf2_ros
)
发布方
/*
静态坐标变换发布方:
发布关于 laser 坐标系的位置信息
实现流程:
1.包含头文件
2.初始化 ROS 节点
3.创建静态坐标转换广播器
4.创建坐标系信息
5.广播器发布坐标系信息
6.spin()
*/
// 1.包含头文件
#include "ros/ros.h"
#include "tf2_ros/static_transform_broadcaster.h"
#include "geometry_msgs/TransformStamped.h"
#include "tf2/LinearMath/Quaternion.h"
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化 ROS 节点
ros::init(argc,argv,"static_brocast");
// 3.创建静态坐标转换广播器
tf2_ros::StaticTransformBroadcaster broadcaster;
// 4.创建坐标系信息
geometry_msgs::TransformStamped ts;
//----设置头信息
ts.header.seq = 100;
ts.header.stamp = ros::Time::now();
ts.header.frame_id = "base_link";
//----设置子级坐标系
ts.child_frame_id = "laser";
//----设置子级相对于父级的偏移量
ts.transform.translation.x = 0.2;
ts.transform.translation.y = 0.0;
ts.transform.translation.z = 0.5;
//----设置四元数:将 欧拉角数据转换成四元数
tf2::Quaternion qtn;
qtn.setRPY(0,0,0);
ts.transform.rotation.x = qtn.getX();
ts.transform.rotation.y = qtn.getY();
ts.transform.rotation.z = qtn.getZ();
ts.transform.rotation.w = qtn.getW();
// 5.广播器发布坐标系信息
broadcaster.sendTransform(ts);
ros::spin();
return 0;
}
订阅方
/*
订阅坐标系信息,生成一个相对于 子级坐标系的坐标点数据,转换成父级坐标系中的坐标点
实现流程:
1.包含头文件
2.初始化 ROS 节点
3.创建 TF 订阅节点
4.生成一个坐标点(相对于子级坐标系)
5.转换坐标点(相对于父级坐标系)
6.spin()
*/
//1.包含头文件
#include "ros/ros.h"
#include "tf2_ros/transform_listener.h"
#include "tf2_ros/buffer.h"
#include "geometry_msgs/PointStamped.h"
#include "tf2_geometry_msgs/tf2_geometry_msgs.h" //注意: 调用 transform 必须包含该头文件
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
// 2.初始化 ROS 节点
ros::init(argc,argv,"tf_sub");
ros::NodeHandle nh;
// 3.创建 TF 订阅节点
tf2_ros::Buffer buffer;
tf2_ros::TransformListener listener(buffer);
ros::Rate r(1);
while (ros::ok())
{
// 4.生成一个坐标点(相对于子级坐标系)
geometry_msgs::PointStamped point_laser;
point_laser.header.frame_id = "laser";
point_laser.header.stamp = ros::Time::now();
point_laser.point.x = 1;
point_laser.point.y = 2;
point_laser.point.z = 7.3;
// 5.转换坐标点(相对于父级坐标系)
//新建一个坐标点,用于接收转换结果
//--------------使用 try 语句或休眠,否则可能由于缓存接收延迟而导致坐标转换失败------------------------
try
{
geometry_msgs::PointStamped point_base;
point_base = buffer.transform(point_laser,"base_link");
ROS_INFO("转换后的数据:(%.2f,%.2f,%.2f),参考的坐标系是:",point_base.point.x,point_base.point.y,point_base.point.z,point_base.header.frame_id.c_str());
}
catch(const std::exception& e)
{
// std::cerr << e.what() << '\n';
ROS_INFO("程序异常.....");
}
r.sleep();
ros::spinOnce();
}
return 0;
}
第一个节点是一个 ROS 节点,它使用 tf2_ros 库实现了静态坐标变换发布方,可以发布关于 laser 坐标系的位置信息。该节点通过在创建 geometry_msgs::TransformStamped 类型的消息并填充相关信息(包括头信息、子级坐标系、相对于父级坐标系的偏移量和四元数)来定义所需的坐标系信息,并使用 tf2_ros::StaticTransformBroadcaster 类型的广播器来广播坐标系信息。
第二个节点是另一个 ROS 节点,它使用 tf2_ros 库实现了订阅坐标系信息,生成一个相对于子级坐标系的坐标点数据,并将其转换成父级坐标系中的坐标点。该节点通过使用 tf2_ros::TransformListener 类型的订阅节点来监听 base_link 和 laser 坐标系之间的坐标转换,并在程序中用 geometry_msgs::PointStamped 类型的消息存储相对于 laser 坐标系的坐标点的信息。 然后,该节点通过调用 tf2_geometry_msgs 库中的 transform 函数将坐标点中相对于 laser 坐标系的数据转换为相对于 base_link 坐标系的数据,并输出转换后的数据和参考坐标系的信息。最后,该节点在 while 循环中使用 ros::Rate 对象设置相应的循环频率,并使用 ros::spinOnce() 来处理未处理的 ROS 消息,从而实现节点的运行。
//urdf
//gazebo
//xacro