ArduPilot开源代码之AP_OSD
ArduPilot开源代码之AP_OSD
- 1. 源由
- 2. 简介
- 3. 补丁
- 4. 框架设计
- 4.1 启动代码 (AP_OSD::init)
- 4.2 任务代码 (AP_OSD::osd_thread)
- 4.3 实例初始化 (AP_OSD::init_backend)
- 5. 重要例程
- 5.1 AP_OSD::update_stats
- 5.2 AP_OSD::update_current_screen
- 5.3 AP_OSD::update_osd
- 6. 总结
- 7. 参考资料
1. 源由
因为自己有两个摄像头:模拟+数字;而数字OpenIPC地面端Jetson-fpv还不太成熟,所以暂时还想使用模拟的飞,等稳定了切换成数字。
问题是数字录像还是要的,以便更好的了解OpenIPC作为数字图传的效果。
- Is it possible for two OSD resolution working at the same time?
- How to setup two VTX (one for analog camera, another for digital camera)
从代码和咨询的角度看,似乎Ardupilot并不支持同时两个OSD在不同分辨率的情况下工作。
所以,还是需要从代码入手,DIY玩的就是“心跳”,对吧。
2. 简介
最多支持两种OSD实例切换,不支持同一时刻,两种OSD同时使用。
#define OSD_MAX_INSTANCES 2
基于AP_OSD_Backend支持以下四种OSD类型:
- OSD_MAX7456: AP_OSD_MAX7456
- OSD_SITL: AP_OSD_SITL
- OSD_MSP: AP_OSD_MSP
- OSD_MSP_DISPLAYPORT: AP_OSD_MSP_DisplayPort
3. 补丁
但是通过AP_OSD: add two osd resolution concurrently support #29149 已经打破该困局,支持同一时刻,两种尺寸的OSD的同时显示:
- Git Repo下如何制作一个patch文件
patch分享/更好的差异化比较,减少宝贵Review时间浪费,也是对代码熟悉程度的体现。
另外,也可以作为系统集成的差异化补丁,快速实现本地集成、编译、测试、验证等。
4. 框架设计
接下来,我们来看下该模块的设计。
4.1 启动代码 (AP_OSD::init)
这里不做过多解释,详见:启动代码流程-ArduPilot飞控启动&运行过程简介
Copter::init_ardupilot└──> osd.init();
- 根据配置内容直接对实例类型进行赋值
- 然后针对对应的四种类型OSD进行初始化
- 创建
osd_thread任务,依据优先级执行例程
AP_OSD::init├──> const AP_OSD::osd_types types[OSD_MAX_INSTANCES] = {│ osd_types(osd_type.get()),│ osd_types(osd_type2.get())│ };├──> for <instance < OSD_MAX_INSTANCES>│ ├──> init_backend(types[instance], instance)│ └──> _backend_count++;└──> <_backend_count > 0>└──> hal.scheduler->thread_create(FUNCTOR_BIND_MEMBER(&AP_OSD::osd_thread, void), "OSD", 1280, AP_HAL::Scheduler::PRIORITY_IO, 1);
4.2 任务代码 (AP_OSD::osd_thread)
- 例程会首先执行
osd_thread_run_once - 然后每隔100ms唤醒对2个OSD实例进行更新
- 若
disableOSD,则无需更新状态 - 对OSD Overlay进行刷新
├──> for <instance < OSD_MAX_INSTANCES>│ └──> _backends[instance]->osd_thread_run_once()└──> <loop>├──> hal.scheduler->delay(100)├──> <!_disable>│ ├──> update_stats();│ └──> update_current_screen();└──> update_osd()
4.3 实例初始化 (AP_OSD::init_backend)
每种实例需要对软硬件进行除此环境设定,这里采用类似probe的方式执行。
- 若,probe失败,则该OSD实例为空指针
- 若,该实例与第一个默认OSD实例冲突,则第二个实例不进行初始化
AP_OSD::init_backend├──> <instance > 0 && _backends[0] && !_backends[0]->is_compatible_with_backend_type(type)>│ └──> return false; // 第二种类型OSD与默认第一类OSD不兼容├──> <switch>│ ├──> <OSD_NONE> break│ ├──> <OSD_TXONLY> break│ ├──> <OSD_MAX7456> <HAL_WITH_SPI_OSD> <HAL_WITH_OSD_BITMAP>│ │ ├──> AP_HAL::OwnPtr<AP_HAL::Device> spi_dev = std::move(hal.spi->get_device("osd"));│ │ ├──> _backends[instance] = AP_OSD_MAX7456::probe(*this, std::move(spi_dev))│ │ └──> break│ ├──> <WITH_SITL_OSD> │ │ ├──> _backends[instance] = AP_OSD_SITL::probe(*this)│ │ └──> break│ ├──> <OSD_MSP> │ │ ├──> _backends[instance] = AP_OSD_MSP::probe(*this);│ │ └──> break│ └──> <OSD_MSP_DISPLAYPORT> <HAL_WITH_MSP_DISPLAYPORT>│ ├──> _backends[instance] = AP_OSD_MSP_DisplayPort::probe(*this)│ └──> break├──> <OSD_ENABLED && _backends[instance] != nullptr>│ ├──> _backends[instance]->init_symbol_set(AP_OSD_AbstractScreen::symbols_lookup_table, AP_OSD_NUM_SYMBOLS)│ └──> return true;└──> return false;
5. 重要例程
5.1 AP_OSD::update_stats
对系统内部的参数进行定期更新
- 地速
- 位置
- 高度
- 空速
- 飞行距离
- 最大地面速度
- 最大高度
- 最大直线与HOME的距离
- 最大电流
- 最小电压
- 最小RSSI
- 最大空速
- 最大ESC温度
AP_OSD::update_stats├──> WITH_SEMAPHORE(_sem);├──> uint32_t now = AP_HAL::millis();├──> <!AP_Notify::flags.armed> //没有启动,则无需更新状态│ ├──> _stats.last_update_ms = now;│ └──> return;│├──> [更新delta_ms]│ ├──> uint32_t delta_ms = now - _stats.last_update_ms;│ ├──> _stats.last_update_ms = now;│ ││ ├──> Vector2f v;│ ├──> Location loc {};│ ├──> Location home_loc;│ ├──> bool home_is_set;│ ├──> bool have_airspeed_estimate;│ ├──> float alt;│ ├──> float aspd_mps = 0.0f;│ └──> [获取地速、HOME以及当前位置、高度、空速]│ ├──> AP_AHRS &ahrs = AP::ahrs();│ ├──> WITH_SEMAPHORE(ahrs.get_semaphore()); // minimize semaphore scope│ ├──> v = ahrs.groundspeed_vector();│ ├──> home_is_set = ahrs.get_location(loc) && ahrs.home_is_set();│ ├──> <home_is_set>│ │ └──>home_loc = ahrs.get_home();│ ├──> ahrs.get_relative_position_D_home(alt);│ └──> have_airspeed_estimate = ahrs.airspeed_estimate(aspd_mps);│├──> [飞行距离更新]│ ├──> float speed = v.length();│ ├──> <speed < 0.178>│ │ └──> speed = 0.0;│ ├──> float dist_m = (speed * delta_ms)*0.001;│ └──> _stats.last_distance_m += dist_m;│├──> [最大地面速度更新]│ └──> _stats.max_speed_mps = fmaxf(_stats.max_speed_mps,speed);│├──> [最大距离HOME位置更新]<home_is_set>│ ├──> float distance = home_loc.get_distance(loc);│ └──> _stats.max_dist_m = fmaxf(_stats.max_dist_m, distance);│├──> [最大高度更新]│ ├──> alt = -alt;│ └──> _stats.max_alt_m = fmaxf(_stats.max_alt_m, alt);│├──> <AP_BATTERY_ENABLED>│ ├──> [最大电流更新]│ │ ├──> AP_BattMonitor &battery = AP::battery();│ │ ├──> float amps;│ │ └──> <battery.current_amps(amps)> _stats.max_current_a = fmaxf(_stats.max_current_a, amps)│ └──> [最小电压更新]│ ├──> float voltage = battery.voltage();│ └──> <voltage > 0> _stats.min_voltage_v = fminf(_stats.min_voltage_v, voltage)│├──> <AP_RSSI_ENABLED>│ └──> [最小RSSI更新]│ ├──> AP_RSSI *ap_rssi = AP_RSSI::get_singleton();│ └──> <ap_rssi> _stats.min_rssi = fminf(_stats.min_rssi, ap_rssi->read_receiver_rssi());│├──> [最大空速更新]│ └──> <have_airspeed_estimate> _stats.max_airspeed_mps = fmaxf(_stats.max_airspeed_mps, aspd_mps);│└──> <HAL_WITH_ESC_TELEM>└──> [最大ESC温度更新]├──> AP_ESC_Telem& telem = AP::esc_telem();├──> int16_t highest_temperature = 0;├──> telem.get_highest_temperature(highest_temperature);└──> _stats.max_esc_temp = MAX(_stats.max_esc_temp, highest_temperature);
5.2 AP_OSD::update_current_screen
默认配置情况下:
arm_scr = 0disarm_scr = 0failsafe_scr = 0rc_channel = 0
// @Param: _CHAN// @DisplayName: Screen switch transmitter channel// @Description: This sets the channel used to switch different OSD screens.// @Values: 0:Disable,5:Chan5,6:Chan6,7:Chan7,8:Chan8,9:Chan9,10:Chan10,11:Chan11,12:Chan12,13:Chan13,14:Chan14,15:Chan15,16:Chan16// @User: StandardAP_GROUPINFO("_CHAN", 2, AP_OSD, rc_channel, 0),// @Param: _ARM_SCR// @DisplayName: Arm screen// @Description: Screen to be shown on Arm event. Zero to disable the feature.// @Range: 0 4// @User: StandardAP_GROUPINFO("_ARM_SCR", 17, AP_OSD, arm_scr, 0),// @Param: _DSARM_SCR// @DisplayName: Disarm screen// @Description: Screen to be shown on disarm event. Zero to disable the feature.// @Range: 0 4// @User: StandardAP_GROUPINFO("_DSARM_SCR", 18, AP_OSD, disarm_scr, 0),// @Param: _FS_SCR// @DisplayName: Failsafe screen// @Description: Screen to be shown on failsafe event. Zero to disable the feature.// @Range: 0 4// @User: StandardAP_GROUPINFO("_FS_SCR", 19, AP_OSD, failsafe_scr, 0),
所以,默认情况以下代码不执行。
AP_OSD::update_current_screen├──> [Switch on ARM/DISARM event]│ ├──> <AP_Notify::flags.armed>│ │ ├──> <!was_armed && arm_scr > 0 │ │ │ │ && arm_scr <= AP_OSD_NUM_DISPLAY_SCREENS │ │ │ │ && get_screen(arm_scr-1).enabled>│ │ │ └──> current_screen = arm_scr-1;│ │ └──> was_armed = true;│ └──> <was_armed>│ ├──> <disarm_scr > 0>│ │ │ && disarm_scr <= AP_OSD_NUM_DISPLAY_SCREENS │ │ │ && get_screen(disarm_scr-1).enabled>│ │ └──> current_screen = disarm_scr-1;│ └──> was_armed = false;│├──> [Switch on failsafe event]│ ├──> <AP_Notify::flags.failsafe_radio │ │ || AP_Notify::flags.failsafe_battery>│ │ ├──> <!was_failsafe && failsafe_scr > 0 │ │ │ │ && failsafe_scr <= AP_OSD_NUM_DISPLAY_SCREENS │ │ │ │ && get_screen(failsafe_scr-1).enabled>│ │ │ ├──> pre_fs_screen = current_screen;│ │ │ └──> current_screen = failsafe_scr-1;│ │ └──> was_failsafe = true;│ └──> <was_failsafe>│ ├──> <get_screen(pre_fs_screen).enabled>│ │ └──> current_screen = pre_fs_screen;│ └──> was_failsafe = false;│├──> <rc_channel == 0> return│└──> <AP_RC_CHANNEL_ENABLED>├──> RC_Channel *channel = RC_Channels::rc_channel(rc_channel-1);├──> <channel == nullptr> return;├──> int16_t channel_value = channel->get_radio_in();├──> [switch (sw_method)] │ ├──> <default/TOGGLE> //switch to next screen if channel value was changed│ │ ├──> <previous_channel_value == 0>│ │ │ └──> previous_channel_value = channel_value; //do not switch to the next screen just after initialization│ │ └──> <abs(channel_value-previous_channel_value) > 200>│ │ ├──> switch_debouncer) {│ │ │ ├──> next_screen();│ │ │ └──> previous_channel_value = channel_value;│ │ └──> <else>│ │ ├──> switch_debouncer = true;│ │ └──> return;│ ││ ├──> <PWM_RANGE> //select screen based on pwm ranges specified│ │ └──> <for (int i=0; i<AP_OSD_NUM_SCREENS; i++>│ │ └──> <get_screen(i).enabled │ │ │ && get_screen(i).channel_min <= channel_value │ │ │ && get_screen(i).channel_max > channel_value>│ │ ├──> <previous_pwm_screen == i>│ │ │ └──> break;│ │ └──> <else>│ │ └──> current_screen = previous_pwm_screen = i;│ ││ └──> <AUTO_SWITCH> //switch to next screen after low to high transition and every 1s while channel value is high│ ├──> <channel_value > channel->get_radio_trim()>│ │ ├──> <switch_debouncer>│ │ │ ├──> uint32_t now = AP_HAL::millis();│ │ │ └──> <now - last_switch_ms > 1000>│ │ │ ├──> next_screen();│ │ │ └──> last_switch_ms = now;│ │ └──> <else>│ │ ├──> switch_debouncer = true;│ │ └──> return;│ └──> <else>│ └──>last_switch_ms = 0;└──> switch_debouncer = false;
5.3 AP_OSD::update_osd
默认初始化时,current_screen = 0。
所以,从这里可以看出,始终更行current_screen对应的OSD。
AP_OSD::update_osd└──> for <instance < _backend_count>├──> _backends[instance]->clear()├──> <!_disable>│ ├──> get_screen(current_screen).set_backend(_backends[instance])│ └──> <_backends[instance]->get_backend_type() != OSD_MSP> get_screen(current_screen).draw()└──> _backends[instance]->flush()
6. 总结
为了让Ardupilot代码支持模拟+数字OSD同时显示更新,需定制固件。
目前,前面提及的补丁尚未合入,且存在一个模拟越来越少使用的问题,要合入可能也存在一定的苦难。
不过,对于我们的测试样机:
- ArduPilot开源飞控之lida2003-H743-5inch套机配置
- ArduPilot开源飞控之lida2003-H743-5inch配置调整
这里已经整理了代码:
- AP_OSD: add two osd resolution concurrently support
- hwdef: enable two osd resolution concurrently feature for Aocoda-RC H743 target
$ git clone git@github.com:SnapDragonfly/ardupilot.git
or
$ git clone https://github.com/SnapDragonfly/ardupilot.git
$ cd ardupilot
$ git checkout Copter-4.5-lida2003
然后进行编译:
- ArduPilot飞控AOCODARC-H7DUAL固件编译
- Ardupilot开源飞控工程项目编译回顾
7. 参考资料
【1】ArduPilot开源飞控系统之简单介绍
【2】ArduPilot之开源代码Task介绍
【3】ArduPilot飞控启动&运行过程简介
【4】ArduPilot之开源代码Library&Sketches设计
【5】ArduPilot之开源代码Sensor Drivers设计
相关文章:
ArduPilot开源代码之AP_OSD
ArduPilot开源代码之AP_OSD 1. 源由2. 简介3. 补丁4. 框架设计4.1 启动代码 (AP_OSD::init)4.2 任务代码 (AP_OSD::osd_thread)4.3 实例初始化 (AP_OSD::init_backend) 5. 重要例程5.1 AP_OSD::update_stats5.2 AP_OSD::update_current_screen5.3 AP_OSD::update_osd 6. 总结7.…...
sysbench手动测试OceanBase v4.2.4集群
环境: 1、ocp(sysbench节点) 192.192.103.128 2、ob集群1-1-1 observer 192.192.103.125、192.192.103.126、192.192.103.127,primary_zone:random haproxy 192.192.103.125、192.192.103.126、192.192.103.127 一、安装sysben…...
腾讯元宝:AI 时代的快速论文阅读助手
1. 背景与需求 在 AI 研究领域,每天都会涌现大量学术论文。如何高效阅读并提取关键信息成为研究者的一大难题。腾讯元宝是腾讯推出的一款大模型,结合了**大语言模型(LLM)和自然语言处理(NLP)**技术&#x…...
重构谷粒商城09:人人开源框架的快速入门
谷粒商城09——人人开源框架的快速入门 前言:这个系列将使用最前沿的cursor作为辅助编程工具,来快速开发一些基础的编程项目。目的是为了在真实项目中,帮助初级程序员快速进阶,以最快的速度,效率,快速进阶…...
AAA 技术详解:认证、授权与计费的原理、应用与配置实践
AAA(Authentication, Authorization, Accounting,即认证、授权和计费)是网络安全的“身份管理员”,负责验证用户身份、分配访问权限并记录行为轨迹。它如同网络世界中的“物业管理系统”,通过三重机制确保接入安全、权…...
OneM2M:全球性的物联网标准-可应用于物联网中
OneM2M 是一个全球性的物联网(IoT)标准,旨在为物联网设备和服务提供统一的框架和接口,以实现设备之间的互操作性、数据共享和服务集成。OneM2M 由多个国际标准化组织(如 ETSI、TIA、TTC、ARIB 等)共同制定,目标是解决物联网领域的碎片化问题,提供一个通用的标准,支持跨…...
redis数据迁移教程(使用RedisShake实现不停机迁移十分便捷)
1.我的场景 需要把本地的redis数据上传到阿里云服务器上面,服务器上redis并没有开aof持久化,但是将rdb文件上传至服务器后每次重启redis,rdb文件会被覆盖导致无法同同步数据,最终决定使用RedisShake 2.RedisShake介绍 什么是 RedisShake RedisShake 是一个用于处理和迁移…...
Linux基本操作指令3
1、wget: 这是一个用于从网络上下载文件的命令行工具。它支持 HTTP、HTTPS 和 FTP 协议。 wget http://download.qt.io/archive/qt/5.12/5.12.9/qt-opensource-linux-x64-5.12.9.run 2、下载完成后,你可以通过以下命令使文件可执行并运行安装程序: ch…...
2025年2月平价旗舰手机性能对比
1、荣耀Magic7 点评:缺席潜望式长焦,3X直立长焦体验还行。兼顾性能、游戏、屏幕、影像、续航、快充等诸多方面,且外围配置比较齐全。 2、vivo x200 点评:潜望式长焦相机,拍照效果好,30W无线充电着实鸡肋&a…...
Python SQLite3 保姆级教程:从零开始学数据库操作
Python SQLite3 保姆级教程:从零开始学数据库操作 本文适合纯新手!无需任何数据库基础,跟着步骤操作即可掌握 SQLite3 的核心用法。 目标:让你像用记事本一样轻松操作数据库! 目录 什么是 SQLite3?环境准…...
第七步:简单爬虫与网页测试
Puppeteer 官方文档:https://puppeteer.bootcss.com/ 1、安装 puppeteer是一个node插件安装命令:npm i puppeteer 2、概念 无头浏览器:就是不打开浏览器的页面,直接进行浏览器后台操作 3、入门 引入:import pup…...
4.桥接模式
概况 桥接模式:将抽象部分与实现部分分离,使它们可以独立变化,通过组合而非继承的方式实现解耦。 业务场景 场景描述:开发一个跨平台的图形绘制系统,支持不同形状(如圆形、矩形)和不同渲染方式…...
Golang学习笔记_44——命令模式
Golang学习笔记_41——观察者模式 Golang学习笔记_42——迭代器模式 Golang学习笔记_43——责任链模式 文章目录 一、核心概念1. 定义2. 解决的问题3. 核心角色4. 类图 二、特点分析三、适用场景1. 事务管理系统2. 多媒体遥控器3. 操作审计系统 四、Go语言实现示例五、高级应用…...
算法中的背包问题详解:部分背包与0-1背包
1. 背包问题概述 背包问题是组合优化中的经典问题,其核心目标是:在给定容量的背包中装入一组物品,使得物品的总价值最大化。根据物品是否可分割或重复选择,背包问题分为多个变种,其中最常见的两种是: 部分…...
【单片机通信技术】STM32 HAL库 SPI主从机通过串口发送数据
一、说明 使用STM32F103C8T6最小系统板,让板载SPI1与SPI2通信,通过串口收发数据。本文章说明了在配置与编写时遇到的一些问题,以及详细说明如何使用cubeMAX进行代码编写。 二、CubeMAX配置 1.时钟配置选择外部高速时钟 2.系统模式与时钟配…...
laravel中 添加公共/通用 方法/函数
一,现在app 下面创建Common目录,然后在创建Common.php 文件 二,修改composer.json文件 添加这个到autoload 中 "files": ["app/Common/Common.php"]"autoload": {"psr-4": {"App\\": &quo…...
Jetpack Compose — 入门实践
一、项目中使用 Jetpack Compose 从此节开始,为方便起见,如无特殊说明,Compose 均指代 Jetpack Compose。 开发工具: Android Studio 1.1 创建支持 Compose 新应用 新版 Android Studio 默认创建新项目即为 Compose 项目。 注意:在 Language 下拉菜单中,Kotlin 是唯一可…...
P8686 [蓝桥杯 2019 省 A] 修改数组--并查集 or Set--lower_bound()的解法!!!
P8686 [蓝桥杯 2019 省 A] 修改数组--并查集 题目 并查集解析代码【并查集解】 Set 解法解析lower_bound代码 题目 并查集解析 首先先让所有的f(i)i,即每个人最开始的祖先都是自己,然后就每一次都让轮到那个数的父亲1(…...
应用案例 | 精准控制,高效运行—宏集智能控制系统助力SCARA机器人极致性能
概述 随着工业4.0的深入推进,制造业对自动化和智能化的需求日益增长。传统生产线面临空间不足、效率低下、灵活性差等问题,尤其在现有工厂改造项目中,如何在有限空间内实现高效自动化成为一大挑战。 此次项目的客户需要在现有工厂基础上进行…...
Greenplum6.19集群搭建
一,安装说明 1.1环境说明 1、首先确定部署的环境,确定下服务器的端口,一般默认是22的端口; 2、当前这份文档是服务器处于10022端口下部署的(现场生产环境要求,22端口在生产环境存在安全隐患)&…...
sqlserver中的锁模式 | SQL SERVER如何开启MVCC(使用row-versioning)【启用行版本控制减少锁争用】
文章目录 引言锁和隔离级别的关系锁模式之间兼容性I 隔离级别SQLServer默认的隔离级别为:“read commited” (已提交读)在SQLServer2005引入了基于行版本控制的隔离级别。SQL SERVER如何开启MVCC(使用row-versioning)sqlserver开启MVCC后的锁II sqlserver中的锁模式**1、共享…...
胜软科技冲刺北交所一年多转港股:由盈转亏,毛利率大幅下滑
《港湾商业观察》施子夫 近期,山东胜软科技股份有限公司(以下简称,胜软科技)递表港交所获受理,独家保荐机构为广发证券(香港)。 在赴港上市之前,胜软科技还曾谋求过A股上市&#x…...
Java零基础入门笔记:多线程
前言 本笔记是学习狂神的java教程,建议配合视频,学习体验更佳。 【狂神说Java】Java零基础学习视频通俗易懂_哔哩哔哩_bilibili 第1-2章:Java零基础入门笔记:(1-2)入门(简介、基础知识)-CSDN博客 第3章…...
Django 中,Form 和 ModelForm的用法和区别
在 Django 中,Form 和 ModelForm 是用于处理表单数据的两种主要方式。它们的主要区别在于是否与模型(Model)直接关联。以下是它们的用法、区别以及高级用法的详细说明: 一、Form 的使用 1. 基本用法 Form 是一个独立的表单类,不与任何模型直接关联。适用于需要手动定义字…...
tcp udp区别
TCP(传输控制协议) 和 UDP(用户数据报协议) 是两种常用的传输层协议,它们在数据传输方式、可靠性和应用场景等方面有显著区别。以下是它们的主要区别: 1. 连接方式 TCP:面向连接的协议。通信前需…...
数据类设计_图片类设计之1_矩阵类设计(前端架构基础)
前言 学的东西多了,要想办法用出来.C和C是偏向底层的语言,直接与数据打交道.尝试做一些和数据方面相关的内容 引入 图形在底层是怎么表示的,用C来表示 认识图片 图片是个风景,动物,还是其他内容,人是可以看出来的.那么计算机是怎么看懂的呢?在有自主意识的人工智能被设计出来…...
C++:入门详解(关于C与C++基本差别)
目录 一.C的第一个程序 二.命名空间(namespace) 1.命名空间的定义与使用: (1)命名空间里可以定义变量,函数,结构体等多种类型 (2)命名空间调用(…...
GC安全点导致停顿时间过长的案例
GC安全点导致停顿时间过长的案例 前言安全点的概念案例分析解决方法如有需要收藏的看官,顺便也用发财的小手点点赞哈,如有错漏,也欢迎各位在评论区评论! 前言 前段时间在使用G1垃圾收集时,因服务读写压力过大…...
linux下 jq 截取json文件信息
背景:通过‘登录名‘ 获取该对象的其他个人信息如名字。 环境准备:麒麟操作系统V10 jq安装包 jq安装包获取方式:yum install jq 或 使用附件中的rpm 或 git自行下载 https://github.com/stedolan/jq/releases/download/ 实现过程介绍&am…...
git lfs使用方法指南【在github保存100M以上大文件】
为了在 GitHub 仓库中存储超过 100MB 的大文件并避免推送失败,使用 Git LFS(Large File Storage) 是最佳解决方案。以下是详细步骤: 一、安装 Git LFS 下载并安装 Git LFS: 访问 Git LFS 官网 下载对应系统的安装包。或…...
