HANDS-FREE学习
HANDS-FREE学习
ROS学习 ROS消息
ROS学习 ROS程序的GDB调试和调试信息
ROS学习 外设的加入
[ INFO] [1478056976.955143122]: Opened joystick: /dev/input/js0. deadzone_: 0.050000.
察看node:
$rosnode list
/joy_node
/rosout
看到对应Node是/joy_node
察看此node详细信息:
$rosnode info /joy_node
--------------------------------------------------------------------------------
Node [/joy_node]
Publications:
* /diagnostics [diagnostic_msgs/DiagnosticArray]
* /joy [sensor_msgs/Joy]
* /rosout [rosgraph_msgs/Log]
Subscriptions: None
Services:
* /joy_node/get_loggers
* /joy_node/set_logger_level
contacting node http://ubuntu:43877/ ...
Pid: 10153
Connections:
* topic: /rosout
* to: /rosout
* direction: outbound
* transport: TCPROS
可以看到,这个Node发布着/joy Topic
$rostopic echo /joy
header:
seq: 388
stamp:
secs: 1478057805
nsecs: 210471365
frame_id: ''
axes: [-0.0, -0.0, -0.0, -0.0, -0.0, -1.0]
buttons: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
---
header:
seq: 389
stamp:
secs: 1478057805
nsecs: 274450075
frame_id: ''
axes: [-0.0, -0.0, -0.0, -0.0, -0.0, -0.0]
buttons: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
看此Topic类型:
rostopic type /joy
sensor_msgs/Joy
看消息具体数据:
rosmsg show sensor_msgs/Joy
std_msgs/Header header
uint32 seq
time stamp
string frame_id
float32[] axes
int32[] buttons
$rosrun turtlesim turtlesim_node
1.4.2: 察看Node,小乌龟Node是/turtlesim
$rosnode list
/rosout
/turtlesim
1.4.3:
$rosnode info /turtlesim
--------------------------------------------------------------------------------
Node [/turtlesim]
Publications:
* /turtle1/color_sensor [turtlesim/Color]
* /rosout [rosgraph_msgs/Log]
* /turtle1/pose [turtlesim/Pose]
Subscriptions:
* /turtle1/cmd_vel [unknown type]
Services:
* /turtle1/teleport_absolute
* /turtlesim/get_loggers
* /turtlesim/set_logger_level
* /reset
* /spawn
* /clear
* /turtle1/set_pen
* /turtle1/teleport_relative
* /kill
contacting node http://ubuntu:37852/ ...
Pid: 15512
Connections:
* topic: /rosout
* to: /rosout
* direction: outbound
* transport: TCPROS
1.4.4: 察看Topic Type:
rostopic type /turtle1/cmd_vel
geometry_msgs/Twist
1.4.5: 此Message格式:
rosmsg show geometry_msgs/Twist
geometry_msgs/Vector3 linear
float64 x
float64 y
float64 z
geometry_msgs/Vector3 angular
float64 x
float64 y
float64 z
#include "ros/ros.h"
#include "sensor_msgs/Joy.h"
#include "geometry_msgs/Twist.h"
ros::Publisher pub;
geometry_msgs::Twist msg_twist;
void messageCallback(const sensor_msgs::Joy::ConstPtr& msg);
void messageCallback(const sensor_msgs::Joy::ConstPtr& msg)
{
ROS_INFO("Key: %f. %f. %f. %f. %f. %f", msg->axes[0], msg->axes[1], msg->axes[2], msg->axes[3], msg->axes[4],msg->axes[5]);
msg_twist.linear.x = (int) msg->axes[5];
msg_twist.linear.y = 0;
msg_twist.linear.z = 0;
msg_twist.angular.x = 0;
msg_twist.angular.y = 0;
msg_twist.angular.z = (int) msg->axes[4];
pub.publish(msg_twist);
}
int main(int argc, char** argv)
{
ros::init(argc, argv, "x9_turtlesim");
ros::NodeHandle n_sub;
ros::NodeHandle n_advert;
pub = n_advert.advertise("turtle1/cmd_vel", 1000);
ros::Subscriber sub = n_sub.subscribe("joy", 1000, messageCallback);
ros::spin();
return 0;
}
ROS学习 ROS的Launch文件
|
|
rplidar_ros详解
UD Tegra K1 安装ROS-indigo
Bash的运行模式和配置文件加载
在下列情况下,我们可以获得一个login shell:
- 登录系统时获得的顶层shell,无论是通过本地终端登录,还是通过网络ssh登录。这种情况下获得的login shell是一个交互式shell。
- 在终端下使用--login选项调用bash,可以获得一个交互式login shell。
- 在脚本中使用--login选项调用bash(比如在shell脚本第一行做如下指定:#!/bin/bash --login),此时得到一个非交互式的login shell。
- 使用"su -"切换到指定用户时,获得此用户的login shell。如果不使用"-",则获得non-login shell。
配置文件的加载:shell首先加载/etc/profile
,然后再尝试依次去加载下列三个配置文件之一,一旦找到其中一个便不再接着寻找:
- ~/.bash_profile
- ~/.bash_login
- ~/.profile
最后一种模式为非交互非登陆的shell,创建这种shell典型有两种方式:
- bash script.sh
- ssh user@remote command
BASH_ENV
,将变量的值作为文件名进行查找,如果找到便加载它。更为直观的示图
至此,四种模式下配置文件如何加载已经讲完,因为涉及的配置文件有些多,我们再以两个图来更为直观的进行描述:
第一张图来自这篇文章,bash的每种模式会读取其所在列的内容,首先执行A,然后是B,C。而B1,B2和B3表示只会执行第一个存在的文件:
+----------------+--------+-----------+---------------+
| | login |interactive|non-interactive|
| | |non-login |non-login |
+----------------+--------+-----------+---------------+
|/etc/profile | A | | |
+----------------+--------+-----------+---------------+
|/etc/bash.bashrc| | A | |
+----------------+--------+-----------+---------------+
|~/.bashrc | | B | |
+----------------+--------+-----------+---------------+
|~/.bash_profile | B1 | | |
+----------------+--------+-----------+---------------+
|~/.bash_login | B2 | | |
+----------------+--------+-----------+---------------+
|~/.profile | B3 | | |
+----------------+--------+-----------+---------------+
|BASH_ENV | | | A |
+----------------+--------+-----------+---------------+
Python module相关知识
模块让你能够有逻辑地组织你的Python代码段。
把相关的代码分配到一个 模块里能让你的代码更好用,更易懂。
模块也是Python对象,具有随机的名字属性用来绑定或引用。
简单地说,模块就是一个保存了Python代码的文件。模块能定义函数,类和变量。模块里也能包含可执行的代码。
Sam学习Python的过程,主要是跟着《Learn PYTHON the Hard WAY》,其中习题40中,明确指出,
A: 模块是包含函数和编来那个的Python文件。
B: 其它程序可以导入这个文件。
C: 然后可以使用 . 操作符访问模块中的函数和变量。
例1:
supports.py:
def apple():
print "I am an Apple!"
tangerine = "Living reflection of a dream"
接下来就可以import这个模块,并用 .操作符调用函数。
import supports
supports.apple()
print supports.tangerine
1. 模块的导入:
模块的导入方式有以下几种:
A: import
B: from .... import
C: from .... import *
导入模式的异同:
A:import:
import supports
supports.apple()
print supports.tangerine
在调用函数,变量和类时,需要使用模块名+.操作符调用。
B:from ModuleName import name
from语句让你从模块中导入一个指定的部分到当前命名空间中.
from supports import apple
这个声明不会把整个supports模块导入到当前的命名空间中,它只会将supports里的apple单个引入到执行这个声明的模块的全局符号表。
C: from ModuleName import *
把一个模块的所有内容全都导入到当前的命名空间也是可行的
B和C连个方式,在使用函数,变量和类时,不需要使用模块名+.操作符调用。 而是直接调用。
例如:
from supports import *
apple()
print tangerine
2. 模块定位:
当使用import ,from... import...导入模块时, Python解析器对模块定位的搜索顺序为:
1. 当前目录。 (即input script所在目录)
2. shell 变量 PYTHONPATH下的每个目录。
3. 默认目录。Python安装目录。 如: /usr/local/lib/python
截至到现在,Python module还是很清晰的。Python由 modulename.py构成。内容放置在modulename.py中。modulename就是文件名。
文件名就是模块名加上后缀.py
导入方式有三种。看来没啥问题。
3. 模块导入的具体行为:
一个模块被导入,那些内容被执行,哪些不被执行呢?这就是模块导入的具体行为定义的:
每个module都包含对象定义和一些语句(statements),这些语句应该是意图要来初始化这个module的,这些语句会在这个module第一次被import的时候执行(多次import只会执行一次,不管是以上两种import的语句中那一种),当这个module被作为一个script来运行的时候也会被执行。
每个module都有自己的private symbol table,当使用第一种import语句import一个module的时候,引入者的local symbol table就加入了这个module,其名字如果没有使用as的话就是被引入的模块名本身。使用第二种import语句这会在引入者的local symbol table中加入具体引用的item,其名称若没使用as则就为item的名称。
这就是为何单纯import时,需要用modulename.item. 而是用from...import时, 直接调用item本身。
例:
fibo.py如下:
1 print ("__name__ :", __name__) 2 def fib(n): 3 a, b = 0, 1 4 result = [] 5 print ("in fib():", __name__) 6 while (b<<span style="font-family: 'Courier New' !important;">n): 7 result.append(b) 8 a, b = b, a+b 9 print(result)
这个fibo.py就是一个module,它有一个函数定义fib(),和一个语句(statement),第一行的print语句,我们在当前文件目录运行Python Interpreter就可以去引入这个模块,并执行模块中定义的fib()函数。
>>> import fibo ('__name__ :', 'fibo') #print语句执行 >>> fibo.fib(10) ('in fib() :', 'fibo') #fib()函数执行 [1, 1, 2, 3, 5, 8]
可以看到,在import的时候,这个module的语句(statements)执行了,所定义的函数并未执行,在通过module名引用module中的函数定义时,函数才被执行。
同样可以在一个script file中引入module,我们在fibo.py所在的目录创建另一个文件calculat.py
1 from fibo import fib 2 for n in range(10, 50, 5): 3 fib(n)
然后用Python解释器运行calcute.py得到结果。
4. Python标准库:
Python有一个标准库,其中定义了一系列的module,这些module中的一部分是直接集成在Interpreter中的,这些built-in module主要提供了很重要的但是Python语言又没有提供的功能,比如跟system call有关的sys module就集成在所有平台的Python Interpreter中,在Interpreter中集成哪些module是可以配置的,并且随平台不同而有差别。
遇到问题:
Sam在看一些例子代码时,首先遇到了:
import serial
import socket
等语句。
那按照以上认识,就应该有serial.py, socket.py等module存在。但Sam在当前目录,PYTHONPATH,/usr/local/lib/python等目录下均未能发现。这就有了疑问。
在疑问研究中,看到如下用法:
#pry
>>>import serial
>>>print serial.__file__
/usr/lib/python2.7/dist-packages/serial/__init__.pyc
>>>import socket
>>>print socket.__file__
/usr/lib/python2.7/socket.pyc
(__file__指向该模块的导入文件名)
Sam由此想到,是否除了 *.py, 还有类似 *.pyc的模块名呢?但__init__.py又是什么鬼?这就牵涉出Python中另一个概念---Pakcage。
5. python中的Package:
Package是一个分层次的文件目录结构,它定义了一个由模块及子包,和子包下的子包等组成的Python的应用环境。
package是一个directory,它包含sub-package或者是module,而module是.py文件,要让Python Interpreter把一个目录作为package,则该目录下必须有__init__.py文件,__init__.py可以为空,当然也可以有对象定义和语句,用来做初始化工作,__init__.py还有个作用就是设置__all__变量。
package本身就可以来作为一个module使用,只是它所包含的sub-module或module可以通过package name用package.module的名称形式去引用,这更有利于组织一系列相关的module,避免module间定义的名称的混乱。
package在实际工程中非常常用,__init__.py也常常不会为空,而会有对象定义和初始化代码来让这个包,也就是这个module,包含其该有的item定义。以后我们会对package做更多了解。
考虑一个在Phone目录下的pots.py文件。这个文件有如下源代码:
#!/usr/bin/python # -*- coding: UTF-8 -*- def Pots(): print "I'm Pots Phone"
同样地,我们有另外两个保存了不同函数的文件:
- Phone/Isdn.py 含有函数Isdn()
- Phone/G3.py 含有函数G3()
现在,在Phone目录下创建file __init__.py:
- Phone/__init__.py
当你导入Phone时,为了能够使用所有函数,你需要在__init__.py里使用显式的导入语句,如下:
from Pots import Pots from Isdn import Isdn from G3 import G3
当你把这些代码添加到__init__.py之后,导入Phone包的时候这些类就全都是可用的了。
#!/usr/bin/python # -*- coding: UTF-8 -*- # 导入 Phone 包 import Phone Phone.Pots() Phone.Isdn() Phone.G3()
以上实例输出结果:
I'm Pots Phone I'm 3G Phone I'm ISDN Phone
如上,为了举例,我们只在每个文件里放置了一个函数,但其实你可以放置许多函数。你也可以在这些文件里定义Python的类,然后为这些类建一个包。
通过学习Pakcage,就可以完全解释:/usr/lib/python2.7/dist-packages/serial/__init__.pyc
即serial是一个pakcage.
具体举例分析:
port_publisher.py:
import os
import select
import socket
import sys
import time
import traceback
import serial
import serial.rfc2217
import slerialtools.list_ports
import dbus
其中,serial 就是一个Package. 在serial目录内,包含有__init__.py.
/
ROS知识点之 ActionLib
# Define the goal uint32 dishwasher_id # Specify which dishwasher we want to use --- # Define the result uint32 total_dishes_cleaned --- # Define a feedback message float32 percent_complete
#goal definition
int32 order
---
#result definition
int32[] sequence
---
#feedback definition
int32[] sequence
打开package.xml:
actionlib actionlib_msgs
roscpp
rospy
message_generation
CMakefile.txt:
## Add actions
add_action_files(DIRECTORY action FILES Fibonacci.action )
## Generate messages
generate_messages(DEPENDENCIES std_msgs actionlib_msgs)
$catkin_make clean
ROS使用记录
ASUS Xtion在ROS系统下的安装使用
GNU C的零长数组和用法
用途 :长度为0的数组的主要用途是为了满足需要变长度 的结构体。
用法 :在一个结构体的最后 ,申明一个长度为0的数组,就可以使得这个结构体是可变长的。对于 编译器来说,此时长度为0的数组并不占用空间,因为数组名本身不占空间,它只是一个偏移量, 数组名这个符号本身代 表了一个不可修改的地址常量 (注意:数组名永远都不会是指针! ),但对于这个数组的大小,我们可以进行动态分配。例如:
typedef
struct{
int len;
char data[0];
}test_t;
int my_length = 10;
test_t *p_test =
(test_t *)malloc(sizeof(test_t) + my_length);
p_test->len = my_length;
......
free(p_test);
之后对于结构体中的数组可以像一般的数组一样进行访问。
BlueZ 5.43 Cross Compile
之前屡次编译BlueZ(http://blog.sina.com.cn/s/blog_602f87700100zb47.html). 中间有段时间以为不会再编译BlueZ了,其一是Android使用自己的Blue协议栈(BluetDroid)取代了BlueZ。其二是Bluetooth不再是工作重心。没想到搞ROS后,又回到Linux环境,再次需要编译Bluez. 这个令人不快的任务又一次放在面前。
0. Download BlueZ
http://www.bluez.org/
1. X86 Version make
sudo apt-get install systemd
sudo apt-get install libical-dev
sudo apt-get install libudev-dev
$./configure
$make
注意,如果没有 --enable-library,不会编译出动态或静态库的。
$./configure --enable-shared --enable-static --enable-library
$make clean;make
可以看到,库被放在了:
./lib/.libs/libbluetooth.so
./lib/.libs/libbluetooth.a
2. CrossCompile:
编译之前,依例看看README:
Fedora20上编译BlueZ-5.43
pkg-config在交叉编译过程中的使用探讨
- 检查库的版本号。如果所需要的库的版本不满足要求,它会打印出错误信息,避免链接错误版本的库文件。
- 获得编译预处理参数,如宏定义,头文件的位置。
- 获得链接参数,如库及依赖的其它库的位置,文件名及其它一些连接参数。
- 自动加入所依赖的其它库的设置。
autoconf交叉编译细节
BLE广播包信息记录
1. 前导
前导是一个8比特的交替序列。他不是01010101就是10101010,取决于接入地址的第一个比特。
- 若接入地址的第一个比特为0:01010101
- 若接入地址的第一个比特为1:10101010
接收机可以根据前导的无线信号强度来配置自动增益控制。
2 接入地址
接入地址有两种类型:广播接入地址和数据接入地址。
- 广播接入地址:固定为0x8E89BED6,在广播、扫描、发起连接时使用。
- 数据接入地址:随机值,不同的连接有不同的值。在连接建立之后的两个设备间使用。
对于数据信道,数据接入地址是一个随机值,但需要满足下面几点要求:
1) 数据接入地址不能超过6个连续的“0”或“1”。
2) 数据接入地址的值不能与广播接入地址相同。
3) 数据接入地址的4个字节的值必须互补相同。
4) 数据接入地址不能有超24次的比特翻转(比特0到1或1到0,称为1次比特翻转)。
5) 数据接入地址的最后6个比特需要至少两次的比特翻转。
6) 符合上面条件的有效随机数据接入地址大概有231个。
3. PDU--协议数据单元:
这部分才是BLE 的关键:
广播报文的报头包含4bit广播报文类型、2bit保留位、1bit发送地址类型和1bit接收地址类型。
广播报文类型:
在Linux BlueZ中,它就是:
typedef struct {
uint8_t evt_type;
uint8_t bdaddr_type;
bdaddr_t bdaddr;
uint8_t length;
uint8_t data[0];
} __attribute__ ((packed)) le_advertising_info;
对应解析代码:
static const char *evttype2str(uint8_t type)
{
switch (type) {
case 0x00:
return "ADV_IND - Connectable undirected advertising";
case 0x01:
return "ADV_DIRECT_IND - Connectable directed advertising";
case 0x02:
return "ADV_SCAN_IND - Scannable undirected advertising";
case 0x03:
return "ADV_NONCONN_IND - Non connectable undirected advertising";
case 0x04:
return "SCAN_RSP - Scan Response";
default:
return "Reserved";
}
}
发送地址类型和接收地址类型指示了设备使用公共地址(Public Address)还是随机地址(Random Address)。公共地址和随机地址的长度一样,都包含6个字节共48位。BLE设备至少要拥有这两种地址类型中的一种,当然也可以同时拥有这两种地址类型。
它在BlueZ中:
typedef struct {
uint8_t evt_type;
uint8_t bdaddr_type;
bdaddr_t bdaddr;
uint8_t length;
uint8_t data[0];
} __attribute__ ((packed)) le_advertising_info;
static const char *bdaddrtype2str(uint8_t type)
{
switch (type) {
case 0x00:
return "Public";
case 0x01:
return "Random";
default:
return "Reserved";
}
}
长度
- 广播报文:长度域包含6个比特,有效值的范围是6~37。
- 数据报文:长度域包含5个比特,有效值的范围是0~31。
广播报文和和数据报文的长度域有所不同,主要原因是:广播报文除了最多31个字节的数据之外,还必须要包含6个字节的广播设备地址。6+31=37,所以需要6比特的长度域。
再次强调:广播时必须要包含6个字节的广播设备地址。
typedef struct {
uint8_t evt_type;
uint8_t bdaddr_type;
bdaddr_t bdaddr;
uint8_t length;
uint8_t data[0];
} __attribute__ ((packed)) le_advertising_info;
图8:广播和扫描响应的数据格式
1) 有效数据部分:包含N个AD Structure,每个AD Structure由Length,AD Type和AD Data组成。其中:
- Length:AD Type和AD Data的长度。
- AD Type:指示AD Data数据的含义。
- AD type的定义在程序的“ble_gap.h”头文件中。定义如下:
1 #define BLE_GAP_AD_TYPE_FLAGS 0x01 2 #define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 3 #define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 4 #define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 5 #define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 6 #define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 7 #define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 8 #define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 9 #define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 10 #define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A 11 #define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D 12 #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E 13 #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F 14 #define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 15 #define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 16 #define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 17 #define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 18 #define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 19 #define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 20 #define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 21 #define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 22 #define BLE_GAP_AD_TYPE_APPEARANCE 0x19 23 #define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A 24 #define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B 25 #define BLE_GAP_AD_TYPE_LE_ROLE 0x1C 26 #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D 27 #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E 28 #define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 29 #define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 30 #define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D 31 #define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF
零扩展和符号扩展
原码:
知道了什么是原码,那反码就更是张飞吃豆芽——小菜一碟了。知道了原码,那么你只需要具备区分0跟1的能力就可以轻松求出反码,为什么呢?因为反码就是在原码的基础上,符号位不变其他位按位取反(就是0变1,1变0)就可以了。
例如:X=-101011 ,
[X]原= 10101011 ,[X]反=11010100
补码:
补码也非常的简单就是在反码的基础上按照正常的加法运算加1。
例如:X=-101011 ,
[X]原= 10101011 ,[X]反=11010100,[X]补=11010101
PS:0的补码是唯一的,如果机器字长为8那么[0]补=00000000。
移码:
移码最简单了,不管正负数,只要将其补码的符号位取反即可。
例如:X=-101011 , [X]原= 10101011 ,[X]反=11010100,[X]补=11010101,[X]移=01010101