机器人应用

机器人操作系统ROS(01):基本概念

  • 1、乌班图Ubuntu

这ROS系统是指机器人操作系统robot operating system,并不是实时操作系统RTOS:realt-ime operation ystem,这个机器人操作系统ROS不具备实时性。ROS在2007年起源于斯坦福大学,在2010年由WG美国公司发布,目标是提高代码复用效率。ROS作为软件框架,只能算次操作系统。 ROS一般安装在类linux系统上,常见的是乌班图Ubuntu。Ubuntu是基于Debian的一款发行,debian是社区型linux,不同于Redhat/suse之类公司化的linux。Ubuntu是基于Debian和GNOME的以桌面应用为主的Linux操作系统,很少用作服务器。后期桌面由Gnome改为Unity,最新版本16.04 LTS,代号Xenial ,32-bit版本大概1.5G。 准备单独电脑或者安装多系统或者安装VMware之类虚拟机:

1.1、如果是物理安装,UltraISO刻录ISO到优盘,install时建立一个50G的EXT4日志文件系统的主分区,建立一个2G的swap格式的用于swap的逻辑分区(内存足其实不需要),建立200M的EXT4格式的用于boot的逻辑分区(也不需要),建立home分区。

1.2、如果是VMware虚拟机安装,10.0的Workstation还支持32-bit,下载大概400M,还需要安装VMwareTools。

1.3、下载当前版本的ROS Kinetic Kame,安装,这个比较新没有教程,按照install instructions一步步就可以,中间如果出现问题多数是因为访问境外网站受限的缘故。

1.4、如果找不到software center,需要修改NoDisplay=false。如果遇到Hash Sum mismatch,一般是因为天朝的网络导致TCP包错,学校可以换edu.cn校园网,公司的只好sudo apt-get update –fix-missing,如果还是提示 failed to download,可以$sudo rm -fR /var/lib/apt/lists/* 然后$ sudo mkdir /var/lib/apt/lists/partial最后再$ sudo apt-get update,一般都会Reading package lists… Done。如果还是不行的话那就PVN翻墙了。翻墙之后选择日本新加坡等地区,然后用https://repogen.simplylinux.ch/generate.php产生source.lists。

  • 2、ROS特点

ROS采用分布式处理框架,又叫Nodes,可执行文件单独设计,运行时依靠通讯,实现模块间的轻度耦合,通讯包括基于服务的同步的远程过程调用通讯以及基于主题Topic的异步的数据流通讯,还有参数服务器上的数据存储。ROS框架的main核心部分主要由WG公司设计和维护,提供分布式计算的基本工具以及整个ROS核心部分的程序编写,universe全球代码由不同国家的ROS社区组织开发和维护:底层库代码例如OpenCV,中间功能代码如人脸识别,上层应用代码完成某一确定的功能。

ROS特点:

2.1、点对点设计。

ROS的点对点设计以及服务和节点管理器等机制,可以分散由计算机视觉和语音识别以及路径规划等功能带来的实时计算压力。

2.2、多语言支持。

ROS支持许多种不同的语言,例如C++、Python、Octave、LISP、Java,也包含其他语言的多种接口实现。为了支持交叉语言,ROS利用了简单的、语言无关的接口定义语言描述模块之间的消息传送。这种语言无关的消息处理,让多种语言可以自由的混合和匹配使用。

  • 3、ROS代码

3.1、重要概念:节点(node)、消息(message)、话题(topic)、服务(service)。

3.1.1节点nonde

node是一些运算任务的进程,也可以称为软件模块。当许多节点同时运行时,可以很方便的将端对端的通讯绘制成一个图表。在这个图表中,进程是图中的节点,端对端的连接关系就是其中弧线连接。

3.1.2消息message

message可以包含任意的嵌套结构和数组,节点之间通过消息进行通讯。

3.1.3话题topic。

消息message以一种发布/订阅的方式传递,一个节点可以在一个给定主题中发布消息,一个节点针对某个主题关注与订阅特定类型的数据,可能同时有多个节点发布或者订阅同一个主题的消息。发布者和订阅者彼此互不了解。

3.1.4服务service。

用一个字符串和一对严格规范的消息定义:一个用于请求,一个用于回应,类似于web服务器的web服务器是由URIs定义的,同时带有完整定义类型的请求和回复文档。

总结:

节点Node-可执行的最基本单元,用C++和Python来编写,

主题Topics-节点间传输数据的总线,

消息Messages-节点向特定主体发出的信息,

服务Services-用户开发的,直接与节点通信,

管理器ROS Maste-节点之间通信的管理员,提供命名,注册服务,跟踪和记录话题的发布和订阅,提供参数服务器。

在上面概念的基础上,需要有一个控制器可以使所有节点有条不紊的执行,这就是ROS控制器(ROS Master)。ROS Master 通过RPC(Remote Procedure Call Protocol,远程过程调用)提供了登记列表和对其他计算图表的查找。没有控制器,节点将无法找到其他节点,交换消息或调用服务。比如控制节点订阅和发布消息的模型如下:

3.2、文件系统。

指的是在硬盘上面查看的ROS源代码的组织形式,重要概念有包(package)、堆(stack)。

3.2.1包package

package包含节点、ROS依赖库、数据套、配置文件、第三方软件、或者任何其他逻辑构成。ROS软件以包的方式组织,包的目标是提供一种易于使用的结构以便于软件的重复使用。

3.2.2堆stack

stack是包的集合,提供一个完整的功能,例如“navigation stack”。Stack与版本号关联,同时也是如何发行ROS软件方式的关键。例如下图是在包和堆在文件中的具体结构:

stack.xml提供关于Stack元数据,包括它的许可信息和Stack之间依赖关系。manifest.xml提供关于Package元数据,包括它的许可信息和Package之间依赖关系,以及语言特性信息像编译旗帜(编译优化参数)。

  • 4、ROS流程

ROS控制器ROS Master允许节点互相发现和通讯,node就像网络上分布的各台计算机:

比如一台机器人连接一部相机,那么机器人和笔记本电脑都可以发现这个相机node,机器人的相机node负责图像采集,机器人的图像处理node负责后期加工,笔记本的显示node负责显示图像:

相机node先注册到ROS-master,然后通过发布比如/img-data这样的topic,机器人图像处理node和笔记本显示node就都可以订阅img-data这个topic。这样,只要相机node从相机接收到数据,就可以直接发布给另外两个node:

上面是推送的流程,那么可不可以由图像处理node请求时候才传输数据?这可以通过srevice实现。类似于node向ROS-master注册topic,node也可以向master注册service。

这个流程是图像处理node请求数据,相机node收集数据,然后响应reply。

机器人姿态(21):姿态试验(续)

MCU这端增加了pitch/yar/roll角度的计算,PC这端用LabVIEW动画显示姿态。

一、

姿态试验

二、

姿态试验

三、

这里是视频

机器人姿态(19):姿态试验

简单试验系统:MCU采用号称最强51的STC-12c5a,一路串口用于蓝牙数据通信,一个定时器资源获取闭环周期。IMU采用九轴MPU9150,IIC总线。无线透传采用蓝牙4.0的CC2540,工作于从模式。PC端插一块CC2540转串口,工作于主模式。上位软件使用LV,接收数据,绘制波形。框图如下:

试验框图

有五组角度:

试验效果都差不多:

各个角度都差不多

手摇从0~+180度~-180度~+180度~-180度, 红线不知道:

两个周期

静止20来分钟,好像陀螺仪漂移很大,不知道:

长时间漂移

机器人姿态(17):安卓系统重力感应App开发

现在的手机都具有传感器,也基本都有低功耗蓝牙。利用加速度计可以写一些游戏,例如桌面台球等等手机小游戏。再加上蓝牙就可以做一些硬件设备,例如体感控制器,挥挥手就可以控制灯泡鼠标,等等。程序实现上,重力感应比较简单,蓝牙BLE相对复杂。

  • 重力感应

Android从SDK1.5开始就支持重力传感器,也称为加速度传感器。这个传感器可以检测手机姿态,手机反转倾斜程度可以由传感器检测到,类似三轴加速度计MPU-3050。

这个主要包括传感器扫描和一个回调函数:

//变量

private SensorManager sm;
private Sensor sensor;
private SensorEventListener mySensorListener;

//ͨ通过服务得到传感器管理对象
sm = (SensorManager) MainActivity.ma.getSystemService(Service.SENSOR_SERVICE);
sensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);//得到重力传感器实例

mySensorListener = new SensorEventListener() {

public void onSensorChanged(SensorEvent event) {
//传感器获取值发生改变,在此处理
x = event.values[0]; //手机横向翻滚,x>0左翻,x<0右翻
y = event.values[1]; //手机纵向翻滚,y>0后翻,y<0前翻
z = event.values[2]; //屏幕朝向上下,z>0朝上,z<0 朝下

//传感器的精度发生改变时响应此函数
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}

sm.registerListener(mySensorListener, sensor, SensorManager.SENSOR_DELAY_FASTEST);
//第一个参数是传感器监听器,第二个是需要监听的传感实例

以上x/y/z单位是重力加速度m/s^-2。

重力加速度传感器

  • 蓝牙通讯

这个主要包括设备扫描、交互控制、基础服务三部分

  1. 设备扫描

一、设备扫描

private BluetoothManager mBluetoothManager;

private BluetoothAdapter mBluetoothAdapter;
private DeviceListAdapter mDeviceListAdapter;//设备列表

private BluetoothDevice mBluetoothDevice;//设备

  1. 交互控制

//变量
private ExpandableListView mGattServicesList;//服务列表
private BluetoothLeService mBluetoothLeService;//服务

private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics;//特征列表

private BluetoothGattCharacteristic mNotifyCharacteristic;//特征

private final ServiceConnection mServiceConnection = new ServiceConnection() {…

//实例化ServiceConnection接口;重写onServiceConnected和onServiceDisconnected…

public void onServiceConnected(ComponentName componentName, IBinder service){

BluetoothLeService mBluetoothLeService =;//在这初始化这个关键服务类

private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {…

//处理蓝牙服务触发的事件

displayGattServices(mBluetoothLeService.getSupportedGattServices());

displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));

//可以设置一个按钮主动发送字符出去用于测试

mBluetoothLeService.sendSetting();

… …

public void onCreate(Bundle savedInstanceState) {…

Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);//在onCreate()里新建Intent

bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);//并绑定服务

//注意后面需要unbindService

 

protected void onResume() {…

registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());//注册分发事件的receiver,注意后面需要unregisterReceiver

boolean result = mBluetoothLeService.connect(mDeviceAddress);//建立服务

private void displayGattServices(List<BluetoothGattService> gattServices) {//示例

 

List<BluetoothGattService> gattServices;

//服务的gat列表

ArrayList<HashMap<String, String>>
gattServiceData;

//服务的MAP表

 

ArrayList<ArrayList<BluetoothGattCharacteristic>>;//特征的gat列表们

ArrayList<ArrayList<HashMap<String, String>>>
gattCharacteristicData;//特征的MAP表们

 

for (BluetoothGattService gattService : gattServices) {

//对于每项的gat服务

HashMap<String, String> newServiceData;

//对应该项的MAP服务

 

–ArrayList<BluetoothGattCharacteristic> newgattCharas;//特征的gat表们

–ArrayList<HashMap<String, String>> newCharacteristicGroupData;//特征的MAP表们

for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {

  1. 基础服务

//GATT负责BLE连接读写属Profile通用规范。Service是Characteristic的集合,例如一个“Heart Rate Monitor”的service可能包含多个Characteristics,其中一个Characteristic可能叫做“heart rate measurement”。Characteristic为一个数据类型,包括一个value以及零到多个对此value的描述(Descriptor),Descriptor对Characteristic的描述一般例如范围、计量单位等。

//变量

private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;

private BluetoothGatt mBluetoothGatt;

private int mConnectionState = STATE_DISCONNECTED;

//需要注意一些函数调用是异步的,需要得到的值不会立即返回,而会在BluetoothGattCallback的回调函数中返回,例如discoverServices与onServicesDiscovered回调。例如readCharacteristic要在onCharacteristicRead里面。setCharacteristicNotification要在onCharacteristicChanged里面。 writeCharacteristic会到onCharacteristicWrite里面。

//操作的回调函数CB。重写接收到的消息的处理。

private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {

//—1—状态改变

public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

if (newState == BluetoothProfile.STATE_CONNECTED) {

–String intentAction = ACTION_GATT_CONNECTED;

–broadcastUpdate(intentAction);//广播意图,在交互控制里面处理

mBluetoothGatt.discoverServices();//发起活动,在交互控制里面处理

//—2—发现服务

public void onServicesDiscovered(BluetoothGatt gatt, int status) {

broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);//广播意图,在交互控制里面处理

//寻找服务之后,我们就可以和设备进行通信,比如下发配置值,获取设备电量什么的

//—3—读取到值

public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic,int status) {

if (characteristic.getUuid().toString().equals(“00002a19-0000-1000-8000-00805f9b34fb”)){//根据UUID来判断读到的是什么值

broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic););//广播意图,在交互控制里面处理

//—4—收到上报值

public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {

//—5—特征被写

public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status)

{

//根据 characteristic.getValue()来判断是哪个值发送成功了

//比如连接上设备之后有一大串命令需要下发,调用多次写命令, 这样需要判断是不是所有命令都成功了

//操作的主动方法。常规用到的有:connect,discoverServices,disconnect,readCharacteristic,setCharacteristicNotification,getServices

//—1—connect

public boolean connect(final String address) {

mBluetoothGatt = device.connectGatt(this, false, mGattCallback);//连接成功,到回调onConnectionStateChange

//—2—disconnect

public void disconnect() {

//—3—read

public void readCharacteristic(BluetoothGattCharacteristic characteristic) {

mBluetoothGatt.readCharacteristic(characteristic);

//—4—读操作示例

public void readBatrery(){

//—5—写操作示例
public void sendSetting(){

  • 读写示例

//中心设备向外围设备的写入命令字

public void WriteSetting(){
BluetoothGattService sendService
= mBluetoothGatt.getService(UUID.fromString(“0000fff0-0000-1000-8000-00805f9b34fb”));
//此处的0000180f…取决于询问硬件
if(sendService!=null) {
BluetoothGattCharacteristic sendCharacteristic
= sendService.getCharacteristic(UUID.fromString(“0000fff1-0000-1000-8000-00805f9b34fb”));
//此处的0000180f…取决于询问硬件
if(sendCharacteristic!=null) {
sendCharacteristic.setValue //(new byte[] { 0x01,0x02,0x03  });
(new byte[]  {0x24,0x4d,0x3c,} );//命令字
mBluetoothGatt.writeCharacteristic(sendCharacteristic);//写命令到设备,

}

//中心设备向外围设备的读取信息

低功耗蓝牙4.0BLE通讯