ArduPilot开源飞控之AP_Mount_Servo

ArduPilot开源飞控之AP_Mount_Servo

  • 1. 源由
  • 2. 框架设计
    • 2.1 公有成员
    • 2.2 受保护成员
      • 私有成员:
  • 3. 重要方法
    • 3.1 AP_Mount_Servo::init
    • 3.2 AP_Mount_Servo::update
    • 3.3 AP_Mount_Servo::has_roll_control
    • 3.4 AP_Mount_Servo::has_pitch_control
    • 3.5 AP_Mount_Servo::has_pan_control
  • 4. 辅助函数
    • 4.1 AP_Mount_Servo::update_angle_outputs
    • 4.2 AP_Mount_Servo::move_servo
    • 4.3 AP_Mount_Servo::get_attitude_quaternion
  • 4. 总结
  • 5. 参考资料

1. 源由

AP_Mount_Servo是PWM舵机控制云台的设备后台程序。通常舵机直接接受PWM信号控制,因此该云台设备驱动类也是最为基础的。

2. 框架设计

  • 继承自 AP_Mount_Backend
  • 用于控制基于舵机的云台
    • 舵机控制: 允许在滚转、俯仰和偏航方向上的运动。
    • 稳定: 区分需要外部稳定的舵机云台和自稳定的无刷PWM云台。
    • 四元数: 使用四元数表示和获取姿态。
  • 其中关于角度更新部分在AP_Mount_Backend::calculate_poi完成

2.1 公有成员

  1. 构造函数:

    AP_Mount_Servo(AP_Mount &frontend, AP_Mount_Params &params, bool requires_stab, uint8_t instance)
    
    • 参数:
      • AP_Mount &frontend: 前端云台对象的引用。
      • AP_Mount_Params &params: 云台参数的引用。
      • bool requires_stab: 指示是否需要稳定的布尔值。
      • uint8_t instance: 实例号。
    • 初始化列表:
      • 使用frontendparamsinstance初始化基类AP_Mount_Backend
      • requires_stabilization设置为requires_stab
      • 将舵机功能索引(_roll_idx_tilt_idx_pan_idx_open_idx)初始化为SRV_Channel::k_none
  2. 方法:

    • void init() override;: 初始化实例。
    • void update() override;: 定期更新云台位置。
    • bool has_roll_control() const override;: 如果云台可以控制滚转,则返回true。
    • bool has_pitch_control() const override;: 如果云台可以控制俯仰,则返回true。
    • bool has_pan_control() const override;: 如果云台可以控制偏航(平移),则返回true。

2.2 受保护成员

  1. 方法:
    • bool get_attitude_quaternion(Quaternion& att_quat) override;: 获取姿态的四元数,并在成功时返回true。

私有成员:

  1. 方法:

    • void update_angle_outputs(const MountTarget& angle_rad);: 根据地球坐标系的目标更新机身坐标系的角度输出。
    • void move_servo(uint8_t rc, int16_t angle, int16_t angle_min, int16_t angle_max);: 将具有给定功能ID的舵机移动到指定角度。所有角度都是机身坐标系的角度,单位为度*10。
  2. 成员:

    • const bool requires_stabilization;: 指示舵机云台是否需要稳定。
    • SRV_Channel::Aux_servo_function_t _roll_idx;: 滚转舵机功能索引。
    • SRV_Channel::Aux_servo_function_t _tilt_idx;: 俯仰舵机功能索引。
    • SRV_Channel::Aux_servo_function_t _pan_idx;: 偏航舵机功能索引。
    • SRV_Channel::Aux_servo_function_t _open_idx;: 打开舵机功能索引。
    • Vector3f _angle_bf_output_rad;: 最终的机身坐标系输出角度,单位为弧度。

3. 重要方法

3.1 AP_Mount_Servo::init

该初始化例程在AP_Mount::init中调用。

AP_Mount_Servo::init()
├── Check if _instance == 0
│   ├── True
│   │   ├── Set _roll_idx to SRV_Channel::k_mount_roll
│   │   ├── Set _tilt_idx to SRV_Channel::k_mount_tilt
│   │   ├── Set _pan_idx to SRV_Channel::k_mount_pan
│   │   └── Set _open_idx to SRV_Channel::k_mount_open
│   └── False (this must be the 2nd mount)
│       ├── Set _roll_idx to SRV_Channel::k_mount2_roll
│       ├── Set _tilt_idx to SRV_Channel::k_mount2_tilt
│       ├── Set _pan_idx to SRV_Channel::k_mount2_pan
│       └── Set _open_idx to SRV_Channel::k_mount2_open
└── Call AP_Mount_Backend::init()

3.2 AP_Mount_Servo::update

该定时更新例程在AP_Mount::update中调用。

AP_Mount_Servo::update()
|
|-- set_rctargeting_on_rcinput_change()
|
|-- auto mount_mode = get_mode()
|
|-- switch (mount_mode)
|   |
|   |-- case MAV_MOUNT_MODE_RETRACT
|   |   |-- _angle_bf_output_rad = _params.retract_angles.get() * DEG_TO_RAD
|   |   |-- mnt_target.angle_rad.set(_angle_bf_output_rad, false)
|   |   |-- mnt_target.target_type = MountTargetType::ANGLE
|   |
|   |-- case MAV_MOUNT_MODE_NEUTRAL
|   |   |-- _angle_bf_output_rad = _params.neutral_angles.get() * DEG_TO_RAD
|   |   |-- mnt_target.angle_rad.set(_angle_bf_output_rad, false)
|   |   |-- mnt_target.target_type = MountTargetType::ANGLE
|   |
|   |-- case MAV_MOUNT_MODE_MAVLINK_TARGETING
|   |   |-- // Do nothing, targets are set elsewhere
|   |
|   |-- case MAV_MOUNT_MODE_RC_TARGETING
|   |   |-- MountTarget rc_target
|   |   |-- get_rc_target(mnt_target.target_type, rc_target)
|   |   |-- switch (mnt_target.target_type)
|   |       |-- case MountTargetType::ANGLE
|   |       |   |-- mnt_target.angle_rad = rc_target
|   |       |-- case MountTargetType::RATE
|   |           |-- mnt_target.rate_rads = rc_target
|   |
|   |-- case MAV_MOUNT_MODE_GPS_POINT
|   |   |-- if (get_angle_target_to_roi(mnt_target.angle_rad))
|   |       |-- mnt_target.target_type = MountTargetType::ANGLE
|   |
|   |-- case MAV_MOUNT_MODE_HOME_LOCATION
|   |   |-- if (get_angle_target_to_home(mnt_target.angle_rad))
|   |       |-- mnt_target.target_type = MountTargetType::ANGLE
|   |
|   |-- case MAV_MOUNT_MODE_SYSID_TARGET
|   |   |-- if (get_angle_target_to_sysid(mnt_target.angle_rad))
|   |       |-- mnt_target.target_type = MountTargetType::ANGLE
|   |
|   |-- default
|       |-- // Do nothing
|
|-- switch (mnt_target.target_type)
|   |
|   |-- case MountTargetType::RATE
|   |   |-- update_angle_target_from_rate(mnt_target.rate_rads, mnt_target.angle_rad)
|   |   |-- FALLTHROUGH
|   |
|   |-- case MountTargetType::ANGLE
|       |-- if ((mount_mode != MAV_MOUNT_MODE_RETRACT) & (mount_mode != MAV_MOUNT_MODE_NEUTRAL))
|           |-- update_angle_outputs(mnt_target.angle_rad)
|
|-- const bool mount_open = (mount_mode == MAV_MOUNT_MODE_RETRACT) ? 0 : 1
|-- move_servo(_open_idx, mount_open, 0, 1)
|
|-- move_servo(_roll_idx, degrees(_angle_bf_output_rad.x)*10, _params.roll_angle_min*10, _params.roll_angle_max*10)
|-- move_servo(_tilt_idx, degrees(_angle_bf_output_rad.y)*10, _params.pitch_angle_min*10, _params.pitch_angle_max*10)
|-- move_servo(_pan_idx,  degrees(_angle_bf_output_rad.z)*10, _params.yaw_angle_min*10, _params.yaw_angle_max*10)

3.3 AP_Mount_Servo::has_roll_control

是否分配roll控制的RC辅助通道。

// returns true if this mount can control its roll
bool AP_Mount_Servo::has_roll_control() const
{
    return SRV_Channels::function_assigned(_roll_idx) && roll_range_valid();
}

3.4 AP_Mount_Servo::has_pitch_control

是否分配pitch控制的RC辅助通道。

bool AP_Mount_Servo::has_pitch_control() const
{
    return SRV_Channels::function_assigned(_tilt_idx) && pitch_range_valid();
}

3.5 AP_Mount_Servo::has_pan_control

是否分配yaw控制的RC辅助通道。

// returns true if this mount can control its pan (required for multicopters)
bool AP_Mount_Servo::has_pan_control() const
{
    return SRV_Channels::function_assigned(_pan_idx) && yaw_range_valid();
}

4. 辅助函数

4.1 AP_Mount_Servo::update_angle_outputs

根据飞机姿态动态调整摄像头角度。

update_angle_outputs
├── 定义并初始化变量
│   ├── ahrs = AP::ahrs()
│   ├── yaw_bf_rad = constrain_float(angle_rad.get_bf_yaw(), radians(_params.yaw_angle_min), radians(_params.yaw_angle_max))
│   └── _angle_bf_output_rad = {angle_rad.roll, angle_rad.pitch, yaw_bf_rad}
├── 检查是否需要稳定化
│   ├── if (!requires_stabilization)
│   │   └── return
├── 获取姿态角度
│   ├── ahrs_angle_rad = {ahrs.get_roll(), ahrs.get_pitch()}
│   ├── 检查是否有pan控制
│   │   └── if (has_pan_control())
│   │       └── ahrs_angle_rad.rotate(-yaw_bf_rad)
├── 添加姿态角度修正
│   ├── _angle_bf_output_rad.x -= ahrs_angle_rad.x
│   ├── _angle_bf_output_rad.y -= ahrs_angle_rad.y
├── 计算导引滤波
│   ├── 获取陀螺仪数据
│   │   └── gyro = ahrs.get_gyro()
│   ├── 计算roll角度变化率
│   │   └── if (!is_zero(_params.roll_stb_lead) && fabsf(ahrs.get_pitch()) < M_PI/3.0f)
│   │       └── roll_rate = gyro.x + (ahrs.sin_pitch() / ahrs.cos_pitch()) * (gyro.y * ahrs.sin_roll() + gyro.z * ahrs.cos_roll())
│   │       └── _angle_bf_output_rad.x -= roll_rate * _params.roll_stb_lead
│   ├── 计算pitch角度变化率
│   │   └── if (!is_zero(_params.pitch_stb_lead))
│   │       └── pitch_rate = ahrs.cos_pitch() * gyro.y - ahrs.sin_roll() * gyro.z
│   │       └── _angle_bf_output_rad.y -= pitch_rate * _params.pitch_stb_lead

4.2 AP_Mount_Servo::move_servo

根据角度计算PWM值,控制伺服器运动(前提就是PWM与角度关系是线性的)。

// move_servo - moves servo with the given id to the specified angle.  all angles are in degrees * 10
void AP_Mount_Servo::move_servo(uint8_t function_idx, int16_t angle, int16_t angle_min, int16_t angle_max)
{
	SRV_Channels::move_servo((SRV_Channel::Aux_servo_function_t)function_idx, angle, angle_min, angle_max);
}

4.3 AP_Mount_Servo::get_attitude_quaternion

获取四元数组。

// get attitude as a quaternion.  returns true on success
bool AP_Mount_Servo::get_attitude_quaternion(Quaternion& att_quat)
{
    // No feedback from gimbal so simply report demanded servo angles (which is
    // not the same as target angles).
    float roll_rad = 0.0f;
    float pitch_rad = 0.0f;
    float yaw_rad = 0.0f;
    if (has_roll_control()) {
        roll_rad = constrain_float(_angle_bf_output_rad.x, radians(_params.roll_angle_min), radians(_params.roll_angle_max));
    }
    if (has_pitch_control()) {
        pitch_rad = constrain_float(_angle_bf_output_rad.y, radians(_params.pitch_angle_min), radians(_params.pitch_angle_max));
    }
    if (has_pan_control()) {
        yaw_rad = constrain_float(_angle_bf_output_rad.z, radians(_params.yaw_angle_min), radians(_params.yaw_angle_max));
    }

    // convert to quaternion
    att_quat.from_euler(roll_rad, pitch_rad, yaw_rad);
    return true;
}

4. 总结

AP_Mount_Servo是通过PWM控制舵机,从而调整云台角度。该云台设备驱动类是最基本或者说最为原始的,电子件最少得云台控制程序。

大部分某宝上的都是这类云台。

在这里插入图片描述

5. 参考资料

【1】ArduPilot开源飞控系统之简单介绍
【2】ArduPilot之开源代码Task介绍
【3】ArduPilot飞控启动&运行过程简介
【4】ArduPilot之开源代码Library&Sketches设计
【5】ArduPilot之开源代码Sensor Drivers设计
【6】ArduPilot开源飞控之AP_Mount
【7】ArduPilot开源飞控之AP_Mount_Backend

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/794011.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构——查找算法

文章目录 1. 查找算法 2. 顺序查找 2. 二分查找 1. 查找算法 查找算法是用于在数据集中定位特定元素的位置的算法。查找是计算机科学中一项基本操作&#xff0c;几乎在所有应用程序中都需要使用。例如&#xff0c;数据库查询、信息检索、字典查找等都涉及到查找操作。查找算…

我们水冷电阻器支持高脉冲负载和高抗振能

我们电阻器是液冷电阻器&#xff0c;与风冷型电阻器相比&#xff0c;尺寸非常小。它们支持高脉冲负载和高抗振能力。 水冷电阻器具有完全绝缘的铝制外壳&#xff0c;带有液体冷却通道。主要的电阻元件是由厚膜浆料制成&#xff0c;具有低热漂移和出色的电阻精度。电阻元件嵌入氧…

Docker部署gitlab私有仓库后查看root默认密码以及修改external_url路径和端口的方法

文章目录 1、docker部署最新版gitlab2、进入gitlab容器3、修改路径地址ip和端口4、检验效果 1、docker部署最新版gitlab #docker安装命令 docker run --detach \--name gitlab \--restart always \-p 1080:80 \-p 10443:443 \-p 1022:22 \-v /gitlab/config:/etc/gitlab \-v …

人工智能算法工程师(中级)课程10-PyTorch神经网络之卷积神经网络与代码详解

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能算法工程师(中级)课程10-PyTorch神经网络之卷积神经网络实战与代码详解。卷积神经网络&#xff08;CNN&#xff09;是一种广泛应用于图像识别、目标检测、视频分析等领域的深度学习模型。本文将详细介绍卷积…

【VIVADO SDK调试遇到DataAbortHandler】

问题 SDK调试遇到DataAbortHandler问题。 运行后不显示结果&#xff0c;debug模式下发现进入DataAbortHandler异常函数。程序中存在大数组。 原因:SDK默认的堆栈为1024bytes,需要将堆栈调大。 修改方法&#xff1a; 解决:对application中src下的lscript.ld双击&#xff0c;…

【游戏引擎之路】登神长阶(七)——x86汇编学习:凡做难事,必有所得

5月20日-6月4日&#xff1a;攻克2D物理引擎。 6月4日-6月13日&#xff1a;攻克《3D数学基础》。 6月13日-6月20日&#xff1a;攻克《3D图形教程》。 6月21日-6月22日&#xff1a;攻克《Raycasting游戏教程》。 6月23日-7月1日&#xff1a;攻克《Windows游戏编程大师技巧》。 7月…

解决GET请求中文乱码问题

解决GET请求中文乱码问题 1、乱码的根本原因2、解决方法方法一&#xff1a;修改Tomcat配置&#xff08;推荐&#xff09;方法二&#xff1a;使用URLEncoder和URLDecoder&#xff08;不推荐用于GET请求乱码&#xff09;方法三&#xff1a;String类编解码&#xff08;不直接解决乱…

欣奇随机美图源码

欣赏养眼美图让人心情愉悦 新增正能量进站引导首页 上传文件解压即可用有手就行 美图输出接口自判断版 http://mt.xqia.net/api.php http://mt.xqia.net/api.php?typejson 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/89520368 更多资源下载&…

FPGA学习笔记(一) FPGA最小系统

文章目录 前言一、FPGA最小系统总结 前言 今天学习下FPGA的最小系统一、FPGA最小系统 FPGA最小系统与STM32最小系统类似&#xff0c;由供电电源&#xff0c;时钟电路晶振&#xff0c;复位和调试接口JTAG以及FLASH配置芯片组成&#xff0c;其与STM32最大的不同之处就是必须要有…

如何ssh远程Windows电脑

参考&#xff1a;https://www.jianshu.com/p/1321b46b40ee 上述教程中&#xff0c;直接根据微软的教程进行openssh安装 遇到的问题 远程windows电脑需要具备什么条件&#xff1f; 需要Windows电脑上安装了openssh server 远程Windows电脑的话&#xff0c;用户怎么创建&…

C++ | Leetcode C++题解之第230题二叉搜索树中第K小的元素

题目&#xff1a; 题解&#xff1a; class MyBst { public:MyBst(TreeNode *root) {this->root root;countNodeNum(root);}// 返回二叉搜索树中第k小的元素int kthSmallest(int k) {TreeNode *node root;while (node ! nullptr) {int left getNodeNum(node->left);if…

产品经理-一份标准需求文档的8个模块(14)

一份标准优秀的产品需求文档包括&#xff1a; ❑ 封面&#xff1b; ❑ 文档修订记录表&#xff1b; ❑ 目录&#xff1b; ❑ 引言&#xff1b; ❑ 产品概述&#xff1a;产品结构图 ❑ 详细需求说明&#xff1a;产品逻辑图、功能与特性简述列表、交互/视觉设计、需求详细描述&am…

vue使用 “xlsx-style“: “^0.8.13“ 报错

关于jszip not a constructor报错配置config.js文件后可能还报错的问题&#xff1a; 在node_modules处找到node_modules\xlsx-style\xlsx.js 文件。 将 if(typeof jszip undefined) jszip require(./jszip).JSZip;(应该在xlsx.js文件1339行左右) 替换成 if(typeof jszip und…

C语言 | Leecode C语言题解之第229题多数元素II

题目&#xff1a; 题解&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*//*假定 num1&#xff0c;num2 为出现次数大于 nums.length / 3 的两个数。&#xff08;最多出现两个&#xff09;遍历 nums&#xff0c; 若出现 num1、num2…

C语言 | Leetcode C语言题解之第230题二叉搜索树中第K小的元素

题目&#xff1a; 题解&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/int search_num(struct TreeNode* root, int k, int *result, int num) {if(num k 1){retu…

Jmeter多用户登录操作实战

在使用Jmeter性能测试时,首先要解决的问题恐怕就会并发压测和多用登录的问题.今天就一篇文章讲清楚这两个问题的解决方案: 一.多并发压测如何配置线程? &#xff08;1&#xff09;同时并发&#xff1a;设置线程组、执行时间、循环次数&#xff0c;这种方式可以控制接口请求的…

Java | Leetcode Java题解之第229题多数元素II

题目&#xff1a; 题解&#xff1a; class Solution {public List<Integer> majorityElement(int[] nums) {HashMap<Integer, Integer> cnt new HashMap<Integer, Integer>();for (int i 0; i < nums.length; i) {if (cnt.containsKey(nums[i])) {cnt.…

windows上修改redis端口号

概况 redis是一个开源的内存数据结构存储系统&#xff0c;常用做数据库、缓存和消息代理。默认的端口号为6379 更改redis端口号步骤如下 先停止redis服务 redis-cli shutdowm 打开redis配置文件 在redis安装目录下&#xff0c;即redis.windows.conf文件。 port 6396 然后…

LabVIEW滤波器性能研究

为了研究滤波器的滤波性能&#xff0c;采用LabVIEW设计了一套滤波器性能研究系统。该系统通过LabVIEW中的波形生成函数&#xff0c;输出幅值及频率可调的正弦波和白噪声两种信号&#xff0c;并将白噪声与正弦波叠加&#xff0c;再通过滤波器输出纯净的正弦波信号。系统通过FFT&…

go-redis 封装事件-client封装模型、批量数据处理的导出器设计

一、redis-go的封装实践-client模型 // Copyright 2020 Lingfei Kong <colin404foxmail.com>. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file.package storageimport ("context&q…