ros2_control的简单应用

news2024/12/28 18:41:18

文章目录

  • 简介
  • 插件实现
    • 函数介绍
    • 代码
  • 调用原理
  • 局限性

简介

在利用moveit_setup_assistant配置我们自己机械手后,当运行demo.launch.py时,会实例化一个moveit对象以及一个基于ros2_control的、虚拟的控制对象,从而可以实现一个完整的控制闭环。
此基于ros2_control的虚拟对象,包含了action(server)相关的实例化、关节状态的发布、虚拟伺服电机的驱动及读取。
我们也可以利用ros2_control,将我们自己的机械手与moveit连接起来,从而实现moveit对我们机械手的控制。但是这样做的话,会损失比较多的自由度。假如电机等伺服机构、传感器等硬件是直接接到ros系统所在板子上的话,用ros2_control是挺方便的,但是我的是接在下位机,然后通过串口通讯控制的,使用ros2_control貌似就不太合适了。
不过也简单尝试一下例程,说不定后面有机会用到。

插件实现

这里我还是用我之前的那个【机械手模型】,来进行演示。

关于ros2_control的介绍可以看这里:【ros2_control doc】,我们这里就不继续啰嗦了。
我们只需要知道一点够了:我们只需要对ros2_control的类hardware_interface::SystemInterface进行实例化,其余的moveit_setup_assistant/ros2_control已经帮我们做好了。
对该类进行重写实现时,根据官方文档【Writing a new hardware interface】,我们需要分别重写下面8个函数

    hardware_interface::CallbackReturn on_init(
        const hardware_interface::HardwareInfo & info) override;

    hardware_interface::CallbackReturn on_configure(
        const rclcpp_lifecycle::State & previous_state) override;

    std::vector<hardware_interface::StateInterface> export_state_interfaces() override;

    std::vector<hardware_interface::CommandInterface> export_command_interfaces() override;

    hardware_interface::CallbackReturn on_activate(
        const rclcpp_lifecycle::State & previous_state) override;
        
    hardware_interface::CallbackReturn on_deactivate(
        const rclcpp_lifecycle::State & previous_state) override;

    hardware_interface::return_type read(
        const rclcpp::Time & time, const rclcpp::Duration & period) override;

    hardware_interface::return_type write(
        const rclcpp::Time & time, const rclcpp::Duration & period) override;

函数介绍

分别介绍一下这几个函数的作用。

  1. hardware_interface::CallbackReturn on_init( const hardware_interface::HardwareInfo & info) override;
    在这个函数内要进行软件方面的初始化、检查等。主要是对将要用到的state、command的缓存空间进行申请、检查urdf规定的接口是不是符合我们的需求等。
  1. hardware_interface::CallbackReturn on_configure( const rclcpp_lifecycle::State & previous_state) override;
    在这个函数内,要进行硬件的连接,成功与其进行了通讯,并进行一些必要的配置(通讯频率、限制等?)
  1. std::vector<hardware_interface::StateInterface> export_state_interfaces() override;
    这个函数主要是将在on_init里面申请好的state存储地址打包,返回给上层操作者
  1. std::vector<hardware_interface::CommandInterface> export_command_interfaces() override;
    这个函数主要是将在on_init里面申请好的command内存地址打包,返回给上层操作者
  1. hardware_interface::CallbackReturn on_activate(const rclcpp_lifecycle::State & previous_state) override;
    在这个函数内,要让执行机构进行复位、清除异常等操作,准备好接收运动指令。
  1. hardware_interface::CallbackReturn on_deactivate(const rclcpp_lifecycle::State & previous_state) override;
    在这个函数内,要让执行机构进行断电、断气、解除负载等操作?
  1. hardware_interface::return_type read(const rclcpp::Time & time, const rclcpp::Duration & period) override;
    读取。从硬件读取此时位置,放到缓存中,再由上层来读取
  1. hardware_interface::return_type write(const rclcpp::Time & time, const rclcpp::Duration & period) override;
    写入。将从上层得到的指令(目标位置)发送给硬件

代码

myrobotinterface.h

#ifndef MYROBOTINTERFACE_H
#define MYROBOTINTERFACE_H

#include <memory>
#include <string>
#include <vector>

#include "hardware_interface/handle.hpp"
#include "hardware_interface/hardware_info.hpp"
#include "hardware_interface/system_interface.hpp"
#include "hardware_interface/types/hardware_interface_return_values.hpp"
#include "hardware_interface/types/hardware_interface_type_values.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_lifecycle/node_interfaces/lifecycle_node_interface.hpp"
#include "rclcpp_lifecycle/state.hpp"

class MyRobotInterface : public hardware_interface::SystemInterface
{

public:
    // 这代码的作用是使此类能够直接使用 MyRobotInterface::sharedPtr
    RCLCPP_SHARED_PTR_DEFINITIONS(MyRobotInterface);

    MyRobotInterface();

    // 初始化时的函数
    hardware_interface::CallbackReturn on_init(
        const hardware_interface::HardwareInfo & info) override;

    // 配置时的函数
    hardware_interface::CallbackReturn on_configure(
        const rclcpp_lifecycle::State & previous_state) override;

    // 导出状态数据的存储地址
    std::vector<hardware_interface::StateInterface> export_state_interfaces() override;

    // 导出命令数据的存储地址
    std::vector<hardware_interface::CommandInterface> export_command_interfaces() override;

    // 激活时的函数
    hardware_interface::CallbackReturn on_activate(
        const rclcpp_lifecycle::State & previous_state) override;

    // 取消激活时的函数
    hardware_interface::CallbackReturn on_deactivate(
        const rclcpp_lifecycle::State & previous_state) override;

    // 读取,从硬件读取此时位置
    hardware_interface::return_type read(
        const rclcpp::Time & time, const rclcpp::Duration & period) override;

    // 写入,将指令发送给硬件
    hardware_interface::return_type write(
        const rclcpp::Time & time, const rclcpp::Duration & period) override;

private:
    // Parameters for the RRBot simulation
    // 用于模拟的参数
    double hw_start_sec_;
    double hw_stop_sec_;
    double hw_slowdown_;

    // Store the command for the simulated robot
    // 为此模拟机器人存储命令
    std::vector<double> hw_commands_;

    // 用于存储每个joint的状态。假如都是旋转关节,那么存储的就是当前的角度
    std::vector<double> hw_states_;

};

#endif // MYROBOTINTERFACE_H

myrobotinterface.cpp

#include "myrobotinterface.h"

MyRobotInterface::MyRobotInterface()
{

}

hardware_interface::CallbackReturn MyRobotInterface::on_init(const hardware_interface::HardwareInfo &info)
{
    // 这个是初始化,但是是偏向于软件方面的初始化;比如ros2_controllers.yaml里面描述的接口是否有问题,一些人为设定的其他参数等等

    // 先让hardware_interface::HardwareInfo执行初始化(也就是赋值info_),它初始化成功了,我们自己再进行自己的初始化
    if (
        hardware_interface::SystemInterface::on_init(info) !=
        hardware_interface::CallbackReturn::SUCCESS)
    {
        return hardware_interface::CallbackReturn::ERROR;
    }

    // 上面经过 hardware_interface::SystemInterface::on_init 之后,info_已经被初始化了,可以直接用
    // stod: string to double

    // BEGIN: This part here is for exemplary purposes - Please do not copy to your production code
    hw_start_sec_ = stod(info_.hardware_parameters["example_param_hw_start_duration_sec"]);
    hw_stop_sec_ = stod(info_.hardware_parameters["example_param_hw_stop_duration_sec"]);
    hw_slowdown_ = stod(info_.hardware_parameters["example_param_hw_slowdown"]);

    // END: This part here is for exemplary purposes - Please do not copy to your production code
    hw_states_.resize(info_.joints.size(), std::numeric_limits<double>::quiet_NaN());
    hw_commands_.resize(info_.joints.size(), std::numeric_limits<double>::quiet_NaN());

    // 遍历urdf文件所描述的所有joint,这里是和外面 ros2_controllers.yaml 里面的controller对应的
    // command指的是moveit发送过来的指令,也就是本关节需要走到哪个角度;state指的是当前关节的状态
    for (const hardware_interface::ComponentInfo & joint : info_.joints)
    {
        // 每个joint只接受1个指令
        // RRBotSystemPositionOnly has exactly one state and command interface on each joint
        if (joint.command_interfaces.size() != 1)
        {
            RCLCPP_FATAL(
                rclcpp::get_logger("RRBotSystemPositionOnlyHardware"),
                "Joint '%s' has %zu command interfaces found. 1 expected.", joint.name.c_str(),
                joint.command_interfaces.size());
            return hardware_interface::CallbackReturn::ERROR;
        }

        // 只接受 position类型的指令
        if (joint.command_interfaces[0].name != hardware_interface::HW_IF_POSITION)
        {
            RCLCPP_FATAL(
                rclcpp::get_logger("RRBotSystemPositionOnlyHardware"),
                "Joint '%s' have %s command interfaces found. '%s' expected.", joint.name.c_str(),
                joint.command_interfaces[0].name.c_str(), hardware_interface::HW_IF_POSITION);
            return hardware_interface::CallbackReturn::ERROR;
        }

        // 只接受一种状态
        if (joint.state_interfaces.size() != 1)
        {
            RCLCPP_FATAL(
                rclcpp::get_logger("RRBotSystemPositionOnlyHardware"),
                "Joint '%s' has %zu state interface. 1 expected.", joint.name.c_str(),
                joint.state_interfaces.size());
            return hardware_interface::CallbackReturn::ERROR;
        }

        // 只接受position状态
        if (joint.state_interfaces[0].name != hardware_interface::HW_IF_POSITION)
        {
            RCLCPP_FATAL(
                rclcpp::get_logger("RRBotSystemPositionOnlyHardware"),
                "Joint '%s' have %s state interface. '%s' expected.", joint.name.c_str(),
                joint.state_interfaces[0].name.c_str(), hardware_interface::HW_IF_POSITION);
            return hardware_interface::CallbackReturn::ERROR;
        }
    }

    return hardware_interface::CallbackReturn::SUCCESS;
}

hardware_interface::CallbackReturn MyRobotInterface::on_configure(const rclcpp_lifecycle::State & /*previous_state*/)
{
    // 这里的函数是进行配置的,是经过init之后,再到这一步
    // 这个也是初始化,但是这个会偏向硬件方面,主要是启动设备、检查设备等

    // BEGIN: This part here is for exemplary purposes - Please do not copy to your production code
    RCLCPP_INFO(
        rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "Configuring ...please wait...");

    // 这里根据前面设定的启动时间,在模拟启动耗时
    for (int i = 0; i < hw_start_sec_; i++)
    {
        rclcpp::sleep_for(std::chrono::seconds(1));
        RCLCPP_INFO(
            rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "%.1f seconds left...",
            hw_start_sec_ - i);
    }
    // END: This part here is for exemplary purposes - Please do not copy to your production code

    // 对状态、命令等模拟参数进行初始化
    // reset values always when configuring hardware
    for (uint i = 0; i < hw_states_.size(); i++)
    {
        hw_states_[i] = 0;
        hw_commands_[i] = 0;
    }

    RCLCPP_INFO(rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "Successfully configured!");

    return hardware_interface::CallbackReturn::SUCCESS;
}

std::vector<hardware_interface::StateInterface> MyRobotInterface::export_state_interfaces()
{
    // 这个是此机器人提供关节当前状态的数据存储地址,以供上层应用查询
    // 上层查询时,直接通过此次获取到的地址读取数值即可,无需重复调用函数

    std::vector<hardware_interface::StateInterface> state_interfaces;
    for (uint i = 0; i < info_.joints.size(); i++)
    {
        state_interfaces.emplace_back(hardware_interface::StateInterface(
            info_.joints[i].name, hardware_interface::HW_IF_POSITION, &hw_states_[i]));
    }

    return state_interfaces;
}

std::vector<hardware_interface::CommandInterface> MyRobotInterface::export_command_interfaces()
{
    // 这个是此机器人提供关节当前正在执行的命令的存储地址,以供上层读写

    std::vector<hardware_interface::CommandInterface> command_interfaces;
    for (uint i = 0; i < info_.joints.size(); i++)
    {
        command_interfaces.emplace_back(hardware_interface::CommandInterface(
            info_.joints[i].name, hardware_interface::HW_IF_POSITION, &hw_commands_[i]));
    }

    return command_interfaces;
}

hardware_interface::CallbackReturn MyRobotInterface::on_activate(const rclcpp_lifecycle::State &/*previous_state*/)
{
    // 设备开始时执行此函数
    // 这个activate。。。,怎么感觉和前面的 on_configure 一样的作用?

    // BEGIN: This part here is for exemplary purposes - Please do not copy to your production code
    RCLCPP_INFO(
        rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "Activating ...please wait...");

    for (int i = 0; i < hw_start_sec_; i++)
    {
        rclcpp::sleep_for(std::chrono::seconds(1));
        RCLCPP_INFO(
            rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "%.1f seconds left...",
            hw_start_sec_ - i);
    }
    // END: This part here is for exemplary purposes - Please do not copy to your production code

    // 在激活时,目标位置和当前位置应该要一样?
    // command and state should be equal when starting
    for (uint i = 0; i < hw_states_.size(); i++)
    {
        hw_commands_[i] = hw_states_[i];
    }

    RCLCPP_INFO(rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "Successfully activated!");

    return hardware_interface::CallbackReturn::SUCCESS;
}

hardware_interface::CallbackReturn MyRobotInterface::on_deactivate(const rclcpp_lifecycle::State &/*previous_state*/)
{
    // 设备停止时执行此函数

    // BEGIN: This part here is for exemplary purposes - Please do not copy to your production code
    RCLCPP_INFO(
        rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "Deactivating ...please wait...");

    for (int i = 0; i < hw_stop_sec_; i++)
    {
        rclcpp::sleep_for(std::chrono::seconds(1));
        RCLCPP_INFO(
            rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "%.1f seconds left...",
            hw_stop_sec_ - i);
    }

    RCLCPP_INFO(rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "Successfully deactivated!");
    // END: This part here is for exemplary purposes - Please do not copy to your production code

    return hardware_interface::CallbackReturn::SUCCESS;
}

hardware_interface::return_type MyRobotInterface::read(const rclcpp::Time &time, const rclcpp::Duration &period)
{
    // 这个是进行执行器关节状态的读取,将读取到的值存放在hw_states_上面。相当于从硬件同步数据

    // BEGIN: This part here is for exemplary purposes - Please do not copy to your production code
    RCLCPP_INFO(rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "Reading...");

    for (uint i = 0; i < hw_states_.size(); i++)
    {
        // Simulate RRBot's movement
        hw_states_[i] = hw_states_[i] + (hw_commands_[i] - hw_states_[i]) / hw_slowdown_;
        RCLCPP_INFO(
            rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "Got state %.5f for joint %d!",
            hw_states_[i], i);
    }
    RCLCPP_INFO(rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "Joints successfully read!");
    // END: This part here is for exemplary purposes - Please do not copy to your production code

    return hardware_interface::return_type::OK;
}

hardware_interface::return_type MyRobotInterface::write(const rclcpp::Time &time, const rclcpp::Duration &period)
{
    // 这个是将需要发送的目标位置写到执行器。
    // 需要写入(执行)的值已经被上层写到 hw_commands_ 了,所以在此处传入进来的参数中,并没看到具体关节的值
    

    // BEGIN: This part here is for exemplary purposes - Please do not copy to your production code
    RCLCPP_INFO(rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "Writing...");

    for (uint i = 0; i < hw_commands_.size(); i++)
    {
        // Simulate sending commands to the hardware
        RCLCPP_INFO(
            rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "Got command %.5f for joint %d!",
            hw_commands_[i], i);
    }
    RCLCPP_INFO(
        rclcpp::get_logger("RRBotSystemPositionOnlyHardware"), "Joints successfully written!");
    // END: This part here is for exemplary purposes - Please do not copy to your production code

    return hardware_interface::return_type::OK;
}

调用原理

需要注意的是,此实例化的类是以插件的形式被ros2_control来调用的(In ros2_control hardware system components are libraries, dynamically loaded by the controller manager using the pluginlib interface. ),也就是我们urdf文件中的ros2_control–》hardware–》plugin节点中指定的插件。
在这里插入图片描述比如说上面的 mock_components/GenericSystem,我们可以在/opt/ros/humble/share/hardware_interface、/opt/ros/humble/include/mock_components找到他们的踪迹。
在这里插入图片描述因此,我们需要把我们的硬件接口编译成动态库,然后填写一个插件描述文件放在文件夹中,然后ros2_control通过名字来找到此插件。

局限性

这样一来有个问题,我希望Action的Server接口是由我们的Qt程序来实现,与我们的Qt程序处于同一个进程,而不是一个插件、动态库的形式,因为我需要取得路径点进行调试、与其他类操作进行交互等,这该如何处理?

可能这个ros2_control,是比较适合组件化、黑盒子的设计吧,而不是我目前需要弄的一体化设计。
暂时不研究这个了。


参考:
【 ros-controls/ros2_control_demos】

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

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

相关文章

简单实现,在nodejs中简单使用kafka

什么是 Kafka Kafka 是由 Linkedin 公司开发的&#xff0c;它是一个分布式的&#xff0c;支持多分区、多副本&#xff0c;基于 Zookeeper 的分布式消息流平台&#xff0c;它同时也是一款开源的基于发布订阅模式的消息引擎系统。 Kafka 的基本术语 消息&#xff1a;Kafka 中的…

【源码复现】图神经网络之PPNP/APPNH

目录 1、论文简介2、论文核心介绍2.1、现有方法局限2.2、PageRank&Personalized PageRank2.3、PPNP&APPNP 3、源码复现3.1、模型总体框架3.2、PPNP3.3、APPNP3.4、MLP(两层) 1、论文简介 论文题目——《PREDICT THEN PROPAGATE: GRAPH NEURAL NETWORKS MEET PERSONALI…

期中之后老师的福音

老师在期中考试后总是会有一大堆事情要做&#xff0c;批改试卷、统计分数、通知学生成绩等等。今天我就要给大家介绍一个能够减轻老师工作负担、提高工作效率的方法——查询系统 简单来说&#xff0c;成绩查询系统就是能够让学生方便的查询成绩&#xff0c;让老师快捷发布成绩的…

iText v1.8.1(OCR截图文字识别工具)

iText for mac是一款OCR&#xff08;光学字符识别&#xff09;工具&#xff0c;可以从图片中识别文字&#xff0c;适用于从扫描版的PDF等任意图片中提取文字。 使用iText&#xff0c;您可以方便快捷地从图片中摘抄和批注文字&#xff0c;满足您的各种需求。其自带截图功能&…

vscode 快速打印console.log

第一步 输入这些 {// Print Selected Variabl 为自定义快捷键中需要使用的name&#xff0c;可以自行修改"Print Selected Variable": {"body": ["\nconsole.log("," %c $CLIPBOARD: ,"," background-color: #3756d4; padding:…

11.10 知识总结(数据的增删改查、如何创建表关系、Django框架的请求生命周期流程图)

一、 数据的增删改查 1.1 用户列表的展示 把数据表中得用户数据都给查询出来展示在页面上 添加数据 id username password gender age action 修改 删除 1.2 修…

9 个可以免费检索意外删除或丢失的文件的专业数据恢复软件

今天&#xff0c;我们将探索一些最佳数据恢复软件&#xff0c;它们可以帮助您从 Windows PC 或存储设备中检索意外删除或丢失的文件&#xff01; 丢失数据或意外删除数据是一种令人不安的经历。值得庆幸的是&#xff0c;存在有效的解决方案来解决这种情况。今天&#xff0c;我…

从0到0.01入门React | 002.精选 React 面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

如何解决错误代码0x80070422,多种修复0x80070422的方法

在使用Windows系统&#xff0c;特别是Windows Update更新你的系统时&#xff0c;可能会遇到错误代码0x80070422。这是一个相对常见的问题&#xff0c;但不用担心&#xff0c;这个问题大多数情况下可以通过一些简单的步骤进行修复。 一.为什么会出现错误0x80070422 错误代码0x8…

本地生活直播的下个红利期来了!虚拟直播遇上本地生活擦出新火花

近年来&#xff0c;本地生活直播发展迅猛&#xff0c;作为一种全新的线下实体店营销方式&#xff0c;它比电商直播更贴近消费者的生活需求。比如消费者通过直播购买套餐或消费券&#xff0c;并在实体店核销。这种情况就可以归属于本地生活直播的服务范围。因此&#xff0c;对于…

Linux ____03、文件类型、属性、修改文件属性(更改文件权限)(命令)

文件类型、属性、修改文件属性 一、文件类型二、文件属性三、修改文件属性1、chgrp&#xff1a;更改文件属组2、chown&#xff1a;更改文件属主&#xff0c;也可以同时更改文件属组3、chmod&#xff1a;更改文件9个属性————————如觉不错&#xff0c;随手点赞&#xff…

Ansys Electronics Desktop仿真——HFSS线圈寄生电阻,电感

利用ANSYS Electronics Desktop&#xff0c;可在综合全面、易于使用的设计平台中集成严格的电磁场分析和系统电路仿真。按需求解器技术让您能集成电磁场仿真器和电路及系统级仿真&#xff0c;以探索完整的系统性能。 HFSS&#xff08;High Frequency Structure Simulator&#…

上门洗衣洗鞋app小程序

上门洗衣洗鞋app小程序作为专业的帮助用户洗衣服务的软件,许多朋友都使用过。在这里,小编就帮助大家收集一些非常不错的洗衣洗鞋软件。 不知道大家是否还在为洗衣而烦恼,而怕麻烦,现在大家都在用网上的洗衣洗鞋小程序来洗衣服,用户只需要打开手机软件,发起订单,门店即可收到订单…

[CANN训练营]UART通信笔记

文章目录 前言一、前提知识1.串行通信2.并行通信3.单工、半双工、全双工通信3.1单工通信3.2半双工通信3.3全双工通信 4.补充&#xff1a;通信速率 二、UART通信1.UART通信2.UART工作原理 总结 前言 在ROS学习中&#xff0c;我们在入门基础除了ROS的小乌龟外&#xff0c;在通信…

2019年五一杯数学建模A题让标枪飞解题全过程文档及程序

2020年五一杯数学建模 A题 让标枪飞 原题再现 标枪的投掷是一项历史悠久的田径比赛项目。标枪投掷距离的远近受到运动员水平&#xff08;出手速度、出手角、初始攻角、出手高度、出手时标枪的初始俯仰角速度等&#xff09;&#xff0c;标枪的技术参数&#xff08;标枪的长度、…

Docker的本地镜像发布到阿里云或者私有库步骤

学习笔记来源Docker 本地镜像发布到阿里云 1、生成镜像&#xff08;使用commit命令&#xff09; 创建阿里云仓库镜像 阿里云开发者平台 https://promotion.aliyun.com/ntms/act/kubernetes.html 创建仓库镜像 选择控制台&#xff0c;进入容器镜像服务 选择个人实例 命名空…

概率论和数理统计(三)数理统计基本概念

前言 “概率论”是给定一个随机变量X的分布F(x),然后求某事件A概率 P ( x ∈ A ) P(x \in A) P(x∈A)或者随机变量X的数字特征.“统计”是已知一组样本数据 { x 1 , x 2 , . . . x n } \{x_1,x_2,...x_n\} {x1​,x2​,...xn​},去求分布F(x) 统计的基本概念 在统计中&#x…

【MySQL】MySQL中的锁

全局锁 全局锁是对整个数据库实例加锁&#xff0c;整个库处于只读状态。 flush tables with read lock 适用场景 全局锁适用于做全库逻辑备份&#xff0c;但是整个库处于只读状态&#xff0c;在备份期间&#xff0c;所有的更新操作、DDL将会被阻塞&#xff0c;会对业务产生影…

python入门:分支结构

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 1.内容导图 2.流程图介绍 绘制要求&#xff1a;不能出现程序语言的语法 3.百分制转五级计分制 分支结构&#xff1a;语句块&#xff0c;冒号缩进表示归属 单分支…