Quantcast
Channel: Sam的技术Blog
Viewing all 158 articles
Browse latest View live

Nvidia Jetson TK1 Kernel和配置

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

这段时间,一直在Nvidia TK1 平台上做事。但Kernel,driver等都依赖朋友公司提供。最近,突然发现Nvidia网上提供一篇文章。对编译Kernel有讲解。
http://www.jetsonhacks.com/2016/06/20/intel-realsense-camera-installation-nvidia-jetson-tk1/


1. 下载Kernel到TK1中:
wget http://developer.download.nvidia.com/embedded/L4T/r21_Release_v4.0/source/kernel_src.tbz2

2. 编译:
tar -xvf kernel_src.tbz2
zcat /proc/config.gz > .config
TK1的 /proc/目录下有个文件,config.gz , 确实是Kernel配置时的配置文件。
make xconfig


 

ROS程序开机自启动

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

在控制机器人的PC,嵌入式系统启动时,常常需要ROS程序随开机启动。Sam尝试了多种方法,现记录如下:

1. ROS官方方法:
Robot_upstart:
The robot_upstart package provides scripts which may be used to install and uninstall Ubuntu Linux upstart jobs which launch groups of roslaunch files.

所以,这个方法可能仅支持Ubuntu Linux。它提供scripte来安装和卸载随机启动的ROS工作。 可以使用roslaunch等。

1.1:安装(indigo-ROS下):
$sudo apt-get install ros-indigo-robot-upstart 

1.2: 设置某个Package的launch文件为开机启动 .launch:
Sam有个Package:beacool_bringup, 它其中有个 .launch文件----beacool_bringup/launch/minimal.launch
$rosrun robot_upstart install beacool_bringup/launch/minimal.launch
这里容易出以下几个问题:
A. 找不到launch文件:
A1:确保package_name/launch/目录的正确。
A2:确保roscd package_name 可以进入。(说明:source ~/catkin_ws/devel/setup.bash 已经起效)

另一点要注意的是Log:
Preparing to install files to the following paths:
/etc/init/beacool.conf
/etc/ros/indigo/beacool.d/.installed_files

此时,Ubuntu启动时,这个Launch就会被调用。

1.3: 其它关键信息:
1.3.1: service名:
service名为:包名的一部分,在以上例子中,Package_Name: beacool_bringup.   所以service名为:beacool

1.3.2: 停止开机启动:
rosrun robot_upstart uninstall service名
rosrun robot_upstart uninstall beacool

1.3.3: service 启动和停止:
sudo service beacool start
sudo service beacool stop

1.3.4: 察看log: 
sudo vi /var/log/upstart/beacool.log

网络上不少地方在描述这部分工作时:均不讲清楚 service名从何而来。带来不少误解。所以专门用红色标记service名



2. 使用Linux桌面系统对应开机启动程序:
不同的Linux桌面系统,开机启动并不相同。Ubuntu实用GNOME桌面系统。它使用启动应用程序来设置随机启动。也可以在终端输入:gnome-session-properties来启动。
其它桌面系统对应软件并不一定相同:例如KDE----System Settings->System Administration->Startup and Shutdown



可以看到,Sam使用这个工具,启动了计算器。
可ROS 程序如何启动呢?
其实思路很简单,就是运行一个终端程序,终端程序则运行一个脚本,这个脚本中设置ROS, 启动ROS应用程序。

Sam想启动的 .launch为: beacool_bringup 包内的minimal.launch
所以创建启动脚本如下:
#! /bin/bash source /opt/ros/indigo/setup.sh 
source /home/exbot/devel/setup.bash 
roslaunch beacool_bringup minimal.launch


其次:在启动程序的命令列表中,使用:
gnome-terminal -x /home/exbot/catkin_ws/beacool_ros/beacool_run.sh




则系统每次启动后,会开启一个终端窗口,并执行脚本中的launch.

此方法在大部分ubuntu+ROS下有用。但在TK1 Ubuntu下未起作用。暂时不知怎么回事。



3. Linux 经典方式, 开机启动Service:
首先介绍背景知识:Linux启动时,可以启动一些Service。 Sam很早之前搞Linux机顶盒,Android机顶盒时。很多程序就是以Service形式启动的。
3.1: 创建Service的方法:
A: 在/etc/init.d/目录下,创建要启动的脚本。例如名为:beacool_rfkill 这个脚本用来启动 bluetooth.
内容如下:
rfkill unblock bluetooth

B: 把脚本增加入Service:
 $ cd /etc/init.d
$ sudo update-rc.d beacool_rfkill defaults 95
此时,会把脚本beacool_rfkill 加入到/etc/rcX.d/目录中。X:0-6, 分别表示不同的启动级别。3为字符界面启动,5为GUI启动。其它不关键。
脚本名则在/etc/rc3.d/中变为:S95beacool_rfkill
命令中,最后的数字表示表示启动顺序。

C: 如果想要去掉此Service:
$ cd /etc/init.d
$ sudo update-rc.d -f beacool_rfkill remove

3.2: ROS程序使用Service方式启动:
为了查看脚本是否有效,可以查看log. Sam在脚本中作了如下动作:
roslaunch beacool_nav amcl_demo.launch >> /home/ubuntu/catkin_ws/src/beacool.log 2>&1
这样,就会把log 发送到指定目录。
Log如下: 
/etc/rc2.d/S96dashgo_launch: 1: /etc/rc2.d/S96dashgo_launch: roslaunch: not found
这说明 ros没加入环境变量中。需要先把环境变量设置好。
可参见后面的写法:
.  /opt/ros/indigo/setup.sh 
.  /home/ubuntu/catkin_ws/devel/setup.sh 
roslaunch beacool_bringup minimal.launch 

此办法有个缺点:
如果有多个ROS工程要加入,例如:其中一个加为S98, 另一个加为S99。则S98会被执行。而S99并未执行。
虽然也可以后台执行,但会导致前一个退出。

所以如果一定要采用此方法:
可以把多个Launch合并。(并不建议)


4. 简单暴力的 rc.local (问题较多的方法):
/etc/rcX.d/中,都包含了/etc/init.d/rc.local.  通常都是最后一刻加入的,例如:S99rc.local
而它又引用了 /etc/rc.local
所以,可以简单的在/etc/rc.local 的exit 0 之前加入调用。

例如:Sam想要加入一个ROS项目:beacool_bringup 的minimal.launch.
A: 先创建一个script:
.  /opt/ros/indigo/setup.sh 
.  /home/ubuntu/catkin_ws/devel/setup.sh 
roslaunch beacool_bringup minimal.launch 
请注意:此时并没有使用source /opt/ros/indigo/setup.bash.
而是采用 .  /opt/ros/indigo/setup.sh 
是因为此时bash还未启动,而source是bash内部命令。此时找不到source.

B: 修改其权限:
sudo chmod 777 beacool_launch

C: 加入rc.local:
/etc/init.d/beacool_launch


此办法有个和方法3类似的缺点:
1. 加入后,如果ROS 程序不退出,则阻塞在这里。这意味着如果要启动多个launch. 则下一个不会被执行。
2. 当然有朋友会说,可以后台执行嘛。
/etc/init.d/beacool_launch & 
但如果后面再启一个launch, 前面beacool_launch所启动的ROS项目会退出。

所以如果一定要采用此方法:
可以把多个Launch合并。(并不建议)


 

ROS程序错误处理集合

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

1. terminate called after throwing an instance of 

'boost::exception_detail::clone_impl >'
  what():  

boost: mutex lock failed in pthread_mutex_lock: Invalid argument

解决方法:
sudo apt-get dist-upgrade


 

ROS底盘Base Controller研究

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

0. Base_Controller基础知识:
在ROS控制模型中,把对ROS底盘的驱动,对各轮子的PID调节,对底盘回报速度和odom处理等模块统称为Base_Controoler.  这部分对机器人底盘制作者,使用者都有意义。这部分最终的意义在于:让底盘的使用者看来,底盘就是一个Node。它吃cmd_vel数据并执行之。并上报odom消息。


ROS相关控制模型中Base_Controller所处位置和作用如下:



ROS设计者对降低耦合性思路真是值得学习:
ROS上位机发送/cmd-vel(Twist). 仅仅是告诉底盘它想以何种线速度,角速度做移动。至于如何做到这个移动,则是Base_Controller负责。底盘制作者根据自己底盘的特性(2轮差速,4轮,N轮,N脚)来把这个命令转换为每个轮子或者脚的动作,并最终转化为每个电机的PWM。
底盘制作者再通过自己的手段得到移动距离,并向ROS上位机发布ODOM。


1. rosserial分析
1.1: http://wiki.ros.org/rosserial
当ROS上位机和下位机使用串口连接时,即可使用rosserial.
rosserial是个原包(就是以前的栈)。 它封装了串行消息和多路topic以及service,通过一个字符设备(Serial Port或者Network Socket)
它里面的包,分为部分:
A. ROS端接口(或者说Core):
rosserial_python,  roserial_server, rosserial_java.
这部分代码在ROS机上申请一个Node并桥接远端平台的命令。

B:Client Libraries:
rosserial_arduino,  rosserial_embeddedlinux, rosseral_windows, rosserial_mbed, rosserial_tivac.
这部分允许用户很容易的在各种平台得到和运行ROS Node,监听和发布Topic等。
它是ROSSerial的Client端。它让那些可以运行ANSI C++的各类微处理器,并使用Serial Port连接到ROS 机器的设备,可以方便的使用类ROS接口。
当这个设备是Arduino时,则可以直接看rosserial_arduino. 如果其它没有支持的平台,如STM32,则需要自己做一些工作。(http://wiki.ros.org/rosserial_client/Tutorials)



C:Examples and  Use Cases:



1.2: rosserial_arduino使用
1.2.1:下载(Sam使用Indigo):
git checkout indigo-devel
它允许允许Arduino上直接使用ROS接口,作为一个Node,发布Topic, 发布TF转换,获取ROS系统时间等。

1.2.2:编译获取Arduino库:
cd ~/catkin_ws
catkin_make

roscd rosserial_arduino
rosrun rosserial_arduino make_libraries.py lib_ros
则在当前目录下生成lib_ros目录。




 

git使用记录

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com


git branch 看本地分支。
git branch -r 看远端分支。
git branch -a 查看本地和远端分支。

git checkout branchName  切换到新分支 




 

ROS底盘Base Controller研究 ros_arduino_bridge

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

0.基础知识:
ros_arduino_bridge也是一个元包(以前叫栈)。它为arduino微处理器提供ROS Driver和Base Controller。这个Driver提供访问模拟和数字Sensors的能力。 PWM Servos,从Encoder获取数据,并产生odometry数据。换句话说,它为Arduino为底盘控制器的ROS模型提供了一个完整的Base Controller模型。这与rosserial是完全不同的。
这个Stack包含的Firmware缺省使用Pololu电机控制shield(https://www.pololu.com/product/2502)和Robogaia Encoder shield(https://www.robogaia.com/two-axis-encoder-counter-mega-shield-version-2.html)。 但可以被很容易的替换为其它电机控制板和Encoder控制。

ros_arduino_bridge的最大优势在于:
1. 完整的Base Controller框架:
2. 逻辑代码放在ROS 设备上,降低了Arduino压力。


1.实际使用
1.1: 下载和编译:
$cd ~/catkin_ws
$catkin_make

1.2:copy arduino库:
$roscd ros_arduino_firmware
$cd src/libraries
把ROSArduinoBridge copy到 Arduino IDE的libraries下。
在Linux下:
$cp ROSArduinoBridge -rf ~/sketchbook/libraries


1.3: Arduino IDE使用:
使用Arduino IDE打开 例子中的ROSArduinoBridge。


1.4:
ROS平台上:
$roslaunch ros_arduino_python arduino.launch

rostopic pub /cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
则设备应该在打转。










 

ROS底盘Base Controller研究 Arduino硬件连接

$
0
0
作者:Sam (甄峰)  sam_code@hotmail.com

在做ROS底盘 Base Controller研究时,底盘控制器采用Arduino (DFRduino UNO R3). 所以先搭建一个实际底盘。

0. 选用设备:
A: Arduino,-- DFRduino UNO R3.
B: 电机驱动模块  12/24V 7A 160W双路直流电机驱动模块 或L298N。
C: 电池。 12V锂电池。
D: 电机直流电机(带编码器)

一些设备可能并不完全合理,但手头已经有了。所以就直接使用了。

1. 电源:
本想着Arduino需要5V电源,所以想使用降压模块(L7805 LM7805三端稳压器电源模块 5V稳压模块 LM2596S DC-DC可调降压模块)
后来查了下DFRduino信息(http://www.dfrobot.com.cn/goods-521.html),里面提到:
输入电压:接上USB时无须外部供电或外部7V~12V DC输入
所以直接接12V锂电池。

2. 电路接线:






 

EAI雷达坐标校正

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

EAI  F4激光雷达该如何安装到地盘上呢?下面把安装过程记录下来:

1. 激光雷达和底盘的关系:
察看gmapping_demo.launch, 可以看到如下语句: 
    args="0.0 0.0 0.2 0.0 3.1415926  0.0 /base_link /laser_frame 40" />
表明:/laser_frame这个雷达TF和机器人中心参考系--/base_link是固定参考系(static_transform_publisher)
0.0 0.0 0.2:表明/laser_frame的中心与机器人中心x,y相同,但高0.2.
0.0 3.1415926  0.0: 表明雷达方向和机器人方向偏差180度。





 

RK3229 Android编译环境搭建和编译过程

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

首先选择Ubuntu12.04 64bit为开发环境。
很多必要的软件已经安装,如:python ,GNU Make等。

1. 必要软件安装:
1.1: JDK:
Android5.1后,采用JDK为Open JDK。而非oracle jdk.
$sudo apt-get install openjdk-7-jdk

检测:
$java -version
Java version "1.70_121"
OpenJDK RunTime  Environment.....


1.2: 其它包
sudo apt-get install git
sudo apt-get install gnupg 
sudo apt-get install flex
sudo apt-get install bison
sudo apt-get install gperf
sudo apt-get install build-essential
sudo apt-get install zip
sudo apt-get install curl
sudo apt-get install libc6-dev
sudo apt-get install libncurses5-dev:i386
sudo apt-get install x11proto-core-dev
sudo apt-get install libx11-dev:i386
sudo apt-get install libreadline6-dev:i386
sudo apt-get install libgl1-mesa-glx:i386
此时,会报错:
Some packages could not be installed. This may mean that you have requested an impossible situation or if you are using the unstable that some required packages have not yet been created or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
libgl1-mesa-glx:i386: Depends: libglapi-mesa:i386(= 8.0.4-0ubuntu0.7)
Recommends: libgl1-mesa-dri:i386

说明是要安装:libgl1-mesa-dir:i386

但当运行:
sudo apt-get install libgl1-mesa-dri:i386时,会发现,它试图Remove ubuntu-desktop. 这是无论如何不能接受的。
然后观察它希望卸载的Package:libegl1-mesa-lts-trusty, libgl1-mesa-dri-lts-trusty, libwayland-egl1-mesa-lts-trusty....
他们有个共同点。 就是包名中包含lts-trusty. 这是Ubuntu14.04的代号。
可以看到libgl1-mesa-dri-Its-trusty已经存在。 则以为这安装  libgl1-mesa-glx:i386时缺乏libgl1-mesa-dri,其实是版本对应不上。
则Sam尝试安装libgl1-mesa-glx-lts-trusty:i386
sudo apt-get install libgl1-mesa-glx-lts-trusty:i386
果然可以成功,且不需要Remove ubuntu-desktop 了。


sudo apt-get install libgl1-mesa-dev
sudo apt-get install g++-multilib
sudo apt-get install mingw32
sudo apt-get install tofrodos
sudo apt-get install python-markdown
sudo apt-get install libxml2-utils
sudo apt-get install xsltproc
sudo apt-get install zlib1g-dev:i386
sudo apt-get install lzop


sudo ln -s /usr/lib/i386-linux-gnu/mesa/libGL.so.1 /usr/lib/i386-linux-gnu/libGL.so




2. 编译:
编译过程相对简单:
U-Boot编译:
$cd u-boot
$make rk322x_box_defconfig
$make

Kernel编译:
$cd kernel
$make rockchip_defconfig
$make rk3229-box.img

Android编译:
$source build/envsetup.sh
$source build.sh
$lunch rk322x_box-userdebug
$make



3. 烧入:






附1:
Ubuntu各版本的代号:
版本号 代号 发布时间
16.10 Yakkety Yak 2016/10/13
16.04 Xenial Xerus 2016/04/21
15.10 Wily Werewolf 2015/10/24
15.04 Vivid Vervet 2015/04/22
14.10 Utopic Unicorn 2014/10/23
14.04 LTS Trusty Tahr 2014/04/18
13.10 Saucy Salamander 2013/10/17
13.04 Raring Ringtail 2013/04/25
12.10 Quantal Quetzal 2012/10/18
12.04 LTS Precise Pangolin 2012/04/26
11.10 Oneiric Ocelot 2011/10/13
11.04(Unity成为默认桌面环境) Natty Narwhal 2011/04/28
10.10 Maverick Meerkat 2010/10/10
10.04 LTS Lucid Lynx 2010/04/29
9.10 Karmic Koala 2009/10/29
9.04 Jaunty Jackalope 2009/04/23
8.10 Intrepid Ibex 2008/10/30
8.04 LTS Hardy Heron 2008/04/24
7.10 Gutsy Gibbon 2007/10/18
7.04 Feisty Fawn 2007/04/19
6.10 Edgy Eft 2006/10/26
6.06 LTS Dapper Drake 2006/06/01
5.10 Breezy Badger 2005/10/13
5.04 Hoary Hedgehog 2005/04/08
4.10(初始发布版本) Warty Warthog 2004/10/20


附录二:
一些软件包,是针对某个Ubuntu版本时,它会显示此版本Ubuntu的代号。


 

Android设备信息获取 TelephonyManager

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

在Android开发中,常需要得到Android Device一些具体信息。如基站(Cell)信息,设备唯一ID,设备网络类型等。读取此类信息,第一个方式就是通过TelephonyManager.

0.基础知识:
TelephonyManager提供访问设备电信信息的途径和办法,应用程序可以利用它得到电信服务和状态信息。应用程序也可以Register 一个Listener去侦测电信服务和状态的变化。

不能直接实例化,而应该通过 Context.getSystemService(Context.TELEPHONY.SERVICE);获取。

1.实际使用
1.1:获取基站信息
1.1.1: 获取所有基站信息: 
TelephonyManager tm = (TelephonyManager) this.getSystemService(TELEPHONY_SERVICE);
List cellInfoList = tm.getAllCellInfo();
if(cellInfoList.size() > 0)
{
for(CellInfo ci: cellInfoList)
{
s = s + ci.toString() + "\n\n";
}
}
可以获取所有的基站信息。
1.1.2:获取周边基站信息
TelephonyManager tm = (TelephonyManager) this.getSystemService(TELEPHONY_SERVICE);
List nclList = tm.getNeighboringCellInfo(); 
 if(nclList.size() > 0) 
 { 
 s = s + "Get Neigh Cell Info: \n"; 
 for(NeighboringCellInfo ci: nclList) 
 { 
 s = s + ci.toString() + "\n\n"; 
 } 
 } 
 else 
 { 
 s = s + "No Neighboring Cell Info" + "\n"; 
 }
这两个方法中,比较推荐使用getAllCellInfo(). 他们在一些Device下会返回null. 

1.13: 利用基站获取位置信息:
CellLocation celllocation = tm.getCellLocation(); 
 if(celllocation != null) 
 { s = s + celllocation.toString() + "\n"; }


1.2:获取运营商信息:
//获取网络类型:GSM/CDMA/SIP。
s = s + "Photo type:" + tm.getPhoneType() + "\n";
//短信代理商URL。Sam显示的竟然是GOOGLE的?  
s = s + "MMS URL:" + tm.getMmsUAProfUrl() + "\n";
//短信代理商
s = s + "MMS Agent:" + tm.getMmsUserAgent() + "\n";
// Mobile Country Code。 获取到的是cn.
s = s + "Network Contry ISO:" + tm.getNetworkCountryIso() + "\n";
//MCC+MNC: 46000 (MCC+MNC (mobile country code + mobile network code)
s = s + "MCC+MNC:" + tm.getNetworkOperator () + "\n";

//运营商名:中国移动
s = s + "Network Operator Name:" + tm.getNetworkOperatorName () + "\n";

//得到网路类型:
getNetworkType();  //CDMA: Either IS95A or IS95B,  UMTS, LTE等。


以上方法,在CDMA模式下有可能不适用。


1.3:获取数据网络信息
//获取数据网路数据流向:0:表示未传输, 3,表示IN/OUT
s = s + "Data Activity:" + tm.getDataActivity() + "\n"; //0. 3 

//获取数据网络装态:0. 未连接。 2:已经连接。
s = s + "Data State:" + tm.getDataState() + "\n"; //0. 2


1.4: 获取SIM卡信息
//SIM卡状态,SIM卡正常是:SIM_STATE_READY
s = s + "SIM State:" + tm.getSimState() + "\n";

// SIM卡国家
s = s + "Country ISO:" + tm.getSimCountryIso() + "\n";
// MCC+MNC
s = s + "MCC+MNC:" + tm.getSimOperator() + "\n";
//运营商名
s = s + "Operator Name:" + tm.getSimOperatorName () + "\n";
//SIM 卡Serial Number
s = s + "Serial Number:" + tm.getSimSerialNumber() + "\n";
//898600560914f3016353

//电话号码:
但它经常被运营商设置的看不到。

1.5:获取IMSI和Device ID(IMEI)
s = s + "IMSI:" + tm.getSubscriberId() + "\n";
s = s + "DeviceID(IMEI):" + tm.getDeviceId() + "\n"; 

IMSI和IMEI的区别在哪呢?

IMSI

国际移动用户识别码(IMSI:International Mobile Subscriber Identification Number)是区别移动用户的标志,储存在SIM卡中,可用于区别移动用户的有效信息。其总长度不超过15位,使用0~9的数字。


IMEI
IMEI(International Mobile Equipment Identity,移动设备国际识别码,又称为国际移动设备标识)是手机的唯一识别号码。IMEI俗称“手机串号”,存储在手机的EEPROM(俗称“码片”)里。
手机在生产时,就被赋予一个IMEI。IMEI由15位数字组成,每位数字仅使用0~9的数字。
IMEI是区别移动设备的标识,储存在移动设备中,可用于监控被窃或无效的移动设备。
IMEI码由GSM(Global System for Mobile Communications,全球移动通信协会)统一分配,授权BABT(British approvals Board of Telecommunications,英国通信认证管理委员会)审受。


很明显,IMSI是区别用户的,存储在SIM卡中,不同的SIM卡有不同的IMSI,而不同的运营商的SIM卡是不一样的,因此,通过读取用户的SIM卡中的IMSI可以区分用户使用的是哪个运营商的网络。(而wifi一般是通过IP来区分运营商和所在的地域,xG网络通过IMSI来区分)

IMEI是区别设备的,存储在手机的EEPROM中,因此IMEI常用来区分用户是否在同一手机上。



 

IMEI以及MEID解析和生成

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

0.基础知识: 

IMEI是国际移动通讯设备识别号(International Mobile Equipment Identity)的缩写,用于GSM系统。

由15位数字组成,前6位(TAC)是型号核准号码,代表手机类型。接着2位(FAC)是最后装配号,代表产地。后6位(SNR)是串号,代表生产顺序号。最后1位(SP)是检验码。

(欧洲型号认证中心今年重新分配了IMEI,FAC被和TAC合并在一起,FAC码的数字统一从00开始,因此无论什么型号什么品牌其7,8位均是00、01、02或03这样向后编排)



MEID是移动通讯设备识别号(Mobile Equipment IDentifier)的缩写,用于CDMA系统。

由15位16进制数字组成(一般使用前14位),前8位是生产商编号,后6位是串号,最后1位是检验码。



IMEI校验码算法
(1).将偶数位数字分别乘以2,分别计算个位数和十位数之和
(2).将奇数位数字相加,再加上上一步算得的值
(3).如果得出的数个位是0则校验位为0,否则为10减去个位数
如:35 89 01 80 69 72 41 偶数位乘以2得到5*2=10 9*2=18 1*2=02 0*2=00 9*2=18 2*2=04 1*2=02,计算奇数位数字之和和偶数位个位十位之和,得到 3+(1+0)+8+(1+8)+0+(0+2)+8+(0+0)+6+(1+8)+7+(0+4)+4+(0+2)=63 => 校验位 10-3 = 7

MEID校验码算法:
(1).将偶数位数字分别乘以2,分别计算个位数和十位数之和,注意是16进制数
(2).将奇数位数字相加,再加上上一步算得的值
(3).如果得出的数个位是0则校验位为0,否则为10(这里的10是16进制)减去个位数
如:AF 01 23 45 0A BC DE 偶数位乘以2得到F*2=1E 1*2=02 3*2=06 5*2=0A A*2=14 C*2=18 E*2=1C,计算奇数位数字之和和偶数位个位十位之和,得到 A+(1+E)+0+2+2+6+4+A+0+(1+4)+B+(1+8)+D+(1+C)=64 => 校验位 10-4 = C



IMEI举例:

小米Note: 866032 02 129870 4.

华为Note:869819 02 084146 9

效验位符合以上算法。

 

 

 

  private static String getimei15(String imei){ 
        if (imei.length() == 14) { 
            char[] imeiChar=imei.toCharArray();   
            int resultInt=0;   
            for (int i = 0; i < imeiChar.length; i++) {   
                int a=Integer.parseInt(String.valueOf(imeiChar[i]));   
                i++;   
                final int temp=Integer.parseInt(String.valueOf(imeiChar[i]))*2;   
                final int b=temp<</span>10?temp:temp-9;   
                resultInt+=a+b;   
            }   
            resultInt%=10;   
            resultInt=resultInt==0?0:10-resultInt;   
            return resultInt + ""; 
        }else{ 
            return ""; 
        } 
    }


 

ROS学习  Parameter的设置与查询

$
0
0
作者: Sam(甄峰)  sam_code@hotmail.com

0. Parameter Server:
roscore在启动时,除了启动Mater Node,用来管理Node, 沟通各节点之间的消息和服务外。 还会创建一个Parameter Server。它用来设置与查询参数。

Parameter Server可以存储:strings, integers, , booleans,lists,字典, iso8601数据,base64-encoded数据。


1. Parameter Server数据的设置和读取
Parameter Server数据的设置和读取有多种方式:
A:C++,Python 的ROS API接口。
B:Launch文件设置。
C:命令行rosparam。


2. ROSCPP API接口对Parameter Server的访问
ROS Parameter API让用户很容易的访问string, integer, float和boolean.  要支持其它选项,则需要使用:
http://docs.ros.org/api/xmlrpcpp/html/classXmlRpc_1_1XmlRpcValue.html

roscpp有两套不同的Parameter  API.  Bare版本是ros::param NameSpace。而Handle版本则是ros::NodeHandle接口。

2.1: 设置Parameter值, 获取Parameter值
2.1.1: NodeHandle方式: 
2.1.1.1: NodeHandle getParam() setParam()模式:
    //NodeHandle Mode Setting/Getting Parameter  
    // 1.  std::string
    std::string name;
    std::string setparam = "SamTest:";
    nh.setParam("InfoName", setparam);
   
    nh.getParam("InfoName", name);
    ROS_INFO("Get Name: %s", name.c_str());
   
    // 2.  char*
    char des[] = "This is a test for parameter server!";
    std::string des_string;
    nh.setParam("Des", des);
   
    nh.getParam("Des", des_string);
    ROS_INFO("Get des: %s", des_string.c_str());
   
    // 3. double
    double linear = 10.0;
    nh.setParam("Linear", linear);
   
    linear = 0;
    nh.getParam("Linear", linear);
    ROS_INFO("Get Linear: %f", linear);
   
    // 4. int
    int count = 23;
    nh.setParam("Count", count);
    count = 0;
    nh.getParam("Count", count);
    ROS_INFO("Get cound: %d", count);
   
    // 5. bool
    bool enable = true;
    nh.setParam("Enable", enable);
    enable = false;
    nh.getParam("Enable", enable);
    if(enable)
        ROS_INFO("Enable: TURE");
    else
        ROS_INFO("Enable: FALSE");
    // 6. std::vector
    std::vector vector_string1;
    std::vector vector_string2;
    vector_string1.push_back("First Item");
    vector_string1.push_back("Second Item");
    vector_string1.push_back("Third Item");
   
    nh.setParam("vec_str", vector_string1);
   
    nh.getParam("vec_str", vector_string2);
    ROS_INFO("vector size is %d", vector_string2.size());
    std::vector::iterator it;
    for(it=vector_string2.begin(); it!=vector_string2.end(); it++)
    {
        ROS_INFO("Get vector:%s", it->c_str());
    }
   
    // 7.std::vector
    std::vector vector_float1;
    std::vector vector_float2;
    vector_float1.push_back(1.11f);
    vector_float1.push_back(2.22f);
    vector_float1.push_back(3.33f);
    vector_float1.push_back(4.44f);
   
    nh.setParam("vec_float", vector_float1);
   
    nh.getParam("vec_float", vector_float2);
    ROS_INFO("vector size is %d", vector_float2.size());
    std::vector::iterator it_f;
    for(it_f=vector_float2.begin(); it_f!=vector_float2.end(); it_f++)
    {
        ROS_INFO("Get vector:%f", *it_f);
    }
其它还有vector, vector以及map等对应方法。
但有一定请注意:getParam()没有float版本。

这个接口内,又分两类方法,一类直接读取,另一个还可以设置一个缺省值,当没有取到数据时,可以使用缺省值。 

2.1.1.2:NodeHandle param()读取模式
    std::string second;
    nh.param("InfoName", second, "Other");
   
    ROS_INFO("Get String: %s", second.c_str());

2.1.2:Bare版本(ros::param namespace):
2.1.2.1: 无缺省用法:
仅以int 为例:
int dat = 0;
ros::param::set("value", 64);
ros::param::get("value", dat);
ROS_INFO("Value is %d", dat);
其它类型的与NodeHandle的getParam() setParam()类似。

2.1.2.2:有缺省获取方法:
ros::param::param("Count", dat, 100);
ROS_INFO("Value is %d", dat);



2.2: 获取Parameter 缓存数据
以下方法可以获取本地缓存,一定程度上加快速度:

ros::NodeHandle::getParamCached() and ros::param::getCached()

可以加快速度(第一次调用后)。但并不推荐使用。

2.3: 检测是否有参数



2.4: 删除Parameter
nh.deleteParam("f_param");
   ros::param::del("f_param");


2.5: 访问私有参数

2.6: 获取Key



3. launch方式设置Parameter





 

Android下PID, UID, TID相关知识

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

0. 基础知识:
Android架构在Linux系统之上。
Linux系统下,每个Process拥有一个PID,Process ID. 每个用户拥有一个UID:User ID, 每个Thread也拥有一个TID。
使用Linux命令,ps, top等。均可以看到PID,User(非UID) UID等信息。
同一个用户,启动的程序,它们的UID相同。

如何看到某个User的UID呢? 使用id命令即可。
$id sam,uid=1000(sam)  gid=1000(sam) .......
(另一方面,top的PID是否就是Process ID, 其实也是存疑的,因为当在Thread模式下时,同一个Process的Thread的PID是不同的)


但在Android下,不少概念有所变化。最关键就是UID,由于Android不是多用户系统,所以,UID的概念有较大变化。每个应用程序都有一个UID。只有UID相同,资源才可以相互使用。所以,某种程度上可以认为,Android系统为每个APP指定一个UID。
每个UID对应一个User,比如:u0_a55。利用ps,可以在user那一栏中看到。



1. Android下如何获取PID, UID, TID
方法一:
使用android.os.Process 这个Class。可以很容易的获取本身的PID, UID, TID.
myPid();
myTid();
myUid();
分别可以得到当前APP的PID, Tid,UID。

方法二:
cat /data/system/packages.list
出现一系列:

com.android.example.spinner 10055 1 /data/data/com.android.example.spinner default 1028,1015
其中第二个数据就是UID。

方法三:
ApplicationInfo  appInfo = getApplicationInfo();
appInfo.uid 即为本App的UID。

方法四:
获取其它App的UID
List packs = getPackageManager().getInstalledApplications(0);
        for(ApplicationInfo info : packs)
        {
        if(info.packageName.equalsIgnoreCase("xxxxxx")  )
        {
        s = "PackageName:" +info.packageName + "\n";
                s = s + "UID:" + info.uid + "\n";
        }
        }


2. 察看某个User的UID:
Android为每个App(非系统) 分配一个User, 每个User对应一个UID。 那如果知道某个User的UID呢?
android.os.Process.getUidForName("u0_a55");

所以类似:
中的参数,都是ps的第一列中显示的User。





 

EAI底盘和F4雷达的使用和解读

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

EAI发布Dashgo底盘和F4雷达之后,软硬件均有升级变化。
Sam手头F4雷达原先使用rplidar_ros驱动,后采用flashgo作驱动。现将手头版本所需处理工作记录下来。

Sam是在两个平台工作:
A. NV  TK1 平台,ARM架构,Ubuntu14.04+ROS indigo。
B: X86平台,Ubuntu14.04 + ROS indigo平台。

1.文件准备:
 1.1:把底盘程序dashgo copy到catkin_ws/src 目录。
 1.2:把雷达程序 flashgo copy到catkin_ws/src目录。
 1.3:下载move_base: 
$cd catkin_ws/src 
$git clone ://github.com/ros-planning/navigation.git
$cd navigation
$git checkout indigo-devel


2. 编译:
cd ~/catkin_ws
catkin_make

3. 创建底盘Dashgo和F4雷达的别名
这个意义有以下几点:
A:设备区分:
F4雷达和Dashgo底盘都是通过USB转Serial连接到主机。我们知道,此类设备通常被命名为/dev/ttyUSBx(x:0~64)或/dev/ttyACMx(x:0~64). 但应用程序并不知道哪个设备对应那个Node。比如有多个USB2Serial设备,名为:/dev/ttyUSB0,  /dev/ttyUSB1, /dev/ttyUSB2, /dev/ACM0, /dev/ACM1.则完全不知道哪个Node对应的雷达和底盘。
所以写udev rules脚本让其名字可辨识。
B:  处理权限:
通常/dev/ttyUSBx  , /dev/ttyACMx, 权限设置为:660。但ROS程序并非ROOT权限或和此Node 同group.所以需要处理。使之可以被ROS设备读写。

EAI的做法与大多数ROS程序员做法类似,利用UDev来提高辨识度。注明VendorID, ProductID。

在dashgo_bringup/startup目录内,有以下几个文件:
create_rplidar_udev.sh
主要内容为:
echo 'KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE:="0666", GROUP:="dialout", SYMLINK+="rplidar"' >/etc/udev/rules.d/rplidar.rules
讲解:有/dev/ttyUSBx设备,vid=10c4, pid=ea60时,则创建它的软连接为:rplidar, 使用权限为666.
但之后Sam手头的雷达有了变化,它插入后,并不是/dev/ttyUSBx, 而是/dev/ttyACMx, 且Vid,Pid也变化了。所以Sam将其修改为:
create_rplidar_udev_new.sh
echo 'KERNEL=="ttyACM*", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", MODE:="0666", GROUP:="dialout", SYMLINK+="rplidar"' >/etc/udev/rules.d/rplidar.rules
有/dev/ttyACMx设备,vid=0483, pid=5740时,则创建它的软连接为:rplidar, 使用权限为666.


create_dashgo_udev.sh
echo 'KERNEL=="ttyACM*", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0042", MODE:="0666", GROUP:="dialout", SYMLINK+="dashgo"' >/etc/udev/rules.d/dashgo.rules
有/dev/ttyACMx设备,pid=0042, vid=2341时,则创建它的软连接为:dashgo, 使用权限为666.
如此,则/dev/rplidar, /dev/dashgo就非常明确的对应雷达和底盘了。
这个方法非常好,值得学习。


VID,PID可以使用lsusb得到。
roscd dashgo_bringup/startup
sudo sh create_dashgo_udev.sh sudo sh create_rplidar_udev_new.sh





 

ROS 公用包学习解析 usb_cam

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

Sam最近在学习ROS过程中,遇到非常多官方Package。对ROS Driver也有所得。现陆续记录如下。

首先从usb_cam Package说起。

0. 简介:
A ROS Driver For V4L USB Camera.
0.1: ROS Driver和Linux driver的区别:
ROS并非全操作系统,它只是架设在Ubuntu上的一个次级系统。提供了一系列通讯方式,工具和包,让开发者更容易工作的一个平台。 
所以,ROS Driver与Linux Driver完全不同。 Linux Driver是在内核模式下获取硬件信息,反馈到用户模式下。并提供在用户模式下控制内核模式下才能访问的硬件的途径(ioctl)。
ROS Driver则不同,它完全是在用户模式下,从Linux层面获取数据。并通过Topic发送Message。使得其它ROS Node可以通过topic得到信息的程序。
usb_cam就是个典型的ROS Driver. 通过它,理解ROS Driver的层级和用途。
它并非Linux传统意义上的Driver, 它其实只是个应用程序,通过V4L2接口设置Camera并获取数据, 利用ROS接口发布Topic,供其它Node实用.
 
 
1. usb_cam的下载和组织结构:
1.1: 下载并编译:
$cd ~/catkin_ws/src

$cd ~catkin_ws
$catkin_make

1.2:目录文件分析:
分析代码组织架构,最好的方法是分析CMakeLists.txt. 从中可以看到,主要的C/C++源码有2个。
src/usb_cam.cpp最终产生libusb_cam.so, 它使用V4L2 接口访问Camera,并提供一些必要的格式转换工具。

nodes/usb_cam_node.cpp最终产生usb_cam_node。(它使用了前面产生的库)。它初始化ROS,利用libusb_cam.so获取Camera数据。并利用image_transport发布各种格式的Image。


1.3:usb_cam_node相关讲解:
usb_cam_node 利用libusb_cam.so使用通用接口访问USB Camera。并publishe Image使用格式为:sensor_msgs::Image.
可以使用image_transport 库去传输压缩格式Image。

1.3.1: Publish Topic:
~/image (sensor_msgs/Image)
  • The image
1.3.2:Parameter:
~video_device (string, default: "/dev/video0")
  • The device the camera is on.
~image_width (integer, default: 640)
  • Image width
~image_height (integer, default: 480)
  • Image height
~pixel_format (string, default: "mjpeg")
  • Possible values are mjpeg, yuyv, uyvy
~io_method (string, default: "mmap")
  • Possible values are mmap, read, userptr
~camera_frame_id (string, default: "head_camera")
  • The camera's tf frame
~framerate (integer, default: 30)
  • The required framerate
~contrast (integer, default: 32)
  • Contrast of video image (0-255)
~brightness (integer, default: 32)
  • Brightness of video image (0-255)
~saturation (integer, default: 32)
  • Saturation of video image (0-255)
~sharpness (integer, default: 22)
  • Sharpness of video image (0-255)
~autofocus (boolean, default: false)
  • Enable camera's autofocus
~focus (integer, default: 51)
  • If autofocus is disabled, the focus of the camera (0=at infinity)
~camera_info_url (string, default: )
  • An url to the camera calibration file that will be read by the CameraInfoManager class
~camera_name (string, default: head_camera)
  • The camera name. This must match the name in the camera calibration

这些参数就是V4L2常用的设置参数。


2. usb_cam使用:
2.1: 字符模式下使用: 
$roscore
$rosrun usb_cam usb_cam_node
$rosrun rqt_image_view rqt_image_view 

2.2: launch文件例子
 

 

ROS 公用包学习解析 image_transport

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

0. image_transport简介
image_transport应该总被用在image订阅和发布上。它为低带宽压缩格式(compressed formats)image传输提供透明支持。例如:为JPEG/PNG压缩和视频流提供单独插件,为此类image提供传输(订阅和发布)。
 
当我们基于Image工作时,我们常希望指定传输策略。例如使用压缩Image或视频流编码。 image_transport提供class和node提供支持位随意格式的各类传输。抽离了格式等复杂信息,所以用户只看到sensor_msgs/Image这个message.
 
指定格式的传输由插件提供,image_transport自身只提供“raw”传输。其它的格式支持依赖于其它子package. image_transport_plugins.
 
1. image_transport 使用:
image_transport可以使用C++或Python接口。我们主要看看C++接口。
1.1: 下载image_transport源码
$cd catkin_ws/src
 
1.2: 学习用法
正常发布和订阅,是通过NodeHandle, 如下:
   1 // Do not communicate images this way!
   2 #include /ros.h>
   3 
   4 void imageCallback(const sensor_msgs::ImageConstPtr& msg)
   5 {
   6   // ...
   7 }
   8 
   9 ros::NodeHandle nh;
  10 ros::Subscriber sub = nh.subscribe("in_image_topic", 1, imageCallback);
  11 ros::Publisher pub = nh.advertise<<SPAN class=ID style="BOX-SIZING: border-box; COLOR: rgb(0,0,0)">sensor_msgs::Image>("out_image_topic", 1);
 
而使用image_transport:
   1 // Use the image_transport classes instead.
   2 #include /ros.h>
   3 #include /image_transport.h>
   4 
   5 void imageCallback(const sensor_msgs::ImageConstPtr& msg)
   6 {
   7   // ...
   8 }
   9 
  10 ros::NodeHandle nh;
  11 image_transport::ImageTransport it(nh);
  12 image_transport::Subscriber sub = it.subscribe("in_image_base_topic", 1, imageCallback);
  13 image_transport::Publisher pub = it.advertise("out_image_base_topic", 1);
image_transport 发布和订阅独特的ROS Topic为每一个可用的Transport。 与ROS Publisher不同,它并非注册一个单独的Topic。 而是多个Topic, Topic命名遵循一个标准规则。在接口中,我们只能指定Base Topic名。其它具体名字,由规则指定。
例如,上面发布了名为:out_image_base_topic地Topic。但这个名称只是Base Topic Name。
而advertise会创建多个以base  Topic  Name 为基础的Topic。 例如: /out_image_base_topic/compressed
.....
 
 
 
1.3:例子察看:
察看image_transport\tutorial目录,其中为例子代码。
首先看CMakeLists.txt.
add_executable(my_publisher src/my_publisher.cpp)
add_executable(my_subscriber src/my_subscriber.cpp)
add_library(resized_publisher src/manifest.cpp src/resized_publisher.cpp src/resized_subscriber.cpp)
 
可以看到,例子中生成了一个库和两个可执行文件。
my_publisher.cpp:
int main(int argc, char** argv)
{
  ros::init(argc, argv, "image_publisher");
  ros::NodeHandle nh;
  image_transport::ImageTransport it(nh);
  image_transport::Publisher pub = it.advertise("camera/image", 1);
  cv::Mat image = cv::imread(argv[1], CV_LOAD_IMAGE_COLOR);
  sensor_msgs::ImagePtr msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", image).toImageMsg();
  ros::Rate loop_rate(5);
  while (nh.ok()) {
    pub.publish(msg);
    ros::spinOnce();
    loop_rate.sleep();
  }
}
 
运行:
$roscore
$rosrun image_transport_tutorial my_publisher /home/sam/image/image1.jpg
 
看效果:
$rosrun rqt_image_view rqt_image_view
选择不同的Topic, 可以看到图像。
 
$rostopic list
 /camera/image
/camera/image/compressed
/camera/image/compressed/parameter_descriptions
/camera/image/compressed/parameter_updates
/camera/image/compressedDepth
/camera/image/compressedDepth/parameter_descriptions
/camera/image/compressedDepth/parameter_updates
/camera/image/theora
/camera/image/theora/parameter_descriptions
/camera/image/theora/parameter_updates

 
 在usb_cam Package中,也使用了image_transport.  只是它使用的接口是advertiseCamera()
 相关API:
 
 
 
 
 
 
 
 

 

ROS 公用包学习解析<三> rgbd_launch

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com


0. rgbd_launch简介:
一组打开RGBD设备,并load 所有nodelets去转化 raw depth/RGB/IR 流到 深度图(depth image), 视差图(disparity image)和点云(point clouds)的launch文件集。

这些Launch文件在ROS中,使用RGB-D设备(如Microsoft Kinect, Xtion)。 它创建一个nodelet graph, 把Device Driver中获取Raw Data转换为点云,视差图或其它指定格式。

rgbd_launch包含一系列common launch文件,他们会被driver指定的launch Package使用。Driver指定的Launch Package包括:openni_launch或freenect_launch.

1. launch 详细分析
两个launch文件最重要:
launch/includes/processing.launch.xml:
从RGB-D driver (openni_camera, freenect_camera)获取数据,并处理。

launch/kinect_frames.launch:
为Kinect启动TF Tree。 它可以由openni_launch或freenect_launch启动。

1.1:processing.lanch.xml详解
这个Launch中,可以启动nodelet去转换Raw RGB和depth image到可以使用的信息,如点云。可以使用参数来设置哪些工作可以做。

rgb_processing (bool, default: true)
  • Launch nodelets for generating raw and rectified monochrome and color images. Given bayer encoded images on the rgb/image_raw topic from the RGB-D driver, the rgb processing chain produces rgb/image_mono,rgb/image_rect_monorgb/image_color and rgb/image_rect_color.
  • 控制是否启动nodelet去产生raw Data和校正(rectified)过的单色以及色彩Image。把从RGB-D driver读取的数据以bayer编码RGB编码放入 rgb/image_raw Topic中。同时产生rgb/image_mono,rgb/image_rect_mono, rgb/image_color and rgb/image_rect_color这系列Topic。
如果rgb_processing被设置为True。则$(find rgbd_launch)/launch/includes/rgb.launch.xml


debayer_processing (bool, default: true)
  • Usage of this parameter requires rgb_processing to be true. Debayers the image into monochrome and color. If set to true then explanation for rgb_processing directly applies. If set to false the rgb processing chain only producesrgb/image_rect_color.

ir_processing (bool, default: true)
  • If set to true, rectifies the raw IR image (ir/image_raw -> ir/image_rect_raw)
  • $(find rgbd_launch)/launch/includes/ir.launch.xml



depth_processing (bool, default: true)
  • Given the raw depth image, rectifies it, converts both the raw and rectified images to metric format (uint16 ->float), and produces a pointcloud. Requires depth/image_raw. Produces depth/image_rect_raw (rectified),depth/image (metric), depth/image_rect (rectified, metric), depth/points (pointcloud).



depth_registered_processing (bool, default: true)
  • Generates a registered RGBD pointcloud from the device data (requires rgb_processing to be enabled). A pointcloud can be generated through a software registration pipeline (sw_registered_processing = true, used when depth_registration for device driver is set to false ) by registering the depth image from the depth frame to an RGB frame and merging with the RGB image. If software registration is being used, depth_processing needs to be enabled. Alternatively, the device can be directly asked to generate a registered depth image in the RGB frame with can be merged with the RGB Image through the hardware registration pipeline (hw_registered_processing = true, used when depth_registration for device driver is set to true)
disparity_processing (bool, default: true)
  • Generates a disparity image from unregistered depth data (i.e. in the depth frame). Converts depth/image_rect_rawand projector/camera_info into the disparity image depth/disparity. Requires depth_processing to be enabled.
sw_registered_processing (bool, default: true)
  • Enables the software registration pipeline. depth/image_rect_raw ->depth_registered/sw_registered/image_rect_raw (registered) -> depth_registered/points ANDdepth_registered/disparity.
hw_registered_processing (bool, default: true)
  • Enables the hardware registration pipeline. depth/image_raw -> depth_registered/hw_registered/image_rect_raw(rectified) -> depth_registered/points AND depth_registered/disparity.



1.2:其它XML:
rgb.launch.xml:
利用nodelet,启动 image_proc/debayer, image_proc/rectify,  image_proc/rectify
换句话说,把Raw Data使用image_proc的nodelet来校准。

depth.launch.xml:
利用nodelet, 启动 image_proc/rectify, depth_image_proc/convert_metric, depth_image_proc/convert_metric, depth_image_proc/point_cloud_xyz。









附1:

RAW RGB与Bayer RGB

    对于Sensor来说,Bayer RGB和RAW RGB两者的图象结构都是BG/GR的。(Bayer pattern说的是COLOR FILTER的结构,分为两种:STD Bayer pattern 与Pair pattern,其中STD Bayer pattern的结构是BG/GR的,而Pair Pattern顾名思义是指BGBG/GRGR的结构,即以四行为一个单位,前两行是BG的结构,后两行是GR的结构,这种结构是美光专门为此申请了专利的,主要是在输出TV模式(NTSC/PAL制)时用到).



 

ROS 公用包学习解析 image_proc, depth_image_proc

$
0
0
作者: Sam (甄峰)    sam_code@hotmail.com

Image矫正和色彩处理功能包。这个Package包含image_proc  node. 这个Node处于Camera Driver与图像处理程序之间。它会消除Raw Data的失真,如果有需要,也可以转换Bayer RGB到YUV422格式。




image_proc提供Node模式和nodelet模式。

Node模式使用:

$ ROS_NAMESPACE=my_camera rosrun image_proc image_proc
image_porc node 会获取 image_raw, camera_info Topic。但不同的Camera,提供的Topic前缀不同,例如:很多Camera加前缀: usb_cam, 它发出Topic也加此前缀,如:/usb_cam/camera_info, /usb_cam/image_raw. 该如何处理呢. 只需要把前缀通知给ROS_NAMESPACE即可。
image_proc会创建很多imaeg_color, image_mono, image_rect, image_rect_color为前缀的Topic。


Subscribed Topics

image_raw (sensor_msgs/Image)
  • Raw image stream from the camera driver.
camera_info (sensor_msgs/CameraInfo)
  • Camera metadata.

Published Topics

image_mono (sensor_msgs/Image)
  • Monochrome unrectified image.
image_rect (sensor_msgs/Image)
  • Monochrome rectified image.
image_color (sensor_msgs/Image)
  • Color unrectified image.
image_rect_color (sensor_msgs/Image)
  • Color rectified image.



与usb_cam配合使用:
$roscore 
$rosrun usb_cam usb_cam_node
$rostopic


$ROS_NAMESPACE=usb_cam rosrun image_proc image_proc
$rostopic



$rosrun rqt_image_view rqt_image_view



 

 

 

image_proc Nodelets模式:

 

 


 

ROS学习 <十一> ROS Nodelet学习

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

0. 背景介绍
ROS是一种基于消息传递的分布式多进程框架。ROS Node之间的通讯,是基于TCP/IP协议,在传递Message或Service时,都需要先打包,后解包。对资源有较大浪费,在实时性上也表现不佳。
在需要传递的数据附载小,频率低时,这样的资源和时间消耗还可以接受。但当传递的是图像,点云等数量巨大的数据时,或实时性要求较高时,传输问题则必需要考虑。nodelet的出现,就是为解决此类问题。

1. ROS Nodelet简介
Nodelet用来提供一种方式,让多个算法运行在同一个进程内,他们之间数据实现zero  copy 传输。
使用shared_ptr实现零copy传输(Zero  Copy Transport). 它使用插件机制。

简单的说:Nodelet即为将之前启动的多个Node捆绑到一起,由一个Manager管理。在同一个Manager内, Topic数据更快,zero Copy.

nodelet package既提供用来实现Nodelet的nodelet base class。 又提供NodeletLoader class用来实例化Nodelet。

 设计目标:
1. 使用现有的ROS C++ 接口。
2. 在Nodelet之间,实现零copy数据传输。
3. 动态加载插件, 以打破构建时间的依赖性。
4. 写Node或nodelet代码,差距最小化。


2.技术概要和Nodelet使用
所有Nodelet代码继承base calss nodelet::Nodelet ,Nodelet代码将作为pluginlib 被动态load.
将提供namespace, 自动remapping arguments and parameter。 
一个nodelet_manager可以管理一个或多个Nodelet。

用法:

nodelet usage:


nodelet load pkg/Type manager - Launch a nodelet of type pkg/Type on manager manager

在Manager内,载入一个Nodelet。pkg为包名,Type为Class名(或库名)



nodelet standalone pkg/Type   - Launch a nodelet of type pkg/Type in a standalone node

以standalone模式Load和启动一个Nodelet

nodelet unload name manager   - Unload a nodelet a nodelet by name from manager
从Manager内卸载一个Nodelet。



nodelet manager               - Launch a nodelet manager node

启动一个Nodelet  Manager 



可以在字符界面使用如:
rosrun nodelet nodelet manager



 

USB接口简介

$
0
0
作者:Sam (甄峰)  sam_code@hotmail.com

USB线在生活和开发中很常用,但它有多种接口和连接器。以前工作中常用的Mini USB, Micro-USB,当前又有更方便的USB-Type C . 那他们之间有何关系,都有什么区别,现总结沟通一下。


首先看USB-Type A,  USB-Type B, USB-Type C:




MiniUSB:





Micro USB:





USB Type C:
更加纤薄的设计、更快的传输速度(最高10Gbps)以及更强悍的电力传输(最高100W)。Type-C双面可插接口最大的特点是支持USB接口双面插入,正式解决了“USB永远插不准”的世界性难题,正反面随便插。





 
Viewing all 158 articles
Browse latest View live