ArduPilot开源代码之AP_RangeFinder

ArduPilot开源代码之AP_RangeFinder

  • 1. 源由
  • 2. 框架设计
    • 2.1 启动代码
    • 2.2 任务代码
  • 3. 重要例程
    • 3.1 状态更新
    • 3.2 传感设备检测
  • 4. 总结
  • 5. 参考资料

1. 源由

AP_RangeFinder的应用的主要用途是用于测量对地距离的,这个与大家通常理解的障碍物避障还是有比较大的差异的。

本次结合代码进行研读。

2. 框架设计

启动代码:

Copter::init_ardupilot└──> Copter::init_rangefinder└──> rangefinder.init

任务代码:

SCHED_TASK(read_rangefinder,      20,    100,  33),└──> Copter::read_rangefinder└──> rangefinder.update

2.1 启动代码

主要作用是对传感器设备进行检测和初始化。

RangeFinder::init├──> <num_instances != 0> // don't re-init if we've found some sensors already│   └──> return├──> <uint8_t i=0; i<RANGEFINDER_MAX_INSTANCES; i++> // set orientation defaults│   └──> params[i].orientation.set_default(orientation_default)├──> <uint8_t i=0, serial_instance = 0; i<RANGEFINDER_MAX_INSTANCES; i++>│   │  // serial_instance will be increased inside detect_instance│   │  // if a serial driver is loaded for this instance│   ├──> WITH_SEMAPHORE(detect_sem);│   ├──> detect_instance(i, serial_instance);│   └──> <drivers[i] != nullptr>│       │  // we loaded a driver for this instance, so it must be│       │  // present (although it may not be healthy). We use MAX()│       │  // here as a UAVCAN rangefinder may already have been│       │  // found│       └──> num_instances = MAX(num_instances, i+1);└──> [initialise status]├──> state[i].status = Status::NotConnected;└──> state[i].range_valid_count = 0;

2.2 任务代码

以固定的频率进行循环遍历,得到相应的数据更新。

// return rangefinder altitude in centimeters
Copter::read_rangefinder├──> <RANGEFINDER_ENABLED != ENABLED>│   ├──> [downward facing rangefinder]│   │   ├──> rangefinder_state.enabled = false;│   │   ├──> rangefinder_state.alt_healthy = false;│   │   └──> rangefinder_state.alt_cm = 0;│   ├──> [upward facing rangefinder]│   │   ├──> rangefinder_up_state.enabled = false;│   │   ├──> rangefinder_up_state.alt_healthy = false;│   │   └──> rangefinder_up_state.alt_cm = 0;│   └──> return├──> rangefinder.update();├──> <RANGEFINDER_TILT_CORRECTION == ENABLED>│   └──> const float tilt_correction = MAX(0.707f, ahrs.get_rotation_body_to_ned().c.z);├──> <RANGEFINDER_TILT_CORRECTION != ENABLED>│   └──> const float tilt_correction = 1.0f;│││  // iterate through downward and upward facing lidar│  struct {│      RangeFinderState &state;│      enum Rotation orientation;│  } rngfnd[2] = {{rangefinder_state, ROTATION_PITCH_270}, {rangefinder_up_state, ROTATION_PITCH_90}};│└──> <for (uint8_t i=0; i < ARRAY_SIZE(rngfnd); i++)>├──> [local variables to make accessing simpler]│   ├──> RangeFinderState &rf_state = rngfnd[i].state;│   └──> enum Rotation rf_orient = rngfnd[i].orientation;├──> [update health]│   └──> rf_state.alt_healthy = ((rangefinder.status_orient(rf_orient) == RangeFinder::Status::Good) &&│                          (rangefinder.range_valid_count_orient(rf_orient) >= RANGEFINDER_HEALTH_MAX));├──> [tilt corrected but unfiltered, not glitch protected alt]│   └──> rf_state.alt_cm = tilt_correction * rangefinder.distance_cm_orient(rf_orient);├──> [remember inertial alt to allow us to interpolate rangefinder]│   └──> rf_state.inertial_alt_cm = inertial_nav.get_position_z_up_cm();├──> [glitch handling] │   //rangefinder readings more than RANGEFINDER_GLITCH_ALT_CM from the last good reading│   // are considered a glitch and glitch_count becomes non-zero│   // glitches clear after RANGEFINDER_GLITCH_NUM_SAMPLES samples in a row.│   // glitch_cleared_ms is set so surface tracking (or other consumers) can trigger a target reset│   ├──> const int32_t glitch_cm = rf_state.alt_cm - rf_state.alt_cm_glitch_protected;│   ├──> bool reset_terrain_offset = false;│   ├──> <if (glitch_cm >= RANGEFINDER_GLITCH_ALT_CM)>│   │   └──> rf_state.glitch_count = MAX(rf_state.glitch_count+1, 1);│   ├──> <else if (glitch_cm <= -RANGEFINDER_GLITCH_ALT_CM) >│   │   └──> rf_state.glitch_count = MIN(rf_state.glitch_count-1, -1);│   ├──> <else>│   │   ├──> rf_state.glitch_count = 0;│   │   └──> rf_state.alt_cm_glitch_protected = rf_state.alt_cm;│   └──> <abs(rf_state.glitch_count) >= RANGEFINDER_GLITCH_NUM_SAMPLES> // clear glitch and record time so consumers (i.e. surface tracking) can reset their target altitudes│       ├──> rf_state.glitch_count = 0;│       ├──> rf_state.alt_cm_glitch_protected = rf_state.alt_cm;│       ├──> rf_state.glitch_cleared_ms = AP_HAL::millis();│       └──> reset_terrain_offset = true;├──> [filter rangefinder altitude]│   ├──> uint32_t now = AP_HAL::millis();│   ├──> const bool timed_out = now - rf_state.last_healthy_ms > RANGEFINDER_TIMEOUT_MS;│   ├──> <rf_state.alt_healthy>│   │   ├──> <if (timed_out)>│   │   │     // reset filter if we haven't used it within the last second│   │   │   ├──> rf_state.alt_cm_filt.reset(rf_state.alt_cm);│   │   │   └──> reset_terrain_offset = true;│   │   └──> <else >│   │       └──> rf_state.alt_cm_filt.apply(rf_state.alt_cm, 0.05f);│   └──> rf_state.last_healthy_ms = now;├──> <reset_terrain_offset> // handle reset of terrain offset│   ├──> <if (rf_orient == ROTATION_PITCH_90)> // upward facing│   │   └──> rf_state.terrain_offset_cm = rf_state.inertial_alt_cm + rf_state.alt_cm;│   └──> < else > // assume downward facing│       └──> rf_state.terrain_offset_cm = rf_state.inertial_alt_cm - rf_state.alt_cm; └──> <HAL_PROXIMITY_ENABLED> <rf_orient == ROTATION_PITCH_270> <rangefinder_state.alt_healthy || timed_out>│  // send downward facing lidar altitude and health to the libraries that require it└──> g2.proximity.set_rangefinder_alt(rangefinder_state.enabled, rangefinder_state.alt_healthy, rangefinder_state.alt_cm_filt.get());

3. 重要例程

3.1 状态更新

针对当前传感器数据有效性进行状态更新。

  • NotConnected
  • NoData
  • OutOfRangeLow
  • OutOfRangeHigh
  • Good
RangeFinder::update├──> <uint8_t i=0; i<num_instances; i++>│   └──> <drivers[i] != nullptr>│       ├──> <(Type)params[i].type.get() == Type::NONE> // allow user to disable a rangefinder at runtime│       │   ├──> state[i].status = Status::NotConnected│       │   ├──> state[i].range_valid_count = 0│       │   └──> continue│       └──> drivers[i]->update()└──> <HAL_LOGGING_ENABLED>└──> Log_RFND()

3.2 传感设备检测

  • ANALOG
  • MBI2C
  • PLI2C
  • PX4_PWM
  • BBB_PRU
  • LWI2C
  • LWSER
  • BEBOP
  • MAVLink
  • USD1_Serial
  • LEDDARONE
  • MBSER
  • TRI2C
  • PLI2CV3
  • VL53L0X
  • NMEA
  • WASP
  • BenewakeTF02
  • BenewakeTFmini
  • PLI2CV3HP
  • PWM
  • BLPing
  • UAVCAN
  • BenewakeTFminiPlus
  • Lanbao
  • BenewakeTF03
  • VL53L1X_Short
  • LeddarVu8_Serial
  • HC_SR04
  • GYUS42v2
  • MSP
  • USD1_CAN
  • Benewake_CAN
  • TeraRanger_Serial
  • Lua_Scripting
  • NoopLoop_P
  • TOFSenseP_CAN
  • NRA24_CAN
  • SIM
RangeFinder::detect_instance├──> <!AP_RANGEFINDER_ENABLED>│   └──> return├──> AP_RangeFinder_Backend_Serial *(*serial_create_fn)(RangeFinder::RangeFinder_State&, AP_RangeFinder_Params&) = nullptr;├──> const Type _type = (Type)params[instance].type.get();├──> <case PLI2C/PLI2CV3/PLI2CV3HP> <AP_RANGEFINDER_PULSEDLIGHTLRF_ENABLED>│   ├──> _add_backend(AP_RangeFinder_PulsedLightLRF::detect│   └──> break;├──> <MBI2C> <AP_RANGEFINDER_MAXSONARI2CXL_ENABLED>│   ├──> uint8_t addr = AP_RANGE_FINDER_MAXSONARI2CXL_DEFAULT_ADDR;│   ├──> <params[instance].address != 0>│   │   └──> addr = params[instance].address;│   ├──> _add_backend(AP_RangeFinder_MaxsonarI2CXL::detect│   └──> break;├──> <LWI2C> <AP_RANGEFINDER_LWI2C_ENABLED>│   ├──> <params[instance].address> // the LW20 needs a long time to boot up, so we delay 1.5s here│   │   ├──> <HAL_RANGEFINDER_LIGHTWARE_I2C_BUS>│   │   │   └──> _add_backend(AP_RangeFinder_LightWareI2C::detect│   │   └──> <!HAL_RANGEFINDER_LIGHTWARE_I2C_BUS>│   │       └──> _add_backend(AP_RangeFinder_LightWareI2C::detect│   └──> break;├──> <TRI2C> <AP_RANGEFINDER_TRI2C_ENABLED>│   ├──> <params[instance].address>│   │   └──> __add_backend(AP_RangeFinder_TeraRangerI2C::detect│   └──> break;├──> <VL53L0X/VL53L1X_Short> │   ├──> <AP_RANGEFINDER_VL53L0X_ENABLED>│   │   └──> _add_backend(AP_RangeFinder_VL53L0X::detect│   ├──> <AP_RANGEFINDER_VL53L1X_ENABLED>│   │   └──> _add_backend(AP_RangeFinder_VL53L1X::detect│   └──> break;├──> <BenewakeTFminiPlus> <AP_RANGEFINDER_BENEWAKE_TFMINIPLUS_ENABLED>│   ├──> uint8_t addr = TFMINIPLUS_ADDR_DEFAULT;│   ├──> <params[instance].address != 0>│   │   └──> addr = params[instance].address;│   ├──> _add_backend(AP_RangeFinder_Benewake_TFMiniPlus::detect│   └──> break;├──> <PX4_PWM> <AP_RANGEFINDER_PWM_ENABLED>│   │  // to ease moving from PX4 to ChibiOS we'll lie a little about│   │  // the backend driver...│   ├──> <AP_RangeFinder_PWM::detect()>│   │   └──> _add_backend(new AP_RangeFinder_PWM(state[instance], params[instance], estimated_terrain_height), instance);│   └──> break;├──> <BBB_PRU> <AP_RANGEFINDER_BBB_PRU_ENABLED>│   ├──> <AP_RangeFinder_BBB_PRU::detect()>│   │   └──> _add_backend(new AP_RangeFinder_BBB_PRU(state[instance], params[instance]), instance);│   └──> break;├──> <LWSER> <AP_RANGEFINDER_LIGHTWARE_SERIAL_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_LightWareSerial::create;│   └──> break;├──> <LEDDARONE> <AP_RANGEFINDER_LEDDARONE_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_LeddarOne::create;│   └──> break;├──> <USD1_Serial> <AP_RANGEFINDER_USD1_SERIAL_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_USD1_Serial::create;│   └──> break;├──> <BEBOP> <AP_RANGEFINDER_BEBOP_ENABLED>│   ├──> <AP_RangeFinder_Bebop::detect()>│   │   └──> _add_backend(new AP_RangeFinder_Bebop(state[instance], params[instance]), instance);│   └──> break;├──> <MAVLink> <AP_RANGEFINDER_MAVLINK_ENABLED>│   ├──> <AP_RangeFinder_MAVLink::detect()>│   │   └──> _add_backend(new AP_RangeFinder_MAVLink(state[instance], params[instance]), instance);│   └──> break;├──> <MBSER> <AP_RANGEFINDER_MAXBOTIX_SERIAL_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_MaxsonarSerialLV::create;│   └──> break;├──> <ANALOG> <AP_RANGEFINDER_ANALOG_ENABLED>│   ├──> <AP_RangeFinder_analog::detect(params[instance])> // note that analog will always come back as present if the pin is valid│   │   └──> _add_backend(new AP_RangeFinder_analog(state[instance], params[instance]), instance);│   └──> break;├──> <HC_SR04> <AP_RANGEFINDER_HC_SR04_ENABLED>│   ├──> <AP_RangeFinder_HC_SR04::detect(params[instance])>  // note that this will always come back as present if the pin is valid│   │   └──> _add_backend(new AP_RangeFinder_HC_SR04(state[instance], params[instance]), instance);│   └──> break;├──> <NMEA> <AP_RANGEFINDER_NMEA_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_NMEA::create;│   └──> break;├──> <WASP> <AP_RANGEFINDER_WASP_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_Wasp::create;│   └──> break;├──> <BenewakeTF02> <AP_RANGEFINDER_BENEWAKE_TF02_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_Benewake_TF02::create;│   └──> break;├──> <BenewakeTFmini> <AP_RANGEFINDER_BENEWAKE_TFMINI_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_Benewake_TFMini::create;│   └──> break;├──> <BenewakeTF03> <AP_RANGEFINDER_BENEWAKE_TF03_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_Benewake_TF03::create;│   └──> break;├──> <TeraRanger_Serial> <AP_RANGEFINDER_TERARANGER_SERIAL_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_TeraRanger_Serial::create;│   └──> break;├──> <PWM> <AP_RANGEFINDER_PWM_ENABLED>│   ├──> <AP_RangeFinder_PWM::detect()>│   │   └──> _add_backend(new AP_RangeFinder_PWM(state[instance], params[instance], estimated_terrain_height), instance);│   └──> break;├──> <BLPing> <AP_RANGEFINDER_BLPING_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_BLPing::create;│   └──> break;├──> <Lanbao> <AP_RANGEFINDER_LANBAO_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_Lanbao::create;│   └──> break;├──> <LeddarVu8_Serial> <AP_RANGEFINDER_LEDDARVU8_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_LeddarVu8::create;│   └──> break;├──> <UAVCAN> <AP_RANGEFINDER_DRONECAN_ENABLED>│   │  /*│   │    the UAVCAN driver gets created when we first receive a│   │    measurement. We take the instance slot now, even if we don't│   │    yet have the driver│   │   */│   ├──> num_instances = MAX(num_instances, instance+1);│   └──> break;├──> <GYUS42v2> <AP_RANGEFINDER_GYUS42V2_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_GYUS42v2::create;│   └──> break;├──> <SIM> <AP_RANGEFINDER_SIM_ENABLED>│   ├──> _add_backend(new AP_RangeFinder_SITL(state[instance], params[instance], instance), instance);│   └──> break;├──> <MSP> <HAL_MSP_RANGEFINDER_ENABLED>│   ├──> <AP_RangeFinder_MSP::detect()>│   │   └──> _add_backend(new AP_RangeFinder_MSP(state[instance], params[instance]), instance);│   └──> break;├──> <USD1_CAN> <AP_RANGEFINDER_USD1_CAN_ENABLED>│   ├──> _add_backend(new AP_RangeFinder_USD1_CAN(state[instance], params[instance]), instance);│   └──> break;├──> <Benewake_CAN> <AP_RANGEFINDER_BENEWAKE_CAN_ENABLED>│   ├──> _add_backend(new AP_RangeFinder_Benewake_CAN(state[instance], params[instance]), instance);│   └──> break;├──> <Lua_Scripting> <AP_SCRIPTING_ENABLED>│   ├──> _add_backend(new AP_RangeFinder_Lua(state[instance], params[instance]), instance);│   └──> break;├──> <NoopLoop_P> ,AP_RANGEFINDER_NOOPLOOP_ENABLED>│   ├──> serial_create_fn = AP_RangeFinder_NoopLoop::create;│   └──> break;├──> <TOFSenseP_CAN> <AP_RANGEFINDER_TOFSENSEP_CAN_ENABLED>│   ├──> _add_backend(new AP_RangeFinder_TOFSenseP_CAN(state[instance], params[instance]), instance);│   └──> break;├──> <NRA24_CAN> <AP_RANGEFINDER_NRA24_CAN_ENABLED>│   ├──> _add_backend(new AP_RangeFinder_NRA24_CAN(state[instance], params[instance]), instance);│   └──> break;├──> <serial_create_fn != nullptr> <AP::serialmanager().have_serial(AP_SerialManager::SerialProtocol_Rangefinder, serial_instance)>│   ├──> auto *b = serial_create_fn(state[instance], params[instance]);│   └──> <b != nullptr>│       └──> _add_backend(b, instance, serial_instance++);└──> <drivers[instance] && state[instance].var_info>  // if the backend has some local parameters then make those available in the tree├──> backend_var_info[instance] = state[instance].var_info;├──> AP_Param::load_object_from_eeprom(drivers[instance], backend_var_info[instance]);      └──> AP_Param::invalidate_count(); // param count could have changed

4. 总结

各传感器设备因设备总线以及协议的差异,存在一定的差异化,在相应的驱动代码中实现,可参考:ArduPilot之开源代码Library&Sketches设计。

作为RangeFinder传感器主要的目的是检测飞机与地面之间的距离

    // The RangeFinder_State structure is filled in by the backend driverstruct RangeFinder_State {float distance_m;               // distance in metersuint16_t voltage_mv;            // voltage in millivolts, if applicable, otherwise 0enum RangeFinder::Status status; // sensor statusuint8_t  range_valid_count;     // number of consecutive valid readings (maxes out at 10)uint32_t last_reading_ms;       // system time of last successful update from sensorconst struct AP_Param::GroupInfo *var_info;};

注:不同设备更新频率方面主要在驱动中进行数据采集更新,详见驱动代码的init方法中如何挂定时回调钩子函数。

5. 参考资料

【1】ArduPilot开源飞控系统之简单介绍
【2】ArduPilot飞控启动&运行过程简介
【3】ArduPilot之开源代码Library&Sketches设计

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Linux关于gittee的远端仓库的连接和git三板斧

目录 1.网页操作 2.Linux操作 查看Linux系统中是否安装git指令 安装git指令 链接远端仓库 设置 .gitignore文件 3.git三板斧 1.网页操作 首先我们要在gittee建立一个仓库 这是我自己的勾选方案&#xff0c;大家可以参考一下。 这个方案勾选最下面的三个选项才有&#x…

在vite中使用react-router-dom-v6 路由报错 Uncaught SyntaxError: Unexpected token ‘<‘

解决方法&#xff1a;将路由表“routes”下面的"index.js"改成“index.jsx”&#xff0c;正确的文件如下图所示。

箱讯科技成功闯入第八届“创客中国”全国总决赛—在国际物流领域一枝独秀

添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 2023年9月26日&#xff0c;第八届“创客中国”数字化转型中小企业创新创业大赛决赛在贵州圆满收官。 经过初赛、复赛、决赛的激烈角逐&#xff0c;箱讯科技与众多强劲对手同台竞技&#xff0c;最终凭借出…

首发Orin N芯片,腾势追赶「智驾第一梯队」

张祥威 编辑 | 德新 英伟达最新一代芯片—— Orin N&#xff0c;腾势拿下 首发。 9月26日&#xff0c;腾势N7推出「高快智驾包」。官方描述中&#xff0c;这一选装将“基于新一代NIVIDIA DRIVE ORIN的 高性能平台”&#xff0c;可以实现高速NOA。 此前&#xff0c;腾势的…

dbeaver 1064 42000 错误 query execution failed

编辑驱动属性&#xff0c;将 allowMultiQueries 设置为 true 参考 https://blog.csdn.net/u200814342A/article/details/132458960

管道-有名管道

一、有名管道 有名管道与匿名管道的不同&#xff1a; 有名管道提供了一个路径名&#xff0c;并以FIFO的文件形式存在于文件系统中。与匿名管道不同&#xff0c;有名管道可以被不相关的进程使用&#xff0c;只要它们可以访问该路径&#xff0c;就能够通过有名管道进行通信。 FI…

安防监控产品经营商城小程序的作用是什么

安防监控产品覆盖面较大&#xff0c;监控器、门禁、对讲机、烟感等都有很高用途&#xff0c;家庭、办公单位各场景往往用量不少&#xff0c;对商家来说&#xff0c;市场高需求背景下也带来了众多生意&#xff0c;但线下门店的局限性&#xff0c;导致商家想要进一步增长不容易。…

Flutter笔记 - ListTile组件及其应用

Flutter笔记 ListTile组件及其应用 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/133411883 目 录 1. …

【Java每日一题】— —第十九题:用二维数组存放九九乘法表,并将其输出。(2023.10.03)

&#x1f578;️Hollow&#xff0c;各位小伙伴&#xff0c;今天我们要做的是第十九题。 &#x1f3af;问题&#xff1a; 用二维数组存放九九乘法表&#xff0c;并将其输出。 测试结果如下&#xff1a; &#x1f3af; 答案&#xff1a; System.out.println("九九乘法表如…

Python中匹配模糊的字符串

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 如何使用thefuzz 库&#xff0c;它允许我们在python中进行模糊字符串匹配。 此外&#xff0c;我们将学习如何使用process 模块&#xff0c;该模块允许我们在模糊…

【AI视野·今日NLP 自然语言处理论文速览 第四十五期】Mon, 2 Oct 2023

AI视野今日CS.NLP 自然语言处理论文速览 Mon, 2 Oct 2023 Totally 44 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Efficient Streaming Language Models with Attention Sinks Authors Guangxuan Xiao, Yuandong Tian, Beidi C…

Redis与分布式-分布式锁

接上文 Redis与分布式-集群搭建 1.分布式锁 为了解决上述问题&#xff0c;可以利用分布式锁来实现。 重新复制一份redis&#xff0c;配置文件都是刚下载时候的不用更改&#xff0c;然后启动redis服务和redis客户。 redis存在这样的命令&#xff1a;和set命令差不多&#xff0…

淘宝天猫渠道会员购是什么意思?如何开通天猫淘宝渠道会员购有什么用?

淘宝天猫渠道会员购是什么意思&#xff1f; 淘宝天猫渠道会员购与淘宝天猫粉丝福利购意思基本相同&#xff0c;都可以领取淘宝天猫大额内部隐藏优惠券、通过草柴APP开通绑定渠道会员还可以获得购物返利。 草柴APP如何绑定开通淘宝天猫渠道会员&#xff1f; 1、手机下载安装「…

笔记二:odoo搜索、筛选和分组

一、搜索 1、xml代码 <!--搜索和筛选--><record id"view_search_book_message" model"ir.ui.view"><field name"name">book_message</field><field name"model">book_message</field><field…

“把握拐点,洞悉投资者情绪与比特币价格的未来之路!“

“本来这篇文章是昨天晚上发的&#xff0c;国庆节庆祝喝多了&#xff0c;心有余而力不足&#xff01;直接头躺马桶GG了” 标准普尔 500 指数 200 天移动平均线云是我几个月来一直分享的下行目标&#xff0c;上周正式重新测试了该目标。200 日移动平均线云表示为: 200 天指数移…

Linux(CentOS/Ubuntu)——安装nginx

如果确定你的系统是基于CentOS或RHEL&#xff0c;可以使用以下命令&#xff1a; ①、安装库文件 #安装gcc yum install gcc-c#安装PCRE pcre-devel yum install -y pcre pcre-devel#安装zlib yum install -y zlib zlib-devel#安装Open SSL yum install -y openssl openssl-de…

【JVM】垃圾回收(GC)详解

垃圾回收&#xff08;GC&#xff09;详解 一. 死亡对象的判断算法1. 引用计数算法2. 可达性分析算法 二. 垃圾回收算法1. 标记-清除算法2. 复制算法3. 标记-整理算法4. 分代算法 三. STW1. 为什么要 STW2. 什么情况下 STW 四. 垃圾收集器1. CMS收集器&#xff08;老年代收集器&…

React antd Table点击下一页后selectedRows丢失之前页选择内容的问题

一、问题 使用了React antd 的<Table>标签&#xff0c;是这样记录选中的行id与行内容的&#xff1a; <TabledataSource{data.list}rowSelection{{selectedRowKeys: selectedIdsInSearchTab,onChange: this.onSelectChange,}} // 表格是否可复选&#xff0c;加 type: …

cygwin编译haproxy

下载安装cygwin cygwin下载、安装-CSDN博客 编译haproxy 打开cygwin终端 下载程序 haproxy程序 OpenPKG Project: Download 输入下面命令下载程序 wget http://download.openpkg.org/components/cache/haproxy/haproxy-2.8.3.tar.gz 解压 tar -zxvf haproxy-2.8.3.tar.gz…

正则表达式的应用(前端写法)

文章目录 1、匹配字符串中&#xff0c;a标签的href值2、校验邮箱3、校验手机号码3、待添加... 1、匹配字符串中&#xff0c;a标签的href值 (1) 代码 /*** description 匹配字符串中&#xff0c;a标签的href值* param {string} str 匹配的字符串* return {Array} 返回href值*/…