赞
踩
转载自:https://blog.csdn.net/subfate/article/details/36644419
李迟 2014-07-03 13:50:49 6272 收藏 10
版权
在搞visca的同时顺便也搞了pelco。这里再做个笔记。
pelco,中文翻译为“派尔高”,在行文和写代码过程,写pelco比写“派尔高”快很多,所以一般就写pelco。这个协议在云台控制中用得比较多,比较出名的有PTZ,用rs232或rs485来通信。pelco有两种协议,D协议和P协议,两者命令封装不太一样,网上有协议的说明文档,也有实现的代码,我找到一个C#写的,某搜索引擎上找得到的介绍派尔高协议的,基本上都是直接把每个命令的数据一一写成数组来调用,个人认为这样不太方便。
本文所讲的是pelco D协议。
一、命令格式
文档中说pelco D协议的命令都是7个字节的(实际上,有些不是),命令格式如下图:
说明:
字节1:D协议同步头为0xFF。
字节2:相机编号(或称地址),范围为1~0xFF,0x01表示相机1。
字节3:CMND1,命令1。
字节4:CMND2,命令2。作为扩展命令,命令数值为奇数。
字节5:数据字节1,作为motion命令,其表示pan的速度。
字节6:数据字节2,作为motion命令,其表示tilt的速度。
字节7:检验码,计算公式:(字节2+字节3+字节4+字节5+字节6)% 0x100。注:检验码是除了同步头及本身(CKSM)字节外的所有字节的的和,再除以265,取余数(用“%”即可)。
命令共2大类,motion命令,和非motion命令(注:可以称为基本命令和扩展命令/高级命令)。其中motion命令,在CMND2中Bit0始终为0。反之,该比特为1表示非motion命令。
motion命令包含了水平移动、垂直移动、光圈、变焦、对焦等功能。这类命令是由命令1和命令2的各个位来表示的。如下图:
要实现某一项功能,只要在对应的位置设为1即可,有些命令是可以同时设置的,但有些是不行的,比如,可以同时实现左(右)转和向上(下)转动,但不能同时左转及右转(两者是互斥的)。
Bit7含义为“sense bit”(sense一词,在linux内核中使用比较多,我其实也搞不明白这个词中文该怎么表达),它决定了Bit4和Bit3的含义。如下图所示:
其实说白了,就是这3个比特的哪些组合可以控制相机上断电,自动扫描,哪些无效,等等。说到这里,想起来了公司某部门发的一个邮件,说某客户想接入云台,是用派尔高协议来控制的,然后还顺带一个中文的协议文档,这个文档翻译得不伦不类,应该是机器翻译的,把“sense bit”翻译成“感觉字节”,一开始看中文文档时,完全一头雾水,后面经过努力,上网上查了英文原版,才有点理解。所以,有时候,看英文原版获取的资源更通俗,更准确。
二、响应
相机返回的响应包有4种,0字节、4字节、7字节、18字节。除了第一种外,其它每种都和上面给出的命令格式相似,同步头+相机地址+信息体+检验码。文档中有每种响应包的具体格式的描述,如果格式来解析即可得到想要的数据。文档中说大部分命令是有返回值的——像上面的motion命令,也有响应包,但我实际测试的结果,串口是没有返回什么数据的,或者是我拿到的那个东西本身就是这样的。
三、协议文档备注
协议文档中每条命令都讲得比较细,不过,有部分命令是厂家自己实现的,比如,有些命令超过7个字节,这跟协议上讲的有冲突,但实际上却是可以的。这个主要是看厂家提供的协议文档了。说到这,不得不提现在我接手的这个任务,厂家提供的文档惜墨如金,不肯多写一点字,文档又不规范,东写一点,西写一点,给的文档也不全,有些命令还要问人家才知道。
四、实现
为了方便,专门为pelco通信定义了PELCOPacket_t结构体(其实它和上一篇文章的visca那个结构体是同一个东西),命令封装如下:
- void _pelco_append_byte(PELCOPacket_t *packet, unsigned char byte)
- {
- packet->bytes[packet->length]=byte;
- (packet->length)++;
- }
-
- void _pelco_init_packet(PELCOPacket_t *packet)
- {
- // set it to null
- memset(packet->bytes, '\0', sizeof(packet->bytes));
- // we start writing at byte 2, the first byte and the second will be filled by the
- // packet sending function(_pelco_send_packet). This function will also append a cksm.
- packet->length = 2;
- }
注意,初始化时,命令包的长度是2,因为pelco协议的真正数据是从第2个字节开始的,这让调用者关注的是真正的数据,而不用理会同步头、相机地址等信息。命令发送如下:
- // All commands are 7 bytes long in D Protocol
- int _pelco_send_packet(PELCOInterface_t *iface, PELCOPacket_t *packet)
- {
- int cksm = 0;
- int i = 0;
-
- // check data:
- if (iface->address>0xff)
- {
- return PELCO_FAILURE;
- }
-
- // build header:
- packet->bytes[0] = 0xff;
- packet->bytes[1] = iface->address;
-
- // see spec, some cmd has 7 bytes, some has 9 bytes
- for (i = 0; i < packet->length; i++)
- {
- cksm += packet->bytes[1+i];
- }
- cksm = cksm % 0x100;
-
- /*
- cksm = (packet->bytes[1] + packet->bytes[2] + packet->bytes[3] +
- packet->bytes[4] + packet->bytes[5]) % 0x100;
- */
- // append footer(cksm)
- _pelco_append_byte(packet,cksm);
-
- return _pelco_write_packet_data(iface,packet);
-
-
- }
因为有些命令不只有7个字节,所以这里用for循环计算每个需要计算的字节,而不是指定哪一些字节被计算。
命令的封装接口比较简单,基本上和visca一样,比如,像stop命令,就是所有的信息体都搞成0就行了。
- int pelco_camera_stop(PELCOInterface_t *iface)
- {
- PELCOPacket_t packet;
-
- _pelco_init_packet(&packet);
- _pelco_append_byte(&packet,0x00);
- _pelco_append_byte(&packet,0x00);
- _pelco_append_byte(&packet,0x00);
- _pelco_append_byte(&packet,0x00);
-
- return _pelco_send_packet_no_reply(iface, &packet);
- }
参考资源:
1、一个C#实现的工程:http://www.codeproject.com/Articles/8034/Pelco-P-and-D-protocol-implementation-in-C
2、一个图文并茂的示例:http://www.commfront.com/RS232_Examples/CCTV/Pelco_D_Pelco_P_Examples_Tutorial.HTM
后记:本文出现很多次“搞”,近来的确是东搞西搞,人在公司,身不由己。本文仅对协议进行描述,不贴出实际的实现代码。
李迟记于2014年7月3日
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。