2 ROS2话题通讯基础(1)

news2024/11/21 2:26:33

2 ROS2话题通讯基础

  • 2.1 ROS2话题通讯介绍
  • 2.2 ROS2常用的消息类型介绍
    • 2.2.1 std_msgs消息类型
    • 2.2.2 geometry_msgs消息类型
  • 2.3 使用C/C++创建基础消息类型的话题通讯
    • 2.3.1 创建C/C++发布话题信息的功能包并配置VSCode环境
    • 2.3.2 编写ROS2发布话题节点CPP文件
    • 2.3.3 配置C/C++发布话题功能包并编译
    • 2.3.4 创建C/C++订阅话题的功能包
    • 2.3.5 编写ROS2订阅话题节点CPP文件
    • 2.3.6 配置C/C++订阅话题功能包并编译
  • 2.4 使用Python创建基础消息类型的话题通讯
    • 2.4.1 创建Python发布话题功能包并编写节点文件
    • 2.4.2 配置Python项目并运行
    • 2.4.3 创建Python订阅话题功能包并编写节点
    • 2.4.4 编译运行节点

  • 其他ROS2学习笔记: ROS2学习笔记
  • 代码仓库:Github连接地址
  • 欢迎各位互相学习交流

2.1 ROS2话题通讯介绍

话题通信是一种单向通信模型,一方发布数据,一方订阅数据,适用于连续不间断的通讯场景,如小车SLAM导航过程中的位姿信息等等。话题是一个通讯的管道,ROS2的话题发布方和接收方无论是C/C++还是Python都可以发布/订阅相同的话题实现通讯,一个话题的发布方,可以有多个订阅方,如下图所示:

在这里插入图片描述

Tips:节点(Node)的概念

ROS的通信对象的构建都依赖于节点(回想之前快速体验的 rclcpp::Node 或者是 from rclpy.node import Node 都是为了创建一个节点所导入的父类),一般情况下一个节点都对应某一个功能模块(例如一个节点负责持续发布SLAM位姿数据等),一个C/C++ 或者Python的文件代码,可以包括多个节点。

2.2 ROS2常用的消息类型介绍

2.2.1 std_msgs消息类型

参考内容

官方文档 std_msgs Msg/Srv Documentation

详解常用的ROS内置消息类型

ROS中geometry_msgs消息类型、nav_msg消息

std_msgs 属于ROS的标准数据类型库,主要包括的消息类型有:

ROS typeC++ type
boolbool
byteuint8_t
charchar
float32float
float64double
int8int8_t
uint8uint8_t
int16int16
uint16uint16
int32int32
uint32uint32
int64int64
uint64uint64_t
stringstd::string
static arraystd::array<T, N>

数组和有条件的字符串的映射

ROS typeC++ type
unbounded dynamic arraystd::vector
bounded dynamic arraycustom_class<T, N>
bounded stringstd::string

2.2.2 geometry_msgs消息类型

参考内容

官方文档 geometry_msgs Msg/Srv Documentation

ROS中geometry_msgs常用消息类型

ROS2 humble的接口官方API

geometry_msgs:常见的几何信息(如点、向量和姿势)提供ROS消息,其中包括的内容有,具体的话题参数,例如在使用乌龟节点控制乌龟运动的cmd_vel话题就是采用geometry_msgs/Twist编写的,具体的用法,可以去查阅官网。

Accel
AccelStamped
AccelWithCovariance
AccelWithCovarianceStamped
Inertia
InertiaStamped
Point
Point32
PointStamped
Polygon
PolygonStamped
Pose
Pose2D
PoseArray
PoseStamped
PoseWithCovariance
PoseWithCovarianceStamped
Quaternion
QuaternionStamped
Transform
TransformStamped
Twist
TwistStamped
TwistWithCovariance
TwistWithCovarianceStamped
Vector3
Vector3Stamped
Wrench
WrenchStamped

2.3 使用C/C++创建基础消息类型的话题通讯

参考内容:

Writing a simple publisher and subscriber (C++)

2.2.2_话题通信_原生消息(C++)_01发布方01源码分析

2.3.1 创建C/C++发布话题信息的功能包并配置VSCode环境

创建发布者功能包时,不添加任何依赖项,回顾之前的项目配置

  1. 创建ROS2 C/C++功能包,其中包名为 cppBaseMsgPub :ros2 pkg create cppBaseMsgPub --build-type ament_cmake

Tips:这里补充还是推荐采用下划线割开的命名方式,否则容易出错
在这里插入图片描述

如果尝试命名节点和依赖项,可以直接采用这种方式,节点名为 cppBaseMsgPubNode ,依赖 rclcppstd_msgsros2 pkg create cppBaseMsgPub --build-type ament_cmake --node-name cppBaseMsgPubNode --dependencies rclcpp std_msgs

pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ ros2 pkg create cppBaseMsgPub --build-type ament_cmake
going to create a new package
... 手动省略
creating ./cppBaseMsgPub/CMakeLists.txt

[WARNING]: Unknown license 'TODO: License declaration'.  This has been set in the package.xml, but no LICENSE file has been created.
It is recommended to use one of the ament license identitifers:
... 手动省略
MIT-0
  1. 在工作空间(这个是vscode的概念)下创建.vsocde文件夹和settings.json文件,配置VSCode的settings.json文件,添加路径
{
    "C_Cpp.default.includePath": ["/opt/ros/humble/include/**"],
    "python.analysis.extraPaths": ["/opt/ros/humble/local/lib/python3.10/dist-packages/"],
}

此时的文件结构如下:可以看到,如果单纯的指定了包名但是没有指定节点名,不会在src目录下创建.cpp文件

pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ tree -a
.(注释:这个就是工作空间)
├── cppBaseMsgPub
│   ├── CMakeLists.txt
│   ├── include
│   │   └── cppBaseMsgPub
│   ├── package.xml
│   └── src
└── .vscode
    └── settings.json

5 directories, 3 files

完成之后配置VSCode环境

2.3.2 编写ROS2发布话题节点CPP文件

  1. 编写发布者代码:根据官网提供的案例,在包的src目录下,创建cppBaseMsgPubNode.cpp文件,对cppBaseMsgPubNode.cpp进行发布者内容编写:总的来说,主要包括创建构造发布节点,计数属性,然后绑定发布函数到定时器上
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

// C++14中的时间库
using namespace std::chrono_literals;

class CppBaseMsgPub: public rclcpp::Node
{
  public:
      /* 1. ROS2节点的构造函数,其中包括一个node对象(初始化时候没有给出节点的名称),
      * 和属性count_(默认初始化为0) */
      CppBaseMsgPub(const char* nodeName):Node(nodeName), count_(0)
      {
        // 2. 创建发布者,参数分别为话题名称myTopicName,和发布队列的长队为10
        publisher_ = this->create_publisher<std_msgs::msg::String>("myTopicName", 10);
        // 3. 创建定时器,设置发布的频率,并绑定定时执行的事件,这里给到的是CppBaseMsgPub类的函数
        timer_ = this->create_wall_timer(500ms, std::bind(&CppBaseMsgPub::timer_callback, this));
      }

  private:
     // 4. 定义回调函数
    void timer_callback()
    {
      auto message = std_msgs::msg::String();
      message.data = "Hello, world! " + std::to_string(count_++);
      RCLCPP_INFO(this->get_logger(), "Cpp Publish: '%s'", message.data.c_str());
      publisher_->publish(message);
    }

    // 5. 计时器、发布者和计数器字段的声明
    rclcpp::TimerBase::SharedPtr timer_;
    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
    size_t count_;

};

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  // 创建节点,给出构造的节点名为cppBaseMsgPubNode
  rclcpp::spin(std::make_shared<CppBaseMsgPub>("cppBaseMsgPubNode"));
  rclcpp::shutdown();
  return 0;
}

2.3.3 配置C/C++发布话题功能包并编译

  1. 配置package.xmlpackage.xml主要对C/C++的功能包依赖项和发布信息进行配置,由于在节点cppBaseMsgPubNode.cpp中主要用到了rclcppstd_msgs两个依赖,因此package.xml的配置主要如下:
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>cppBaseMsgPub</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="pldz@R7000.com">pldz</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <!-- 添加依赖项 -->
  <depend>rclcpp</depend>
  <depend>std_msgs</depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>
  1. 配置CmakeLists.txt:主要包括的内容有五部分,并且需要按照顺序进行配置好
find_package()                  // 1. 列出依赖项,通俗的说是项目编译所需要的全部依赖项名称,节点和项目是两个概念,一个项目可以有多个节点
add_executable()                // 2. 可执行文件的路径,通俗来说是编译节点的main函数入口
target_include_directories()    // 3. 编译节点所需要的include的位置
ament_target_dependencies()     // 4. 编译节点所需要的依赖项,这一步的目的是连接编译该节点所需要的依赖项
install()                       // 5. 通俗来说,是将编译好的节点给拷贝到ROS功能包的目录,使得能够通过指令ros2 run <包名> <节点名>的配置,默认这一步的目的就是将build文件夹的内容拷贝到install的lib文件夹下
ament_package()                 // 6. 生成ament工具的环境,缺少这一步,无法在install文件夹下生成setup.bash文件等等

因此该项目的CmakeLists.txt如下所示:

cmake_minimum_required(VERSION 3.8)
project(cppBaseMsgPub)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)

# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

# 1. 添加依赖项列表
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

# 2. 生成节点的主函数入口和节点名称
add_executable(cppBaseMsgPubNode src/cppBaseMsgPubNode.cpp)


# 3. Include路径配置,这里其实没有用上,可以不用配置
target_include_directories(cppBaseMsgPubNode PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)

# 4. ament工具的编译所需要的依赖
ament_target_dependencies(
  cppBaseMsgPubNode
  "rclcpp"
  "std_msgs"
)

# 5. 安装规则
install(TARGETS cppBaseMsgPubNode
  DESTINATION lib/${PROJECT_NAME})

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # comment the line when a copyright and license is added to all source files
  set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # comment the line when this package is in a git repo and when
  # a copyright and license is added to all source files
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

# 6. 配置ament环境,生成功能包
ament_package()

  1. 编译功能包:colcon build
pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ colcon build
WARNING: Package name "cppBaseMsgPub" does not follow the naming conventions. It should start with a lower case letter and only contain lower case letters, digits, underscores, and dashes.
Starting >>> cppBaseMsgPub
... 手动省略
Summary: 1 package finished [4.44s]
  1 package had stderr output: cppBaseMsgPub
  1. 运行节点:激活功能包环境source ./install/setup.bash,然后运行ros2 run cppBaseMsgPub cppBaseMsgPubNode
pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ source ./install/setup.bash 
pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ ros2 run cppBaseMsgPub cppBaseMsgPubNode 
[INFO] [1683015931.213646661] [cppBaseMsgPubNode]: Cpp Publish: 'Hello, world! 0'
[INFO] [1683015931.713349843] [cppBaseMsgPubNode]: Cpp Publish: 'Hello, world! 1'
[INFO] [1683015932.213429705] [cppBaseMsgPubNode]: Cpp Publish: 'Hello, world! 2'
^C[INFO] [1683015932.588202160] [rclcpp]: signal_handler(signum=2)
pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ 

2.3.4 创建C/C++订阅话题的功能包

  1. 由于上面操作过一遍从功能包开始的配置节点依赖项,这里直接提前在创建功能包的时候直接指定依赖项,省去后续的配置,取名订阅话题的功能包为cppBaseMsgSub,节点名称为cppBaseMsgSubNode,如ros2 pkg create cppBaseMsgSub --build-type ament_cmake --node-name cppBaseMsgSubNode --dependencies rclcpp std_msgs

Tips:这里补充还是推荐采用下划线割开的命名方式,否则容易出错
在这里插入图片描述

pldz@pldz-pc:~/share/ROS2_DEMO/2_Chapter/code$ ros2 pkg create cppBaseMsgSub --build-type ament_cmake --node-name cppBaseMsgSubNode --dependencies rclcpp std_msgs
going to create a new package
package name: cppBaseMsgSub
... 手动省略
MIT
MIT-0
  1. 2.3.1节在工作空间下配置过vscode的settings.json这里就不再配置vscode了

2.3.5 编写ROS2订阅话题节点CPP文件

  1. 直接在cppBaseMsgSubNode.cpp文件进行编辑,创建订阅节点,订阅话题myTopicName与之前的发布话题类型和名称一致即可:
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

// 占位符,结合std::bind函数的绑定使用
using std::placeholders::_1;

class CppBaseMsgSub: public rclcpp::Node
{
  public:
    /* 1. ROS2节点的构造函数 */
    CppBaseMsgSub(const char* nodeName):Node(nodeName)
    {
      // 2.声明订阅话题类型,并绑定回调函数
      subscription_ = this->create_subscription<std_msgs::msg::String>(
      "myTopicName", 10, std::bind(&CppBaseMsgSub::topic_callback, this, _1));
    }

  private:
    // 3. 定义订阅到消息的回调函数
    void topic_callback(const std_msgs::msg::String & msg) const
    {
      RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg.data.c_str());
    }

    // 4. 计时器、发布者和计数器字段的声明
    rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  // 初始化订阅节点
  rclcpp::spin(std::make_shared<CppBaseMsgSub>("cppBaseMsgSubNode"));
  rclcpp::shutdown();
  return 0;
}

2.3.6 配置C/C++订阅话题功能包并编译

  1. 由于是直接在创建包的时候指定了依赖项,可以直接编译colcon build,运行查看效果:

在这里插入图片描述

2.4 使用Python创建基础消息类型的话题通讯

2.4.1 创建Python发布话题功能包并编写节点文件

  1. 创建Python发布者功能包,其中功能包名称为pythonBaseMsgPub,不指定节点名和依赖项,后续手动配置packages.xmlsetup.pyros2 pkg create pythonBaseMsgPub --build-type ament_python,目前文件结构如下所示:

在这里插入图片描述

Tips:这里补充还是推荐采用下划线割开的命名方式,否则容易出错
在这里插入图片描述

  1. pythonBaseMsgPub/pythonBaseMsgPub文件夹下创建pythonBaseMsgPubNode.py文件,内容如下所示
import rclpy
from rclpy.node import Node

from std_msgs.msg import String


class PythonBaseMsgPub(Node):

    def __init__(self, nodeName):
        # 1. 初始化父类构造函数,其中节点名需要创建时候指定,计数属性count_从0开始
        super().__init__(nodeName)
        self.count_ = 0
        # 2. 声明发布者,发布消息类型为String,话题名为myTopicName,队列大小为10
        self.publisher_ = self.create_publisher(String, 'myTopicName', 10)
        # 3. 创建定时器,其中更新频率为0.5秒,并绑定回调函数
        self.timer = self.create_timer(0.5, self.timer_callback)
        
    # 4. 定义回调函数
    def timer_callback(self):
        msg = String()
        msg.data = 'Hello World: %d' % self.count_
        self.publisher_.publish(msg)
        self.get_logger().info('Publishing: "%s"' % msg.data)
        self.count_ += 1


def main(args=None):
    rclpy.init(args=args)
    pythonBaseMsgPubNode = PythonBaseMsgPub("pythonBaseMsgPubNode")
    rclpy.spin(pythonBaseMsgPubNode)
    # 销毁节点
    pythonBaseMsgPubNode.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

2.4.2 配置Python项目并运行

  1. 配置Python项目的packages.xml:主要是添加可执行的依赖项rclpystd_msgs
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>pythonBaseMsgPub</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="pldz@R7000.com">pldz</maintainer>
  <license>TODO: License declaration</license>

  <!-- 与C/C++不同的是,Python文件是一个可执行的脚本,因此依赖项的关键字为exec_depend -->
  <exec_depend>rclpy</exec_depend>
  <exec_depend>std_msgs</exec_depend>

  <test_depend>ament_copyright</test_depend>
  <test_depend>ament_flake8</test_depend>
  <test_depend>ament_pep257</test_depend>
  <test_depend>python3-pytest</test_depend>

  <export>
    <build_type>ament_python</build_type>
  </export>
</package>

  1. 配置setup.py文件指定节点的main函数入口:
from setuptools import setup

package_name = 'pythonBaseMsgPub'

setup(
    name=package_name,
    version='0.0.0',
    packages=[package_name],
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='pldz',
    maintainer_email='pldz@R7000.com',
    description='TODO: Package description',
    license='TODO: License declaration',
    tests_require=['pytest'],
    # 指定编译节点的main函数入口
    entry_points={
        'console_scripts': [
            'pythonBaseMsgPubNode = pythonBaseMsgPub.pythonBaseMsgPubNode:main',
        ],
    },
)

  1. 编译:colcon build

2.4.3 创建Python订阅话题功能包并编写节点

  1. 创建功能包pythonBaseMsgSub,并直接给出节点名pythonBaseMsgSubNode和依赖项rclpystd_msgs,如下所示:ros2 pkg create pythonBaseMsgSub --build-type ament_python --node-name pythonBaseMsgSubNode --dependencies rclpy std_msgs

Tips:这里补充还是推荐采用下划线割开的命名方式,否则容易出错
在这里插入图片描述

  1. 编写订阅者节点:
import rclpy
from rclpy.node import Node

from std_msgs.msg import String


class PythonBaseMsgSub(Node):

    def __init__(self, nodeName):
        # 1. 构造函数,初始化node节点
        super().__init__(nodeName)
        # 2. 声明订阅者,订阅话题`myTopicNmae`,并绑定回调函数
        self.subscription = self.create_subscription(String,'myTopicName',self.listener_callback,10)

    # 3. 定义回调函数
    def listener_callback(self, msg):
        self.get_logger().info('I heard: "%s"' % msg.data)


def main(args=None):
    rclpy.init(args=args)
    pythonBaseMsgSubNode = PythonBaseMsgSub("pythonBaseMsgSubNode")
    rclpy.spin(pythonBaseMsgSubNode)
    pythonBaseMsgSubNode.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

2.4.4 编译运行节点

  1. 由于指定了依赖项和节点名,不需要多余的进行packages.xmlsetup.py的配置

  2. 编译colcon build,联合C/C++的一起运行,可以看到话题通讯是多对多的

在这里插入图片描述

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

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

相关文章

【Elasticsearch】SQL操作相关

文章目录 SQL操作数据准备查询索引下的数据SQL转化为DSL(本质)SQL与DSL混合使用查看所有索引查询指定索引查看索引(表)结构where条件过滤group by分组having 对分组后的数据进行过滤order by 排序limit 限制查询数量cursor 游标->为缓存设计聚合操作支持的函数和运算比较运算…

虚拟机和Docker有什么区别?

虚拟机 对于虚拟机&#xff0c;抽象层或抽象软件成为管理程序。管理程序就是帮助虚拟机模拟物理计算机的东西。在管理程序下面&#xff0c;我们有些硬件。管理程序管理单个物理主机上不同虚拟机之间的资源分配。管理程序管理单个物理主机上不同虚拟机之间的资源分配。也就是管…

微信小程序学习实录3(环境部署、百度地图微信小程序、单击更换图标、弹窗信息、导航、支持腾讯百度高德地图调起)

百度地图微信小程序 一、环境部署1.need to be declared in the requiredPrivateInfos2.api.map.baidu.com 不在以下 request 合法域名3.width and heigth of marker id 9 are required 二、核心代码&#xff08;一&#xff09;逻辑层index.js&#xff08;二&#xff09;渲染层…

vue diff算法与虚拟dom知识整理(2) snabbdom简介并搭建开发环境

snabbdom算是diff算法 和 虚拟dom 的一个鼻租了 vue源码借鉴了snabbdom 这个单词翻译出来叫速度 命名还是用了点心的 后面是 dom 这个 我们大概去猜作者的意思 大概想表示的就是 一个比较快的dom操作 snabbdom的get地址如下 https://github.com/snabbdom/snabbdom 这里的简…

「OceanBase 4.1 体验」|快速安装部署[OBD方式]

文章目录 一、Oceanbase数据库简介1.1 核心特性1.2 系统架构1.2.1 存储层1.2.2 复制层1.2.3 均衡层1.2.4 事务层1.2.4.1 原子性1.2.4.2 隔离性 1.2.5 SQL 层1.2.5.1 SQL 层组件1.2.5.2 多种计划 1.2.6 接入层 二、OceanBase 数据库社区版部署2.1 部署方式2.2 基础环境配置2.3 通…

【华为OD机试真题】信号发射和接收(javaC++python)100%通过率 超详细代码注释 代码深度解读

信号发射和接收 知识点数组栈 单调栈时间限制: 1s 空间限制: 256MB 限定语言:不限 题目描述: 有一个二维的天线矩阵&#xff0c;每根天线可以向其他天线发射信号也能接收其他天线的信号&#xff0c;为了简化起见&#xff0c;我们约定每根天线只能向东和向南发射信号&#xf…

【ROS仿真实战】获取机器人在gazebo位置真值的三种方法(三)

文章目录 前言一. 使用ROS tf库二、 使用Gazebo Model Plugin三、 使用libgazebo_ros_p3d插件四、总结 前言 在ROS和Gazebo中&#xff0c;获取机器人的位置信息通常通过ROS消息传递进行。在这篇文章中&#xff0c;我们将介绍三种获取机器人在Gazebo中位置真值的方法&#xff1…

CTF ASCII码 密码解密题 简单

1. 题目 这次的CTF题目就是一张图片如下&#xff0c;并且说有几个蛋被打乱过。明显是一个密码学的解码题。 2. 解题思路 左边表格给出10种颜色&#xff0c;特别是第二列给出了数字0&#xff0c;种种迹象都指向了10进制。每一个蛋都有三种颜色&#xff0c;代表每个蛋都是三位…

【GORM框架】一文学会用gorm实现对单表的增删改查操作

博主简介&#xff1a;努力学习的大一在校计算机专业学生&#xff0c;热爱学习和创作。目前在学习和分享&#xff1a;数据结构、Go&#xff0c;Java等相关知识。博主主页&#xff1a; 是瑶瑶子啦所属专栏: GORM框架学习 近期目标&#xff1a;写好专栏的每一篇文章 文章目录 一、…

M1 Mac配置JAVA环境

1、下载JDK 目前JDK有Oracle的JDK还有zulu的Open JDK可供选择&#xff0c;因为需要JAVA1.8所以下文以zulu的JDK为例。 Zulu官网&#xff1a;https://www.azul.com/downloads/?packagejdk 选择所需的JDK版本&#xff08;注意选择ARM架构&#xff09;> 下载.dmg包 > 安装 …

DAY 47 Ngnix优化与防盗链

Ngnix优化主要有两种&#xff0c;一种是配置上的优化&#xff0c;一种是内核上的优化 隐藏响应头中的版本号 方法一&#xff1a;curl命令 网页查看 隐藏版本信息 修改nginx的运行用户和组 方法一&#xff1a;在编译安装时&#xff0c;指定运行用户和组 [root nginx-1.12.2]#…

【英语】100个句子记完7000个雅思单词

其实主要的7000词其实是在主题归纳里面&#xff0c;不过过一遍100个句子也挺好的&#xff0c;反正也不多。 文章目录 Sentence 01Sentence 02Sentence 03Sentence 04Sentence 05Sentence 06Sentence 07Sentence 08Sentence 09Sentence 10Sentence 11Sentence 12Sentence 13Sent…

Linux常用的压缩、解压缩以及scp远程传输命令的使用

Linux常用的压缩、解压缩以及scp远程传输命令的使用 1.压缩命令2 解压命令3. 大文件压缩分割为多个压缩文件4. 远程传输命令scp4.1 将本地文件复制到远程主机目录4.2 将本地目录复制到远程主机目录4.3 将远程主机的文件复制到本机4.4 复制远程主机目录到本机 1.压缩命令 tar -…

Packet Tracer - 综合技能练习(配置新交换机的初始设置、SSH 和端口安全)

Packet Tracer - 综合技能练习 地址分配表 设备 接口 IP 地址 子网掩码 S1 VLAN 1 10.10.10.2 255.255.255.0 PC1 NIC 10.10.10.10 255.255.255.0 PC2 NIC 10.10.10.11 255.255.255.0 场景 网络管理员要求您配置新交换机。 在本练习中&#xff0c;您将使用一…

二分搜索算法通解框架

文章介绍了二分搜索最常见的几个场景的使用&#xff1a;寻找一个数、寻找左侧边界以及寻找右侧边界。阅读本文只需读者了解二分搜索的使用限制和基本原理即可。 我相信&#xff0c;友好的讨论交流会让彼此快速进步&#xff01;文章难免有疏漏之处&#xff0c;十分欢迎大家在评…

密码学【java】初探究加密方式之对称加密

文章目录 一 常见加密方式二 对称加密2.1 Cipher类简介2.2 Base算法2.3 补充&#xff1a;Byte&bit2.4 DES加密演示2.5 DES解密2.6 补充&#xff1a;对于IDEA控制台乱码的解决方法2.7 AES加密解密2.8 补充&#xff1a; toString()与new String ()用法区别2.9 加密模式2.9.1 …

MySQL学习笔记第六天

第06章多表查询 5. 7种SQL JOINS的实现 A是员工表&#xff0c;B是部门表。 5.7.1 代码实现 #8. UNION 和 UNION ALL的使用 # UNION&#xff1a;会执行去重操作 # UNION ALL:不会执行去重操作&#xff0c;效率优于前者&#xff0c;开发中优先使用 #结论&#xff1a;如果明确…

【Java入门合集】第二章Java语言基础(四——第二章结束)

【Java入门合集】第二章Java语言基础&#xff08;四——第二章结束&#xff09; 博主&#xff1a;命运之光 专栏&#xff1a;JAVA入门 学习目标 掌握变量、常量、表达式的概念&#xff0c;数据类型及变量的定义方法&#xff1b; 掌握常用运算符的使用&#xff1b; 掌握程序的顺…

【LeetCode股票买卖系列:188. 买卖股票的最佳时机 IV | 暴力递归=>记忆化搜索=>动态规划】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

Hibernate(一)——入门

在之前经常用到操作数据库的框架是Mybatis或者Mybatis-plus。 Hibernate在項目中用过&#xff0c;但没有深入的了解过&#xff0c;所以这次趁着假期把这个框架了解一下。 目录 概念Hibernate和Mybatis的区别Hibernate使用依赖引入Hibernate配置文件XML配置文件详解properties文…