chono challenge


  • Home

  • Archives

ros在同一节点同时订阅和发布消息

Posted on 2019-12-10

ROS版本: ROS Kinetic

操作系统:Ubuntu16.04 LTS

方法一,采用类的方法

参考网站
https://blog.csdn.net/ethan_guo/article/details/80226121
当然也可以用python 实现,我们与例程中的方法为例,这里只谈如何实现在类的订阅并讨论其机制。telker代码不变:

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

def talker():
pub = rospy.Publisher('hello', String, queue_size=1)
rospy.init_node('talker', anonymous=True)
rate = rospy.Rate(10) # 10hz
while not rospy.is_shutdown():
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()

if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass

以下是listener 代码

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
# -*- coding: utf-8 -*-
import rospy
from std_msgs.msg import String
import time

pub = rospy.Publisher('pub_with_sub', String, queue_size=10) #发布话题设为全局变量

class listener():
def __init__(self):
print("class comeing!")
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("hello", String, self.callback,queue_size = 1)
# spin() simply keeps python from exiting until this node is stopped

def callback(self,data):
rospy.loginfo( "I heard %s", data.data)
print("call back comeing!")
pub.publish(data.data)

if __name__ == '__main__':
listener()
print("class circulation!!")
rospy.spin()

执行这两端代码,观察输出,可以发现只有在启动时,会执行

1
2
print("call back comeing!")
print("class comeing!")

这两段代码,而回调函数中的

1
print("call back comeing!")

会在每次订阅到发布的消息后执行,这里就涉及到rospy.spin()的工作机制,它并不是一直循环这个listener()类。而是循环进入类后的订阅函数,这个函数叫做ROS消息回调处理函数。可以参考官方网站查看其具体原理。

到这里其实还有一个小问题,那就是关于画图,如果我们想在回调函数中实现画图,或者在回调函数中修改变量的值,而在类的构造函数中执行与此变量有关的操作,那么我们只需要在类中加一个循环即可:

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from std_msgs.msg import String
import time

pub = rospy.Publisher('pub_with_sub', String, queue_size=10) #发布话题设为全局变量

class listener():
def __init__(self):
print("class comeing!")
self.da = []
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("hello", String, self.callback,queue_size = 1)
# spin() simply keeps python from exiting until this node is stopped
#############加入的循环####################
while not rospy.is_shutdown():
print(self.da)#此处可以是画图的语句
##########################################
def callback(self,data):
rospy.loginfo( "I heard %s", data.data)
self.da = data.data
print("call back comeing!")
pub.publish(data.data)

if __name__ == '__main__':
listener()
print("class circulation!!")
rospy.spin()

这时候可以发现,回调函数中得到的变量在构造函数的循环中执行了。实时画图在后面的文章中讨论。

方法二,全局变量

下面介绍一下Python中用全局变量的方法实现.
以ros wiki上面的话题通信教程为例。
http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28python%29
这里定义了talker 和 listener :
talker:

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

def talker():
pub = rospy.Publisher('pub1', String, queue_size=1)
rospy.init_node('talker', anonymous=True)
rate = rospy.Rate(10) # 10hz
while not rospy.is_shutdown():
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()

if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass

这里我么修改listener,在文件中加入了一个全局变量pub,然后直接将订阅的话题通过
pub再次发布出去,当然,这里只是个测试,实际中肯定是对该消息进行处理后再发布的,写改后的listener如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from std_msgs.msg import String
import time

pub = rospy.Publisher('pub_with_sub', String, queue_size=10) #发布话题设为全局变量
def callback(data):
rospy.loginfo( "I heard %s", data.data)
pub.publish(data.data)
def listener():
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("pub1", String, callback,queue_size = 1)
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()

if __name__ == '__main__':
listener()

这时,我们像教程中一样运行这两个程序结果并没有什么区别,但如果我们用rostopic list 查看,就会发现比原教程中多了一个话题,就是问在listener中发布的,接下来,我们创建一个listen_listener.py的文件来订阅这个话题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from std_msgs.msg import String
import time

def callback(data):
rospy.loginfo( "I heard %s", data.data)
def listener():
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("pub_with_sub", String, callback,queue_size = 1)
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()

if __name__ == '__main__':
listener()

ok,别忘了将文件设置为可执行文件,这是后,我们同时打开这三个文件。会发现显示同样的内容。实际上是这样一个结构:
talker发布->listener订阅 再发布 -> listen_listener再订阅!

gazebo和ros通信实现发球

Posted on 2019-12-07

YouTube上有一个视频,是一个乒乓球机器人在gazebo里面的方针
https://www.youtube.com/watch?v=HBNGeYZKJM4
因为项目需要,需要实现这个发球的装置。因为第一次接触gazebo和ros所以这里把自己的研究过程记录下来。

预备知识

1.ros的安装和通信机制,主要是话题和服务通信。
这里只需要根据根据ros wiki上的教程实现前20讲,就可以实现安装(包括gazebo_ros包)和简单入门。
http://wiki.ros.org/ROS/Tutorials
2.gazebo的一些基础知识(非必须),这里可以看一下gazebo的入门教程
http://gazebosim.org/tutorials

总体实现思路

整个方针的实现可以分为以下几步:

###环境的搭建
这里我们并不采用gazebo教程里面直接gui插入模型的方法,而是采用ros和gazebo的通信机制实现。如果我们按前面的方法正确安装了ros。接下来,打开终端,依次执行下列命令,每个命令可以打开一个终端
$roscore
$rosrun gazebo_ros gazebo
这事我们就打开了gazebo界面。接下来,我们需要一个小球.
$rosrun gazebo_ros spawn_model -database robocup_spl_ball -sdf -model my_ball1
ok,那么现在我们已经把所有需要的模型加载进来了(虽然就1个球)
参考网站:http://gazebosim.org/tutorials/?tut=ros_comm

###动起来
如果仔细看了上面的教程和参考网站,那我们就会有一个整体的思路:利用gazebo提供的话题和服务就可以实现,在环境的搭建中,我们是直接采用spawn_sdf_model服务实现的模型的加载。接下来我们需要把加载的网球删除。接着实现流程如下:
1.使用spawn_sdf_model服务加载一个网球,并指定小球的位置
2.使用apply_body_wrench服务,给网球施加一个斜向上的力,使其做斜抛运动
3.当球弹出后,进入while循环,使用get_model_state服务得到小球的位置,当小球位置飞出预定轨迹后,跳出循环。
4.使用delete_model服务将这个小球删除,回到1.
程序如下:

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
#!/usr/bin/env python


import time
import rospy
from gazebo_msgs.srv import SpawnModel
from gazebo_msgs.srv import DeleteModel
from gazebo_msgs.srv import ApplyBodyWrench
from gazebo_msgs.srv import GetModelState
from geometry_msgs.msg import Pose
from geometry_msgs.msg import Wrench
#初始位置
initial_pose = Pose()
initial_pose.position.x = -4
initial_pose.position.y = -1
initial_pose.position.z = 1
#所用力的大小
initial_wrench = Wrench()
initial_wrench.force.x = 0.16
initial_wrench.force.y = 0.0
initial_wrench.force.z = 0.25
#ctrl+h显示隐藏文档,将XXX替换为自己的目录,从自己的目录中找的这个文件
f = open('/home/XXXXX/.gazebo/models/robocup_spl_ball/model.sdf','r')
sdff = f.read()
#产生小球的服务
rospy.wait_for_service('gazebo/spawn_sdf_model')
spawn_model_prox = rospy.ServiceProxy('gazebo/spawn_sdf_model', SpawnModel)
#施加一个作用力
rospy.wait_for_service('gazebo/apply_body_wrench')
apply_wrench = rospy.ServiceProxy('gazebo/apply_body_wrench', ApplyBodyWrench)
#删除小球
rospy.wait_for_service('gazebo/delete_model')
deletesrv = rospy.ServiceProxy('gazebo/delete_model', DeleteModel)
#得到小球位置
rospy.wait_for_service('gazebo/get_model_state')
get_m_state = rospy.ServiceProxy('gazebo/get_model_state', GetModelState)
while(1):
spawn_model_prox("my_ball", sdff, "robotos_name_space", initial_pose, "world")
time.sleep(1)

apply_wrench("my_ball::ball", "world", None, initial_wrench, rospy.Time.from_sec(0), rospy.Duration.from_sec(0.2))
s = get_m_state("my_ball","world")
while(1):
if(s.pose.position.x < 6):
s = get_m_state("my_ball","world")
print(s.pose.position.x)
else:
rospy.wait_for_service('gazebo/delete_model')
deletesrv = rospy.ServiceProxy('gazebo/delete_model', DeleteModel)
ass = deletesrv("my_ball")
print(ass)
break

关于程序中各个服务的的调用方法,可以直接参考相关的消息和服务文档。

最后,可以加上一个球场,改变网球的形状,使仿真环境更加逼真。这需要我们自己去创建自己的模型。
突然发现经常出现小球删除不掉的情况,会出现
DeleteModel: Model pushed to delete queue, but delete service timed out waiting for
\ model to disappear from simulation”
调试了好久也没找出问题。有人说是gazebo的bug,真是迷了。。。

Untitled

Posted on 2019-12-01

ros笔记

Posted on 2019-11-19

小问题

1.在launch文件中,node标签内,type = 可执行文件(对于c++,直接talker,因为编译完成后talker就是可执行文件,而对于Python文件,应该是python.py)
2.python 文件添加可执行权限可以直接右键->权限去选择,也可以使用命令行 chmod +x client.py
3.ros中消息的使用
pointstamped ps
ps.point.x
ps.header.stamp(这是时间戳格式)而时间戳格式又包括两个属性,分别是
ps.header.stamp.secs和ps,header.stamp.nsecs

其余的消息都可以查找其文档说明。

c++常用代码段

Posted on 2019-09-20

c/c++计时函数 clock()

在 #include<time.h>中,有个计时函数clock(),其返回的输出类型为clock_t类型。返回从“开启这个程序进程”到“程序中调用clock()函数”时 之间的CPU时钟计时单元(clock tick)数。

1
2
clock_t currentime;//整数
currentime = clock();//返回当前程序运行计时单元数。

在time.h文件中,还定义了一个常量CLOCKS_PER_SEC,它用来表示一秒钟会有多少个时钟计时单元,其定义如下:

#define CLOCKS_PER_SEC ((clock_t)1000)

可以看到可以看到每过千分之一秒(1毫秒), 调用clock()函数返回的值就加1。即可以认为该clock()函数返回的时间单位是毫秒。

visual studio 2017

Posted on 2019-08-23

visual studio 安装可直接安装社区免费版,不过一个月后需要免费申请账号使用

与其他库的配合使用(win10)

opencv

1.下载opencv,添加bin文件的环境变量
2.新建项目文件,在项目属性vc++中添加包含文件(include)和库文件(lib)
3.添加链接文件,在链接器,输入中,添加opencv_world34x.lib,和opencv_world34xd.lib(x代表opencv版本,例如3.4.7就是347)
4.运行时出现dll找不到,需要将两个dll文件添加到c:\windows\system32中。

代码运行时/#include “pch.h”应该放在第一行,不然会出先cv不是命名空间类似的错误

冒泡实现

Posted on 2019-08-03

#c++实现

#verilog实现

cs50笔记

Posted on 2019-07-29

cs50

make 命令编译时不用后缀,会自动编译
(第四集 47:34)在terminal运行程序时,当程序陷入错误,推出只需,ctrl+c即可.

在第四集54分钟左右,一位同学提出了一个问题,可以让百分比一直停在那个位置么?我觉得应该时大卫误解了这个问题,他回答的是对齐的问题。这里思考一下原地增加的方法?
发现原来大卫也考虑到这个问题,在后来的几分钟,用/r解决了这个问题。

第五集:

由于数据转换错误导致的溢出引起爆炸。flight501事件

数据的非精确计算导致0.88+0.01<0.89

第六集

局部变量和全局变量用同一个x表示,那么在含有函数的局部变量操作时,操作的是局部变量

第七集

信息加密的安全性

第八集

冒泡排序 最坏n^2步; 选择排序 (n+1)n/2步;

第九集

归并排序,时间复杂度为(n*log(n))!

第十集

大卫从给老奶奶买票的经历说起,讲了设计不仅是要作对,还要从用户的的角度去考虑做好。这是设计者需要考虑的问题。所以设计的第一版要关注反馈。

内存中的地址地址0即 0x00000000是专用的,只有操作系统 才能控制即,可表示为NULL

两个分配内存的方法 new 和 malloc 其区别在这儿https://www.cnblogs.com/QG-whz/p/5140930.html

内存泄漏的一个情况, int *a; a = malloc(sizeof(int)); a=5;这样的话刚才给a分配的内存就再也找不到了,这就是内存泄漏。
段错误出现的一种情况,如果我int *b; *b=12; 有可能会出现段错误,因为如果不主动给b分配内存,那么里面可能是个任意值(任意地址),如果在这个任意地址上面写个数,如果这个地址不是系统分配给我的,那么就出现段错误。

第十一集

缓冲区溢出和缓冲区漏洞攻击。增加一些if判断条件以免使程序崩溃或者受到攻击。

《c++ Prime Plus》(中文第六版)

1.endl确保程序继续运行前刷新输出(将其立即显示在屏幕上);而”/n”不能提供这样的保证
2.区分函数原型和函数定义
3.const声明常量比#define 更好,因为其可以指定类型。
4.数组越界访问。 编译器不会检查数组下标是否有效,比如 int month[12]; month[13]=2; cout<< month[13]; 编译时不会出错,但运行时会提示 “stack smashing detected”。即数组越界。
5.采用char name[20]; cin>>name;接收字符串,只能接收到空格前的第一个单词。如果程序中连续接收两次输入:
“char name1[30];
char name2[30]
cin >> name1;
cout << name1;
cin >> name2;
cout << name2;”如果输入那name1 为li ming那么程序不会等name2输入,而是直接把ming 给name2, –参见《c++ Prime Plus》(中文第六版)p77.
6.访问类成员(如cin.getline())的方式是从访问结构成员变量的方式衍生出来的
7.结构中的位字段,c++允许指定占用特定位数的结构成员,这使得创建与某个硬件设备上的寄存器对应的数据结构非常方便。 –p94
8.int ptr; 和 int ptr;没有区别;但是int* p1,p2;声明的是一个指针p1和一个int 型变量p2。 声明指针时,每一个指针前面必须有一个。 –p100
9.一定要在对指针应用
运算符前,将指针初始化为一个确定的,适当的地址。 例如 int fellow; *fellow =3; 这里系统会给指针分配一个内存,但时并没有给3的地址初始化,即没有初始化fellow,这就有可能发生危险。fellow可能为任意值。
10.一定要配对地使用new和delete;否则将发生内存泄漏(memory leak),即被分配的内存再也不能用了。如果发生内存泄漏,则程序将有序不断寻找更多内存而终止。另外,不能用delete释放声明变量所获得的内存,只能释放new分配的内存。–p104
11.将整数+1,其值增加1.但将指针变量+1后,增加的量等于它指向类型的字节数。
12.对数组啊int a[20];数组名被解释为其第一个元素的地址,而对数组名应用地址运算符时,得到的是整个数组的地址。
13.在编译时给数组分配内存称为静态联编,在程序运行时选择数组的长度,称为动态联编。
14.自动存储、静态存储和动态存储。 堆栈和内存泄漏。 –P117
15.逗号运算符 –P138
16.读取文件和键盘 –P155
17.ctype库函数,使用isalpha()来检查字符是否为字母字符,使用isdigitals()来测试字符是否为数字字符。。。。 P177
18.cin方法输入错误时返回false, 例如 用int n; while(cin >> n){}时输入为非int型数据时将跳出循环。
19.arr[i] == *(arr+i); &aarr[i] == arr + 1; 数组名和指针的关系。
20.函数的地址是存储其机器语言代码的内存的开始地址。
21.在链接编译模块时,请确保所有对象文件或库都是由同一个编译器生成的。如果有源代码,通常可以用自己的编译器重新编译源代码来消除链接错误。
22.作用域解析运算符::, using 声明使一个名称可用,而using编译指令将使所有的名称都可用。
23.无法使用对象来调用构造函数,因为构造函数在构造出对象之前,对象是不存在的。因此构造函数都用来构造对象,而不能被对象调用。 –P354
24.内联函数,其定义位于类声明中的函数都将自动成为内联函数,inline限定符可以在类声明定义之外定义成员函数–P347
25.函数重载和多态指的是同一回事,都是指可以同时有多个同一名称的函数。 –P276
26.程序清单10.6讨论了用两种方式初始化类的方法的不同,一种直接利用构造函数创建,而采用赋值的方式是先创建一个临时对象,再进行赋值 , –P361 P404创建shove对象时又强调了这一特性。
27.通过函数重载,可以创建多个同名的构造函数,条件是每个函数的特征标不同。 – P362
28.引用,C++中int & rodents = rats ,&是类型标识符,就像生命中char
指的是指向char的指针一样,int&指的是指向int的引用。
29.删除对象可以释放对象本身占用的内存,但并不能自动释放属于对象成员的指针指向的内存。因此,必须使用析构函数。在析构函数中使用delete语句可确保对象过期时,由构造函数使用new分配的内存释放。 –P429
30.警告:如果类中包含了使用new初始化的指针成员,应定义一个复制构造函数,以复制指向的数据,而不是指针,这被称为深度复制。–P436
31.C++包含让程序员能够限制程序结构的特性-使用explicit防止单参数构造函数的隐式转换,使用const限制方法修改数据,等等。这样做的根本原因是:在编译阶段出现错误优于在运行阶段出现错误。 –P538

一些好的博客

Posted on 2019-07-27

闲来无事,经常在网上随便逛逛,偶尔遇到一些好的博客,在这里记录下来。已备参考,持续更新。。。。。。

技术博客:

http://cxd2014.github.io/archive/
这个博客是在实习的时候偶然翻到的,关于找工作和技术博客积累的几篇有很大感悟。

https://36kr.com/p/5175121
这篇文章讲的计算机架构的,知道了这两个大神,另外就是,对于技术要养成比较敏感的习惯。

https://liam.page/2014/09/08/latex-introduction/
https://www.jianshu.com/p/3e842d67ada2
这两篇文章主要介绍了latex的安装和主要使用

http://blog.miskcoo.com/
一个让我感到惭愧的博客,作为集成电路专业学生,写个MIPS参考别人代码还憋了好久,这个本科贵系学生。。。不说了,磕吧!

小觅双目摄像头使用

Posted on 2019-07-14

安装

小觅深度版相较于zed相机,内部集成计算芯片,不再需要显卡支持。
但sdk使用起来资料并不多,而且c++用的又比较少,因此,用起来看来要费不少力气

首先第一关下载sdk,根据说明利用get_image.exe显示图像比较简单

下一步就是涉及到使用cmake和visual studio.visual studio之前接触过,可cmake是干啥的都不知道,因此
刚开始根据read me操作第二步生成样例工程就遇到了问题,如下图所示:

显示could not find any instance of Visual Studio.
经过一番折腾,发现之前用的是2019版的visual studio社区版,用visual studio installer卸载后,安装17版即可,如下图所示:

在可用一栏可以选择不同版本。
在已安装一栏,选择“使用c++的桌面开发”.即可安装所需要的组件。

配置使用

https://slightech.github.io/MYNT-EYE-D-SDK/vs2017.html
按照这个工程样例,一步一步进行操作即可

该方法运行时采用的是release模式,若改为debug模式,可能会出现链接错误

LNK2019 无法解析的外部符号 “void __cdecl cv::imshow。。。。。。。。

这种情况是因为debug库的问题
https://blog.csdn.net/pengyouyou/article/details/83958181
按照该方法在链接 -> 输入 -> 中除了opencv_world341.lib,再加入opencv_world341d.lib即可解决

123

John Doe

29 posts
© 2020 John Doe
Powered by Hexo
|
Theme — NexT.Muse v5.1.4