Mujoco 学习系列(二)基础功能与xml使用

这篇文章是 Mujoco 学习系列第二篇,主要介绍一些基础功能与 xmI 使用,重点在于如何编写与读懂 xml 文件。

运行这篇博客前请先确保正确安装 Mujoco 并通过了基本功能与GUI的验证,即至少完整下面这个博客的 第二章节 内容:

  • Mujoco 学习系列(一)安装与部署

1. 启动仿真器

在第一篇博客中已经介绍了如何通过命令启动仿真器,但实际上mujoco提供了很多种方式启动,不同启动方式在后面的工作中会有不同的作用。

1.1 python 命令行启动

  • 只启动仿真器,不加载模型
(mojoco) $ python -m mujoco.viewer

在这里插入图片描述

  • 启动仿真器,同时加载模型(这里加载自带的小车模型)
(mojoco) $ python -m mujoco.viewer --mjcf=./model/car/car.xml

在这里插入图片描述

1.2 python 脚本启动

  • 启动仿真器,不加载模型(阻塞)
import mujocomojoco.viewer.launch()
  • 启动仿真器,同时加载模型(阻塞)
import mujocomodel_xml_path = "./model/car/car.xml"
mujoco.viewer.launch_from_path(model_xml_path)

上面两种阻塞方式启动后 terminal 会一直等待你在仿真器中操作完并关闭。mujoco 也提供了非阻塞方式启动仿真器 launch_passive(model, data),但在启动时必须将模型加载进来,同时需要手动管理 mj_step() 函数,而以阻塞方式启动的仿真器不需要显示调用该函数。因为是非阻塞方式启动,需要将仿真器放在一个循环中,否则一启动就会立刻关闭。

  • 启动仿真器,同时加载模型(非阻塞)
import timeimport mujoco
import mujoco.viewermodel_xml_path = "./model/car/car.xml"
model = mujoco.MjModel.from_xml_path(model_xml_path)
data = mujoco.MjData(model)with mujoco.viewer.launch_passive(model=model, data=data) as viewer:while viewer.is_running():step_start = time.time()        # 每一帧仿真的开始时间,用于控制仿真的时间步长mujoco.mj_step(model, data)     # [核心] 手动推进一次仿真# 给 simulate GUI 加锁,防止数据修改线程与渲染线程出现冲突with viewer.lock():# 这行主要是提升交互体验,你在运行后可以发现环境中每个接触点都会有黄色的圆柱在闪烁viewer.opt.flags[mujoco.mjtVisFlag.mjVIS_CONTACTPOINT] = int(data.time % 2)viewer.sync()   # 将最新的数据同步给GUI中并显示# 到达此处说明当前帧的运算和渲染已经结束了,计算一下到下一帧的时间间隔,用于控制仿真节奏# 如果仿真在这一步消耗了很长时间,那么该值是有可能为负time_until_next_step = model.opt.timestep - (time.time() - step_start)if time_until_next_step > 0:time.sleep(time_until_next_step)    # 休眠一下后准备计算下一帧

在这里插入图片描述

运行之后就可以看到上图中的效果,可以发现在小车三个轮子的位置处有黄色的矮圆柱体在闪烁,这就是代码中 viewer.opt.flags 部分起的作用。


2. 编写 xml 文件

在上一章节中其实遗留了一个问题:多个模型的加载在机器人仿真中是必要的,但 mujoco 本身是不支持同时加载多个 xml 文件的,因为 mujoco 是 面向单物理场景 设计的,只不过有方法来实现这点,上面例子中的小车本质上就是在一个 xml 文件中创建了不同元素并将其组合,多个模型加载问题可以被转化成不同元素但不进行组合。

在编写之前需要先理解 mujoco 如何解析 xml 文件的,特别是哪些标签是核心的、哪些是可以以类形式定义等。

  • 官方解释链接:XMLreference.html

我将 xml 的标签分为两类:

  • 环境标签:这类标签定义了全局仿真配置,包括重力、第三人称相机视角、密度、时间步长等;
  • 对象标签:这类标签是可以继承、包含、相互作用,有点类似代码中的 class;

这种分类方式实际上不严谨,但对于初学者而言可以先这样简化地去理解。

2.1 立方体与平面

首先是最简单的一个例子,在一个空间中有一个立方体和一个平面,期望立方体自由落体后掉在平面上:

<mujoco><!-- 场景 --><worldbody><!-- 光源 --><light diffuse="0.5 0.5 0.5" pos="0 0 3" dir="0 0 -1"/> <!-- 平面 --><geom name="ground" type="plane" size="1 1 0.1" rgba="0.5 0.5 0.5 1"/><!-- 对象 --><body name="cube" pos="0 0 1"><joint type="free"/>	<!-- 该对象与外界的链接方式 --><geom type="box" size="0.1 0.1 0.1" rgba="0.0 0.0 0.5 1"/></body></worldbody>
</mujoco>

上面的例子中顶级标签为 <mujoco>,其他所有对象都在 <worldbody> 标签下,在这个标签中有两个对象 平面立方体

【Note】:虽然mujoco官方文档和很多教程都告诉你可以省略 name 字段,没有显示声明的情况下会自动分配一个匿名值,但我会将 name 字段一直写上去,因为 mujoco 不允许出现同名对象,同时有 name 字段可以帮你更快定位到问题。

直接运行就可以看到一个立方体自由落体到平面上:

(mujoco) $ python -m mujoco.viewer --mjcf=./merge.xml

在这里插入图片描述

实际上在xml中的 平面 也是一个对象,但我个人习惯地面对象不用 body 标签包裹以区分运动对象和地面,所以下面的写法也是正确的:

<mujoco><!-- 场景 --><worldbody><!-- 光源 --><light diffuse="0.5 0.5 0.5" pos="0 0 3" dir="0 0 -1"/> <!-- 平面 --><body name="ground" pos="0 0 0" ><geom type="plane" size="1 1 0.1" rgba="0.5 0.5 0.5 1"/></body><!-- 对象 --><body name="cube" pos="0 0 1"><joint type="free"/><geom type="box" size="0.1 0.1 0.1" rgba="0.0 0.0 0.5 1"/>  <!-- 对象的几何形状 --></body></worldbody>
</mujoco>

同理,如果想要在不同位置添加一个新的立方体则如下所示,新的立方体中多了一个 euler 属性表示其初始角度信息,更多属性以及其默认值可以在官网文档中找到:

<mujoco><worldbody><light diffuse="0.5 0.5 0.5" pos="0 0 3" dir="0 0 -1"/> <geom name="ground" type="plane" size="1 1 0.1" rgba="0.5 0.5 0.5 1"/><!-- 立方体1 --><body name="cube1" pos="0 0 1"><joint type="free"/><geom type="box" size="0.1 0.1 0.1" rgba="0.0 0.0 0.5 1"/> </body><!-- 立方体2 --><body name="cube2" pos="0.5 0.5 0.5" euler="0 20 30"><joint type="free"/><geom type="box" size="0.1 0.1 0.1" rgba="0.5 0.0 0.0 1"/></body></worldbody>
</mujoco>

运行后也是两个立方体自由落体,只不过初试高度和角度不同,因此最终落地姿势也不同。

(mujoco) $ python -m mujoco.viewer --mjcf=./merge.xml

在这里插入图片描述

2.2 环境标签

通常情况下环境标签是在第一步就需要做的,为了避免不同平台中存在差异,虽然 mujoco 允许在运行过程中修改环境标签的值,例如更改重力方向,但在没有特殊需求的情况下这些值应该被定义为一个静态值。

在 mujoco 中通过 xml 里的 <option> 标签定义环境,可以修改的属性值有以下几个:

在这里插入图片描述

我最常用的是下面几个:

  • timestep:仿真时间步长,默认 0.002 0.002 0.002s,影响计算速度与精度的最重要参数;
  • gravity:重力方向,默认 ( 0 , 0 , − 9.81 ) (0,0,-9.81) (0,0,9.81)
  • density:环境介质密度,默认 0 0 0,可以修改你的仿真环境是在水下还是空气中,默认在空气中;

xml 文件示例如下:

<mujoco><!-- 环境标签 --><option gravity="0 0 -1" /><worldbody><light diffuse="0.5 0.5 0.5" pos="0 0 3" dir="0 0 -1"/> <geom name="ground" type="plane" size="1 1 0.1" rgba="0.5 0.5 0.5 1"/><body name="cube" pos="0 0 1"><joint type="free"/><geom type="box" size="0.1 0.1 0.1" rgba="0.0 0.0 0.5 1"/> </body></worldbody>
</mujoco>

【Note】:注意环境标签 <option> 的位置,由于环境标签是全局作用的,因此需要将其放在顶级域名之下。

2.3 单位与轴

因为存在 万向节死锁 的问题,有些算法会调整 rpy 的旋转顺序,mujoco 提供了标签 <compile> 来定义单位与轴旋转顺序;在没有明确定义的情况下度数单位为 弧度,但也可以通过修改来确定度的单位为 角度

在这里插入图片描述

示例如下:

<mujoco><compiler angle="degree" eulerseq="yzx"/><worldbody><light diffuse="0.5 0.5 0.5" pos="0 0 3" dir="0 0 -1"/> <geom name="ground" type="plane" size="1 1 0.1" rgba="0.5 0.5 0.5 1"/><body name="cube" pos="0 0 1"><joint type="free"/><geom type="box" size="0.1 0.1 0.1" rgba="0.0 0.0 0.5 1"/> </body></worldbody></mujoco>

这些本质上和环境标签是同一类型,都是确定好后不会频繁变化的,因此在曾经结构上也是顶级位置。

2.4 通用资产定义

有些属性或变量可能会被多个对象使用,如果每个对象都重新写一遍会非常冗余,mujoco 提供了 <asset> 标签用来定义通用资产,并且允许对象直接使用。

<mujoco><asset><!-- 定义材质 --><material name="blue" rgba="0 0 0.5 1"/><!-- 定义凸包 -->      <mesh name="tetrahedron" vertex="0 0 0  1 0 0  0 1 0  0 0 1"/></asset><worldbody><light diffuse="0.5 0.5 0.5" pos="0 0 3" dir="0 0 -1"/> <geom name="ground" type="plane" size="1 1 0.1" rgba="0.5 0.5 0.5 1"/><body name="cube" pos="0 0 1"><joint type="free"/><!-- 使用材质和凸包 --><geom type="box" size="0.1 0.1 0.1" material="blue" mesh="tetrahedron"/> </body></worldbody></mujoco>

上面的示例中使用了 mesh 这个标签,本质是表面网格,但 网格也可以定义成不带面的网格(本质上是点云)。在这种情况下,即使编译器属性 convexhull 为 false,凸包也会自动构建。这使得直接在 XML 中构建简单形状变得非常简单。例如,可以如下创建金字塔:

如果你想要使用 mesh 原本的含义,即物体表面渲染方式,那么这样写即可:

<mujoco><asset><material name="blue" rgba="0 0 0.5 1"/><!-- 前提是同级目录下有这个文件 --><mesh name="forearm" file="forearm.stl"/></asset><worldbody><light diffuse="0.5 0.5 0.5" pos="0 0 3" dir="0 0 -1"/> <geom name="ground" type="plane" size="1 1 0.1" rgba="0.5 0.5 0.5 1"/><body name="cube" pos="0 0 1"><joint type="free"/><geom type="box" size="0.1 0.1 0.1" material="blue" mesh="forearm"/> </body></worldbody></mujoco>

【Note】:由于 mujoco 不允许相同的 name 属性,因此定义 <asset> 标签时可以用一些带有前缀的变量,如 name="asset_blue",这样可以避免在复杂工程中存在名称冲突的情况,特别是有些厂商提供的模型文件中也定义了颜色和材质等对象。

2.5 文件包含

如果把所有的配置都写在一个文件中会非常难以梳理,mujoco 提供了 <include> 标签实现文件包含,我通常会将环境、单位、通用资产的定义写在一个 common.xml 文件中,在主文件中只关注对象的运动关系:

【Note】:所有包含与被包含文件中的元素都必须在 <mujoco> 这个根标签下,这是mujoco识别的依据。

  • common.xml 文件
<mujoco><asset><material name="blue" rgba="0 0 0.5 1"/></asset>
</mujoco>
  • merge.xml 文件
<mujoco><!-- 包含公共变量与资产 --><include file="./common.xml"/> <worldbody><light diffuse="0.5 0.5 0.5" pos="0 0 3" dir="0 0 -1"/> <geom name="ground" type="plane" size="1 1 0.1" rgba="0.5 0.5 0.5 1"/><body name="cube" pos="0 0 1"><joint type="free"/><geom type="box" size="0.1 0.1 0.1" material="blue"/> </body></worldbody></mujoco>

2.6 关节约束

重头戏来了 <joint> 关节约束。mujoco 对关节约束的定义和 urdf 文件基本一致,允许一下几种形式的约束:

  • free:三个平移自由度 + 三个旋转自由度;
  • ball:三个旋转自由度的球形关节,四元数 (1,0,0,0) 对应于定义初始状态;
  • slide:一个平移自由度的滑动或平移关节,需要明确平移方向;
  • hinge:铰链类型创建具有一个旋转自由度的铰链关节,需要明确旋转轴;

【Note】:为了更好的交互效果,这里提前引入了<actuator> 标签,否则无法在仿真器中拖拽。

示例如下:

<mujoco><worldbody><light diffuse="0.5 0.5 0.5" pos="0 0 3" dir="0 0 -1"/><geom name="ground" type="plane" size="5 5 0.1" rgba="0.5 0.5 0.5 1" friction="0.1 0.05 0.05"/><!-- 可拖拽立方体 --><body name="draggable_cube" pos="0 0 1"><joint name="x_slide" type="slide" axis="1 0 0" damping="5" stiffness="50" range="-3 3"/><joint name="y_slide" type="slide" axis="0 1 0" damping="5" stiffness="50" range="-3 3"/><geom name="cube" type="box" size="0.1 0.1 0.1" rgba="0 0.5 0.8 1" mass="5"/></body></worldbody><actuator><!-- 位置伺服控制器 --><position name="x_pos" joint="x_slide" kp="500" kv="20"/><position name="y_pos" joint="y_slide" kp="500" kv="20"/></actuator></mujoco>

启动仿真器后可以在右侧的 Control 面板中拖动滑块以观察立方体运动。

在这里插入图片描述

2.7 定义执行器

在上面的小节中提前用到了执行器 <actuator> ,这一小节将更细致介绍如何定义执行器标签来控制环境中的对象,你可以将执行器理解为 电机

mujoco 提供了很多执行器工具,在其官网文档中点击左侧 XML Reference 连接后往下拉或者搜索 actuator 即可找到可用的执行器标签。为关节或对象添加执行器后就可以在控制对象的时候添加合适的参数,否则所有 joint 都是 free 形式。
在这里插入图片描述
我这里只列举我最常用的几个执行器,感兴趣的可以查看其官网并进行实验。

2.7.1 通用执行器 general

通用执行器允许独立设置所有执行器组件,包括传输类型、激活动态、增益类型等。是一个非常灵活的执行器类型,允许用户自定义执行器的动态特性、增益、偏置,可以实现各种类型的执行器,如直接驱动、位置伺服、速度伺服等。

这个例子实现了一个力执行器,为了让滑块能够在力消失时停下来,在地面和滑块中都添加了friction 属性以体现摩擦力:

<mujoco><worldbody><light diffuse="0.5 0.5 0.5" pos="0 0 5" dir="0 0 -1"/> <!-- 地面:高滑动摩擦 --><geom name="ground" type="plane" size="5 5 0.1" pos="0 0 0" rgba="0.5 0.5 0.5 1" friction="1.5 0.3 0.05"solimp="0.9 0.95 0.001" solref="0.02 1"/><!-- 滑块:中等摩擦 --><body name="slider" pos="0 0 0.1"><joint name="slide_joint" type="slide" axis="1 0 0" damping="0.2"/><geom type="box" size="0.2 0.1 0.1" rgba="0 0.5 0.8 1" mass="0.5" friction="1.0 0.2 0.02"/></body></worldbody><actuator><general name="force" joint="slide_joint" ctrlrange="-1 1"/></actuator>
</mujoco>

启动仿真器后在右侧控制面板中拖拽 force 滑块就可以给其传入一个力,点击 Clear all 就可以将力清空然后观察滑块逐渐停下来。

在这里插入图片描述

由于 joint 的活动范围可以通过其属性 range 定义,如果不想给物体添加摩擦力也可以通过限制活动范围让物体停下来,停下后即便有力物体也不会继续运动

<mujoco><worldbody><light diffuse="0.5 0.5 0.5" pos="0 0 5" dir="0 0 -1"/> <!-- 地面--><geom name="ground" type="plane" size="5 5 0.1" pos="0 0 0" rgba="0.5 0.5 0.5 1"solimp="0.9 0.95 0.001" solref="0.02 1"/><!-- 滑块 添加了range属性限制活动范围 --><body name="slider" pos="0 0 0.1"><joint name="slide_joint" type="slide" axis="1 0 0" damping="0.2" range="-2 2"/><geom type="box" size="0.2 0.1 0.1" rgba="0 0.5 0.8 1" mass="0.5" /></body></worldbody><actuator><general name="force" joint="slide_joint" ctrlrange="-1 1"/></actuator>
</mujoco>

2.7.2 位置伺服 position

位置伺服在上面的小节中已经用了一次,这个控制器就是一个位置环伺服,有点类似与 PID 一样的控制器,所以你在滑动的时候会发现有一个明显的回调过程,通过修改 kpkv 可以体验阻尼大小。

<mujoco><worldbody><light diffuse="0.5 0.5 0.5" pos="0 0 5" dir="0 0 -1"/> <geom name="ground" type="plane" size="5 5 0.1" pos="0 0 0" rgba="0.5 0.5 0.5 1"solimp="0.9 0.95 0.001" solref="0.02 1"/><body name="slider" pos="0 0 0.1"><joint name="slide_joint" type="slide" axis="1 0 0" damping="0.2" range="-2 2"/><geom type="box" size="0.2 0.1 0.1" rgba="0 0.5 0.8 1" mass="0.5" /></body></worldbody><actuator><position name="position" joint="slide_joint" kp="100" kv="10"/></actuator>
</mujoco>

在这里插入图片描述

2.7.3 速度伺服 velocity

既然有位置伺服那当然还有速度伺服,和位置伺服同理,速度伺服也用来调控速度到目标值

<mujoco><worldbody><light diffuse="0.5 0.5 0.5" pos="0 0 5" dir="0 0 -1"/> <geom name="ground" type="plane" size="5 5 0.1" pos="0 0 0" rgba="0.5 0.5 0.5 1"solimp="0.9 0.95 0.001" solref="0.02 1"/><body name="slider" pos="0 0 0.1"><joint name="slide_joint" type="slide" axis="1 0 0" damping="0.2" range="-2 2"/><geom type="box" size="0.2 0.1 0.1" rgba="0 0.5 0.8 1" mass="0.5" /></body></worldbody><actuator><velocity name="velocity" joint="slide_joint" kv="50"/></actuator>
</mujoco>

在这里插入图片描述

2.7.4 电机执行器 motor

电机只能输出与关节自由度相同的力和力矩,如果你很明确这个 joint 需要输出的是力,那么建议用这个,虽然通用执行器也可以实现相同的效果,但设置起来没有电机执行器简洁。

<mujoco><worldbody><light diffuse="0.5 0.5 0.5" pos="0 0 5" dir="0 0 -1"/> <geom name="ground" type="plane" size="5 5 0.1" pos="0 0 0" rgba="0.5 0.5 0.5 1"solimp="0.9 0.95 0.001" solref="0.02 1"/><body name="slider" pos="0 0 0.1"><joint name="slide_joint" type="slide" axis="1 0 0" damping="0.2" range="-2 2"/><geom type="box" size="0.2 0.1 0.1" rgba="0 0.5 0.8 1" mass="0.5" /></body></worldbody><actuator><motor name="motor" joint="slide_joint" gear="1"/></actuator>
</mujoco>

在这里插入图片描述

2.8 显示坐标轴

坐标轴的显示在仿真中非常重要,打开仿真器后展开左侧工具栏中的 Rendering 标签,通过选择 Frame 即可选择想要显示的坐标轴。
在这里插入图片描述

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

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

相关文章

面向SDV的在环测试深度解析——仿真中间件SIL KIT应用篇

1.引言 在汽车行业向软件定义汽车&#xff08;SDV&#xff09;转型的过程中&#xff0c;传统硬件在环&#xff08;HIL&#xff09;测试方案因难以适应新的技术架构与需求&#xff0c;其局限性日益凸显。传统HIL对硬件依赖性强&#xff0c;扩展性差&#xff0c;更换ECU或传感器…

windows使用anaconda安装pytorch cuda版本

Windows安装PytorchCUDA环境_使用conda安装pytorch cuda10.2版本-CSDN博客

Axure中使用动态面板实现图标拖动交换位置

要在Axure中实现图标拖动交换位置的功能&#xff0c;可以通过动态面板结合交互事件来实现。 实现步骤 准备图标元素 将每个图标转换为动态面板&#xff08;方便拖动和交互&#xff09;。 设置拖动交互 选中图标动态面板 → 添加“拖动时”交互 → 选择“移动”当前动态面板&am…

从零开始的嵌入式学习day24

标准IO 头文件需求&#xff1a; #include <stdio.h>1.fopen和fclose (1)fopen fopen的函数功能是打开一个文件。 首先看看fopen的函数声明&#xff1a; FILE *fopen(const char *path, const char *mode);第一个参数path是文件地址&#xff0c;传入的是不可变的字符…

抓包分析工具与流量监控软件

目录 一、抓包分析工具&#xff1a;定位问题的“放大镜” 1.1 工作原理简述 1.2 主流工具盘点 1.3 抓包的实战应用 二、流量监控软件&#xff1a;网络全景的“雷达系统” 2.1 功能特征 2.2 常用工具概览 2.3 实战应用场景 五、结语&#xff1a;深入可见&#xff0c;安…

DRIVEGPT4: 通过大语言模型实现可解释的端到端自动驾驶

《DriveGPT4: Interpretable End-to-End Autonomous Driving via Large Language Model》 2024年10月发表&#xff0c;来自香港大学、浙江大学、华为和悉尼大学。 多模态大型语言模型&#xff08;MLLM&#xff09;已成为研究界关注的一个突出领域&#xff0c;因为它们擅长处理…

Vue3 Form 表单限制输入小写字母、数字和下划线

方案一&#xff1a;Element Plus 表单验证 <template><el-form :model"form" :rules"rules" ref"formRef" label-width"120px"><el-form-item label"用户名" prop"username"><el-input v-m…

23、电网数据管理与智能分析 - 负载预测模拟 - /能源管理组件/grid-data-smart-analysis

76个工业组件库示例汇总 电网数据管理与智能分析组件 1. 组件概述 本组件旨在模拟一个城市配电网的运行状态&#xff0c;重点关注数据管理、可视化以及基于模拟数据的智能分析&#xff0c;特别是负载预测功能。用户可以通过界面交互式地探索电网拓扑、查看节点状态、控制时间…

单片机复用功能重映射Remap功能

目录 一、查看“DS5319 stm32f10x中等密度mcu数据手册&#xff08;英文&#xff09;”手册 二、查看“RM0008 STM32F10xxx参考手册&#xff08;中文&#xff09;”手册 三、重映射&#xff08;Remap&#xff09;功能程序编写 自己学习过程中容易遗忘的知识点&#xff0c;记录…

链表面试题9之环形链表进阶

那么上一题我们已经知道了双指针的变法以及拓展的用法&#xff0c;那么这里我们直接难度升级。 想回去复习的这里放个链接&#xff1a;链表的面试题8之环形链表-CSDN博客 题目链接&#xff1a;142. 环形链表 II - 力扣&#xff08;LeetCode&#xff09; 我们来看这道题目主要…

游戏引擎学习第299天:改进排序键 第二部分

回顾并为当天内容做准备 我们会现场编写完整的游戏代码。回顾上周发现自己对游戏中正确的排序规则并没有清晰的理解。主要原因是我们更擅长三维游戏开发&#xff0c;缺乏二维游戏和二维游戏技术的经验&#xff0c;对于二维精灵排序、模拟三维效果的最佳方案等没有太多技巧和经…

Redis从入门到实战 - 高级篇(中)

一、多级缓存 1. 传统缓存的问题 传统的缓存策略一般是请求到达Tomcat后&#xff0c;先查询Redis&#xff0c;如果未命中则查询数据库&#xff0c;存在下面的问题&#xff1a; 请求要经过Tomcat处理&#xff0c;Tomcat的性能成为整个系统的瓶颈Redis缓存失效时&#xff0c;会…

Python训练营打卡 Day31

文件的规范拆分和写法 今日的示例代码包含2个部分 notebook文件夹内的ipynb文件&#xff0c;介绍下今天的思路项目文件夹中其他部分&#xff1a;拆分后的信贷项目&#xff0c;学习下如何拆分的&#xff0c;未来你看到的很多大项目都是类似的拆分方法 知识点回顾&#xff1a;文件…

2025年护网行动蓝队防御全解析:构建智能动态防御体系

2025年&#xff0c;随着网络攻击手段的智能化、混合化升级&#xff0c;护网行动中的蓝队防御已从传统的被动防护转向“动态感知、智能研判、主动反制”的立体化模式。如何在攻防不对称的对抗中实现“看得见、防得住、溯得清”&#xff1f;本文将结合前沿技术与实战经验&#xf…

React Contxt详解

React Contxt详解 React 的 Context API 是用于跨组件层级传递数据的解决方案&#xff0c;尤其适合解决「prop drilling」&#xff08;多层组件手动传递 props&#xff09;的问题。以下是关于 Context 的详细解析&#xff1a; 文章目录 React Contxt详解一、Context 核心概念二…

使用 lock4j-redis-template-spring-boot-starter 实现 Redis 分布式锁

在分布式系统中&#xff0c;多个服务实例可能同时访问和修改共享资源&#xff0c;从而导致数据不一致的问题。为了解决这个问题&#xff0c;分布式锁成为了关键技术之一。本文将介绍如何使用 lock4j-redis-template-spring-boot-starter 来实现 Redis 分布式锁&#xff0c;从而…

Vue响应式系统演进与实现解析

一、Vue 2 响应式实现详解 1. 核心代码实现 // 依赖收集器&#xff08;观察者模式&#xff09; class Dep {constructor() {this.subscribers new Set();}depend() {if (activeEffect) {this.subscribers.add(activeEffect);}}notify() {this.subscribers.forEach(effect &g…

Mujoco 学习系列(一)安装与部署

这个系列文章用来记录 Google DeepMind 发布的 Mujoco 仿真平台的使用过程&#xff0c;Mujoco 是具身智能领域中非常知名的仿真平台&#xff0c;以简单易用的API和精准的物理引擎而著称&#xff08;PS&#xff1a;原来Google能写好API文档啊&#xff09;&#xff0c;也是我平时…

Ai学习之openai api

一、什么是openai api 大家对特斯拉的马斯克应该是不陌生的&#xff0c;openai 就是马斯克投资的一家研究人工智能的公司&#xff0c;它就致力于推动人工智能技术的发展&#xff0c;目标是确保人工智能对人类有益&#xff0c;并实现安全且通用的人工智能。 此后&#xff0c;O…

leetcode 合并区间 java

用 ArrayList<int[]> merged new ArrayList<>();来定义数组的list将数组进行排序 Arrays.sort(intervals,(a,b) -> Integer.compare(a[0],b[0]));如果前面的末尾>后面的初始&#xff0c;那么新的currentInterval的末尾这两个数组末尾的最大值&#xff0c;即…