用stm32f407ZGT6驱动二自由度云台(舵机)以及舵机安装时的注意事项

写作目的:今天在尝试使用舵机的时候遇到了一点问题,所以想把这些问题记录下来,方便以后再次遇到的时候,可以快速解决,也方便大家遇到的时候可以快速解决。

一.180°的舵机安装

        在安装舵机之前,应该先调试舵机,如果用-90°——90°来表示方向的话,则应该先确定舵机的零度的位置,再进行安装;如果用0°——180°来表示方向的话,则应该确定90°的位置,再进行安装。先确定位置再安装的方法会使舵机的角度就会比较容易调节,或者说比较容易设定。

 二自由度云台(舵机)安装图

/*
周期为20ms 
0.5ms——-90°
1  ms——-45°
1.5ms—— 0°
2  ms—— 45°
2.5ms—— 90°
当高级定时器TIM8周期为20ms时 
arr=200   pcs=16800   
TIM8_Init(200,16800);//5ms
高电平时间  t=(crr/arr)*20ms=crr/10ms
当ccr为10时对应的高电平为1ms
公式推导——线性变化:
令servo_angle=a*t+b  (t以ms为单位)
==>0.5a+b=-90
==>a+b=-45
==>a=90,b=-135
==>servo_angle=90/10*crr-135=9*crr-135 ==>crr=(servo_angle+135)/9
*/
void servo_angle(int yaw_angle,int pitch_angle)
{
   int ccr;
   if(yaw_angle>90) yaw_angle=90;
   else if(yaw_angle<-90) yaw_angle=-90;
   if(pitch_angle>90) pitch_angle=90;
   else if(pitch_angle<-90) pitch_angle=-90;
   TIM8->CCR1=(yaw_angle+135)/9; //(这个安装刚刚好)
   TIM8->CCR2=(pitch_angle+135-50)/9;//(-50)是为了矫正安装误差
}

第一种方式表示代码以及推导过程 

/*
周期为20ms 
0.5ms—— 0°
1  ms——45°
1.5ms——90°
2  ms——135°
2.5ms——180°
当高级定时器TIM8周期为20ms时 
arr=200   pcs=16800   
TIM8_Init(200,16800);//5ms
这样表示更容易理解:
crr=(servo_angle/180)*20+5  (servo_angle/180是一种对应的占比,20对应180最大时的crr,5对应0°时的基数)
当servo_angle=0时    crr=5刚好 t=(crr/arr)*20ms=0.5ms  对应0°
当servo_angle=180时 crr=25刚好 t=(crr/arr)*20ms=2.5ms  对应180°
这样就是一种线性关系
完全正:Servo_SetAngle(90,40);	(因为是刚刚接触,所以没有找到正确的脚度就可以安装,所以存在误差)
pitch_angle越小,越往下(但好像不只是180°)
yaw_angle越小,从上往下看顺时针
*/
void Servo_SetAngle(float yaw_angle,float pitch_angle)
{
	if(yaw_angle>180) yaw_angle=180;
    else if(yaw_angle<0) yaw_angle=0;
    if(pitch_angle>180) pitch_angle=180;
    else if(pitch_angle<0) pitch_angle=0;
	TIM_SetCompare1(TIM8, (yaw_angle * 20/ 180  + 5));
	TIM_SetCompare2(TIM8, (pitch_angle  * 20/ 180 + 5));
}

 第二种方式表示代码以及推导过程 

二.舵机的调试

     舵机的调试比较简单,如果代码没有遗落的话,基本都是可以直接套用就行,但是我在调试的用的是高级定时器TIM8,在调试的时候,就忽略了两个问题,一个是直接用stm32f1芯片的板子时候定时器的引脚是可以直接用的,但是这一次不知道为什么需要先复用引脚PC6,PC7才能正常使用,就因为这两语句废了我两小时;另一个原因是因为我用的是高级定时器TIM8所以需要添加一个语句“TIM_CtrlPWMOutputs(TIM8,ENABLE);//高级定时器输出必须使能这句”,原因可能是(个人的理解):

        在stm32单片机中,高级定时器(Advanced Timer)具有多个输出通道。定时器TIM8有多个PWM输出通道。这些输出通道可以用于控制电机、LED灯等外部设备的电平或电流。

为了使用这些输出通道并使其产生PWM信号,需要通过使能(enable)相关的定时器输出来启动它们的工作。而在stm32单片机中,默认情况下,高级定时器的输出是禁用的,需要通过特定的函数来启用它们。通过调用"TIM_CtrlPWMOutputs(TIM8, ENABLE)"这句代码,将定时器TIM8的PWM输出功能使能。这样,定时器TIM8的输出通道将开始产生PWM信号,以控制外部设备的电平或电流。

  上面这两个问题就是我在调试过程中遇到的问题以及对应问题可能的原因,希望对大家有帮助!

以下是完整的代码:

#include "timer.h"
#include "servo_lhw.h"
int main(void)
{ 
	
    //Delay function initialization
    //延时函数初始化
	delay_init(168);
	TIM8_Init(200-1,16800-1);//20ms

	while(1)
	{		
	   Servo_SetAngle(90,40);	   
	}
}
void TIM8_Init(u16 arr, u16 psc)
{

	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	GPIO_InitTypeDef  GPIO_InitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE);  	//TIM8时钟使能    
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);//使能GPIOC时钟
	GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM8); //GPIOC6复用为定时器8(这句话也要加上去)
	GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_TIM8); //GPIOC7复用为定时器8(这句话也要加上去)
    GPIO_InitStructure.GPIO_Pin =GPIO_Pin_6 |GPIO_Pin_7; //TIM8对应引脚PC6,PC7
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉
    GPIO_Init(GPIOC,&GPIO_InitStructure);              //初始化PC6,7
    
	/*** Initialize timer 8 || 初始化定时器8 ***/
	//Set the counter to automatically reload //设定计数器自动重装值 
	TIM_TimeBaseStructure.TIM_Period = arr; 
	//Pre-divider //预分频器 
	TIM_TimeBaseStructure.TIM_Prescaler = psc; 	
	//Set the clock split: TDTS = Tck_tim //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 
	//TIM up count mode //TIM向上计数模式	
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
	//Initializes the timebase unit for TIMX based on the parameter specified in TIM_TimeBaseInitStruct
	//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure); 
	
	TIM_OCStructInit(&TIM_OCInitStructure);
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;/*PWM模式*/
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;/*输出*/
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;/*比较极性高*/
	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
    TIM_OC1Init(TIM8,&TIM_OCInitStructure); 	
    TIM_OC2Init(TIM8,&TIM_OCInitStructure); 	
    TIM_OC1PreloadConfig(TIM8,TIM_OCPreload_Enable);/*输出比较预装载使能*/
	TIM_OC2PreloadConfig(TIM8,TIM_OCPreload_Enable);/*输出比较预装载使能*/
    	// Advanced timer output must be enabled

	TIM_ARRPreloadConfig(TIM8,ENABLE);/*自动重载预装载使能*/
    TIM_CtrlPWMOutputs(TIM8,ENABLE);//高级定时器输出必须使能这句
	//Enable timer //使能定时器
	TIM_Cmd(TIM8, ENABLE); 		
}
#include "servo_lhw.h"

/*
周期为20ms 
0.5ms——-90°
1  ms——-45°
1.5ms—— -0°
2  ms—— 45°
2.5ms—— 90°
当定时器周期为20ms时 
arr=200   pcs=16800   
TIM8_Init(200,16800);//5ms
高电平时间  t=(crr/arr)*20ms
当ccr为10时对应的高电平为1ms
servo_angle=90/10*crr-135 ==>crr=(servo_angle+135)/9
*/
void servo_angle(int yaw_angle,int pitch_angle)
{
   int ccr;
   if(yaw_angle>90) yaw_angle=90;
   else if(yaw_angle<-90) yaw_angle=-90;
   if(pitch_angle>90) pitch_angle=90;
   else if(pitch_angle<-90) pitch_angle=-90;
   TIM8->CCR1=(yaw_angle+135)/9; //(这个安装刚刚好)
   TIM8->CCR2=(pitch_angle+135-50)/9;//(-50)是为了矫正安装误差
}
/*
周期为20ms 
0.5ms—— 0°
1  ms——45°
1.5ms——90°
2  ms——135°
2.5ms——180°
当定时器周期为20ms时 
arr=200   pcs=16800   
TIM8_Init(200,16800);//5ms
高电平时间  t=(crr/arr)*20ms
当ccr为10时对应的高电平为1ms
servo_angle=90/10*crr-135 ==>crr=(servo_angle+135)/9
完全正:Servo_SetAngle(90,40);	(因为是刚刚接触,所以没有找到正确的脚度就可以安装,所以存在误差)
pitch_angle越小,越往下(但好像不只是180°)
yaw_angle越小,从上往下看顺时针
*/
void Servo_SetAngle(float yaw_angle,float pitch_angle)
{
	if(yaw_angle>180) yaw_angle=180;
    else if(yaw_angle<0) yaw_angle=0;
    if(pitch_angle>180) pitch_angle=180;
    else if(pitch_angle<0) pitch_angle=0;
	TIM_SetCompare1(TIM8, (yaw_angle * 20/ 180  + 5));
	TIM_SetCompare2(TIM8, (pitch_angle  * 20/ 180 + 5));
}

附带stm32引脚图

  • 13
    点赞
  • 117
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
根据提供的引用内容,openmv云台舵机是通过OpenMV加舵机云平台控制的。在代码中,通过接收OpenMV传回的数据来控制云台舵机的运动。具体来说,通过串口通信将信息发送给STM32,然后根据接收到的数据来控制舵机的偏移角度。在接收数据的函数中,根据不同的状态和接收到的数据,将数据存储在openmv数组中,并根据接收到的结束标志进行相应的处理。通过这种方式,实现了对openmv云台舵机的控制。\[1\] 此外,还有一些其他的设置和操作与openmv云台舵机相关。例如,在代码中使用了sensor.set_vflip(True)来进行垂直方向的翻转,以确保在电脑端显示的画面是正常的。这个设置对后续的STM32端代码的书写也有影响。\[3\] 综上所述,openmv云台舵机是通过OpenMV加舵机云平台控制的,通过接收OpenMV传回的数据来控制舵机的运动角度。同,还需要进行一些相关的设置和操作来确保正常的显示和运行。 #### 引用[.reference_title] - *1* *2* [基于OpenMV和正点原子开发的自动追球小车(带云台舵机)](https://blog.csdn.net/qq_54411426/article/details/126656332)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [openmv识别红色物体并返回坐标给stm32单片机,通过pid控制舵机云台](https://blog.csdn.net/qq_52798893/article/details/125852284)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值