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.pswp.cn/news/906352.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/906352.shtml
英文地址,請注明出處:http://en.pswp.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;即…