两轴舵机云台的一点实践

2023-05-16

两轴舵机云台的一点实践

    • 效果演示
    • 硬件使用情况
    • 定时器中断代码
    • 计算机体系下的云台角代码
    • 舵机控制代码
    • 工程源码下载

简介:
为了学习姿态解算相关知识,最近做了一个作品,模仿炮塔跟随系统,用陀螺仪使两个舵机指向空间中的某一特定方向,实际上用欧拉角旋转矩阵法只完成了功能,然后针对舵机延迟问题做了一个微分控制。但由于欧拉角不能解算全姿态,实际能稳定的角度并不大, 将旋转矩阵换成四元数来表示之后解算结果不对,不知道是小弟哪里弄错了?东西很多纯属瞎扯,望大佬们轻喷。

效果演示

视频: 两轴舵机云台
作品一览

硬件使用情况

陀螺仪:MPU6050 *1
舵机:MG996R *2
主控芯片:STM32F103C8T6 *1

定时器中断代码

这部分代码使用TIM2定时器中断提供100Hz的控制频率,并且针对舵机位置控制延迟的问题,对舵机位置做了一个微分比例补偿控制,提高了响应速度。这部分代码在 main.c 里面。

// 全局变量声明
	float pitch,roll,yaw; 	//欧拉角	
	float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;//四元数
	float hy=0,hp=0;   			//参考系下云台角
	float by,bp,br;         //参考系下姿态角(也就是欧拉角)
	float bhy=0,bhp=0,bhr=0;//机体系下云台角
	float Kd1=10.0;					//舵机1补偿系数	
	float Kd2=10.0;					//舵机2补偿系数	

/********************************************/
//定时器2中断服务程序 周期:10ms  频率:100Hz
void TIM2_IRQHandler(void)   //TIM2中断
{
	static int t=0;
	u8 button;
	float bhylast=0, bhplast=0;	     //机体系下上一时刻的云台角
	float bhyincre=0, bhpincre=0;      //机体系下上一时刻的云台角增量
	float bhycomp = 0, bhrcomp = 0;                 //舵机转角度补偿量,与角速度有关
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)     //检查TIM2更新中断发生与否
	{	 TIM_ClearITPendingBit(TIM2, TIM_IT_Update  );    //清除更新中断标志 	
			
			bhylast=bhy, bhplast=bhp;		   			//记录机体系下上一时刻的云台角
			if(mpu_dmp_get_data(&roll,&pitch,&yaw)==0)   //更新姿态角(由于安装问题实际roll和pitch互换了)
			{ 
				yaw=-yaw, pitch=-pitch, roll=-roll;     //由于安装问题实际yaw,roll,pitch均倒向			
				
				CalHeadDegree();               //利用欧拉角旋转矩阵计算机体系下的云台角:hby,hbp
				
				bhyincre = bhy - bhylast;      //计算云台转动角速度
				bhpincre = bhp - bhplast;    
						
				bhycomp = Kd1*bhyincre;         //计算舵机1补偿量
				bhrcomp = Kd2*bhpincre;  		//计算舵机2补偿量
				
				HeadTurnToXY(bhy+bhycomp ,bhp+bhrcomp);    //进行角度补偿输出
						
				t++;
			  if(t>=10)t=0,	LED0=!LED0;  //每10*10=100ms闪动	
			}	
	}
}

计算机体系下的云台角代码

这个函数将云台在参考坐标系内的指向向量旋转到机体系去,并且化为机体系下的云台角,注释掉的部分是用四元数表示的旋转矩阵,此部分放在 servo.c 里面。


/********************************************/
void CalHeadDegree(void)      //计算机体系下的云台角
{
	const float DEG2RAD = 0.0174533;   //度化弧度因子
	const float RAD2DEG = 57.29578 ;   //弧度化度因子
	float xn=cos(hy*DEG2RAD)*cos(hp*DEG2RAD);   //参考系下的云台指向向量
	float	yn=sin(hy*DEG2RAD)*cos(hp*DEG2RAD);
	float zn=sin(hp*DEG2RAD);           
	float xb,yb,zb,normalizer;  			//机体系下的云台指向向量、模长
	float cby,sby,cbp,sbp,cbr,sbr;       //姿态角的正余弦值
//	printf("xn:%f\tyn:%f\tzn:%f\r\n",xn,yn,zn);

	normalizer = invSqrt(xn*xn + yn*yn +zn*zn);   //求出向量模长的倒数		
	xn *= normalizer;	        //向量单位化
	yn *= normalizer;
	zn *= normalizer;	
	
	bp=pitch,br=roll,by=yaw;				//先算出姿态角的三角值方便计算
	cby=cos(by*DEG2RAD),sby=sin(by*DEG2RAD);       
	cbp=cos(bp*DEG2RAD),sbp=sin(bp*DEG2RAD);
	cbr=cos(br*DEG2RAD),sbr=sin(br*DEG2RAD);
//  printf("yaw:%f\tpitch:%f\troll:%f\r\n",yaw,pitch,roll);
	
	xb =                 cbp*cby*xn                 + cbp*sby*yn      -sbp*zn;//套用欧拉角旋转矩阵公式
	yb = (sbr*sbp*cby - cbr*sby)*xn + (sbr*sbp*sby + cbr*cby)*yn + sbr*cbp*zn;
	zb = (cbr*sbp*cby + sbr*sby)*xn + (cbr*sbp*sby - sbr*cby)*yn + cbr*cbp*zn;
//  printf("xb:%f\tyb:%f\tzb:%f\t",xb,yb,zb);

//	xb = (q0*q0+q1*q1-q2*q2-q3*q3)*xn + 2*(q1*q2-q0*q3)*yn + 2*(q1*q3+q0*q2)*zn;//套用四元数旋转矩阵公式	               
//	yb = 2*(q1*q2+q0*q3)*xn +(q0*q0-q1*q1+q2*q2-q3*q3)*yn + 2*(q2*q3-q0*q1)*zn;   
//	zb = 2*(q1*q3-q0*q2)*xn + 2*(q2*q3+q0*q1) *yn + (q0*q0-q1*q1-q2*q2+q3*q3)*zn;	
//	xb=yb, yb=-xb;
	
	normalizer = invSqrt(xb*xb + yb*yb +zb*zb);   //求出向量模长的倒数		
	xb *= normalizer;	        //向量单位化
	yb *= normalizer;
	zb *= normalizer;	
//  printf("normalizer:%f\r\n",normalizer);
	                                                    //利用几何关系计算机体系下的云台角 
	bhp = asin(zb)*RAD2DEG;          										
	bhy = acos( xb*invSqrt(xb*xb+yb*yb) )*RAD2DEG;		
	bhp = -bhp;									         //加上正负号
	if(yb<0) bhy=-bhy;           
//	printf("bhp:%f\tbhy:%f\r\n",bhp,bhy);
}

舵机控制代码

以下函数用来控制舵机,使它们指向机体系下的一个方向 (hby,hbp)
水平角hby:-90°~90° 俯仰角hbp: 0°~180° ,放在 servo.c 里面。


/********************************************/
/************************************************/
void Servo1RunToDegree(float degree)   //舵机1转到degree角度,degree:-90~90
{
	float pwm;
	if(degree>=-120 && degree<=120){
		pwm = 1.0394*degree + 1848.55;
		TIM_SetCompare2(TIM3,pwm);	//修改比较值,修改占空比
	}
}
void Servo2RunToDegree(float degree)   //舵机2转到degree角度,degree:0~180
{
	float pwm;
	if(degree>=-30 && degree<=210){
		pwm = -1.0306*degree + 1939.10; 
		TIM_SetCompare1(TIM4,pwm);	//修改比较值,修改占空比	
	}
}

/************************************************/
void HeadTurnToXY(float x,float y)       //云台转到水平x,俯仰y位置, x:-90~90, y:0~180
{
		Servo1RunToDegree(x);
	  Servo2RunToDegree(y);
}

工程源码下载

链接:https://pan.baidu.com/s/1f9QcTQm-TCXQcAJTKidhYg
提取码:rggw

参考资料: 四元数姿态解算 (来源网络,侵权请联系我删除,感谢作者整理)

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

两轴舵机云台的一点实践 的相关文章

随机推荐

  • ROS安装包--rqt

    ROS安装包 rqt 安装命令刷新缓存 安装命令 sudo apt get install ros kinetic rqt sudo apt get install ros kinetic rqt common plugins sudo a
  • 【无标题】

    ROS自定义话题传输出现md5sum错误 问题描述 提前从一个程序中使用rosbag record命令对某一话题进行了录制 xff0c 之后用rostopic echo命令确定了录入了信息 但是给另一程序发布的时候 xff0c 终端报错 x
  • 关于CAN标准帧和扩展帧为什么分别占位是11bit和29bit

    关于CAN标准帧和扩展帧为什么分别占位是11bit和29bit 文章目录 关于CAN标准帧和扩展帧为什么分别占位是11bit和29bit前言一 关于标准帧二 关于扩展帧总结写在结尾 前言 之前一直没明白CAN标准帧和扩展帧为什么分别占位是1
  • 旭日x3派个人配置总结(ubuntu server + xrdp)

    旭日x3派基本设置 旭日x3派使用文档 首发 多方位玩转旭日x3派 XRDP 43 Xface4远程桌面设置 安装xrdp并解决闪退 黑屏问题 ROS2 Foxy配置 解决 Failed to connect to raw githubus
  • 思岚S2激光雷达1—初次连接

    1 去官网下载Robostudio xff0c 我这里是windows http www slamtec com robostudio 2 连接激光雷达 3 去官网下载SDK 4 在SDK文件夹里的tools里面找驱动下载驱动 5 电脑成功
  • ZED2双目相机1:标定

    一 下载及安装 xff08 1 xff09 按照下面这个链接 xff1a https blog csdn net TengYun zhang article details 123072847 下载完是这样的 xff1a xff08 2 x
  • ZED2双目相机2:畸变矫正

    1 运行ZED2相机 xff08 注意是在ZED WS工作空间里 xff09 xff08 1 xff09 关闭anconda xff08 如果有的话 xff09 xff1a conda deactivate span class token
  • 用android代码实现一个可以万能播放器

    要实现一个万能播放器需要使用多媒体库 xff0c 可以使用Android自带的MediaPlayer类以及ExoPlayer库 以下是一个简单的示例代码 xff1a 在XML布局文件中添加一个SurfaceView和几个按钮 xff1a s
  • 初出茅庐的小李第108篇博客二进制打印

    二进制打印介绍 C语言在格式化打印的时候有很多格式控制 xff0c 比如十进制打印用 d输出 xff0c 十六进制用 x输出 xff0c 八进制用 o格式输出 xff0c 但是当我们期望看一个数据的二进制的时候就必须借助计算器或者其他比较不
  • QGroundControl 自定义命令小工具的使用

    Custom Command Widgets 不用编译qgc的源码 xff0c 仅仅需要编写一个QML UIs文件这个小工具窗口可以被加载 xff0c 并且从重启之后仍然可以使用 xff0c 而且不受操作系统的限制主要有两个用途 xff11
  • HTTP请求方式GET和POST代码示例

    HTTP请求方式GET和POST代码示例 1 HTTP名词解释1 2 HTTP传输方式1 2 1GET名词解释1 2 1POST名词解释 1 3Http中Post 和Get代码实现 1 HTTP名词解释 HTTP大名叫做超文本传输协议 xf
  • Postman工具常见操作

    Postman常见操作 1 新建GET或POST请求 xff08 1 xff09 打开Postman xff0c 选择File gt New xff08 2 xff09 选择Request xff0c 进入 xff08 3 xff09 输入
  • Ubuntu18.04+ROS melodic 跑通VINS-MONO的一些踩坑记录

    VINS MONO的一些踩坑记录 0 本机环境 笔者的环境为Ubuntu 18 04 43 ros melodic 43 opencv 4 1 1 43 Eigen 3 3 9 43 ceres solver 1 14 跟VINS MONO
  • GPIO库函数开发和寄存器开发的区别

    函数原型为 xff1a void GPIO SetBits GPIO TypeDef GPIOx uint16 t GPIO Pin xff08 1 xff09 gt 箭头操作符要求左操作数必须是个指针GPIO TypeDef GPIOx
  • C++ 编译

    C 43 43 编译原理 参考博客 https www cnblogs com kevinWu7 p 10163443 html C C 43 43 编译就是要将C C 43 43 的代码映射到相应的机器码 xff0c 以及讨论其中的内存管
  • STM32串口中断的方式发送

    我将其改为真正的中断发送 步骤一 xff1a 初始化GPIO GPIO InitTypeDef GPIO InitStructure GPIO InitStructure GPIO Pin 61 GPIO Pin 10 LED1 PC10
  • 什么是大端小端 and 如何判断大端小端

    1 为什么会有大小端模式之分呢 xff1f 这是因为在计算机系统中 xff0c 我们是以字节为单位的 xff0c 每个地址单元都对应着一个字节 xff0c 一个字节为8bit 但是在C语言中除了8bit的char之外 xff0c 还有16b
  • python中串口通信的步骤及实现

    python内置的库函数确实很强大 xff0c serial库中包含了串口通信所用到的一些函数 本文用python实现了串口的一种简单通信 代码实现 xff1a span class token keyword import span se
  • 结构体作用(STM32)

    结构体作用 xff08 STM32 xff09 来源 xff1a 正点原子 MDK 中很多地方使用结构体以及结构体指针 xff0c 下面总结一下其使用结构体的主要作用 1 结构体是将不同的数据类型整合为一个有机整体 xff0c 方便数据管理
  • 两轴舵机云台的一点实践

    两轴舵机云台的一点实践 效果演示硬件使用情况定时器中断代码计算机体系下的云台角代码舵机控制代码工程源码下载 简介 xff1a 为了学习姿态解算相关知识 xff0c 最近做了一个作品 xff0c 模仿炮塔跟随系统 xff0c 用陀螺仪使两个舵