目录

应用场景

名词解释

陀螺仪

加速度计

磁力计(又叫磁罗盘)

坐标系

姿态表示

滤波原理

滤波主要过程

预备知识

预测

校正

加速度计校正

磁力计校正

更新四元数

源码分析

主程序运行流程图

函数功能简述

源码分析

头文件

using @@@

namespace attitude_estimator_q

类定义: class AttitudeEstimatorQ

构造函数   

析构函数

start();

print();

task_main_trampoline();

task_main();

update_parameters();

init();

update();

update_mag_declination();

attitude_estimator_q_main();


前言:多旋翼的姿态估计算法通常采用自适应显示互补滤波算法、扩展卡尔曼滤波算法、梯度下降算法等,以上三种方法均是对姿态解算的实现,采用的基本思路都是利用陀螺仪的动态稳定性来估计实时姿态,同时由于陀螺仪随时间积分累计漂移误差的固有缺陷,需找一个不随时间变化影响的传感器来估计姿态并进行修正标定。三种方法各有优缺点,互补与梯度算法更适用于处理性能受限的飞行器,例如微型四轴等采用低频Cortex-M0或M1的处理器,而在条件允许性能足够的情况下,建议考虑采用扩展卡尔曼滤波的算法。

PX4 源码中采用的是改进的互补滤波算法,在原有加速度计校准陀螺仪的基础上,增加磁力计和GPS数据进行更进一步的四元数校准补偿,它的优点是运算简单,因此成为PX4中默认的姿态解算算法)

通过下文介绍的多旋翼姿态估计来了解互补滤波算法

应用场景

本文中 mahony 的应用场景为 多旋翼无人机的姿态估计。 

 
陀螺仪、加速度计、MPU6050 详述

名词解释

陀螺仪

陀螺仪,测量角速度,具有高动态特性,它是一个间接测量角度的器件。它测量的是角度的导数,即角速度,要将角速度对时间积分才能得到角度。由于噪声等误差影响,在积分作用下不断积累,最终导致陀螺仪的低频干扰和漂移。

加速度计

输出当前加速度(包含重力加速度 g)的方向【也叫重力感应器】,在悬停时,输出为 g。由其测量原理导致的高频信号敏感,使得加速度计在振动环境中高频干扰较大。

磁力计(又叫磁罗盘)

输出为当前机体与地磁场的夹角。测量原理与指南针相似。低频特性较好,易受周围磁场干扰。 
磁力计的工作原理参考:http://blog.sina.com.cn/s/blog_402c071e0102v8ig.html

坐标系

  • 导航坐标系:在多旋翼中,又叫地球坐标系、地理坐标系。通常,采用北东地(NED)构成坐标系的 X,Y,Z 轴。
  • 机体坐标系 :固联在多旋翼飞行器上,即,坐标系原点定位于飞行器中心点(假设中心点与重心点重合)。

关于航空导航用到的坐标系,请参考 AIAA 系列丛书。在多旋翼中,因为只在低空飞行,且时间较短,只需要以上两个。

姿态表示

  • 欧拉角 :较直观,描述刚体在三维欧式空间中的姿态。此时,坐标系为机体坐标系,随着刚体的旋转而旋转。缺点:万向节锁。 
  • 四元数:由一组四维向量,表示刚体的三维旋转。适合用于计算机计算。 
  • 方向余弦矩阵DCM:用欧拉角余弦值或四元数,表示的坐标系的旋转。

滤波原理

互补滤波要求两个信号的干扰噪声处在不同的频率,通过设置两个滤波器的截止频率,确保融合后的信号能够覆盖需求频率。 
在 IMU 的姿态估计中,互补滤波器对陀螺仪(低频噪声)使用高通滤波;对加速度/磁力计(高频噪声)使用低频滤波。 
(此处尚未对传感器数据实测,噪声和有用频率未知。。。。待后期补足)

互补滤波中,两个滤波器的截止频率一致,此时就需要根据有用频率的值对其进行取舍。

机体水平时,加速度计无法测量绕 Z 轴的旋转量,即偏航角。磁力计也有同样问题,无法测得要磁轴的旋转量。故,需要加速度计和磁力计同时对陀螺仪进行校正。

滤波主要过程


式中,q^ 表示系统姿态估计的四元数表示; δ 是经过 PI 调节器产生的新息; e 表示实测的惯性向量 v¯ 和预测的向量v^ 之间的相对旋转(误差)。 
P(⋅) —— pure quaternion operator(四元数实部为0),表示只有旋转。

PI 调节器中:

参数 kp 用于控制加速度计和陀螺仪之间的交叉频率
参数 kI 用于校正陀螺仪误差


预备知识

主要是公式,不包含推导过程。。。。

欧拉角与机体角速度的关系:


旋转矩阵与机体角速度的关系:

四元数与机体角速度的关系:

参考:北航全权老师课件 第五章内容、惯性导航(秦永元)第九章内容。

预测

与卡尔曼滤波相似,互补滤波也分为预测-校正。 
在预测环节,由三轴陀螺仪测得的角速度,通过式(1)计算出四元数姿态预测。表示从地球坐标系到机体坐标系,或机体坐标系姿态在地球坐标系下的表示。

校正

在预测环节得到的四元数 ,通过加速度计和磁力计的值进行校正。该环节通常分为两部分:

通过加速度计得到 ,然后校正四元数中的横滚(roll)和俯仰(pitch)分量。
当磁力计可读时,通过 校正四元数中的偏航(yaw)分量。

加速度计校正

加速度计信号首先经过低通滤波器(消除高频噪声):


然后,对得到的结果进行归一化(normalized)


计算偏差:


式中, v表示重力向量在机体坐标系的向量。


此时,由 v 与加速度计向量垂直分量叉乘,得到误差值。【两个物理意义相同的向量,理论上叉乘为零】

磁力计校正

数据预处理与加速度计相同,先滤波,然后归一化,得到

1. 无 GPS 校准时:
计算误差:

式中,w 计算过程如下:

磁力计的输出(m)在机体坐标系下,将其转换到导航坐标系:

导航坐标系的 x 轴与正北对齐,故,可以将磁力计在 xoy 平面的投影折算到 x 轴。

再次变换到机体坐标系:


2. 有 GPS 校准时:
在 px4 中,磁力计使用 GPS 信息 [0,0,mag] 进行校准,故,公式与加速度计相同。


此时,由 w 与磁力计向量叉乘,得到误差值。【两个物理意义相同的向量,理论上叉乘为零】

更新四元数

由加速度计和磁力计校准得到的误差值:

由该误差值得到修正值:(只有 ki 修正bias)

修正后的角速度值:

根据一阶龙格库塔方法求解一阶微分方程:

可以求出四元数微分方程的差分形式:

四元数规范化:


源码分析

该部分源码直接截取 px4 开源飞控源码(BSD证书)。 
px4 为 pixhawk 飞控的固件代码,内部涉及很多滤波及导航的算法。有较大参考价值。

源码,参考日期:20160603;

https://github.com/hsteinhaus/PX4Firmware/blob/master/src/modules/attitude_estimator_so3/attitude_estimator_so3_main.cpp

https://github.com/ArduPilot/PX4Firmware/blob/master/src/modules/attitude_estimator_q/attitude_estimator_q_main.cpp

           参数            默认值    

  • ATT_W_ACC     0.2f    加速度计权重
  • ATT_W_MAG    0.1f    磁力计权重
  • ATT_W_EXT_HDG    0.1f    外部航向权重
  • ATT_W_GYRO_BIAS    0.1f    陀螺仪偏差权重
  • ATT_MAG_DECL    0.0f    磁偏角(°)
  • ATT_MAG_DECL_A    1    启用基于GPS的自动磁偏角校正
  • ATT_EXT_HDG_M    0    外部航向模式
  • ATT_ACC_COMP    1    启用基于GPS速度的加速度补偿
  • ATT_BIAS_MAX    0.05f    陀螺仪偏差上限
  • ATT_VIBE_THRESH    0.2f    振动水平报警阈值

主程序运行流程图

函数功能简述

  • AttitudeEstimatorQ::AttitudeEstimatorQ();   构造函数,初始化参数;
  • AttitudeEstimatorQ::~AttitudeEstimatorQ(); 析构函数,杀掉所有任务;
  • int AttitudeEstimatorQ::start();   启动【attitude_estimator_q】进程,主函数入口: task_main_trampoline
  • void AttitudeEstimatorQ::print();  打印姿态信息;
  • void AttitudeEstimatorQ::task_main_trampoline(int argc, char *argv[])

  {

   attitude_estimator_q::instance->task_main();

  }

  • void AttitudeEstimatorQ::task_main();  主任务进程;
  • void AttitudeEstimatorQ::update_parameters(bool force);   

false: 查看参数是否更新;

true: 获取新参数, 并由磁偏角更新四元数;

  • bool AttitudeEstimatorQ::init();    由加速度计和磁力计初始化旋转矩阵,有GPS时,校正磁偏角。
  • bool AttitudeEstimatorQ::update(float dt);  调用init(); 互补滤波
  • void AttitudeEstimatorQ::update_mag_declination(float new_declination);  使用磁偏角更新四元数
  • int attitude_estimator_q_main(int argc, char *argv[]);

attitude_estimator_q { start }:实例化instance,运行instance->start();

attitude_estimator_q { stop }:delete instance,指针置空;

attitude_estimator_q { status}:instance->print(),打印姿态信息。


源码分析

此处源码逐行分析,可以使用 Ctrl+f 快速定位;
uORB 相关的数据结构,请参考 px4/Firmware/msg;

/*代码前的注释段(L34~L40)* @file attitude_estimator_q_main.cpp** Attitude estimator (quaternion based)*姿态估计(基于四元数)* @author Anton Babushkin <anton.babushkin@me.com>*/

头文件

(l42~l76)
#include <px4_config.h>
#include <px4_posix.h>//add missing check;
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <poll.h>
#include <fcntl.h>
#include <float.h>
#include <errno.h>
#include <limits.h>
#include <math.h>
#include <uORB/uORB.h>
#include <uORB/topics/sensor_combined.h>
#include <uORB/topics/vehicle_attitude.h>
#include <uORB/topics/control_state.h>
#include <uORB/topics/vehicle_control_mode.h>
#include <uORB/topics/vehicle_global_position.h>
#include <uORB/topics/vision_position_estimate.h>//视觉位置估计, 未找到文件【待查】;
#include <uORB/topics/att_pos_mocap.h>//mocap-->vicon;
#include <uORB/topics/airspeed.h>
#include <uORB/topics/parameter_update.h>
#include <uORB/topics/estimator_status.h>
#include <drivers/drv_hrt.h>#include <mathlib/mathlib.h>
#include <mathlib/math/filter/LowPassFilter2p.hpp>
#include <lib/geo/geo.h>
#include <lib/ecl/validation/data_validator_group.h>#include <systemlib/systemlib.h>
#include <systemlib/param/param.h>
#include <systemlib/perf_counter.h>
#include <systemlib/err.h>
#include <systemlib/mavlink_log.h>


using @@@

(l78~l82)
extern "C" __EXPORT int attitude_estimator_q_main(int argc, char *argv[]);using math::Vector;
using math::Matrix;
using math::Quaternion;

此处,extern “C” 表示以 C 格式编译; __EXPORT 表示 将函数名输出到链接器(Linker); using 关键字 表示引入名称到 using 说明出现的声明区域。。

__export 
This keyword aids those programming Microsoft Windows. __export causes the function name to be exported to the linker.

namespace attitude_estimator_q

(l84~l89)
class AttitudeEstimatorQ;namespace attitude_estimator_q
{
AttitudeEstimatorQ *instance;
}//定义命名空间,通过命名空间调用instance;

类定义: class AttitudeEstimatorQ

 

    (l92~l210)
class AttitudeEstimatorQ
{//类定义; 
public:AttitudeEstimatorQ();//构造函数~AttitudeEstimatorQ();//析构函数int        start();//开始任务,成功--返回OK;static void task_main_trampoline(int argc, char *argv[]);//跳转到 task_main() ,未使用传入参数;static函数只能被本文件中的函数调用;void        task_main();void        print();
private:static constexpr float _dt_max = 0.02;//最大时间间隔;//constexpr(constant expression)常数表达式,c11新关键字;//优化语法检查和编译速度;bool        _task_should_exit = false;//如果为 true ,任务退出;int     _control_task = -1;//进程ID, 默认-1表示没有任务;int     _sensors_sub = -1;//sensor_combined subscribe(订阅);int     _params_sub = -1;//parameter_update subscribe;int     _vision_sub = -1;//视觉位置估计;int     _mocap_sub = -1;//vicon姿态位置估计;int     _airspeed_sub = -1;//airspeed subscribe;int     _global_pos_sub = -1;//vehicle_global_position subscribe;orb_advert_t    _att_pub = nullptr;//vehicle_attitude publish(发布);orb_advert_t    _ctrl_state_pub = nullptr;//发布控制状态主题control_state;orb_advert_t    _est_state_pub = nullptr;//estimator_statusstruct {param_t w_acc;//ATT_W_ACCparam_t w_mag;//ATT_W_MAGparam_t w_ext_hdg;//ATT_W_EXT_HDG 外部航向权重;param_t w_gyro_bias;//ATT_W_GYRO_BIASparam_t mag_decl;//ATT_MAG_DECLparam_t mag_decl_auto;//ATT_MAG_DECL_A 磁偏角自动校正;param_t acc_comp;//ATT_ACC_COMPparam_t bias_max;//ATT_BIAS_MAX 陀螺仪偏差上限;param_t vibe_thresh;//ATT_VIBE_THRESH 振动报警阈值;param_t ext_hdg_mode;//ATT_EXT_HDG_M 外部航向模式;}       _params_handles;//有用参数的句柄;float       _w_accel = 0.0f;//ATT_W_ACC >>> w_acc >>> _w_accel;float       _w_mag = 0.0f;float       _w_ext_hdg = 0.0f;float       _w_gyro_bias = 0.0f;float       _mag_decl = 0.0f;bool        _mag_decl_auto = false;bool        _acc_comp = false;float       _bias_max = 0.0f;float       _vibration_warning_threshold = 1.0f;//振动警告阈值;hrt_abstime _vibration_warning_timestamp = 0;int     _ext_hdg_mode = 0;Vector<3>   _gyro;//陀螺仪;Vector<3>   _accel;//加速度计;Vector<3>   _mag;//磁力计;vision_position_estimate_s _vision = {};//buffer;Vector<3>   _vision_hdg;att_pos_mocap_s _mocap = {};//buffer;Vector<3>   _mocap_hdg;airspeed_s _airspeed = {};//buffer;Quaternion  _q;//四元数;Vector<3>   _rates;//姿态角速度;Vector<3>   _gyro_bias;//陀螺仪偏差;vehicle_global_position_s _gpos = {};//buffer;Vector<3>   _vel_prev;//前一时刻的速度:Vector<3>   _pos_acc;//加速度(body frame??)DataValidatorGroup _voter_gyro;//数据验证,剔除异常值;DataValidatorGroup _voter_accel;DataValidatorGroup _voter_mag;//姿态速度的二阶低通滤波器;math::LowPassFilter2p _lp_roll_rate;math::LowPassFilter2p _lp_pitch_rate;math::LowPassFilter2p _lp_yaw_rate;//绝对时间(ms)hrt_abstime _vel_prev_t = 0;//前一时刻计算速度时的绝对时间;bool        _inited = false;//初始化标识;bool        _data_good = false;//数据可用;bool        _failsafe = false;//故障保护;bool        _vibration_warning = false;//振动警告;bool        _ext_hdg_good = false;//外部航向可用;orb_advert_t    _mavlink_log_pub = nullptr;//mavlink log advert;//performance measuring tools (counters)perf_counter_t _update_perf;perf_counter_t _loop_perf;//未看到使用。。。;void update_parameters(bool force);//更新参数;int update_subscriptions();//未使用【待查??】bool init();bool update(float dt);// 偏航角旋转后,立即更新磁偏角;void update_mag_declination(float new_declination);
};

构造函数
   

(l213~l235)
AttitudeEstimatorQ::AttitudeEstimatorQ() :_vel_prev(0, 0, 0),_pos_acc(0, 0, 0),_voter_gyro(3),//数据成员3个;_voter_accel(3),_voter_mag(3),_lp_roll_rate(250.0f, 30.0f),//低通滤波(采样频率,截止频率);_lp_pitch_rate(250.0f, 30.0f),_lp_yaw_rate(250.0f, 20.0f)
{_voter_mag.set_timeout(200000);//磁力计超时;//读取Attitude_estimator_q_params.c中的参数;_params_handles.w_acc       = param_find("ATT_W_ACC");_params_handles.w_mag       = param_find("ATT_W_MAG");_params_handles.w_ext_hdg   = param_find("ATT_W_EXT_HDG");//外部航向权重;_params_handles.w_gyro_bias = param_find("ATT_W_GYRO_BIAS");_params_handles.mag_decl    = param_find("ATT_MAG_DECL");_params_handles.mag_decl_auto   = param_find("ATT_MAG_DECL_A");//磁偏角自动校正;_params_handles.acc_comp    = param_find("ATT_ACC_COMP");_params_handles.bias_max    = param_find("ATT_BIAS_MAX");//陀螺仪偏差上限;_params_handles.vibe_thresh = param_find("ATT_VIBE_THRESH");//振动警告阈值;_params_handles.ext_hdg_mode    = param_find("ATT_EXT_HDG_M");
}

析构函数

l240~l262
AttitudeEstimatorQ::~AttitudeEstimatorQ()
{//杀掉所有任务;if (_control_task != -1) {/* task wakes up every 100ms or so at the longest */_task_should_exit = true;/* wait for a second for the task to quit at our request */unsigned i = 0;do {/* wait 20ms */usleep(20000);/* if we have given up, kill it */if (++i > 50) {px4_task_delete(_control_task);break;}} while (_control_task != -1);}attitude_estimator_q::instance = nullptr;
}

start();

l264~l282
int AttitudeEstimatorQ::start()
{ASSERT(_control_task == -1);/* start the task *///启动任务,返回进程ID;_control_task = px4_task_spawn_cmd("attitude_estimator_q",/*name*/SCHED_DEFAULT,/*任务调度程序*/SCHED_PRIORITY_MAX - 5,/*优先级*/2500,/*栈大小*/(px4_main_t)&AttitudeEstimatorQ::task_main_trampoline,/*主函数入口*/nullptr);if (_control_task < 0) {warn("task start failed");return -errno;}return OK;
}

print();


l284~l292
void AttitudeEstimatorQ::print()
{//打印当前姿态信息;warnx("gyro status:");_voter_gyro.print();warnx("accel status:");_voter_accel.print();warnx("mag status:");_voter_mag.print();
}

task_main_trampoline();

l294~l297
void AttitudeEstimatorQ::task_main_trampoline(int argc, char *argv[])
{attitude_estimator_q::instance->task_main();
}

task_main();

l299~l655
void AttitudeEstimatorQ::task_main()
{#ifdef __PX4_POSIX
//记录事件执行所花费的时间,performance counters;perf_counter_t _perf_accel(perf_alloc_once(PC_ELAPSED, "sim_accel_delay"));perf_counter_t _perf_mpu(perf_alloc_once(PC_ELAPSED, "sim_mpu_delay"));perf_counter_t _perf_mag(perf_alloc_once(PC_ELAPSED, "sim_mag_delay"));
#endif
//从uORB订阅主题;_sensors_sub = orb_subscribe(ORB_ID(sensor_combined));
//订阅传感器读数,包含数据参见:Firmware/msg/sensor_combined.msg_vision_sub = orb_subscribe(ORB_ID(vision_position_estimate));//视觉;_mocap_sub = orb_subscribe(ORB_ID(att_pos_mocap));//vicon; _airspeed_sub = orb_subscribe(ORB_ID(airspeed));//空速,见Firmware/msg/airspeed.msg;_params_sub = orb_subscribe(ORB_ID(parameter_update));//bool saved;_global_pos_sub = orb_subscribe(ORB_ID(vehicle_global_position));//位置估计值(GPS);update_parameters(true);//获取新参数;hrt_abstime last_time = 0;px4_pollfd_struct_t fds[1] = {};fds[0].fd = _sensors_sub;//文件描述符;fds[0].events = POLLIN;//读取事件标识;//POLLIN: data other than high-priority data may be read without blocking;while (!_task_should_exit) {int ret = px4_poll(fds, 1, 1000);//timeout = 1000; fds_size = 1; 详见Linux的poll函数;//对字符设备读写;if (ret < 0) {// Poll error, sleep and try againusleep(10000);PX4_WARN("Q POLL ERROR");continue;} else if (ret == 0) {// Poll timeout, do nothingPX4_WARN("Q POLL TIMEOUT");continue;}update_parameters(false);//检查orb是否更新;// Update sensorssensor_combined_s sensors;int best_gyro = 0;int best_accel = 0;int best_mag = 0;if (!orb_copy(ORB_ID(sensor_combined), _sensors_sub, &sensors)) {// Feed validator with recent sensor data//(put)将最近的传感器数据送入验证组(DataValidatorGroup)for (unsigned i = 0; i < (sizeof(sensors.gyro_timestamp) / sizeof(sensors.gyro_timestamp[0])); i++) {//遍历每个陀螺仪数据;/* ignore empty fields *///忽略空值;if (sensors.gyro_timestamp[i] > 0) {float gyro[3];for (unsigned j = 0; j < 3; j++) {if (sensors.gyro_integral_dt[i] > 0) {//delta time 大于零;gyro[j] = (double)sensors.gyro_integral_rad[i * 3 + j] / (sensors.gyro_integral_dt[i] / 1e6);//=角度/时间(1e6用于us->s转换);} else {/* fall back to angular rate *///没有数据更新,回退;gyro[j] = sensors.gyro_rad_s[i * 3 + j];}}_voter_gyro.put(i, sensors.gyro_timestamp[i], &gyro[0], sensors.gyro_errcount[i], sensors.gyro_priority[i]);//最后一个参数gyro_priority[]用于支持传感器优先级;}/* ignore empty fields */if (sensors.accelerometer_timestamp[i] > 0) {_voter_accel.put(i, sensors.accelerometer_timestamp[i], &sensors.accelerometer_m_s2[i * 3],sensors.accelerometer_errcount[i], sensors.accelerometer_priority[i]);}//NED 坐标系下, 单位 m/s^2/* ignore empty fields */if (sensors.magnetometer_timestamp[i] > 0) {_voter_mag.put(i, sensors.magnetometer_timestamp[i], &sensors.magnetometer_ga[i * 3],sensors.magnetometer_errcount[i], sensors.magnetometer_priority[i]);}//NED 坐标系下, 单位 Gauss}// Get best measurement values//获取最佳测量值(DataValidatorGroup)hrt_abstime curr_time = hrt_absolute_time();_gyro.set(_voter_gyro.get_best(curr_time, &best_gyro));_accel.set(_voter_accel.get_best(curr_time, &best_accel));_mag.set(_voter_mag.get_best(curr_time, &best_mag));if (_accel.length() < 0.01f) {warnx("WARNING: degenerate accel!");continue;}//退化,即非满秩,此处为奇异值(0);if (_mag.length() < 0.01f) {warnx("WARNING: degenerate mag!");continue;}//同上;_data_good = true;//数据可用;if (!_failsafe) {uint32_t flags = DataValidator::ERROR_FLAG_NO_ERROR;#ifdef __PX4_POSIXperf_end(_perf_accel);//执行事件结束,计算均值方差等;perf_end(_perf_mpu);perf_end(_perf_mag);
#endifif (_voter_gyro.failover_count() > 0) {//陀螺仪数据故障计数大于0, 记录错误日志;_failsafe = true;flags = _voter_gyro.failover_state();mavlink_and_console_log_emergency(&_mavlink_log_pub, "Gyro #%i failure :%s%s%s%s%s!",_voter_gyro.failover_index(),((flags & DataValidator::ERROR_FLAG_NO_DATA) ? " No data" : ""),((flags & DataValidator::ERROR_FLAG_STALE_DATA) ? " Stale data" : ""),((flags & DataValidator::ERROR_FLAG_TIMEOUT) ? " Data timeout" : ""),((flags & DataValidator::ERROR_FLAG_HIGH_ERRCOUNT) ? " High error count" : ""),((flags & DataValidator::ERROR_FLAG_HIGH_ERRDENSITY) ? " High error density" : ""));}if (_voter_accel.failover_count() > 0) {//同上,故障日志;_failsafe = true;flags = _voter_accel.failover_state();mavlink_and_console_log_emergency(&_mavlink_log_pub, "Accel #%i failure :%s%s%s%s%s!",_voter_accel.failover_index(),((flags & DataValidator::ERROR_FLAG_NO_DATA) ? " No data" : ""),((flags & DataValidator::ERROR_FLAG_STALE_DATA) ? " Stale data" : ""),((flags & DataValidator::ERROR_FLAG_TIMEOUT) ? " Data timeout" : ""),((flags & DataValidator::ERROR_FLAG_HIGH_ERRCOUNT) ? " High error count" : ""),((flags & DataValidator::ERROR_FLAG_HIGH_ERRDENSITY) ? " High error density" : ""));}if (_voter_mag.failover_count() > 0) {//同上,故障日志;_failsafe = true;flags = _voter_mag.failover_state();mavlink_and_console_log_emergency(&_mavlink_log_pub, "Mag #%i failure :%s%s%s%s%s!",_voter_mag.failover_index(),((flags & DataValidator::ERROR_FLAG_NO_DATA) ? " No data" : ""),((flags & DataValidator::ERROR_FLAG_STALE_DATA) ? " Stale data" : ""),((flags & DataValidator::ERROR_FLAG_TIMEOUT) ? " Data timeout" : ""),((flags & DataValidator::ERROR_FLAG_HIGH_ERRCOUNT) ? " High error count" : ""),((flags & DataValidator::ERROR_FLAG_HIGH_ERRDENSITY) ? " High error density" : ""));}if (_failsafe) {//故障安全机制;mavlink_and_console_log_emergency(&_mavlink_log_pub, "SENSOR FAILSAFE! RETURN TO LAND IMMEDIATELY");}}//若启用振动报警,且振动级别超过设定阈值,触发报警; //振动级别由数据的方均根(RMS)给出;if (!_vibration_warning && (_voter_gyro.get_vibration_factor(curr_time) > _vibration_warning_threshold ||_voter_accel.get_vibration_factor(curr_time) > _vibration_warning_threshold ||_voter_mag.get_vibration_factor(curr_time) > _vibration_warning_threshold)) {if (_vibration_warning_timestamp == 0) {_vibration_warning_timestamp = curr_time;} else if (hrt_elapsed_time(&_vibration_warning_timestamp) > 10000000) {_vibration_warning = true;mavlink_and_console_log_critical(&_mavlink_log_pub, "HIGH VIBRATION! g: %d a: %d m: %d",(int)(100 * _voter_gyro.get_vibration_factor(curr_time)),(int)(100 * _voter_accel.get_vibration_factor(curr_time)),(int)(100 * _voter_mag.get_vibration_factor(curr_time)));}} else {_vibration_warning_timestamp = 0;}}// Update vision and motion capture heading//更新视觉和vicon航向bool vision_updated = false;orb_check(_vision_sub, &vision_updated);bool mocap_updated = false;orb_check(_mocap_sub, &mocap_updated);if (vision_updated) {orb_copy(ORB_ID(vision_position_estimate), _vision_sub, &_vision);//将订阅主题的内容复制到buffer(_vision)中;math::Quaternion q(_vision.q);math::Matrix<3, 3> Rvis = q.to_dcm();math::Vector<3> v(1.0f, 0.0f, 0.4f);//没看出 v 向量具体含义,疑似磁偏校正;// Rvis is Rwr (robot respect to world) while v is respect to world.// Hence Rvis must be transposed having (Rwr)' * Vw// Rrw * Vw = vn. This way we have consistency_vision_hdg = Rvis.transposed() * v;}//通过视觉得到的姿态估计q->Rvis,将v转换到机体坐标系;if (mocap_updated) {orb_copy(ORB_ID(att_pos_mocap), _mocap_sub, &_mocap);math::Quaternion q(_mocap.q);math::Matrix<3, 3> Rmoc = q.to_dcm();math::Vector<3> v(1.0f, 0.0f, 0.4f);// Rmoc is Rwr (robot respect to world) while v is respect to world.// Hence Rmoc must be transposed having (Rwr)' * Vw// Rrw * Vw = vn. This way we have consistency_mocap_hdg = Rmoc.transposed() * v;}// Update airspeedbool airspeed_updated = false;orb_check(_airspeed_sub, &airspeed_updated);if (airspeed_updated) {orb_copy(ORB_ID(airspeed), _airspeed_sub, &_airspeed);}// Check for timeouts on dataif (_ext_hdg_mode == 1) {_ext_hdg_good = _vision.timestamp_boot > 0 && (hrt_elapsed_time(&_vision.timestamp_boot) < 500000);} else if (_ext_hdg_mode == 2) {_ext_hdg_good = _mocap.timestamp_boot > 0 && (hrt_elapsed_time(&_mocap.timestamp_boot) < 500000);}bool gpos_updated;orb_check(_global_pos_sub, &gpos_updated);if (gpos_updated) {orb_copy(ORB_ID(vehicle_global_position), _global_pos_sub, &_gpos);if (_mag_decl_auto && _gpos.eph < 20.0f && hrt_elapsed_time(&_gpos.timestamp) < 1000000) {/* set magnetic declination automatically */update_mag_declination(math::radians(get_mag_declination(_gpos.lat, _gpos.lon)));}//磁偏自动校正,且水平偏差的标准差小于20,根据位置估计值(GPS)(vehicle_global_position)校正磁偏角;//get_mag_declination()函数查表得到地磁偏角,进行补偿。}if (_acc_comp && _gpos.timestamp != 0 && hrt_absolute_time() < _gpos.timestamp + 20000 && _gpos.eph < 5.0f && _inited) {/* position data is actual *///基于GPS的位置信息,微分得到加速度值;if (gpos_updated) {Vector<3> vel(_gpos.vel_n, _gpos.vel_e, _gpos.vel_d);/* velocity updated */if (_vel_prev_t != 0 && _gpos.timestamp != _vel_prev_t) {float vel_dt = (_gpos.timestamp - _vel_prev_t) / 1000000.0f;//时间间隔,单位(s)/* calculate acceleration in body frame */_pos_acc = _q.conjugate_inversed((vel - _vel_prev) / vel_dt);}//由ned坐标系下的速度求出机体坐标系下的加速度;_vel_prev_t = _gpos.timestamp;_vel_prev = vel;}} else {/* position data is outdated, reset acceleration *///位置信息已过时,重置;_pos_acc.zero();_vel_prev.zero();_vel_prev_t = 0;}/* time from previous iteration */hrt_abstime now = hrt_absolute_time();float dt = (last_time > 0) ? ((now  - last_time) / 1000000.0f) : 0.00001f;//用极小值0.00001表示零,预防除零错误;last_time = now;if (dt > _dt_max) {dt = _dt_max;}//时间间隔上限;if (!update(dt)) {continue;}//调用update(dt),**互补滤波**,更新四元数;//############若不熟悉update(),请转到函数查看;Vector<3> euler = _q.to_euler();struct vehicle_attitude_s att = {};att.timestamp = sensors.timestamp;att.roll = euler(0);att.pitch = euler(1);att.yaw = euler(2);att.rollspeed = _rates(0);att.pitchspeed = _rates(1);att.yawspeed = _rates(2);for (int i = 0; i < 3; i++) {att.g_comp[i] = _accel(i) - _pos_acc(i);}//补偿重力向量;/* copy offsets */memcpy(&att.rate_offsets, _gyro_bias.data, sizeof(att.rate_offsets));//memcpy(*dest,*src,size);Matrix<3, 3> R = _q.to_dcm();/* copy rotation matrix */memcpy(&att.R[0], R.data, sizeof(att.R));att.R_valid = true;memcpy(&att.q[0], _q.data, sizeof(att.q));att.q_valid = true;//获取姿态振动, RMS;att.rate_vibration = _voter_gyro.get_vibration_factor(hrt_absolute_time());att.accel_vibration = _voter_accel.get_vibration_factor(hrt_absolute_time());att.mag_vibration = _voter_mag.get_vibration_factor(hrt_absolute_time());/* the instance count is not used here */int att_inst;orb_publish_auto(ORB_ID(vehicle_attitude), &_att_pub, &att, &att_inst, ORB_PRIO_HIGH);//广播姿态信息;{//使用当前姿态,更新control_state,并发布;struct control_state_s ctrl_state = {};ctrl_state.timestamp = sensors.timestamp;/* attitude quaternions for control state */ctrl_state.q[0] = _q(0);ctrl_state.q[1] = _q(1);ctrl_state.q[2] = _q(2);ctrl_state.q[3] = _q(3);/* attitude rates for control state *///低通滤波,输入参数为当前值;ctrl_state.roll_rate = _lp_roll_rate.apply(_rates(0));ctrl_state.pitch_rate = _lp_pitch_rate.apply(_rates(1));ctrl_state.yaw_rate = _lp_yaw_rate.apply(_rates(2));/* Airspeed - take airspeed measurement directly here as no wind is estimated */if (PX4_ISFINITE(_airspeed.indicated_airspeed_m_s) && hrt_absolute_time() - _airspeed.timestamp < 1e6&& _airspeed.timestamp > 0) {ctrl_state.airspeed = _airspeed.indicated_airspeed_m_s;ctrl_state.airspeed_valid = true;} else {ctrl_state.airspeed_valid = false;}/* the instance count is not used here */int ctrl_inst;/* publish to control state topic *///发布控制状态主题,control_state.msg。orb_publish_auto(ORB_ID(control_state), &_ctrl_state_pub, &ctrl_state, &ctrl_inst, ORB_PRIO_HIGH);}{struct estimator_status_s est = {};est.timestamp = sensors.timestamp;est.vibe[0] = _voter_accel.get_vibration_offset(est.timestamp, 0);est.vibe[1] = _voter_accel.get_vibration_offset(est.timestamp, 1);est.vibe[2] = _voter_accel.get_vibration_offset(est.timestamp, 2);/* the instance count is not used here */int est_inst;/* publish to control state topic */orb_publish_auto(ORB_ID(estimator_status), &_est_state_pub, &est, &est_inst, ORB_PRIO_HIGH);}}
}


update_parameters();

l657~l686
void AttitudeEstimatorQ::update_parameters(bool force)
{bool updated = force;if (!updated) {orb_check(_params_sub, &updated);//查看参数是否更新;}if (updated) {//获取新参数;parameter_update_s param_update;orb_copy(ORB_ID(parameter_update), _params_sub, ¶m_update);param_get(_params_handles.w_acc, &_w_accel);param_get(_params_handles.w_mag, &_w_mag);param_get(_params_handles.w_ext_hdg, &_w_ext_hdg);param_get(_params_handles.w_gyro_bias, &_w_gyro_bias);float mag_decl_deg = 0.0f;param_get(_params_handles.mag_decl, &mag_decl_deg);update_mag_declination(math::radians(mag_decl_deg));int32_t mag_decl_auto_int;param_get(_params_handles.mag_decl_auto, &mag_decl_auto_int);_mag_decl_auto = mag_decl_auto_int != 0;//自动磁偏角校正;int32_t acc_comp_int;param_get(_params_handles.acc_comp, &acc_comp_int);_acc_comp = acc_comp_int != 0;param_get(_params_handles.bias_max, &_bias_max);//陀螺仪偏差上限;param_get(_params_handles.vibe_thresh, &_vibration_warning_threshold);//振动警告阈值;param_get(_params_handles.ext_hdg_mode, &_ext_hdg_mode);}
}

init();

1、k 为导航坐标系(NED)的 z 轴(D)在机体坐标系中的表示;

导航系中,D正方向朝下;

2、i 为导航坐标系(NED)的 x 轴(N)在机体坐标系;

i = (_mag - k * (_mag * k)); //施密特正交化;


//因 向量 k 已归一化,故分母等于1;

3、为导航坐标系(NED)的 yy 轴(E)在机体坐标系;

j = k % i //叉乘求正交向量; 

4、构造旋转矩阵 R
R.set_row(0, i); R.set_row(1, j); R.set_row(2, k);


5、转换为四元数 qq ,根据设定校正磁偏,归一化;

l688~l728
bool AttitudeEstimatorQ::init()
{// Rotation matrix can be easily constructed from acceleration and mag field vectors// 'k' is Earth Z axis (Down) unit vector in body frameVector<3> k = -_accel;k.normalize();// 'i' is Earth X axis (North) unit vector in body frame, orthogonal with 'k'Vector<3> i = (_mag - k * (_mag * k));i.normalize();// 'j' is Earth Y axis (East) unit vector in body frame, orthogonal with 'k' and 'i'Vector<3> j = k % i;// Fill rotation matrixMatrix<3, 3> R;R.set_row(0, i);R.set_row(1, j);R.set_row(2, k);// Convert to quaternion_q.from_dcm(R);// Compensate for magnetic declinationQuaternion decl_rotation;decl_rotation.from_yaw(_mag_decl);_q = decl_rotation * _q;_q.normalize();if (PX4_ISFINITE(_q(0)) && PX4_ISFINITE(_q(1)) &&PX4_ISFINITE(_q(2)) && PX4_ISFINITE(_q(3)) &&_q.length() > 0.95f && _q.length() < 1.05f) {_inited = true;} else {_inited = false;}return _inited;
}

update();


1、init();//执行一次;

由加速度计和磁力计初始化旋转矩阵和四元数;

2、mag_earth = _q.conjugate(_mag);

不使用外部航向,或外部航向异常时,采用磁力计校准; 
将磁力计读数从机体坐标系转换到导航坐标系; 

3、mag_err = _wrap_pi(atan2f(mag_earth(1), mag_earth(0)) - _mag_decl);

将磁力计的读数由向量换算到角度; 该角度减去磁偏,得到磁场偏差; 
_mag_decl 由GPS得到; 
**atan2f: 2 表示两个输入参数; 支持四象限内角度换算; 输出弧度值; 
**_wrap_pi: 将(0~2pi)的角度映射到(-pi~pi);

4、corr += _q.conjugate_inversed(Vector<3>(0.0f, 0.0f, -mag_err)) * _w_mag;

将磁场偏差转换到机体坐标系,并乘以其对应权重; 
 

5、_q.normalize();

四元数归一化; 
这里的归一化用于校正update_mag_declination后的偏差。

corr += (k % (_accel - _pos_acc).normalized()) * _w_accel;

6、向量 k 是重力加速度向量(0,0,1)转换到机体坐标系; 
_accel 是加速度计的读数; 
_pos_acc 是由位置估计(GPS) 微分得到的加速度; 
_accel - _pos_acc 表示飞行器加速度向量减去其水平分量; 
k 与 (_accel - _pos_acc)叉乘,得到偏差; 


7、_gyro_bias += corr * (_w_gyro_bias * dt);

得到陀螺仪修正值 
此处修正值为 mahony 滤波的 pi 控制器的 积分部分; 
因为 _gyro_bias 不归零,故不断累积; 

8、_rates = _gyro + _gyro_bias;

_rates 表示角速度; 


9、corr += _rates;

这里的 corr = (Ea+Em) + (Ea+Em)*dt + gyro; 
个人认为这里的 corr 才是更新后的角速度;

10、_q += _q.derivative(corr) * dt;

更新四元数,derivative为求导函数,使用一阶龙格库塔求导。 

l730~l817
bool AttitudeEstimatorQ::update(float dt)
{if (!_inited) {if (!_data_good) {return false;}return init();}Quaternion q_last = _q;//保存上一状态,以便恢复;// Angular rate of correctionVector<3> corr;//初始化元素为0;//_ext_hdg_good表示外部航向数据可用;if (_ext_hdg_mode > 0 && _ext_hdg_good) {if (_ext_hdg_mode == 1) {// Vision heading correction//视觉航向校正;// Project heading to global frame and extract XY component//将航向投影到导航坐标系,提取XY分量;Vector<3> vision_hdg_earth = _q.conjugate(_vision_hdg);float vision_hdg_err = _wrap_pi(atan2f(vision_hdg_earth(1), vision_hdg_earth(0)));// Project correction to body framecorr += _q.conjugate_inversed(Vector<3>(0.0f, 0.0f, -vision_hdg_err)) * _w_ext_hdg;}if (_ext_hdg_mode == 2) {// Mocap heading correction// Project heading to global frame and extract XY componentVector<3> mocap_hdg_earth = _q.conjugate(_mocap_hdg);float mocap_hdg_err = _wrap_pi(atan2f(mocap_hdg_earth(1), mocap_hdg_earth(0)));// Project correction to body framecorr += _q.conjugate_inversed(Vector<3>(0.0f, 0.0f, -mocap_hdg_err)) * _w_ext_hdg;}}if (_ext_hdg_mode == 0  || !_ext_hdg_good) {// Magnetometer correction// Project mag field vector to global frame and extract XY componentVector<3> mag_earth = _q.conjugate(_mag);float mag_err = _wrap_pi(atan2f(mag_earth(1), mag_earth(0)) - _mag_decl);// Project magnetometer correction to body framecorr += _q.conjugate_inversed(Vector<3>(0.0f, 0.0f, -mag_err)) * _w_mag;}_q.normalize();// Accelerometer correction// Project 'k' unit vector of earth frame to body frame// Vector<3> k = _q.conjugate_inversed(Vector<3>(0.0f, 0.0f, 1.0f));// Optimized version with dropped zerosVector<3> k(2.0f * (_q(1) * _q(3) - _q(0) * _q(2)),2.0f * (_q(2) * _q(3) + _q(0) * _q(1)),(_q(0) * _q(0) - _q(1) * _q(1) - _q(2) * _q(2) + _q(3) * _q(3)));corr += (k % (_accel - _pos_acc).normalized()) * _w_accel;// Gyro bias estimation_gyro_bias += corr * (_w_gyro_bias * dt);for (int i = 0; i < 3; i++) {//陀螺仪最大偏差上限;_gyro_bias(i) = math::constrain(_gyro_bias(i), -_bias_max, _bias_max);}_rates = _gyro + _gyro_bias;// Feed forward gyrocorr += _rates;// Apply correction to state_q += _q.derivative(corr) * dt;// Normalize quaternion_q.normalize();//判断四元数是否发散,若发散,则沿用之前的四元数;if (!(PX4_ISFINITE(_q(0)) && PX4_ISFINITE(_q(1)) &&PX4_ISFINITE(_q(2)) && PX4_ISFINITE(_q(3)))) {// Reset quaternion to last good state_q = q_last;_rates.zero();_gyro_bias.zero();return false;}return true;
}


update_mag_declination();

l819~l832
void AttitudeEstimatorQ::update_mag_declination(float new_declination)
{// Apply initial declination or trivial rotations without changing estimation//忽略微小旋转;if (!_inited || fabsf(new_declination - _mag_decl) < 0.0001f) {_mag_decl = new_declination;} else {// Immediately rotate current estimation to avoid gyro bias growth//磁偏超过一定值后,校正姿态;Quaternion decl_rotation;decl_rotation.from_yaw(new_declination - _mag_decl);//由磁偏角度转化为四元数;_q = decl_rotation * _q;//四元数相乘表示角度相加;_mag_decl = new_declination;}
}


attitude_estimator_q_main();

l834~l890
int attitude_estimator_q_main(int argc, char *argv[])
{//外部调用接口;if (argc < 2) {warnx("usage: attitude_estimator_q {start|stop|status}");return 1;}if (!strcmp(argv[1], "start")) {if (attitude_estimator_q::instance != nullptr) {warnx("already running");return 1;}//实例化,instance;attitude_estimator_q::instance = new AttitudeEstimatorQ;if (attitude_estimator_q::instance == nullptr) {warnx("alloc failed");return 1;}if (OK != attitude_estimator_q::instance->start()) {delete attitude_estimator_q::instance;attitude_estimator_q::instance = nullptr;warnx("start failed");return 1;}return 0;}if (!strcmp(argv[1], "stop")) {if (attitude_estimator_q::instance == nullptr) {warnx("not running");return 1;}//删除实例化对象,指针置空;delete attitude_estimator_q::instance;attitude_estimator_q::instance = nullptr;return 0;}//打印当前姿态信息;if (!strcmp(argv[1], "status")) {if (attitude_estimator_q::instance) {attitude_estimator_q::instance->print();warnx("running");return 0;} else {warnx("not running");return 1;}}warnx("unrecognized command");return 1;
}



原文:https://blog.csdn.net/luoshi006/article/details/51513580 
 

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 【cartographer】园区场景自动驾驶-降低回环检测运算量

    园区场景自动驾驶-降低回环检测运算量 概述 在园区进行建图时&#xff0c;地图较大&#xff0c;运行定位模式时的回环检测计算量很大&#xff0c;计算机负担大。为降低纯定位模式下的计算量&#xff0c;将回环检测的全图匹配更换为大范围匹配。 背景 有gps和rtk信息的辅助&…...

    2024/4/21 14:47:27
  2. CSS3的calc()使用

    calc()对大家来说&#xff0c;或许很陌生&#xff0c;不太会相信calc()是css中的部分。因为看其外表像个函数&#xff0c;既然是函数为何又出现在CSS中呢&#xff1f;这一点也让我百思不得其解&#xff0c;今天有一同事告诉我&#xff0c;说CSS3中有一个属性能实现自适应的布局…...

    2024/4/29 12:08:41
  3. 双眼皮埋线抽出线恢复

    ...

    2024/4/20 7:53:18
  4. 双眼皮埋线吃辣椒了

    ...

    2024/4/20 15:16:07
  5. 双眼皮埋线长了小疙瘩

    ...

    2024/4/29 14:50:01
  6. 双眼皮埋线拆线重做了

    ...

    2024/4/30 4:17:15
  7. 双眼皮埋线拆了什么样

    ...

    2024/4/25 4:36:05
  8. 4. webpack处理图片资源

    常用的样式loader file-loader&#xff1a;可以用来帮助webpack打包处理一系列的图片文件&#xff1b;比如&#xff1a;.png 、 .jpg 、.jepg等格式的图片。 url-loader&#xff1a;功能类似于 file-loader&#xff0c;但是在文件大小&#xff08;单位 byte&#xff09;低于指…...

    2024/4/20 15:16:03
  9. 由浅入深Webpack

    一.使用Webpack 1.Webpack命令 webpack -h帮助命令webpack -v查看版本webpack <entry> [<entry>] <output>输入一个或多个entry打包命令 2.Webpack-cli 安装npm install -g webpack-cli作用&#xff1a;交互式的初始化一个项目初始化webpack项目webpack-…...

    2024/4/27 16:15:06
  10. webpack的初步入门

    语雀地址&#xff1a;https://www.yuque.com/chenzilong/mhtr5g/ygh2u8 目录 *. 写在开始 *.1 方式方法 *.2 阶段目标 *.3 本文的主线图 *.4 学习要求 1. 前端发展开始说起 1.1 发展历史 1.2 日益复杂的前端 1.3 包管理的发展 2. 前端为什么需要打包 3. 前端可选的…...

    2024/5/5 10:09:28
  11. webpack 更改默认host port 端口 webpack-dev-server

    在webpack.config.js中编辑节点 devServer: { host:’127.0.0.1’, port:8088 },...

    2024/4/29 14:29:23
  12. 关于webpack的loader小教程:如何删除代码中的console

    关于webpack的loader小教程:如何删除代码中的console 在开发环境中&#xff0c;我们经常会加入很多console.log来做代码的调试&#xff0c;但是我们并不希望当项目上线后,还会有打印的值,因此我们需要将这些console在上线前全部删掉。虽然webpack4中已经集成了去除console的功…...

    2024/5/5 3:28:22
  13. 双眼皮埋线不用拆线

    ...

    2024/5/4 18:49:35
  14. 双眼皮埋线半年还肿

    ...

    2024/4/21 14:47:21
  15. Processing Images(处理图像)

    Processing Images&#xff08;处理图像&#xff09; Core Image has three classes thatsupport image processing on iOS and OS X:&#xff08;在IOS和OS X上 Core Image 有三个类支持图像的处理&#xff09; CIFilter is a mutable object that represents an effect. A fi…...

    2024/5/4 16:05:50
  16. R统计绘图-corrplot热图绘制细节调整2(更改变量可视化顺序、非相关性热图绘制、添加矩形框等)

    上一篇文章推送的是怎样调整corrplot热图的可视化参数&#xff0c;以修改字符和图例位置&#xff0c;数据可视化形式和字符小大和颜色等这篇是一个补充部分&#xff0c;记录怎样修改参数以变量排序方式和突出部分数据。本流程还是使用R统计绘图-环境因子相关性热图中的不同土壤…...

    2024/5/5 0:58:49
  17. 流程定制

    今天在github上找到了一个用于流程定制的项目&#xff0c;svg实现流程图绘制&#xff0c;及流程图转xpdl和xml&#xff0c;导入导出json&#xff0c;感觉很棒&#xff0c;推荐给大家&#xff0c;也用于自己记录 项目链接&#xff1a;https://github.com/zhangyuanliang/flowch…...

    2024/5/4 20:57:20
  18. 轻量级流程图控件GoJS现已发布v2.1.50最新版本!

    GoJS是一款功能强大&#xff0c;快速且轻量级的流程图控件&#xff0c;可帮助你在JavaScript 和HTML5 Canvas程序中创建流程图&#xff0c;且极大地简化您的JavaScript / Canvas 程序。 接下来让我们一起看看GoJS最新版本的具体情况吧&#xff1a; 2.1.50 的更新情况&#xf…...

    2024/4/21 14:47:17
  19. Angularjs执行流程

    一、启动阶段大家应该都知道&#xff0c;当浏览器加载一个HTML页面时&#xff0c;它会将HMTL页面先解析成DOM树&#xff0c;然后逐个加载DOM树中的每一个元素节点。我们可以把AngularJS当做一个类似jQuery的js库&#xff0c;我们通过<script>标签引入到HTML中&#xff0c…...

    2024/5/4 17:45:17
  20. openlayers--绘制图形

    文章目录版本说明引入依赖根据geojson绘制地图创建绘制图层绘制图形关闭绘图根据坐标绘制多边形删除图层所有图形清除图层总结参考版本说明 angular&#xff1a; ~10.1.0 typescript:&#xff1a;~4.0.2 ol: ^6.4.3 引入依赖 import ol/ol.css; import Map from ol/Map; imp…...

    2024/5/1 9:44:20

最新文章

  1. C++中的构造函数以及默认拷贝构造函数

    构造函数 构造函数是在创建类的新对象时自动调用的函数&#xff0c;用于初始化对象的状态。构造函数的名称与类名相同&#xff0c;没有返回类型。 基本构造函数类型&#xff1a; 默认构造函数&#xff1a; 定义&#xff1a;没有参数的构造函数&#xff0c;或者是所有参数都有…...

    2024/5/5 19:20:04
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 数据结构——线性表(顺序存储结构)

    语言&#xff1a;C语言软件&#xff1a;Visual Studio 2022笔记书籍&#xff1a;数据结构——用C语言描述如有错误&#xff0c;感谢指正。若有侵权请联系博主 一、线性表的逻辑结构 线性表是n个类型相同的数据元素的有限序列&#xff0c;对n>0&#xff0c;除第一元素无直接…...

    2024/5/1 8:30:49
  4. 蓝桥杯第十五届抱佛脚(十)贪心算法

    蓝桥杯第十五届抱佛脚&#xff08;十&#xff09;贪心算法 贪心算法基本概念 贪心算法是一种在算法设计中常用的方法&#xff0c;它在每一步选择中都采取在当前状态下最好或最优&#xff08;即最有利&#xff09;的选择&#xff0c;从而希望导致结果是最好或最优的算法。 贪…...

    2024/5/5 8:38:28
  5. 分享一个Python爬虫入门实例(有源码,学习使用)

    一、爬虫基础知识 Python爬虫是一种使用Python编程语言实现的自动化获取网页数据的技术。它广泛应用于数据采集、数据分析、网络监测等领域。以下是对Python爬虫的详细介绍: 架构和组成:下载器:负责根据指定的URL下载网页内容,常用的库有Requests和urllib。解析器:用于解…...

    2024/5/5 7:27:13
  6. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/4 23:54:56
  7. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/4 23:54:56
  8. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/5/4 23:54:56
  9. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/4 23:55:17
  10. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/5/4 23:54:56
  11. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/5/4 23:55:05
  12. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/5/4 23:54:56
  13. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/5/4 23:55:16
  14. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/5/4 23:54:56
  15. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/4 18:20:48
  16. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/5/4 23:54:56
  17. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/5/4 23:55:17
  18. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/5/4 23:55:06
  19. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/5/4 23:54:56
  20. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/4 23:55:06
  21. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/5 8:13:33
  22. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/5/4 23:55:16
  23. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/5/4 23:54:58
  24. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/4 23:55:01
  25. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/5/4 23:54:56
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57