0%

移植

参考文章:
https://blog.csdn.net/wwt18811707971/article/details/83043257?utm_source=app&app_version=4.5.8

对于移植STM32F103VET6的代码到STM32F103RET6(12M晶振),步骤是1.1,2.1

在keil下编译,已经定义好的代码提示未定义的解决办法

参考文章:
https://allen5g.blog.csdn.net/article/details/92842050

编译出现如下错误:
…\main.c(24): error: #20: identifier “TIM_TimeBaseInitTypeDef” is undefined
…\main.c: TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
…\main.c: ^
…\main.c(47): error: #20: identifier “TIM_CounterMode_Up” is undefined
…\main.c: TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

所有提示未定义的代码都已经确定定义过,但为什么会出现这样的情况?

最后发现,在stm32f10x_conf.h 里面包含stm32f10x_tim.h头文件的代码被注释掉了,重新包含这个头文件就把上面的问题解决了。

如果还有报错,勾选C99。

当电脑安装了NVDIA驱动后,在安装ubuntu的时候出现画面卡住,无法正常安装。

卡死在logo界面

在grub引导界面,用方向键选到install ubuntu,不要按回车,而是按e,进入参数配置编辑界面;

找到quiet splash,在后面空一格再加上
acpi_osi=linux nomodeset

然后按F10即可进入正常的安装流程

(这种方法是只使用核显,该方法不太好,如果你要使用英伟达显卡加速深度学习训练)

编辑grub文件

在上述步骤完成后,进入ubuntu图形界面时,执行指令
sudo gedit /etc/default/grub
找到quiet splash,在后面空一格再加上
acpi_osi=linux nomodeset

保存后,更新grub配置:
sudo update-grub

参考文章:
https://blog.csdn.net/ysy950803/article/details/78507892?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161841262216780264033414%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=161841262216780264033414&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-78507892.first_rank_v2_pc_rank_v29&utm_term=%E8%A7%A3%E5%86%B3nvidia%E6%98%BE%E5%8D%A1%E7%9A%84%E7%94%B5%E8%84%91%E5%AE%89%E8%A3%85Ubuntu

https://blog.csdn.net/sherpahu/article/details/89792000?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161841269816780357232913%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=161841269816780357232913&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-1-89792000.first_rank_v2_pc_rank_v29&utm_term=ubuntu%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%E8%B8%A9%E5%9D%91

参数服务器在ROS中主要用于实现不同节点之间的数据共享。参数服务器相当于是独立于所有节点的一个公共容器,可以将数据存储在该容器中,被不同的节点调用,当然不同的节点也可以往其中存储数据,关于参数服务器的典型应用场景如下:

导航实现时,会进行路径规划,比如: 全局路径规划,设计一个从出发点到目标点的大致路径。本地路径规划,会根据当前路况生成时时的行进路径

上述场景中,全局路径规划和本地路径规划时,就会使用到参数服务器:

路径规划时,需要参考小车的尺寸,我们可以将这些尺寸信息存储到参数服务器,全局路径规划节点与本地路径规划节点都可以从参数服务器中调用这些参数
参数服务器,一般适用于存在数据共享的一些应用场景。

cpp实现

参数服务器新增(修改)参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
参数服务器操作之新增与修改(二者API一样)_C++实现:
在 roscpp 中提供了两套 API 实现参数操作
ros::NodeHandle
setParam("键",值)
ros::param
set("键","值")

示例:分别设置整形、浮点、字符串、bool、列表、字典等类型参数
修改(相同的键,不同的值)

*/
#include "ros/ros.h"

int main(int argc, char *argv[])
{
/* code */
ros::init(argc,argv,"set_param_c");
ros::NodeHandle nh;
nh.setParam("type","xiaohuang");
nh.setParam("radius",0.15);
ros::param::set("type_","xiaobai");
ros::param::set("radius_param",0.15);

nh.setParam("radius",0.2);
ros::param::set("radius_param",0.2);
return 0;
}

参数服务器获取参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/*
参数服务器操作之查询_C++实现:
在 roscpp 中提供了两套 API 实现参数操作
ros::NodeHandle

param(键,默认值)
存在,返回对应结果,否则返回默认值

getParam(键,存储结果的变量)
存在,返回 true,且将值赋值给参数2
若果键不存在,那么返回值为 false,且不为参数2赋值

getParamCached键,存储结果的变量)--提高变量获取效率
存在,返回 true,且将值赋值给参数2
若果键不存在,那么返回值为 false,且不为参数2赋值

getParamNames(std::vector<std::string>)
获取所有的键,并存储在参数 vector 中

hasParam(键)
是否包含某个键,存在返回 true,否则返回 false

searchParam(参数1,参数2)
搜索键,参数1是被搜索的键,参数2存储搜索结果的变量

ros::param ----- 与 NodeHandle 类似





*/
#include "ros/ros.h"

int main(int argc, char *argv[])
{
/* code */
ros::init(argc,argv,"get_param_c");
ros::NodeHandle nh;
double radius=nh.param("radius",0.5);
ROS_INFO("radius=%.2f",radius);

double radius2=0.0;
bool result=nh.getParam("radius",radius2);
if (result)
{
ROS_INFO("radius is %.2f",radius2);
}else{
ROS_INFO("radius not exist");
}

std::vector<std::string> names;
nh.getParamNames(names);
for (auto &&name : names)
{
ROS_INFO("paramName is %s",name.c_str());
}

bool flag1=nh.hasParam("radius");
bool flag2=nh.hasParam("radiusxxx");
ROS_INFO("radius is exist? %d",flag1);
ROS_INFO("radiusxxx is exist? %d",flag2);

std::string key;
nh.searchParam("radius",key);
ROS_INFO("result is %s",key.c_str());

double radius_param=ros::param::param("radius",100.5);
ROS_INFO("radius_param =%.2f",radius_param);

std::vector<std::string> names_param;
ros::param::getParamNames(names_param);
for (auto &&name_param : names_param)
{
ROS_INFO("key:%s",name_param.c_str());
}

return 0;
}

参数服务器删除参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/* 
参数服务器操作之删除_C++实现:

ros::NodeHandle
deleteParam("键")
根据键删除参数,删除成功,返回 true,否则(参数不存在),返回 false

ros::param
del("键")
根据键删除参数,删除成功,返回 true,否则(参数不存在),返回 false


*/

#include "ros/ros.h"

int main(int argc, char *argv[])
{
/* code */
ros::init(argc,argv,"param_del_c");
ros::NodeHandle nh;
bool flag1=nh.deleteParam("radius");
if (flag1){
ROS_INFO("delet succes");
} else{
ROS_INFO("delet fault");
}

bool flag2=ros::param::del("radius_param");
if (flag2){
ROS_INFO("delet succes");
} else{
ROS_INFO("delet fault");
}
return 0;
}

python实现

参数服务器新增(修改)参数

1
2
3
4
5
6
7
8
9
10
11
12
#! /usr/bin/env python
#coding=utf-8
import rospy

if __name__ == "__main__":
rospy.init_node("param_set_p")
rospy.set_param("type_p","xiaohuache")
rospy.set_param("radius_p",10)

rospy.set_param("radius_p",20)

pass

参数服务器获取参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#! /usr/bin/env python
"""
参数服务器操作之查询_Python实现:
get_param(键,默认值)
当键存在时,返回对应的值,如果不存在返回默认值
get_param_cached
get_param_names
has_param
search_param
"""
import rospy

if __name__ == "__main__":
rospy.init_node("param_get_p")
radius=rospy.get_param("radius_p",15)
radius1=rospy.get_param("radius_p_",15)
rospy.loginfo("radius is %.2f",radius)
rospy.loginfo("radius is %.2f",radius1)

names=rospy.get_param_names()
for name in names:
rospy.loginfo("param name is %s",name)

flag1=rospy.has_param("radius_p")
if flag1:
rospy.loginfo("radius_p is exist")
else:
rospy.loginfo("radius_p not exist")

key=rospy.search_param("radius_p")
rospy.loginfo("key =%s",key)



pass

参数服务器删除参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#! /usr/bin/env python
"""
参数服务器操作之删除_Python实现:
rospy.delete_param("键")
键存在时,可以删除成功,键不存在时,会抛出异常
"""
import rospy

if __name__ == "__main__":
rospy.init_node("param_del_p")
try:
rospy.delete_param("type_p")
except Exception as e:
rospy.loginfo("deleted param is not exist")
pass

新工程

1
2
3
4
5
6
7
git init 
git add . //.表示全部文件
git commit -m "frist commit"
git remote add origin https://github.com/usrname/repositoriesName.git
git push -u origin master
或者 git branch -M main
git push -u origin main

再次提交

1
2
3
git add . 
git commit -m "commit"
git push -u origin master

服务通信也是ROS中一种极其常用的通信模式,服务通信是基于请求响应模式的,是一种应答机制。
也即: 一个节点A向另一个节点B发送请求,B接收处理请求并产生响应结果返回给A。

自定义srv

服务通信中,数据分成两部分,请求与响应,在 srv 文件中请求和响应使用—分割,具体实现如下:

功能包下新建 srv 目录,添加 xxx.srv 文件,内容:

1
2
3
4
5
6
7
# 客户端请求时发送的两个数字
int32 num1
int32 num2
---
# 服务器响应发送的数据
int32 sum

编辑配置文件

package.xml中添加编译依赖与执行依赖

1
2
3
<build_depend>message_generation</build_depend>

<exec_depend>message_runtime</exec_depend>

CMakeLists.txt编辑 srv 相关配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
)

cpp实现

vscode配置

1
2
3
4
5
"includePath": [
"/opt/ros/noetic/include/**",
"/usr/include/**",
"/xxx/yyy工作空间/devel/include/**" //配置 head 文件的路径
],

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
需求:
编写两个节点实现服务通信,客户端节点需要提交两个整数到服务器
服务器需要解析客户端提交的数据,相加后,将结果响应回客户端,
客户端再解析

服务器实现:
1.包含头文件
2.初始化 ROS 节点
3.创建 ROS 句柄
4.创建 服务 对象
5.回调函数处理请求并产生响应
6.由于请求有多个,需要调用 ros::spin()

*/
#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;
}

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/*
需求:
编写两个节点实现服务通信,客户端节点需要提交两个整数到服务器
服务器需要解析客户端提交的数据,相加后,将结果响应回客户端,
客户端再解析

服务器实现:
1.包含头文件
2.初始化 ROS 节点
3.创建 ROS 句柄
4.创建 客户端 对象
5.请求服务,接收响应

*/
// 1.包含头文件
#include "ros/ros.h"
#include "demo03_server_client/AddInts.h"

int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");

// 调用时动态传值,如果通过 launch 的 args 传参,需要传递的参数个数 +3
if (argc != 3)
// if (argc != 5)//launch 传参(0-文件路径 1传入的参数 2传入的参数 3节点名称 4日志路径)
{
ROS_ERROR("请提交两个整数");
return 1;
}


// 2.初始化 ROS 节点
ros::init(argc,argv,"AddInts_Client");
// 3.创建 ROS 句柄
ros::NodeHandle nh;
// 4.创建 客户端 对象
ros::ServiceClient client = nh.serviceClient<demo03_server_client::AddInts>("AddInts");
//等待服务启动成功
//方式1
ros::service::waitForService("AddInts");
//方式2
// client.waitForExistence();
// 5.组织请求数据
demo03_server_client::AddInts ai;
ai.request.num1 = atoi(argv[1]); //转成整型
ai.request.num2 = atoi(argv[2]);
// 6.发送请求,返回 bool 值,标记是否成功
bool flag = client.call(ai);
// 7.处理响应
if (flag)
{
ROS_INFO("请求正常处理,响应结果:%d",ai.response.sum);
}
else
{
ROS_ERROR("请求处理失败....");
return 1;
}

return 0;
}

配置 CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
add_executable(AddInts_Server src/AddInts_Server.cpp)
add_executable(AddInts_Client src/AddInts_Client.cpp)


add_dependencies(AddInts_Server ${PROJECT_NAME}_gencpp)
add_dependencies(AddInts_Client ${PROJECT_NAME}_gencpp)


target_link_libraries(AddInts_Server
${catkin_LIBRARIES}
)
target_link_libraries(AddInts_Client
${catkin_LIBRARIES}
)

需要先启动服务:rosrun 包名 服务

然后再调用客户端 :rosrun 包名 客户端 参数1 参数2

优化:

在客户端发送请求前添加:client.waitForExistence();

或:ros::service::waitForService(“AddInts”);

这是一个阻塞式函数,只有服务启动成功后才会继续执行

此处可以使用 launch 文件优化,但是需要注意 args 传参特点

python实现

vscode配置

配置settings.json

1
2
3
4
5
6
{
"python.autoComplete.extraPaths": [
"/opt/ros/noetic/lib/python3/dist-packages",
]
}

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#! /usr/bin/env python
"""
需求:
编写两个节点实现服务通信,客户端节点需要提交两个整数到服务器
服务器需要解析客户端提交的数据,相加后,将结果响应回客户端,
客户端再解析

服务器端实现:
1.导包
2.初始化 ROS 节点
3.创建服务对象
4.回调函数处理请求并产生响应
5.spin 函数

"""
# 1.导包
import rospy
from demo03_server_client.srv import AddInts,AddIntsRequest,AddIntsResponse
# 回调函数的参数是请求对象,返回值是响应对象
def doReq(req):
# 解析提交的数据
sum = req.num1 + req.num2
rospy.loginfo("提交的数据:num1 = %d, num2 = %d, sum = %d",req.num1, req.num2, sum)

# 创建响应对象,赋值并返回
# resp = AddIntsResponse()
# resp.sum = sum
resp = AddIntsResponse(sum)
return resp


if __name__ == "__main__":
# 2.初始化 ROS 节点
rospy.init_node("addints_server_p")
# 3.创建服务对象
server = rospy.Service("AddInts",AddInts,doReq)
# 4.回调函数处理请求并产生响应
# 5.spin 函数
rospy.spin()

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#! /usr/bin/env python

"""
需求:
编写两个节点实现服务通信,客户端节点需要提交两个整数到服务器
服务器需要解析客户端提交的数据,相加后,将结果响应回客户端,
客户端再解析

客户端实现:
1.导包
2.初始化 ROS 节点
3.创建请求对象
4.发送请求
5.接收并处理响应

优化:
加入数据的动态获取


"""
#1.导包
import rospy
from demo03_server_client.srv import *
import sys

if __name__ == "__main__":

#优化实现
if len(sys.argv) != 3:
rospy.logerr("请正确提交参数")
sys.exit(1)


# 2.初始化 ROS 节点
rospy.init_node("AddInts_Client_p")
# 3.创建请求对象
client = rospy.ServiceProxy("AddInts",AddInts)
# 请求前,等待服务已经就绪
# 方式1:
# rospy.wait_for_service("AddInts")
# 方式2
client.wait_for_service()
# 4.发送请求,接收并处理响应
# 方式1
# resp = client(3,4)
# 方式2
# resp = client(AddIntsRequest(1,5))
# 方式3
req = AddIntsRequest()
# req.num1 = 100
# req.num2 = 200

#优化
req.num1 = int(sys.argv[1])
req.num2 = int(sys.argv[2])

resp = client.call(req)
rospy.loginfo("响应结果:%d",resp.sum)

设置权限

终端下进入 scripts 执行:chmod +x *.py

配置 CMakeLists.txt

1
2
3
4
5
6
catkin_install_python(PROGRAMS
scripts/AddInts_Server_p.py
scripts/AddInts_Client_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

需要先启动服务:rosrun 包名 服务

然后再调用客户端 :rosrun 包名 客户端 参数1 参数2

自定义消息

1.定义msg文件

功能包下新建 msg 目录,添加文件 Person.msg

1
2
3
4
string name
uint16 age
float64 height

2.编辑配置文件

package.xml中添加编译依赖与执行依赖

1
2
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

CMakeLists.txt编辑 msg 相关配置

1
2
3
4
5
6
7
8
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
# 需要加入 message_generation,必须有 std_msgs

1
2
3
4
5
6
## 配置 msg 源文件
add_message_files(
FILES
Person.msg
)

1
2
3
4
5
6
# 生成消息时依赖于 std_msgs
generate_messages(
DEPENDENCIES
std_msgs
)

1
2
3
4
5
6
7
8
#执行时依赖
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES demo02_talker_listener
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)

C++ 需要调用的中间文件(…/工作空间/devel/include/包名/xxx.h)

Python 需要调用的中间文件(…/工作空间/devel/lib/python3/dist-packages/包名/msg)

后续调用相关 msg 时,是从这些中间文件调用的

cpp实现

vscode配置

将前面生成的 head 文件路径配置进 c_cpp_properties.json 的 includepath属性:

1
2
3
4
5
"includePath": [
"/opt/ros/noetic/include/**",
"/usr/include/**",
"/xxx/yyy工作空间/devel/include/**" //配置 head 文件的路径
],

发布方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/*
需求: 循环发布人的信息

*/

#include "ros/ros.h"
#include "demo02_talker_listener/Person.h"

int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");

//1.初始化 ROS 节点
ros::init(argc,argv,"talker_person");

//2.创建 ROS 句柄
ros::NodeHandle nh;

//3.创建发布者对象
ros::Publisher pub = nh.advertise<demo02_talker_listener::Person>("chatter_person",1000);

//4.组织被发布的消息,编写发布逻辑并发布消息
demo02_talker_listener::Person p;
p.name = "sunwukong";
p.age = 2000;
p.height = 1.45;

ros::Rate r(1);
while (ros::ok())
{
pub.publish(p);
p.age += 1;
ROS_INFO("我叫:%s,今年%d岁,高%.2f米", p.name.c_str(), p.age, p.height);

r.sleep();
ros::spinOnce();
}



return 0;
}

订阅方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
需求: 订阅人的信息

*/

#include "ros/ros.h"
#include "demo02_talker_listener/Person.h"

void doPerson(const demo02_talker_listener::Person::ConstPtr& person_p){
ROS_INFO("订阅的人信息:%s, %d, %.2f", person_p->name.c_str(), person_p->age, person_p->height);
}

int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");

//1.初始化 ROS 节点
ros::init(argc,argv,"listener_person");
//2.创建 ROS 句柄
ros::NodeHandle nh;
//3.创建订阅对象
ros::Subscriber sub = nh.subscribe<demo02_talker_listener::Person>("chatter_person",10,doPerson);

//4.回调函数中处理 person

//5.ros::spin();
ros::spin();
return 0;
}

配置 CMakeLists.txt

需要添加 add_dependencies 用以设置所依赖的消息相关的中间文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
add_executable(person_talker src/person_talker.cpp)
add_executable(person_listener src/person_listener.cpp)



add_dependencies(person_talker ${PROJECT_NAME}_generate_messages_cpp)
add_dependencies(person_listener ${PROJECT_NAME}_generate_messages_cpp)


target_link_libraries(person_talker
${catkin_LIBRARIES}
)
target_link_libraries(person_listener
${catkin_LIBRARIES}
)

python实现

vscode配置

为了方便代码提示以及误抛异常,需要先配置 vscode,将前面生成的 python 文件路径配置进 settings.json

1
2
3
4
5
6
7
{
"python.autoComplete.extraPaths": [
"/opt/ros/noetic/lib/python3/dist-packages",
"/xxx/yyy工作空间/devel/lib/python3/dist-packages"
]
}

发布方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#! /usr/bin/env python
"""
发布方:
循环发送消息

"""
import rospy
from demo02_talker_listener.msg import Person


if __name__ == "__main__":
#1.初始化 ROS 节点
rospy.init_node("talker_person_p")
#2.创建发布者对象
pub = rospy.Publisher("chatter_person",Person,queue_size=10)
#3.组织消息
p = Person()
p.name = "葫芦瓦"
p.age = 18
p.height = 0.75

#4.编写消息发布逻辑
rate = rospy.Rate(1)
while not rospy.is_shutdown():
pub.publish(p) #发布消息
rate.sleep() #休眠
rospy.loginfo("姓名:%s, 年龄:%d, 身高:%.2f",p.name, p.age, p.height)

订阅方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 #! /usr/bin/env python
"""
订阅方:
订阅消息

"""
import rospy
from demo02_talker_listener.msg import Person

def doPerson(p):
rospy.loginfo("接收到的人的信息:%s, %d, %.2f",p.name, p.age, p.height)


if __name__ == "__main__":
#1.初始化节点
rospy.init_node("listener_person_p")
#2.创建订阅者对象
sub = rospy.Subscriber("chatter_person",Person,doPerson,queue_size=10)
rospy.spin() #4.循环

终端下进入 scripts 执行:chmod +x *.py

配置 CMakeLists.txt

1
2
3
4
5
6
7
8
catkin_install_python(PROGRAMS
scripts/talker_p.py
scripts/listener_p.py
scripts/person_talker.py
scripts/person_listener.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

话题通信

发布方cpp实现

1
2
3
4
5
6
1、包含头文件
ROS中文本类型 ---》 std_msgs/String.h
2、初始化ROS节点
3、创建节点句柄
4、创建发布者对象
5、编写发布逻辑并发布数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "ros/ros.h"
#include "std_msgs/String.h"

int main(int argc , char *argv[])
{
//初试化ros节点
ros::init(argc,argv,"nodeName"); //节点名称
//创建节点句柄
ros::NodeHandle nh;
//创建发布者对象
ros::Publisher pub=nh.advertise<std_msgs::String>("topicName",10);
//范型:话题类型,话题名称,话题数据队列长度
//编写发布逻辑并发布数据
//先创建被发布的数据
std_msgs::String msg;
//循环发布数据
while(ros::ok()) //ros::ok() 节点不死
{
msg.data="hello";
pub.publish(msg);
}
return 0;
}

CMakeList

1
2
add_executable()
target_link_libraries()
1
rostopic echo topicName

以10HZ发布数据,数据后面有编号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc , char *argv[])
{
setlocale(LC_ALL,""); //解决中文乱码
//2、初试化ros节点
ros::init(argc,argv,"nodeName"); //节点名称
//3、创建节点句柄
ros::NodeHandle nh;
//4、创建发布者对象
ros::Publisher pub=nh.advertise<std_msgs::String>("topicName",10);
//范型:话题类型,话题名称,话题数据队列长度
//5、编写发布逻辑并发布数据
//要求以10HZ的频率发布数据,并且文本后添加编号
//先创建被发布的数据
std_msgs::String msg;
//发布频率
ros::Rate rate(10); //10HZ
//计数器
int count=0;
//循环发布数据
while(ros::ok()) //ros::ok() ros进程没死
{
count ++;
// 字符串拼接 sstream
std::stringstream ss;
ss << "hello --->" << count;
msg.data=ss.str();
//msg.data="hello";
pub.publish(msg);
//日志输出
ROS_INFO("发布的数据是%s",ss.str().c_str());
rate.sleep();
ros::spinOnce();//官方建议添加,处理回调函数
}
return 0;
}

订阅方cpp实现

1
2
3
4
5
6
1、包含头文件
ROS中文本类型 ---》 std_msgs/String.h
2、初始化ROS节点
3、创建节点句柄
4、创建订阅者对象
5、处理订阅到的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "ros/ros.h"
#include "std_msgs/String.h"
void doMsg(const std_msgs::String::ConstPtr &msg) //常指针类型
{
//通过msg获取并操作订阅到的数据
ROS_INFO("订阅方订阅到的数据是:%s",msg->data.c_str());
}
int main(int argc , char *argv[])
{
setlocale(LC_ALL,""); //解决中文乱码
//初试化ros节点
ros::init(argc,argv,"nodeName"); //节点名称
//创建节点句柄
ros::NodeHandle nh;
//创建订阅者对象
ros::Subscriber pub=nh.subscribe("topicName",10,doMsg); //doMsg是回调函数用于处理收到的数据
ros::spin(); //回头,处理回调函数
return 0;
}

发布方python实现

1
2
3
4
1、导包
2、初始化ros节点
3、创建发布者对象
4、编写发布逻辑并发布数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#! /usr/bin/env python
import rospy
from std_msgs.msg import String

if __name__ == "__main__":
#2、初始化ros节点
rospy.init("nodeName")
#3、创建发布者对象
pub = rospy.Publisher("topicName",String,queue_size=10)
#4、编写发布逻辑并发布数据
#创建数据
msg=String()
#使用循环发布数据
while not rospy.is_shutdown():
msg.data ="hello"
pub.publish(msg)
pass

CMakeList

1
catkin_install_python()

以10HZ发布数据,数据后面有编号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#! /usr/bin/env python
import rospy
from std_msgs.msg import String

if __name__ == "__main__":
#2、初始化ros节点
rospy.init("nodeName")
#3、创建发布者对象
pub = rospy.Publisher("topicName",String,queue_size=10)
#4、编写发布逻辑并发布数据
#创建数据
msg=String()
#指定发布频率
rate=rospy.Rate(1)
#设置计数器
count=0
#使用循环发布数据
while not rospy.is_shutdown():
count +=1
msg.data ="hello" +str(count)
pub.publish(msg)
rospy.loginfo("发布的数据是%s",msg.data)
rate.sleep()
pass

发布方python实现

1
2
3
4
5
1、导包
2、初始化ros节点
3、创建订阅者对象
4、回调函数处理数据
5、spin()
1
2
3
4
5
6
7
8
9
10
11
12
13
# usr/bin/env python
#coding=utf-8
import rospy
from std_msgs.msg import String

def doMsg(msg):
rospy.loginfo("data is %s",msg.data)

if __name__ == "__main__":
rospy.init_node("nodeName")
sub=rospy.Subcriber("topicName",String,doMsg,queue_size=10)
rospy.spin()
pass

linux文件系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/ 根目录。一般根目录下只存放目录,在linux下有且只有一个根目录,所有的东西都是从这里开始。当在终端输入/home,其实是先从
/(根目录)开始,再进入到home目录。

/bin,/usr/bin 可执行二进制文件的目录,如常用的命令ls、tar、mv、cat等。

/boot 存放linux系统启动时用到的一些文件,如linux的内核文件:/boot/vmliunz,系统引导管理器:/boot/grub

/dev 存放linux系统下的设备文件,访问该目录下的某个文件,相当于访问某个设备,常用的是挂载光驱mount /dev/cdrom/mnt

/etc 系统配置文件存放的目录,不建议在此目录下存放可执行文件,重要的配置文件有,/etc/inittab,/etc/fstab,/etc/init.d,/etc/X11,
/etc/sysconfig,/etc/xinetd.d

/home 系统默认的用户家目录,新增用户账号时,用户的家目录都存放在此目录下。

~ 表示当前用户的家目录,~edu 表示用户edu的家目录。

/lib,/usr/lib,/usr/local/lib 系统使用的库函数的目录,程序在执行过程中,需要调用一些额外的参数时需要函数库的协助。

/lost+found 系统异常产生错误时,会将一些遗失的片段放置于此目录下

/mnt,/media 光盘默认挂载点,通常光盘挂载于/mnt/cdrom 下,也不一定,可以选择任意位置进行挂载。

/opt 给主机额外安装软件所摆放的目录

/proc 此目录的数据都在内存中,如系统核心,外部设备,网络状态,由于数据都存放于内存中,所以不占用磁盘空间,
比较重要的文件有:/proc/cpuinfo,/porc/interrupts,/proc/dma,/proc/ioports,/proc/net/*等

/root 系统管理员root的家目录

/sbin,/usr/sbin,/usr/local/sbin 防止管理员使用的可执行命令,如fdisk,shutdown,mount等。
于/bin不同的是,这几个目录是给系统管理员root使用的命令,一般用户只能查看而不能设置和使用

/tmp 一般用户或正在执行的程序临时存放文件的目录,任何人都可以访问,重要数据不可放置在此目录下

/srv 服务启动之后需要访问的数据目录,如www服务器需要访问的网页数据存放在/srv/www 内

/usr 应用程序存放目录

/usr/bin 存放应用程序

/usr/share 存放共享数据

/usr/lib 存放不能直接运行,却是许多程序运行所必需的一些库函数文件

/usr/local 存放软件升级包

/usr/share/doc 系统说明文件存放目录

/usr/sharc/man 程序说明文件存放目录

/var 放置系统执行过程中经常变化的文件

/var/log 随时更改的日志文件

/var/spool/mail 邮件存放的目录

/var/run 程序或服务启动后,其pid存放在该目录下。

文件及文件夹查看

ls -a 查看所有文件及文件夹,包括隐藏文件和目录

ls -l 以列表形式查看所有文件和目录

ll 等同于 ls -al 等同于以上两个命令的结合

切换目录

cd 切换到当前用户的主目录(home/用户目录)

cd ~ 切换到当前用户的主目录(home/用户目录)

cd . 切换到当前目录

cd .. 切换到上级目录

cd - 可进入上次所在的目录

cd / 切换到系统根目录/

如果路径是从根路径开始的,则路径的前面需要加上 “ / ”,如 “ /mnt ”,通常进入某个目录里的文件夹,前面不用加 “ / ”。

文件夹操作

rm -f 才能删除文件夹,而且使用命令行是永久性删除,而使用GUI是移到回收站可恢复的。

文件复制

cp test.txt . ‘.’ 表示当前路径

cp test.txt hello.txt 将test复制并命名为hello

cp -r 复制文件夹 -r表示文件夹

cp test/.md Downloads/ ‘‘表示模糊匹配

文件剪切

mv test.txt Downloads/

mv test.txt a.txt 重命名

mv test/* Downloads

输出、重定向

‘echo’ 控制台输出

echo “hello world”

‘>’重定向符号

Linux允许将命令执行结果重定向到一个文件,本应显示在终端上的内容保存到指定文件中。

echo “hello world” > test.txt

ls > test.txt

test.txt 如果不存在,则创建,存在则覆盖其内容

注意:>输出重定向会覆盖原来的内容,>>输出重定向则会追加到文件的尾部

echo “hello” >> test.txt

cat 查看&合并文件内容

cat xxx.py 可以用来快速查看某个文件内容,输出到控制台

cat test.txt >> haha.txt 将test.txt的内容追加到haha.txt中

cat 1.txt 2.txt > 1_2.txt将1.txt 2.txt内容合并到1_2.txt中

tar 归档管理

tar [参数] 打包文件名 文件

打包并压缩

打包指定目录或文件tar -czvf xxx.tar.gz my-file my-dir

解压缩包

解包到指定目录:tar -xzvf xxx.tar.gz -C my-dir (需要先创建my-dir目录)

zip 文件压缩

压缩文件:zip [-r] 目标文件(没有扩展名) 源文件

文件:zip bak * 当前目录所有文件,也可以指定文件

文件夹:zip -r bak * 当前目录所有文件&目录递归 -r表示递归 不然仅仅压缩了一个空的文件夹

解压文件:unzip -d 解压后目录文件 压缩文件

解压到指定目录:unzip -d ./target_dir bak.zip

解压到当前目录:unzip bak.zip

wget 文件下载

下载普通文件

wget http://p1.qhimgs4.com/t01ce0387e64e3428ca.jpg

以指定文件名保存文件

wget -O girl.jpg http://p1.qhimgs4.com/t01ce0387e64e3428ca.jpg

断点续传

wget -c http://p1.qhimgs4.com/t01ce0387e64e3428ca.jpg

tree 目录树状结构

使用tree命令可以查看指定目录的树状结构

which 查看命令位置

1
2
3
4
poplar@PoplarTang:~/Lesson$ which python
/usr/bin/python
poplar@PoplarTang:~/Lesson$ which ls
/bin/ls

ifconfig 查看ip地址

ping 测试网络是否联通

ssh 连接远程电脑

如果远程电脑是新装电脑,有可能会因为ssh服务证书问题而无法连接,可以通过在远程电脑上重装ssh服务解决。

  1. 重装ssh服务,生成证书

    1
    2
    sudo apt-get remove openssh-server
    sudo apt-get install openssh-server
  2. 重启ssh服务
    sudo service ssh restart

  3. 检查sshd服务是否存活
    sudo service ssh status

  4. 推出ssh
    exit

chmod 修改文件权限

使用ls -l 可以查看文件和目录的权限

第一个 ‘-‘表示文件,’d’表示文件夹

字母法权限修改:rwx

chmod u/g/o/a +/-/= rwx 文件

1
2
3
4
u	user 表示该文件的所有者
g group 表示与该文件的所有者属于同一组( group )者,即用户组
o other 表示其他以外的人
a all 表示这三者皆是
1
2
3
+	增加权限
- 撤销权限
= 设定权限
1
2
3
r	read 表示可读取,对于一个目录,如果没有r权限,那么就意味着不能通过ls查看这个目录的内容。
w write 表示可写入,对于一个目录,如果没有w权限,那么就意味着不能在目录下创建新的文件。
x excute 表示可执行,对于一个目录,如果没有x权限,那么就意味着不能通过cd进入这个目录。

数字法权限修改:421

1
2
3
4
r	读取权限,数字代号为 "4"
w 写入权限,数字代号为 "2"
x 执行权限,数字代号为 "1"
- 不具任何权限,数字代号为 "0"

如执行:chmod u=rwx,g=rx,o=r filename 就等同于:chmod u=7,g=5,o=4 filename

系统信息命令

查看系统版本

发行版本号

lsb_release -a

内核版本及系统位数

uname -a

内核版本及gcc版本

cat /proc/version

查看硬件信息

cpu信息

cat /proc/cpuinfo or lscpu

内存信息

sudo dmidecode -t memory

运行时信息

top实时CPU&内存使用情况(可以查看pid号,user,和哪个命令占用)

free当前内存占用情况

ps -aux查看当前进程状态(CPU、内存占用、开启时间)

kill根据进程pid杀死指定进程,可以配合参数-9强制杀死

1、声明

首先已经有了clash for windows,而且能够正常使用。

2、下载clash for linux

可以从https://github.com/Dreamacro/clash/releases/tag/v1.3.0 ,下载。

在.config下建clash文件夹,(查看隐藏文件ctrl+h)。

将下载的clash解压到clash文件夹下,右键属性可读写可执行。

将windows下的配置文件,复制到clash文件夹下。一般文件是在c盘/user/user’name/.config/clash下,有个config.yaml和Country.mmdb

不过我这边用的不是config.yaml,所以找到的是profiles下的xxxxx.yml。将该文件复制到ubuntu的clash文件夹下,并重命名为config.yaml。

3、启动clash

在clash文件夹下,开启终端 ./clash (以文件名而定)

没报错就算是启动好了。

4、设置代理

启动完clash后,还不能正常上网,需要设置代理。

在ubuntu网路设置中,选择手动设置网路代理。

设置http的代理为127.0.0.1:7890,设置socks主机127.0.0.1:7891。(根据config.yaml里面的内容来设置)

5、测试和关闭

完成以上布置可以试试google和youtube能不能使用。

关闭的话,需要在运行clash的终端ctrl+c关闭clash,同时网络代理要禁用,不然上不了任何网站。

6、小bug

发现以上操作后好像windows和ubuntu上如果同时用clash,就会有一个变慢,甚至有时候打不开。