unity3d 摄像机跟随角色时 画面抽搐问题

本文探讨了在Unity中,摄像机update与fixedUpdate频率不同步以及是否使用插值对摄像机和角色移动时画面稳定性的影响。实验结果显示,未进行插值处理时,摄像机高速移动会导致画面抽搐;而角色更新频率与摄像机不一致也会引起跑步时的抽搐现象。解决方案包括采用插值平滑移动和确保更新频率同步。

//摄像机update频率更新情况下

position rotation 结果
不插值 插值 摄像机高速移动抽搐
插值 插值 角色跑步抽搐
不插值 不插值 摄像机高速移动抽搐
插值 不插值 角色跑步抽搐 且 摄像机高速移动抽搐(不明显)

//摄像机fixedupdate频率更新情况下

position rotation 结果
不插值 插值 摄像机高速移动抽搐(不明显)
插值 插值 正常
不插值 不插值 摄像机高速移动抽搐
插值 不插值 摄像机高速移动抽搐

总结
rotation和position未插值 导致摄像机高速移动导致画面抽搐(推测由于鼠标不是匀速运动引起的)
角色刚体更新频率和摄像机更新频率不一致(摄像机update更新,角色刚体fixedupdate更新,频率不一致,角色更新速度一次,摄像机可能更新位置一次或者多次) 导致角色跑步画面抽搐

附测试代码

摄像机

public class CameraController : MonoBehaviour
{
   
   
    public GameObject _lookAt;
    public float _distance;
    public float _mouseSensitivity;
    public float _height;
    public bool isNeedPosDamping;
    public bool isNeedRotateDamping;
    public float _moveDamping = 2.5f;
    public float _rotateDamping = 2.5f;
    private const float MINRX=-2f;
    private const float MAXRX=89f;

    private Vector3 _camForward
    {
   
   
        get => transform.forward;
    }
    public Vector3 _camUp{
   
    get; private set; }
    public Vector3
### STM32F103C8 舵机初始化抽搐问题的原因及解决方案 舵机在使用STM32F103C8初始化出现抽搐问题,通常与PWM信号的周期、占空比设置不准确或系统配置不稳定有关。以下是详细分析和解决方案。 #### 1. 原因分析 - **PWM信号周期不准确**:舵机通常需要一个固定周期的PWM信号(如20ms),如果周期不稳定或超出范围,可能导致舵机抽搐[^1]。 - **占空比抖动**:舵机的控制依赖于PWM信号的占空比(通常为0.5ms至2.5ms)。如果占空比在初始化阶段频繁变化或超出有效范围,可能会导致舵机无法稳定定位[^1]。 - **定器配置错误**:如果定器的分频系数(Prescaler)、自动重载值(ARR)或捕获/比较寄存器(CCR)设置不当,可能导致PWM信号频率或占空比偏离预期[^1]。 - **系统钟不稳定**:如果系统钟配置不正确或受到干扰,可能影响定器的工作精度,从而导致PWM信号异常[^1]。 - **外部干扰**:电源噪声或电磁干扰也可能导致PWM信号失真,进而引发舵机抽搐[^1]。 #### 2. 解决方案 ##### (1)确保PWM信号周期准确 舵机通常要求PWM信号周期为20ms。可以通过以下公式计算定器参数: - 分频系数(Prescaler):\( \text{Prescaler} = \frac{\text{SystemCoreClock}}{\text{目标计数频率}} - 1 \)。 - 自动重载值(ARR):\( \text{ARR} = \text{目标周期} \times \text{计数频率} - 1 \)。 示例代码如下: ```c uint16_t Prescaler = (uint16_t)((SystemCoreClock / 1000000) - 1); // 设置分频系数为1us uint16_t ARR = 20000 - 1; // 周期为20ms,对应20000个计数周期 ``` ##### (2)稳定占空比输出 舵机的占空比应保持在0.5ms至2.5ms范围内。可以通过调整捕获/比较寄存器(CCR)实现精确控制。例如,设置1ms脉宽的代码如下: ```c TIM_OCInitStruct.TIM_Pulse = 1000; // 脉宽为1ms,对应1000个计数周期 ``` ##### (3)优化定器配置 确保定器模式配置正确,例如选择向上计数模式(TIM_CounterMode_Up)并使能自动重载预装载(TIM_ARRPreload_Enable)。这有助于提高PWM信号的稳定性。 示例代码如下: ```c TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; TIM_ARRPreloadConfig(TIM2, ENABLE); ``` ##### (4)检查系统钟 确保系统钟配置正确且稳定。例如,使用HSE(外部高速晶振)作为系统钟源,并通过PLL倍频至72MHz。 示例代码如下: ```c RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; // PLL * 9 = 72MHz HAL_RCC_OscConfig(&RCC_OscInitStruct); RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2); ``` ##### (5)减少外部干扰 - 确保舵机供电电压稳定,避免电源波动。 - 使用滤波电容减少电源噪声。 - 避免强电磁场对信号线的影响。 #### 3. 示例代码 以下是一个完整的PWM初始化代码示例,用于生成周期为20ms、脉宽为1ms的PWM信号: ```c #include "stm32f10x.h" void TIM2_PWM_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; TIM_OCInitTypeDef TIM_OCInitStruct; // 使能GPIOA和TIM2钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 配置GPIOA.0为复用推挽输出 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); // 配置TIM2基本参数 uint16_t Prescaler = (uint16_t)((SystemCoreClock / 1000000) - 1); // 设置分频系数为1us uint16_t ARR = 20000 - 1; // 周期为20ms,对应20000个计数周期 TIM_TimeBaseInitStruct.TIM_Period = ARR; TIM_TimeBaseInitStruct.TIM_Prescaler = Prescaler; TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); // 配置TIM2通道1为PWM模式 TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStruct.TIM_Pulse = 1000; // 脉宽为1ms,对应1000个计数周期 TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM2, &TIM_OCInitStruct); // 使能TIM2 TIM_Cmd(TIM2, ENABLE); } int main(void) { // 初始化PWM TIM2_PWM_Init(); while (1) { // 主循环 } } ``` ####
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值