模块学习2:基于PELCO-D协议对云台进行定点控制

2023-05-16

开发手上的一个云台,使用的就是PELCO-D协议。这个协议开始网上找了一圈,发现下载完整版的协议大多是还都要收费,后面在官方下载了一份原版完整版协议的协议内容,配合网上搜索到的资料完成对手上这块云台的配置。 虽然原版的协议支持很多功能,包括摄像头的一些控制,这当然与具体的产品有关,手上的这款只是对云台的控制,包括复位,预置设置,调用和删除等一些基础的功能。
由于最终是要结合手上的串口摄像机,完成定时定点进行拍照的功能,所以这里先写云台的功能函数,下面写摄像头模块时再一起结合。

先来简单了解一下协议本身。

PELCO-D:

数据格式: 1 位起始位、 8 位数据、 1 位停止位,无效验位。波特率: 9600B/S(根据本身改变);
命令格式:

字节 1字节 2字节 3字节 4字节 5字节 6字节 7
同步字节地址码指令码 1指令码 2数据码 1数据码 2校验码

说明
1.该协议中所有数值都为十六进制数;
2.同步字节始终为 FFH ;
3.地址码为摄像机的逻辑地址号,地址范围: 00H –FFH ;
4.指令码表示不同的动作;
5.数据码 1、2 分别表示水平、垂直方向速度( 00-3FH ),FFH 表示 “turbo ”速度;
6.校验码 = MOD[ (字节 2 + 字节 3 + 字节 4 + 字节 5 + 字节 6)/100H]。

指令码格式:

Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0
命令字 1Sence码00自动 /手动扫描摄像机打开/关闭光圈关闭光圈打开焦距拉近
命令字 2焦距拉远视角变宽视角变窄0

说明
Sence 码:与 Bit4 和 Bit3 有关。在 Bit4 和 Bit3 为 1 的情况下,如果 Sence 码为 1,则命令就是自动扫描和和摄像机打开;如果 Sence 码为 0,则命令就是手动扫描和摄像机关闭。当然如果Bit4 或 Bit3 为 0 的话那命令就无效了;
数据 1: 表示镜头左右平移的速度,数值从 $00( 停止 )到$3F( 高速 ),另外还有一个值是 $FF ,表示最高速;
数据 2: 表示镜头上下移动的速度,数值从 $00( 停止 )到$3F( 最高速 );
校验码:指 Byte2 到 Byte6 这 5 个数的和 (若超过 255 则除以 256 然后取余数 )。

以上就是PELCO-D协议的大致内容,如果是PELCO-P协议可以参考文末的文档做出相应的修改即可。

下面列出几组参考用例
以地址码 0x01 为例:
{0xff,0x01,0x00,0x08,0x00,0xff,0x08,}// 上
{0xff,0x01,0x00,0x10,0x00,0xff,0x10,}// 下
{0xff,0x01,0x00,0x04,0xff,0x00,0x04,}// 左
{0xff,0x01,0x00,0x02,0xff,0x00,0x02,}// 右
{0xff,0x01,0x00,0x07,0x00,0x01,0x09,}// 转至预置点 001 
{0xff,0x01,0x00,0x03,0x00,0x01,0x05,}// 设置预置点 001 
{0xff,0x01,0x00,0x05,0x00,0x01,0x07,}// 删除预置点 001 
//以下几组我使用的云台没有功能,仅做参考。
{0xff,0x01,0x00,0x20,0x00,0x00,0x21,}// 变倍短
{0xff,0x01,0x00,0x40,0x00,0x00,0x41,}// 变倍长
{0xff,0x01,0x00,0x80,0x00,0x00,0x81,}// 聚焦近
{0xff,0x01,0x01,0x00,0x00,0x00,0x02,}// 聚焦远
{0xff,0x01,0x02,0x00,0x00,0x00,0x03,}// 光圈小
{0xff,0x01,0x04,0x00,0x00,0x00,0x05,}// 光圈大
{0xff,0x01,0x00,0x0b,0x00,0x01,0x0d,}// 灯光关
{0xff,0x01,0x00,0x09,0x00,0x01,0x0b,}// 灯光开

以上对应的停命令均是 : 
{0xff,0x01,0x00,0x00,0x00,0x00,0x01,}// 停命令

下面是各个封装的功能函数。

返回校验和

/********************************************************************
名称:uint16_t  ADD8_Check(uint8_t *num_Data,uint16_t num_Size)
功能:返回校验和
输入:校验数组,校验长度
输出:校验值
作者:liuguizhou
**********************************************************************/
uint16_t  ADD8_Check(uint8_t *num_Data,uint16_t num_Size){
	uint16_t i;
	uint16_t data_sum=0;
	for(i=1; i<num_Size; i++){
		data_sum += num_Data[i];
	}
	data_sum = (data_sum%256)&0xFF;	
	return data_sum;
}

复位功能

这个复位功能需要参考完整版协议,上面没有提到。
可以参考这篇博客,有个别功能的讲解。
协议要点整理

/********************************************************************
名称:void PTZ_rest()
功能:云台复位
输入:无
输出:无
作者:liuguizhou
**********************************************************************/
void PTZ_rest(void)
{
	uint16_t num=0;
	uint8_t check_num = 0;
	PTZ_TX_BUF[num++]=Sync_byte;
	PTZ_TX_BUF[num++]=PTZ_addres; 	//PTZ地址码
	PTZ_TX_BUF[num++]=0x00; 				//command1
	PTZ_TX_BUF[num++]=0x33;					//command2
	PTZ_TX_BUF[num++]=REST_level_speed; 
	PTZ_TX_BUF[num++]=REST_pitch_speed; 
	check_num = ADD8_Check(PTZ_TX_BUF,num);
	PTZ_TX_BUF[num++]=check_num; 
	PTZ_Send_String(PTZ_TX_BUF, num);
}

云台停止移动

/********************************************************************
名称:void PTZ_stop()
功能:云台停止移动
输入:无
输出:无
作者:liuguizhou
**********************************************************************/
void PTZ_stop(void)
{
	uint16_t num=0;
	uint8_t check_num = 0;
	PTZ_TX_BUF[num++]=Sync_byte;
	PTZ_TX_BUF[num++]=PTZ_addres; 	//PTZ地址码
	PTZ_TX_BUF[num++]=0x00; 				//command1
	PTZ_TX_BUF[num++]=0x00;			//command2
	PTZ_TX_BUF[num++]=0x00; 				//level_speed
	PTZ_TX_BUF[num++]=0x00; 		//pitch_speed
	check_num = ADD8_Check(PTZ_TX_BUF,num);
	PTZ_TX_BUF[num++]=check_num; 
	PTZ_Send_String(PTZ_TX_BUF, num);
}

云台上下移动

/********************************************************************
名称:void PTZ_up_down(uint8_t command2)
功能:云台上下移动
输入:功能码2
输出:无
作者:liuguizhou
**********************************************************************/
void PTZ_up_down(uint8_t command2)
{
	uint16_t num=0;
	uint8_t check_num = 0;
	PTZ_TX_BUF[num++]=Sync_byte;
	PTZ_TX_BUF[num++]=PTZ_addres; 	//PTZ地址码
	PTZ_TX_BUF[num++]=0x00; 				//command1
	PTZ_TX_BUF[num++]=command2;			//command2
	PTZ_TX_BUF[num++]=0x00; 				//level_speed
	PTZ_TX_BUF[num++]=PTZ_speed; 		//pitch_speed
	check_num = ADD8_Check(PTZ_TX_BUF,num);
	PTZ_TX_BUF[num++]=check_num; 
	

云台左右移动

/********************************************************************
名称:void PTZ_left_right(uint8_t command2)
功能:云台左右移动
输入:功能码2
输出:无
作者:liuguizhou
**********************************************************************/
void PTZ_left_right(uint8_t command2)
{
	uint16_t num=0;
	uint8_t check_num = 0;
	PTZ_TX_BUF[num++]=Sync_byte;
	PTZ_TX_BUF[num++]=PTZ_addres; 	//PTZ地址码
	PTZ_TX_BUF[num++]=0x00; 				//command1
	PTZ_TX_BUF[num++]=command2;			//command2
	PTZ_TX_BUF[num++]=PTZ_speed; 				//level_speed
	PTZ_TX_BUF[num++]=0x00; 		//pitch_speed
	check_num = ADD8_Check(PTZ_TX_BUF,num);
	PTZ_TX_BUF[num++]=check_num; 
	PTZ_Send_String(PTZ_TX_BUF, num);
}

云台预置点的设置、调用和删除

/********************************************************************
名称:void PTZ_Set_preset_point(uint8_t command2, uint8_t serial_num)
功能:云台设置预置点
输入:功能码2, 预置点参数
输出:无
作者:liuguizhou
**********************************************************************/
void PTZ_Set_preset_point(uint8_t command2, uint8_t serial_num)
{
	uint16_t num=0;
	uint8_t check_num = 0;
	PTZ_TX_BUF[num++]=Sync_byte;
	PTZ_TX_BUF[num++]=PTZ_addres; 	//PTZ地址码
	PTZ_TX_BUF[num++]=0x00; 				//command1
	PTZ_TX_BUF[num++]=command2;			//command2
	PTZ_TX_BUF[num++]=0x00; 				
	PTZ_TX_BUF[num++]=serial_num; 		
	check_num = ADD8_Check(PTZ_TX_BUF,num);
	PTZ_TX_BUF[num++]=check_num; 
	PTZ_Send_String(PTZ_TX_BUF, num);
}

/********************************************************************
名称:void PTZ_Delete_preset_point(uint8_t command2, uint8_t serial_num)
功能:云台删除预置点
输入:功能码2, 预置点参数
输出:无
作者:liuguizhou
**********************************************************************/
void PTZ_Delete_preset_point(uint8_t command2, uint8_t serial_num)
{
	uint16_t num=0;
	uint8_t check_num = 0;
	PTZ_TX_BUF[num++]=Sync_byte;
	PTZ_TX_BUF[num++]=PTZ_addres; 	//PTZ地址码
	PTZ_TX_BUF[num++]=0x00; 				//command1
	PTZ_TX_BUF[num++]=command2;			//command2
	PTZ_TX_BUF[num++]=0x00; 				
	PTZ_TX_BUF[num++]=serial_num; 		
	check_num = ADD8_Check(PTZ_TX_BUF,num);
	PTZ_TX_BUF[num++]=check_num; 
	PTZ_Send_String(PTZ_TX_BUF, num);
}


/********************************************************************
名称:void PTZ_Delete_preset_point(uint8_t command2, uint8_t serial_num)
功能:云台调用预置点
输入:功能码2, 预置点参数
输出:无
作者:liuguizhou
**********************************************************************/
void PTZ_Call_preset_point(uint8_t command2, uint8_t serial_num)
{
	uint16_t num=0;
	uint8_t check_num = 0;
	PTZ_TX_BUF[num++]=Sync_byte;
	PTZ_TX_BUF[num++]=PTZ_addres; 	//PTZ地址码
	PTZ_TX_BUF[num++]=0x00; 				//command1
	PTZ_TX_BUF[num++]=command2;			//command2
	PTZ_TX_BUF[num++]=0x00; 				
	PTZ_TX_BUF[num++]=serial_num; 
	check_num = ADD8_Check(PTZ_TX_BUF,num);
	PTZ_TX_BUF[num++]=check_num; 
	PTZ_Send_String(PTZ_TX_BUF, num);
}

以上就是最基础的云台控制功能,下面就要实现跑点的操作。这个云台本身无法获取当前位置的信息,所以只有采取发送移动指令,运行一段时间,停止指令。但是每次这样通过时间控制,难免会出现空转,卡转等一些情况,所以还是采取先设置预置点,再依次跑预置点的方案。这样子会更准确一些,其实这里可以看到,预置点就是记录位置信息,所以肯定是可以获取位置信息的,而且通过查看协议,也可以看到有获取位置信息的功能码,不过经过测试,我手上这款云台并不支持这个功能。

/********************************************************************
/********************************************************************
名称:void PTZ_Init(void)
功能:云台第一次初始化
输入:无
输出:无
作者:liuguizhou
**********************************************************************/
void PTZ_Init(void)
{
	if(PTZ_Init_flag == 1){
		if(preset_point_count == 0){
			PTZ_move_left_right(left,14);
			if(set_Preset_point_success_flag == 1){
				set_Preset_point_success_flag = 0;
				Preset_point = ((Preset_point)%256)&0xff;
				PTZ_Set_preset_point(Set_preset_point, Preset_point);
				stop_timer_flag = 1;
				Timer_Start(ETIM1);
				feed_dogs();
				}
			}
		if((preset_point_count >= 1 && preset_point_count < 3) || (preset_point_count > 6 && preset_point_count < 9)){
			PTZ_move_left_right(left,76);
			if(set_Preset_point_success_flag == 1){
				set_Preset_point_success_flag = 0;
				Preset_point = ((Preset_point+1)%256)&0xff;
				PTZ_Set_preset_point(Set_preset_point, Preset_point);
				stop_timer_flag = 1;
				Timer_Start(ETIM1);
				feed_dogs();
			}
		}
		if(preset_point_count == 3 || preset_point_count == 6){
			PTZ_move_up_down(down, 35);
			if(set_Preset_point_success_flag == 1){
				set_Preset_point_success_flag = 0;
				Preset_point = ((Preset_point+1)%256)&0xff;
				PTZ_Set_preset_point(Set_preset_point, Preset_point);
				stop_timer_flag = 1;
				Timer_Start(ETIM1);
				feed_dogs();
			}
		}	
		if(preset_point_count > 3 && preset_point_count < 6){
			PTZ_move_left_right(right, 76);
			if(set_Preset_point_success_flag == 1){
				set_Preset_point_success_flag = 0;
				Preset_point = ((Preset_point+1)%256)&0xff;
				PTZ_Set_preset_point(Set_preset_point, Preset_point);
				stop_timer_flag = 1;
				Timer_Start(ETIM1);
				feed_dogs();
			}
		}
	}
}



名称:void PTZ_move_left_right(uint8_t command2,uint16_t move_time)
功能:云台左右移动
输入:功能码2, 移动时间
输出:无
作者:liuguizhou
**********************************************************************/
void PTZ_move_left_right(uint8_t command2,uint16_t move_time)
{
	if(preset_point_count < 9){
		if(move_success_flag == 1){
			PTZ_left_right(command2);
			move_timer_flag = 1;
			Timer_Start(ETIM2);
			move_success_flag = 0;
			feed_dogs();
		}
		if(move_timer_count >= move_time){
			Timer_Close(ETIM2);
			move_timer_count = 0;
			stop_success_flag = 1;
			feed_dogs();
			}
		
		if(stop_success_flag == 1){
			set_Preset_point_success_flag = 1;
			printf("set_Preset_point_success_flag\r\n");
			PTZ_stop();
			stop_success_flag = 0;
			feed_dogs();
		}
		if(stop_timer_count >= 20){
			Timer_Close(ETIM1);
			stop_timer_count = 0;
			stop_timer_flag = 0;
			move_success_flag = 1;
			preset_point_count++;
			printf("preset_point_count+++ = %d \r\n", preset_point_count);
			feed_dogs();
		}
	}
}

/********************************************************************
名称:void PTZ_move_up_down(uint8_t command2, uint16_t move_time)
功能:云台上下移动
输入:功能码2,移动时间
输出:无
作者:liuguizhou
**********************************************************************/
void PTZ_move_up_down(uint8_t command2, uint16_t move_time)
{
	if(preset_point_count < 9){
		if(move_success_flag == 1){
			move_timer_flag = 1;
			Timer_Start(ETIM2);
			PTZ_up_down(command2);
			move_success_flag = 0;
			feed_dogs();
		}
		if(move_timer_count == move_time){
			move_timer_count = 0;
			Timer_Close(ETIM2);
			stop_success_flag = 1;
			feed_dogs();
			}
		
		if(stop_success_flag == 1){
			set_Preset_point_success_flag = 1;
			PTZ_stop();
			stop_success_flag = 0;
			feed_dogs();
		}
		if(stop_timer_count == 20){
			Timer_Close(ETIM1);
			stop_timer_count = 0;
			stop_timer_flag = 0;
			move_success_flag = 1;
			preset_point_count++;
			printf("preset_point_count--- = %d \r\n", preset_point_count);
			feed_dogs();
		}
	}
}

这就完成了云台定点移动的基本功能,之前找资料下载了一个相对比较完整的小程序,我一起打包上传到资源中,有需要自取。
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

模块学习2:基于PELCO-D协议对云台进行定点控制 的相关文章

  • docker容器webui界面之portainer

    docker通常下都是命令行管理 xff0c 不太方便 xff0c web管理能直观一点 xff0c 如果是公司有运维组 xff0c ssh账号也不用给到开发这边 单机安装命令 docker run d p 19000 9000 name
  • Windows 10安装ubuntu18.04双系统(bios和boot manager)

    1 按照网上教程制作系统盘 xff1b 2 在windows下创建空白区 xff0c 为ubuntu分配空间 xff1b 3 用做好的系统盘安装系统 由于各个厂商计算机的bios和boot manager启动键不同 xff0c 自行百度 本
  • OpenCv入门(三)——阈值化处理

    目录 0x01 OTSU 0X02 固定阈值化 0x03 自适应阈值化 0x04 双阈值化 0x05 半阈值化 在图像处理中 xff0c 处理灰度图像的计算量要小于处理彩色图像 xff0c 而二值化图像 xff08 只含灰度值0或1 xff
  • 运行gazebo时出现[Err] [REST.cc:205] Error in REST request

    出现错误 xff1a Err REST cc 205 Error in REST request libcurl 51 SSL no alternative certificate subject name matches target h
  • 安装双系统ubuntu18.04后,不能进入ubuntu界面的解决办法

    某天晚上电脑自动升级了bios xff0c 作为新手小白此时还没有意识到问题 第二天开机发现电脑不仅不能进去ubuntu xff0c 连bios都进不去了 多次开机关机重复后 xff0c 灵机一动改成重启 xff0c 终于有进入bios的界
  • Python中集合的使用

    1 set add xff09 xff1a 向集合中添加元素 xff0c 是整体添加进集合set中 xff1b set update 向集合中添加元素 xff0c update是将字符串中的拆分成字符进行追加 xff1b eg s1 61
  • Resource not found问题

    在运行ros中的xacro文件时出现的如下问题 resource not found mbot description ROS path 0 61 opt ros melodic share ros ROS path 1 61 opt ro
  • 启动Moveit Setup Assistant出错

    1 首先安装moveit配置助手 xff0c 我的ubuntu版本是18 04 xff0c 所以运行 xff1a sudo apt get install ros melodic moveit 填写个人密码安装 source opt ros
  • 形参如何改变实参

    把实参数组传递给函数 xff0c 则形参从数组那里得到了起始地址 xff0c 因此数组与实参数组共占了同一段内存单元 xff0c 在函数调用期间 xff0c 该变了形参数组的值 xff0c 也就改变了实参数组的值 例 xff1a int i
  • Linux下ARM 和单片机的串口通信设计

    摘要 xff1a 介绍Linux 环境下串口通信的设计方法和步骤 xff0c 并介绍了ARM9 微处理器s3c2440 在Linux 下和C8051Fxxx 系列单片机进行串行通信的设计方法 xff0c 给出了硬件连接和通信程序流程图 该方
  • AT+CSQ信号质量指示含义

    AT 43 CSQ 命令解释 xff1a 检查网络信号强度和SIM卡情况 命令格式 xff1a AT 43 CSQ lt CR gt 命令返回 xff1a AT 43 CSQ lt rssi gt lt ber gt 其中 lt rssi
  • MIPI接口和DVP接口的区别及优点

    DVP是并口 xff0c 需要PCLK VSYNC HSYNC D 0 xff1a 11 可以是8 10 12bit数据 xff0c 看ISP或baseband是否支持 xff1b MIPI是LVDS xff0c 低压差分串口 只需要要CL
  • 立体耳机插头和四极耳机插头三段、四段处的区别

    立体 耳机插头 和四极 耳机插头 三段 四段处的区别 在日常生活中 xff0c 通常较为细心的消费者就会发现 xff0c 适用于NOKIA手机的 耳机插头 和适用于iphone的 耳机插头 是互补兼容的 xff0c 但是iphone HTC
  • Nuttx学习笔记(一)

    最近在工作上需要用到这个nuttx实时操作系统 xff0c 并且对这个系统进行学习记录以及记录下自己所遇到过的问题 目录 一 环境配置 xff08 1 xff09 基础环境 xff08 2 xff09 下载nuttx xff08 3 xff
  • kernel command line 参数详解

    Linux内核在启动的时候 xff0c 能接收某些命令行选项或启动时参数 当内核不能识别某些硬件进而不能设置硬件参数或者为了避免内核更改某些参数的值 xff0c 可以通过这种方式手动将这些参数传递给内核 如果不使用启动管理器 xff0c 比
  • Internal error: Oops:

    01 02 00 02 24 110 SysRq Emergency Remount R O 01 02 00 02 24 221 mdss fb release all unknown process adbd pid 61 415 mf
  • /proc/meminfo详解

    cat proc meminfo MemTotal 2052440 kB 总内存 MemFree 50004 kB 空闲内存 Buffers 19976 kB 给文件的缓冲大小 Cached 436412 kB 高速缓冲存储器 http b
  • 浅谈Camera工作原理

    一 摄像头简介 摄像头 xff08 CAMERA xff09 又称为电脑相机 电脑眼等 xff0c 它作为一种视频输入设备 xff0c 在过去被广泛的运用于视频会议 远程医疗及实时监控等方面 近年以来 xff0c 随着互联网技术的发展 xf
  • EVT、DVT、PVT、MP等简介

    PLM xff08 Product Lifecycle Management xff09 System xff1a PLM是协助产品能够顺利完成在新产品开发 xff08 NPI xff1a New Product Introduction
  • UbuntuServer 12.04 svn服务的创建

    以下是我整理后的步骤 xff1a 1 安装必要的软件包 xff1a sudo apt get install subversion sudo apt get install libapache2 svn 2 创建一个SVN账号和SVN组 x

随机推荐