使用 Python、XML 和 YAML 编写 ROS 2 Launch 文件

系列文章目录

ROS2 重要概念
ament_cmake_python 用户文档
ROS2 ament_cmake 用户文档
使用 rosdep 管理 ROS 2 依赖项


文章目录

  • 系列文章目录
  • 前言
  • 一、Launch 文件示例
    • 1.1 Python 版本
    • 1.2 XML 版本
    • 1.3 YAML 版本
  • 二、从命令行使用 Launch 文件
    • 1. Launching
    • 2. 设置参数
    • 3. 控制海龟
  • 三、Python、XML 或 YAML: 我应该使用哪种语言?
  • 四、为什么要使用 ROS 2 Launch
  • `少侠请留步,点赞、收藏、关注`


前言

ROS 2 launch 文件可以用 Python、XML 和 YAML 编写。本指南介绍了如何使用这些不同的格式来完成相同的任务,并对何时使用每种格式进行了讨论。


一、Launch 文件示例

下面是一个用 Python、XML 和 YAML 实现的 Launch 文件。每个 Launch 文件都执行以下操作:

  • 使用默认值设置命令行参数

  • 包含另一个 launch 文件

  • 在另一个命名空间中包含另一个启动文件

  • 启动节点并设置其名称空间

  • 启动一个节点,设置其名称空间,并在该节点中设置参数(使用参数)

  • 创建一个节点,将消息从一个话题重新映射到另一个话题

1.1 Python 版本

首先介绍涉及到的几个 方法

  1. ament_index_python.get_package_share_path(package_name, print_warning=True)
以 pathlib.Path 的形式返回给定软件包的共享目录。
例如,如果您将软件包 "foo "安装到"/home/user/ros2_ws/install",并以 "foo"作为参数调用此函数,那么它将返回一个代表"/home/user/ros2_ws/install/share/foo"的路径,然后您就可以用它来构建共享文件的路径,即 get_package_share_path('foo') /'urdf/robot.urdf'
  1. launch.LaunchDescription
基础: LaunchDescriptionEntity
可启动系统的描述。
该描述由一系列实体组成,这些实体代表了系统设计师的意图。
该描述还可能有参数,参数由该启动描述中的 launch.actions.DeclareLaunchArgument 操作声明。
该描述的参数可通过 get_launch_arguments() 方法访问。参数是通过搜索此启动描述中的实体和每个实体的描述(可能包括由这些实体产生的实体)收集的。
  1. launch.actions.declare_launch_argument.DeclareLaunchArgument(Action)
基础: Action
声明新启动参数的 Action。
启动参数存储在同名的 "启动配置 "中。请参阅 launch.actions.SetLaunchConfiguration 和 launch.substitutions.LaunchConfiguration。
在 launch.LaunchDescription 中声明的任何启动参数都会在包含该启动描述时作为参数显示出来,例如,在 launch.actions.IncludeLaunchDescription 动作中作为附加参数,或在使用 ros2 launch .... 启动时作为命令行参数。
除了名称(也是参数结果的存储位置)外,启动参数还可能有一个默认值、一个有效值选择列表和一个描述。如果给出了默认值,那么该参数就变成了可选参数,默认值将被放置在启动配置中。如果没有给出默认值,并且在包含启动说明时也没有给出值,则会发生错误。如果给出了一个选择列表,而给定值不在其中,则会发生错误。
默认值可以使用 Substitutions,但名称和描述只能是 Text,因为它们在启动前需要一个有意义的值,例如在列出命令行参数时。
需要注意的是,声明启动参数必须在启动描述的某个部分,而这个部分在不启动的情况下是可以描述的。例如,如果你在条件组中或作为事件处理程序的回调声明了一个启动参数,那么像 ros2 launch 这样的工具可能无法在启动描述之前知道该参数。在这种情况下,该参数在命令行上将不可见,但如果该参数在访问后未满足要求(且没有默认值),则可能引发异常。
换句话说,访问该操作的后置条件要么是同名的启动配置设置了值,要么是由于没有设置任何值且没有默认值而引发异常。但是,前置条件并不能保证在条件或情况夹杂后面的参数是可见的。
例如;
ld = LaunchDescription([DeclareLaunchArgument('simple_argument'),DeclareLaunchArgument('with_default_value', default_value='default'),DeclareLaunchArgument('with_default_and_description',default_value='some_default',description='this argument is used to configure ...'),DeclareLaunchArgument('mode',default_value='A',description='Choose between mode A and mode B',choices=['A', 'B']),# other actions here, ...
])
  1. launch.actions.GroupAction
基础: Action
可产生其他操作的 Action。
此操作用于嵌套其他操作,而无需包含单独的启动说明,同时还可选择具有一个条件(与所有其他操作一样)、扩展和转发启动配置和环境变量,以及/或仅为组及其产生的操作声明启动配置。
Scoped=True 时,对启动配置和环境变量的更改仅限于组操作中的操作范围。
当 scopeed=True 和 forwarding=True 时,所有现有的启动配置和环境变量都可在作用域上下文中使用。
当 scope=True 和 forwarding=False 时,所有现有的启动配置和环境变量都会从作用域上下文中移除。
launch_configurations 字典中定义的任何启动配置都将在当前上下文中设置。当 scopeed=False 时,即使 GroupAction 已完成,这些配置也将持续存在。当 scoped=True 时,这些配置将仅对 GroupAction 中的动作可用。当 scope=True 和 forwarding=False 时,launch_configurations 字典将在清除前进行评估,然后在清除的 scope 上下文中重新设置。
  1. launch.actions.IncludeLaunchDescription
基础: Action
包含启动描述源并在访问时生成其实体的动作。
可以向启动描述传递参数,这些参数是通过 launch.actions.DeclareLaunchArgument 动作声明的。
如果给定的参数与已声明的启动参数名称不匹配,则仍会使用 launch.actions.SetLaunchConfiguration 动作将其设置为启动配置。这样做的原因是,在给定的启动描述中,并非总能检测到所有已声明启动参数类的实例。
另一方面,如果给定的启动描述声明了启动参数,但未向此操作提供其值,有时会引发错误。不过,只有当声明的启动参数是无条件的(有时声明启动参数的操作只有在特定情况下才会被访问),并且没有默认值可供选择时,才会产生这种错误。
有条件包含的启动参数如果没有默认值,在尽力进行参数检查后仍无法提前发现未满足的参数时,最终将引发错误。
  1. launch.launch_description_sources.PythonLaunchDescriptionSource(LaunchDescriptionSource)
基础: LaunchDescriptionSource
Python 启动文件的封装,可在启动过程中加载。
  1. launch.substitutions.LaunchConfiguration(Substitution)
可访问启动配置变量的替代变量。
  1. launch.substitutions.TextSubstitution(Substitution)
可对单个字符串文本进行替换。
  1. PushROSNamespace(Action)
推送 ros 命名空间的动作。
在有作用域的 `GroupAction` 中使用时,它会自动弹出。没有其他方法可以弹出它。 
  1. XMLLaunchDescriptionSource(FrontendLaunchDescriptionSource)
封装 XML 启动文件,可在启动过程中加载。
  1. YAMLLaunchDescriptionSource(FrontendLaunchDescriptionSource)
封装 YAML 启动文件,可在启动过程中加载。
  1. Node(ExecuteProcess)
执行一个 ROS 节点的操作。

Python 代码如下

# example_launch.pyimport osfrom ament_index_python import get_package_share_directoryfrom launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.actions import GroupAction
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration
from launch.substitutions import TextSubstitution
from launch_ros.actions import Node
from launch_ros.actions import PushRosNamespace
from launch_xml.launch_description_sources import XMLLaunchDescriptionSource
from launch_yaml.launch_description_sources import YAMLLaunchDescriptionSourcedef generate_launch_description():# args that can be set from the command line or a default will be usedbackground_r_launch_arg = DeclareLaunchArgument("background_r", default_value=TextSubstitution(text="0"))background_g_launch_arg = DeclareLaunchArgument("background_g", default_value=TextSubstitution(text="255"))background_b_launch_arg = DeclareLaunchArgument("background_b", default_value=TextSubstitution(text="0"))chatter_py_ns_launch_arg = DeclareLaunchArgument("chatter_py_ns", default_value=TextSubstitution(text="chatter/py/ns"))chatter_xml_ns_launch_arg = DeclareLaunchArgument("chatter_xml_ns", default_value=TextSubstitution(text="chatter/xml/ns"))chatter_yaml_ns_launch_arg = DeclareLaunchArgument("chatter_yaml_ns", default_value=TextSubstitution(text="chatter/yaml/ns"))# include another launch filelaunch_include = IncludeLaunchDescription(PythonLaunchDescriptionSource(os.path.join(get_package_share_directory('demo_nodes_cpp'),'launch/topics/talker_listener_launch.py')))# include a Python launch file in the chatter_py_ns namespacelaunch_py_include_with_namespace = GroupAction(actions=[# push_ros_namespace to set namespace of included nodesPushRosNamespace('chatter_py_ns'),IncludeLaunchDescription(PythonLaunchDescriptionSource(os.path.join(get_package_share_directory('demo_nodes_cpp'),'launch/topics/talker_listener_launch.py'))),])# include a xml launch file in the chatter_xml_ns namespacelaunch_xml_include_with_namespace = GroupAction(actions=[# push_ros_namespace to set namespace of included nodesPushRosNamespace('chatter_xml_ns'),IncludeLaunchDescription(XMLLaunchDescriptionSource(os.path.join(get_package_share_directory('demo_nodes_cpp'),'launch/topics/talker_listener_launch.xml'))),])# include a yaml launch file in the chatter_yaml_ns namespacelaunch_yaml_include_with_namespace = GroupAction(actions=[# push_ros_namespace to set namespace of included nodesPushRosNamespace('chatter_yaml_ns'),IncludeLaunchDescription(YAMLLaunchDescriptionSource(os.path.join(get_package_share_directory('demo_nodes_cpp'),'launch/topics/talker_listener_launch.yaml'))),])# start a turtlesim_node in the turtlesim1 namespaceturtlesim_node = Node(package='turtlesim',namespace='turtlesim1',executable='turtlesim_node',name='sim')# start another turtlesim_node in the turtlesim2 namespace# and use args to set parametersturtlesim_node_with_parameters = Node(package='turtlesim',namespace='turtlesim2',executable='turtlesim_node',name='sim',parameters=[{"background_r": LaunchConfiguration('background_r'),"background_g": LaunchConfiguration('background_g'),"background_b": LaunchConfiguration('background_b'),}])# perform remap so both turtles listen to the same command topicforward_turtlesim_commands_to_second_turtlesim_node = Node(package='turtlesim',executable='mimic',name='mimic',remappings=[('/input/pose', '/turtlesim1/turtle1/pose'),('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),])return LaunchDescription([background_r_launch_arg,background_g_launch_arg,background_b_launch_arg,chatter_py_ns_launch_arg,chatter_xml_ns_launch_arg,chatter_yaml_ns_launch_arg,launch_include,launch_py_include_with_namespace,launch_xml_include_with_namespace,launch_yaml_include_with_namespace,turtlesim_node,turtlesim_node_with_parameters,forward_turtlesim_commands_to_second_turtlesim_node,])

1.2 XML 版本

<!-- example_launch.xml --><launch><!-- args that can be set from the command line or a default will be used --><arg name="background_r" default="0" /><arg name="background_g" default="255" /><arg name="background_b" default="0" /><arg name="chatter_py_ns" default="chatter/py/ns" /><arg name="chatter_xml_ns" default="chatter/xml/ns" /><arg name="chatter_yaml_ns" default="chatter/yaml/ns" /><!-- include another launch file --><include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.py" /><!-- include a Python launch file in the chatter_py_ns namespace--><group><!-- push_ros_namespace to set namespace of included nodes --><push_ros_namespace namespace="$(var chatter_py_ns)" /><include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.py" /></group><!-- include a xml launch file in the chatter_xml_ns namespace--><group><!-- push_ros_namespace to set namespace of included nodes --><push_ros_namespace namespace="$(var chatter_xml_ns)" /><include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.xml" /></group><!-- include a yaml launch file in the chatter_yaml_ns namespace--><group><!-- push_ros_namespace to set namespace of included nodes --><push_ros_namespace namespace="$(var chatter_yaml_ns)" /><include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.yaml" /></group><!-- start a turtlesim_node in the turtlesim1 namespace --><node pkg="turtlesim" exec="turtlesim_node" name="sim" namespace="turtlesim1" /><!-- start another turtlesim_node in the turtlesim2 namespaceand use args to set parameters --><node pkg="turtlesim" exec="turtlesim_node" name="sim" namespace="turtlesim2"><param name="background_r" value="$(var background_r)" /><param name="background_g" value="$(var background_g)" /><param name="background_b" value="$(var background_b)" /></node><!-- perform remap so both turtles listen to the same command topic --><node pkg="turtlesim" exec="mimic" name="mimic"><remap from="/input/pose" to="/turtlesim1/turtle1/pose" /><remap from="/output/cmd_vel" to="/turtlesim2/turtle1/cmd_vel" /></node>
</launch>

1.3 YAML 版本

# example_launch.yamllaunch:# args that can be set from the command line or a default will be used
- arg:name: "background_r"default: "0"
- arg:name: "background_g"default: "255"
- arg:name: "background_b"default: "0"
- arg:name: "chatter_py_ns"default: "chatter/py/ns"
- arg:name: "chatter_xml_ns"default: "chatter/xml/ns"
- arg:name: "chatter_yaml_ns"default: "chatter/yaml/ns"# include another launch file
- include:file: "$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.py"# include a Python launch file in the chatter_py_ns namespace
- group:- push_ros_namespace:namespace: "$(var chatter_py_ns)"- include:file: "$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.py"# include a xml launch file in the chatter_xml_ns namespace
- group:- push_ros_namespace:namespace: "$(var chatter_xml_ns)"- include:file: "$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.xml"# include a yaml launch file in the chatter_yaml_ns namespace
- group:- push_ros_namespace:namespace: "$(var chatter_yaml_ns)"- include:file: "$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.yaml"# start a turtlesim_node in the turtlesim1 namespace
- node:pkg: "turtlesim"exec: "turtlesim_node"name: "sim"namespace: "turtlesim1"# start another turtlesim_node in the turtlesim2 namespace and use args to set parameters
- node:pkg: "turtlesim"exec: "turtlesim_node"name: "sim"namespace: "turtlesim2"param:-name: "background_r"value: "$(var background_r)"-name: "background_g"value: "$(var background_g)"-name: "background_b"value: "$(var background_b)"# perform remap so both turtles listen to the same command topic
- node:pkg: "turtlesim"exec: "mimic"name: "mimic"remap:-from: "/input/pose"to: "/turtlesim1/turtle1/pose"-from: "/output/cmd_vel"to: "/turtlesim2/turtle1/cmd_vel"

二、从命令行使用 Launch 文件

1. Launching

上述任何启动文件都可以通过 ros2 launch 运行。要在本地试用它们,可以创建一个新软件包,然后使用

ros2 launch <package_name> <launch_file_name>

或通过指定 launch 文件的路径直接运行该文件

ros2 launch <path_to_launch_file>

2. 设置参数

要设置传递给启动文件的参数,应使用 key:=value 语法。例如,可以用以下方式设置 background_r 的值:

ros2 launch <package_name> <launch_file_name> background_r:=255
ros2 launch <path_to_launch_file> background_r:=255

3. 控制海龟

要测试重映射是否有效,可以在另一个终端运行以下命令来控制海龟:

ros2 run turtlesim turtle_teleop_key --ros-args --remap __ns:=/turtlesim1

三、Python、XML 或 YAML: 我应该使用哪种语言?

ROS 1 中的启动文件是用 XML 编写的,因此对于来自 ROS 1 的用户来说,XML 可能是最熟悉的。

对于大多数应用程序来说,选择哪种 ROS 2 启动格式取决于开发人员的偏好。不过,如果你的启动文件需要有 XML 或 YAML 无法实现的灵活性,你可以使用 Python 来编写启动文件。由于以下两个原因,使用 Python 编写 ROS 2 启动文件更为灵活:

  • Python 是一种脚本语言,因此您可以在启动文件中使用该语言及其库。

  • ros2/launch(一般启动功能)和 ros2/launch_ros(ROS 2 特定启动功能)都是用 Python 编写的,因此你可以访问 XML 和 YAML 可能无法提供的较低级别的启动功能。

尽管如此,用 Python 编写的启动文件可能比 XML 或 YAML 编写的文件更复杂、更冗长。

四、为什么要使用 ROS 2 Launch

ROS 2 系统通常由运行在多个不同进程(甚至不同机器)上的多个节点组成。虽然每个节点都可以单独运行,但很快就会变得非常麻烦。

ROS 2 中的启动系统旨在通过一条命令自动运行多个节点。它可以帮助用户描述系统配置,然后按描述执行。系统配置包括运行哪些程序、在哪里运行、传递哪些参数,以及 ROS 特有的约定,通过为每个组件提供不同的配置,可以方便地在整个系统中重复使用组件。它还负责监控已启动进程的状态,并对这些进程的状态变化做出报告和/或反应。

上述所有内容都在一个启动文件中指定,该文件可以用 Python、XML 或 YAML 编写。使用 ros2 launch 命令运行该启动文件后,所有指定的节点都将运行。

设计文档详细介绍了 ROS 2 启动系统的设计目标(目前尚未提供所有功能)。


少侠请留步,点赞、收藏、关注

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

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

相关文章

idea中的.idea文件夹以及*.iml文件(新版idea没有*.iml文件了),新旧版idea打开同一个项目会不会出现不兼容

一、背景 我们有可能会在同一台电脑上安装2个 intellj idea。比如一个community edition一个ultimate edition&#xff08;一个安装板一个绿色解压版&#xff09; 当然了&#xff0c;两个idea之间可能版本号也会有差。 这篇文章就来讨论两个问题&#xff0c;一是关于idea产生…

深度学习中的数据类型介绍:FP32, FP16, TF32, BF16, Int16, Int8 ...

文章目录 0. 前言1. 数据的存储方式2. 不同数据类型介绍2.1 深度学习中常用的数据类型2.2 BF16 类型的优势2.3 不同数据类型的使用场景 0. 前言 相比于 CPU&#xff0c;GPU 在架构设计时将更多的晶体管用于数据处理&#xff0c;而不是数据缓存和流量控制&#xff0c;因此可以高…

致:CSGO游戏搬砖人的一封信

最近大家还在坚持操作CSGO游戏搬砖项目不&#xff1f; 这个项目虽是稳赚项目&#xff0c;但也有行情好和行情不好的时候&#xff0c;平台的大中小各种活动的举办&#xff0c;都会对我们的项目造成一定影响。行情的上下波动势必然会影响卡价的波动&#xff0c;影响选品的快慢&a…

客户案例:CAC2.0监测异常账号行为,缓解暴力破解攻击

客户背景 某IT互联网公司专注于高精度导航定位技术的研发、制造和产业化推广&#xff0c;是国内高精度导航定位产业的领先企业之一。该公司以上海为总部&#xff0c;旗下拥有20国内省级本地化服务机构&#xff0c;并且其业务覆盖海外市场&#xff0c;公司产品和解决方案在不同…

棱镜七彩亮相工控中国大会,以软件供应链安全助力新型工业化高质量发展

2023年11月1日-3日&#xff0c;2023第三届工控中国大会在苏州国际会议中心举办&#xff0c;本届大会由中国电子信息产业发展研究院、中国工业经济联合会、国家智能制造专家委员会、国家产业基础专家委员会、江苏省工业和信息化厅、江苏省国有资产监督管理委员会、苏州市人民政府…

HTML 表格

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>表格标签</title>/* <style>.yun {widt…

C++学习 --函数

目录 1&#xff0c; 函数定义 1-1&#xff0c; 有返回值 1-2&#xff0c; 无返回值 2&#xff0c; 函数声明 3&#xff0c; 函数分文件编写 3-1&#xff0c; 创建自定义头文件 3-2&#xff0c; 创建源文件 3-3&#xff0c; 自定义头文件中编写函数声明 3-4&#xff0c…

北京陪诊小程序|陪诊系统开发|陪诊小程序未来发展不可小觑

近几年随着互联网快速发展&#xff0c;各行业领域都比较注重线上服务系统&#xff0c;通过陪诊小程序开发可以满足更多用户使用需求&#xff0c;同时还能提高用户使用体验。现在陪诊类的软件应用得到全面推广&#xff0c;在医疗行业当中陪诊小程序更贴近用户生活&#xff0c;可…

【漏洞复现】Apache_Tomcat7+ 弱口令 后台getshell漏洞

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞扫描3、漏洞验证 说明内容漏洞编号漏洞名称Tomcat7 弱口令 && 后台getshell漏洞漏洞评级高…

掌动智能:功能测试及拨测主要功能

在企业中对于功能测试及拨测而言&#xff0c;用户只需提供应用包和产品文档&#xff0c;由资深测试专家设计并执行测试&#xff0c;覆盖核心场景&#xff0c;包含特定业务流程以及行业通用特殊场景&#xff0c;支持需求定制。 执行过程严格监控&#xff0c;依据应用功能和业务需…

【番外篇】C++语法学习笔记

学习目标&#xff1a;C的一些高级操作 根据C菜鸟教程自学的笔记&#xff0c;大家有想学习C的话可以根据这个网站进行学习。这个推荐有一定基础的再去进行自学。新手的话还是建议直接看一些视频跟着学 学习内容&#xff1a; 1. 运算符重载 说到C中的运算符重载&#xff0c;首…

8年资深测试总结,接口自动化框架的设计与实现,一文打通...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、自动化测试框架…

Ionic 模块组件的理解

1 Ionic4.x 文件分析 1.1 app.module.ts 分析 Ionic 是一个基于 Angular 的移动应用开发框架&#xff0c;能帮助开发者使用 Web 技术&#xff08;HTML5、CSS3、JavaScript&#xff09;创建跨平台的应用程序。在 Ionic 应用程序中&#xff0c;app.module.ts 文件是整个应用程序的…

基于javaweb+mysql的jsp+servlet学生成绩管理系统(管理员、教师、学生)

博主24h在线&#xff0c;想要源码文档部署视频直接私聊&#xff0c;9.9元拿走&#xff01; 基于javawebmysql的jspservlet学生成绩管理系统(管理员、教师、学生)(javajspservletjavabeanmysqltomcat) 运行环境 Java≥8、MySQL≥5.7、Tomcat≥8 开发工具 eclipse/idea/myecl…

UE5 c++将自定义UserWdiget添加到对应菜单栏

前言&#xff1a; 为了实现与UserWidget一致的右键添加&#xff0c;便有了此章 注&#xff1a;这里使用的是UE5.3 目标内容&#xff1a; 这里可以参考UserWidget的源码&#xff0c;拷贝一份属于自己的就ok&#xff08;本篇章只是全改成了属于自己的CommonUserWidget&#xff…

Android 使用.9图 NinePatchDrawable实现动态聊天气泡

最近一段时间&#xff0c;在做一个需求&#xff0c;需要实现一个聊天气泡的动画效果&#xff0c;如下图所示&#xff1a; GitHub源码demo &#xff0c;建议下载demo&#xff0c;运行查看。 动态聊天气泡动画 静态聊天气泡 经过一段时间调研&#xff0c;实现方案如下: 实现方…

栈(定义,基本操作,顺序存储,链式存储)

目录 1.栈的定义1.重要术语2.特点 2.栈的基本操作3.栈的顺序存储1.顺序栈的定义2.基本操作1.初始化2.进栈3.出栈4.读栈顶 3.共享栈 4.栈的链式存储 1.栈的定义 栈( Stack&#xff09;是只允许在一端进行插入或删除操作的线性表。 一种受限的线性表&#xff0c;只能在栈顶进行插…

高校为什么需要大数据挖掘平台?

目前数据挖掘已经成为各种应用领域的重要技术&#xff0c;大学数据挖掘课程的开放已经出现。数据挖掘课程整合了多门学科知识。该课程包括各种理论知识&#xff0c;也离不开相关的实用技术。整个教学过程是培养和提高学生全面创新和解决问题的能力。过去&#xff0c;教学过程理…

Vscode禁止插件自动更新

由于电脑的vscode版本不是很新。2022.10月份的版本1.7.2&#xff0c;电脑vscode的python插件装的也是2022年4月份的某个版本&#xff0c;但插件经常自动更新&#xff0c;导致python代码无法Debug,解决办法&#xff1a; 点设置&#xff0c;搜autoUpdate, 把红色框选成无

MicroStation二次开发问题记录(1):打开项目时自动加载dll文件

环境配置 Windows10 MicroStation CE Update16 Visual Studio 2019 前言 开发好的dll文件若每次都需要在打开MS时单独加载&#xff0c;则过于繁琐&#xff0c;因此可以在确定的工程项目文件中进行一次设置&#xff0c;在打开该文件时自动加载 一、加载dll文件 1. 点击File—Se…