<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://blog.leihub.cn/</id>
  <title type="text">阿雷的小窝</title>
  <subtitle type="text">我的学习经历</subtitle>
  <updated>2026-09-10T16:28:25.000Z</updated>
  <author><name>阿雷</name></author>
  <link rel="alternate" href="https://blog.leihub.cn/"/>
  <link rel="self" href="https://blog.leihub.cn/atom.xml"/>
  <generator uri="https://github.com/CuteLeaf/Firefly">Firefly v6.16.8</generator>
    <entry>
      <id>https://blog.leihub.cn/archives/1057/</id>
      <title type="text">群晖照片异地备份到 Unraid + Immich 相册搭建详细教程：rsync 同步与踩坑全记录</title>
      <published>2026-09-10T16:22:24.000Z</published>
      <updated>2026-09-10T16:28:25.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/1057/"/>
      <summary type="text">我家里同时有白群晖和 unRAID 两台 NAS ，准备把群晖里攒了几年的照片进行异地备份，单盘 NAS 一旦坏了，照片可就全没了。 我自己折腾了两天，踩了一堆坑，终于跑通了一套「unRAID 定时拉取群晖 + Immich 相册」的方案。</summary>
      <content type="html"><![CDATA[<p>我家里同时有白群晖和 unRAID 两台 NAS ，准备把群晖里攒了几年的照片进行异地备份，单盘 NAS 一旦坏了，照片可就全没了。
我自己折腾了两天，踩了一堆坑，终于跑通了一套「unRAID 定时拉取群晖 + Immich 相册」的方案。今天把完整过程整理出来，从组网到备份再到相册，新手照着走也能一步到位。</p>
<p><a name="零"></a></p>
<section><h2>零、开始前的准备<a href="#零开始前的准备"><span>#</span></a></h2><section><h3>准备项目<a href="#准备项目"><span>#</span></a></h3>

<table><thead><tr><th>类别</th><th>内容</th></tr></thead><tbody><tr><td>硬件</td><td>一台群晖（数据源）、一台 unRAID（备份端，强烈建议带一块 SSD 做 cache 池）</td></tr><tr><td>账号</td><td>无需注册（EasyTier 去中心化，组网密钥一致即可）</td></tr><tr><td>前置知识</td><td>会用 SSH 登录、懂一点 Docker/Compose 概念</td></tr></tbody></table></section><section><h3>本文示例环境<a href="#本文示例环境"><span>#</span></a></h3>

<table><thead><tr><th>机器</th><th>系统</th><th>硬件</th><th>角色</th></tr></thead><tbody><tr><td>白群晖</td><td>DSM 7.x</td><td>存有照片/资料</td><td>数据源</td></tr><tr><td>unRAID</td><td>unRAID 6/7</td><td>i5-12400 / 32G / 16T 机械盘 + 一块 SSD</td><td>备份端 + 相册</td></tr></tbody></table><hr /><p><a name="一"></a></p></section></section>
<section><h2>一、这套方案解决什么问题<a href="#一这套方案解决什么问题"><span>#</span></a></h2><p>先说需求：我有一台白群晖（存了几年照片和资料，是数据源），一台 unRAID 服务器（i5-12400 + 32G 内存 + 16T 机械盘 + 一块 SSD），两台机器<strong>不在同一个物理网络</strong>。目标是：</p><ol>
<li>
<p>把群晖的照片、资料<strong>异地备份</strong>到 unRAID 的 16T 盘上；</p>
</li>
<li>
<p>在 unRAID 上搭一个** Immich 相册库**，方便随时翻照片。</p>
</li>
</ol><p>一开始最自然的想法是「群晖用 Hyper Backup 主动推到 unRAID」，但实操下来发现这条路坑特别多，最后改成了「unRAID 主动拉取」，反而更稳。这篇文章就是这套最终方案的完整教程。</p><hr /><p><a name="二"></a></p></section>
<section><h2>二、整体架构一览<a href="#二整体架构一览"><span>#</span></a></h2><p>整个流程就三步：</p><ol>
<li>
<p><strong>组网</strong>：用 EasyTier 把两台机器打通（去中心化虚拟局域网，P2P 直连）；</p>
</li>
<li>
<p><strong>备份</strong>：unRAID 定时用 SSH + rsync 把群晖照片「拉」到本地 16T 盘；</p>
</li>
<li>
<p><strong>相册</strong>：Immich 以「外部库」方式挂载拉下来的照片，只建索引、不重复占空间。</p>
</li>
</ol><p>涉及到的软硬件清单：</p>

<table><thead><tr><th>角色</th><th>设备</th><th>系统</th><th>关键配置</th></tr></thead><tbody><tr><td>数据源</td><td>白群晖</td><td>DSM 7.x</td><td>EasyTier（套件）、SSH、rsync 服务</td></tr><tr><td>备份端</td><td>unRAID</td><td>unRAID 6/7</td><td>EasyTier（Docker）、Immich（Docker Compose）</td></tr></tbody></table><hr /><p><a name="三"></a></p></section>
<section><h2>三、EasyTier 组网<a href="#三easytier-组网"><span>#</span></a></h2><p>两台机器跨公网，先得让它们互相能访问。我用的是 <strong>EasyTier</strong>。安装可见我之前写的一篇文章<a href="/archives/936/">EasyTier 私有虚拟网络搭建全流程 - 阿雷的小窝</a></p><p>EasyTier 组好网后，出现了一个诡异的现象：<strong>从群晖主动连 unRAID 时，ping 通、但 TCP 连不上</strong>。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>ping -c 3 10.x.x.4        # 3/3 通，11ms ✅</span></div></div><div><div><div>2</div></div><div><span>timeout 5 bash -c 'cat &lt; /dev/null &gt; /dev/tcp/10.126.126.4/873' &amp;&amp; echo "通" || echo "不通"</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p></p><figure><img src="http://imgbed.leihub.cn/img/Pasted%20image%2020260910174817.png" alt="Pasted image 20260910174817" /><figcaption>Pasted image 20260910174817</figcaption></figure><p></p><p>查了半天，靠 <code>easytier-cli peer</code> 揪出规律：<strong>EasyTier 2.6.4 在「群晖出站」方向上的 TCP 有问题</strong>——群晖主动发起的 TCP、目标也是 2.6.4 节点时会不通；但反过来（unRAID 主动连群晖）完全正常。</p><p>也就是说：</p><ul>
<li>
<p>❌ 群晖主动连 unRAID（推模式）→ 不行</p>
</li>
<li>
<p>✅ unRAID 主动连群晖（拉模式）→ 正常</p>
</li>
</ul><p></p><figure><img src="http://imgbed.leihub.cn/img/Pasted%20image%2020260910174727.png" alt="Pasted image 20260910174727" /><figcaption>Pasted image 20260910174727</figcaption></figure><p></p><p>这个「ping 通、TCP 断」的判断过程，浓缩成一张决策树（排查时照着走，少绕弯）：</p><p>搞了半天没解决，决定不跟这个 bug 死磕，直接改用<strong>拉模式</strong>（unRAID 主动 SSH 到群晖），方向反过来就绕开了。</p><hr /><p><a name="四"></a></p></section>
<section><h2>四、群晖端准备<a href="#四群晖端准备"><span>#</span></a></h2><section><h3>4.1 先开三个开关（缺一不可）<a href="#41-先开三个开关缺一不可"><span>#</span></a></h3>

<table><thead><tr><th>位置</th><th>操作</th></tr></thead><tbody><tr><td>控制面板 → 终端机和 SNMP → 终端机</td><td>勾选「启用 SSH 服务」</td></tr><tr><td>控制面板 → 文件服务 → rsync</td><td>勾选「启动 rsync 服务」</td></tr><tr><td>控制面板 → 用户与群组 → 高级</td><td>勾选「启用家目录服务」</td></tr></tbody></table><p>这三条是 DSM 的硬约束：</p><ol>
<li>
<p><strong>SSH 登录只对 <code>administrators</code> 组开放</strong>——普通用户 shell 是 <code>/sbin/nologin</code>，连上直接 <code>Permission denied</code>；</p>
</li>
<li>
<p><strong>不开家目录服务</strong>，<code>authorized_keys</code> 无处安放，报 <code>Could not chdir to home directory</code>；</p>
</li>
<li>
<p><strong>不开 rsync 服务</strong>，即使走 SSH 也会报 <code>rsync error: service disabled (code 52)</code>。</p>
</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/Pasted%20image%2020260910223251.png" alt="Pasted image 20260910223251" /><figcaption>Pasted image 20260910223251</figcaption></figure><p></p></section><section><h3>4.2 建一个最小权限的备份账号<a href="#42-建一个最小权限的备份账号"><span>#</span></a></h3><p>在「控制面板 → 用户与群组」新建账号 <code>backup</code>，<strong>关键一步：把它加入 <code>administrators</code> 组</strong>（对应上面的硬约束 1）。有效权限再用三层锁住：共享文件夹只读、应用权限只放 rsync、SSH 来源限定。</p></section><section><h3>4.3 最坑的一个：DSM 的 ACL 覆盖了 chmod<a href="#43-最坑的一个dsm-的-acl-覆盖了-chmod"><span>#</span></a></h3><p>账号建好后，部署公钥时大概率会卡在权限上——即使你把 <code>authorized_keys</code> 设成了 600，sshd 日志里还是报：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>Authentication refused: bad ACL permission for file /volume1/homes/backup/.ssh/authorized_keys</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>根因</strong>：DSM 家目录 <code>drwx--x--x+</code> 那个 <code>+</code> 是 <code>synoacltool</code> 挂的扩展 ACL，DSM 给 sshd 打了 patch 专门检查它，太宽就报 <code>bad ACL permission</code>。而 <strong><code>chmod</code> 只改传统权限位，动不了 ACL</strong>，所以怎么 chmod 都没用。</p><p>正确解法是用 <code>synoacltool -del</code> 删掉 ACL，再 chmod：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>synoacltool -del /volume1/homes/backup/.ssh/authorized_keys</span></div></div><div><div><div>2</div></div><div><span>synoacltool -del /volume1/homes/backup/.ssh</span></div></div><div><div><div>3</div></div><div><span>synoacltool -del /volume1/homes/backup</span></div></div><div><div><div>4</div></div><div><span>chmod 755 /volume1/homes/backup</span></div></div><div><div><div>5</div></div><div><span>chmod 700 /volume1/homes/backup/.ssh</span></div></div><div><div><div>6</div></div><div><span>chmod 600 /volume1/homes/backup/.ssh/authorized_keys</span></div></div><div><div><div>7</div></div><div><span>chown -R backup:users /volume1/homes/backup/.ssh</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>跑完验证一下，<code>+</code> 号应该消失：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>ls -la /volume1/homes/backup/.ssh/    # authorized_keys 应为 -rw-------，且无 + 号</span></div></div></code></pre><div><div></div><div></div></div></figure></div><hr /><p><a name="五"></a></p></section></section>
<section><h2>五、unRAID 端配置免密拉取<a href="#五unraid-端配置免密拉取"><span>#</span></a></h2><p>群晖端就绪后，回到 unRAID 配置 SSH 免密和拉取脚本。</p><section><h3>5.1 生成密钥（注意路径）<a href="#51-生成密钥注意路径"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>mkdir -p /boot/config/ssh</span></div></div><div><div><div>2</div></div><div><span>ssh-keygen -t ed25519 -N "" -f /boot/config/ssh/syno_pull</span></div></div></code></pre><div><div></div><div></div></div></figure></div><blockquote><p><strong>为什么放 <code>/boot/config/ssh</code>？</strong> unRAID 的 <code>/root</code> 是内存盘，重启就清空，密钥放那儿会丢。<code>/boot</code> 是 U 盘，能持久化。</p></blockquote></section><section><h3>5.2 把公钥部署到群晖<a href="#52-把公钥部署到群晖"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>ssh-copy-id -i /boot/config/ssh/syno_pull.pub backup@10.x.x.20</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>（如果报了 ACL 相关的错，就是 4.3 那步没处理干净，回去先删 ACL。）</p></section><section><h3>5.3 密钥持久化（关键一步）<a href="#53-密钥持久化关键一步"><span>#</span></a></h3><p><code>/boot</code> 是 FAT32，权限位不持久，私钥直接放上面会是 777，被 OpenSSH 以「权限过宽」拒绝。所以正确姿势是「U 盘存源 + 开机复制到内存 + chmod」。</p><p><strong>先装 User Scripts 插件</strong>（如果没有）：</p><ul>
<li>
<p>Unraid 网页 → <strong>Apps（Community Applications）</strong> → 搜索 <code>User Scripts</code> → 安装；</p>
</li>
<li>
<p>装完左侧导航栏会出现 <strong>User Scripts</strong> 入口。</p>
</li>
</ul><p></p><figure><img src="http://imgbed.leihub.cn/img/Pasted%20image%2020260910223744.png" alt="Pasted image 20260910223744" /><figcaption>Pasted image 20260910223744</figcaption></figure><p></p><p>然后在 User Scripts 里新建脚本（点 <code>ADD NEW SCRIPT</code>），运行时机选 <strong>At Startup of Array</strong>：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>#!/bin/bash</span></div></div><div><div><div>2</div></div><div><span>mkdir -p /root/.ssh</span></div></div><div><div><div>3</div></div><div><span>cp /boot/config/ssh/syno_pull     /root/.ssh/syno_pull</span></div></div><div><div><div>4</div></div><div><span>chmod 600 /root/.ssh/syno_pull</span></div></div><div><div><div>5</div></div><div><span>ssh-keyscan 10.x.x.20 &gt;&gt; /root/.ssh/known_hosts 2&gt;/dev/null</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>5.4 验证免密登录<a href="#54-验证免密登录"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>ssh -i /root/.ssh/syno_pull backup@10.x.x.20 "whoami"</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>成功的标志</strong>：直接输出 <code>backup</code>、不提示密码：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>backup</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>如果还提示 <code>backup@10.x.x.20's password:</code>，说明公钥没被接受，回头查 4.3 的 ACL。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/Pasted%20image%2020260910224934.png" alt="Pasted image 20260910224934" /><figcaption>Pasted image 20260910224934</figcaption></figure><p></p><hr /><p><a name="六"></a></p></section></section>
<section><h2>六、正式备份与定时<a href="#六正式备份与定时"><span>#</span></a></h2><section><h3>6.1 先确认群晖上的备份源路径<a href="#61-先确认群晖上的备份源路径"><span>#</span></a></h3><p>命令里的 <code>/volume1/photo/</code> 只是示例，你要换成自己群晖上<strong>真实的共享文件夹名</strong>。先在群晖 SSH 里看：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>ls /volume1/</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>会列出所有共享文件夹，比如 <code>photo</code>、<code>video</code>、<code>homes</code>、<code>docker</code> 等，记下你要备份的那个名字，路径就是 <code>/volume1/&lt;文件夹名&gt;/</code>。</p><blockquote><p>如果你想备份的是群晖「家目录」里的照片（Synology Photos 默认存这里），路径通常是 <code>/volume1/homes/&lt;用户名&gt;/Photos</code>。</p></blockquote></section><section><h3>6.2 先 dry-run 空跑一遍<a href="#62-先-dry-run-空跑一遍"><span>#</span></a></h3><p>正式拉之前，务必先空跑，确认文件量和权限都对：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>rsync -av --dry-run --stats \</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>--exclude '@eaDir' --exclude '#recycle' --exclude '@tmp' \</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>--exclude '@snapshot' --exclude '.DS_Store' --exclude 'Thumbs.db' \</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>-e "ssh -i /root/.ssh/syno_pull -o BatchMode=yes" \</span></div></div><div><div><div>5</div></div><div><span><span>  </span></span><span>backup@10.x.x.20:/volume1/photo/ /mnt/user/backup-photos/ 2&gt;&amp;1 | tail -10</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>参数逐项解释</strong>（知道含义才不会瞎改）：</p>

<table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td><code>-a</code></td><td>归档模式（保留权限、时间戳等），等价 <code>-rlptgoD</code></td></tr><tr><td><code>-v</code></td><td>显示详细输出</td></tr><tr><td><code>--dry-run</code></td><td>只模拟，不实际传文件（空跑）</td></tr><tr><td><code>--stats</code></td><td>末尾输出统计信息（文件数、大小）</td></tr><tr><td><code>--exclude</code></td><td>排除指定目录/文件，可多次</td></tr><tr><td><code>-e "ssh -i ..."</code></td><td>指定走 SSH，并用指定私钥</td></tr><tr><td><code>--partial</code>（正式跑才加）</td><td>断点续传，中断重跑不从头来</td></tr><tr><td><code>--info=progress2</code>（正式跑才加）</td><td>显示总体进度条</td></tr></tbody></table><blockquote><p><code>--exclude '@eaDir'</code> 一定要加：那是群晖生成的缩略图/索引目录，不排除会白拉几十万张缩略图、还干扰 Immich 扫描。<code>#recycle</code>、<code>@tmp</code>、<code>@snapshot</code> 同理，都是群晖的系统目录。</p></blockquote><p>看末尾的 <code>Number of files</code> 和 <code>Total file size</code>，确认数量合理、没有一堆 <code>Permission denied</code>，就可以正式跑了。</p><p><strong>成功的标志</strong>（实测输出示例，数字以你自己的为准）：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>Number of files: 34,713 (reg: 28,878, dir: 5,725, link: 110)</span></div></div><div><div><div>2</div></div><div><span>Total file size: 53,988,164,580 bytes</span></div></div></code></pre><div><div></div><div></div></div></figure></div><ul>
<li>
<p>文件数、总大小和你群晖上对得上 → 数量没问题；</p>
</li>
<li>
<p>没有刷屏的 <code>Permission denied</code> → 权限没问题；</p>
</li>
<li>
<p>然后去掉 <code>--dry-run</code> 正式拉。</p>
</li>
</ul><blockquote><p>注意：上面这个数字里 <code>@eaDir</code> 还没排除时会虚高（缩略图也算进去了），正式跑带上 <code>--exclude '@eaDir'</code> 后，真实照片数会少一大截，这是正常的。</p></blockquote></section><section><h3>6.3 正式拉取<a href="#63-正式拉取"><span>#</span></a></h3><p>去掉 <code>--dry-run</code>，加上断点续传：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>rsync -av --partial --info=progress2 \</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>--exclude '@eaDir' --exclude '#recycle' --exclude '@tmp' \</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>--exclude '@snapshot' --exclude '.DS_Store' --exclude 'Thumbs.db' \</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>-e "ssh -i /root/.ssh/syno_pull -o BatchMode=yes" \</span></div></div><div><div><div>5</div></div><div><span><span>  </span></span><span>backup@10.x.x.20:/volume1/photo/ /mnt/user/backup-photos/</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p></p><figure><img src="http://imgbed.leihub.cn/img/Pasted%20image%2020260910231023.png" alt="Pasted image 20260910231023" /><figcaption>Pasted image 20260910231023</figcaption></figure><p></p></section><section><h3>6.4定时自动备份<a href="#64定时自动备份"><span>#</span></a></h3><p>在 User Scripts 里把上面的命令包装成脚本，运行时机选 <strong>Scheduled</strong>（比如每天凌晨 3 点）。首次跑完，之后就是增量同步，只传改动的文件。</p><hr /><p><a name="七"></a></p></section></section>
<section><h2>七、Immich 搭建与照片管理<a href="#七immich-搭建与照片管理"><span>#</span></a></h2><p>照片备份到本地后，用 Immich 做相册。这一步有个<strong>致命坑</strong>必须避开，否则重启就丢数据。</p><section><h3>7.1 用 Docker Compose 部署（完整配置）<a href="#71-用-docker-compose-部署完整配置"><span>#</span></a></h3><p><strong>先装 Docker Compose Manager 插件</strong>（如果还没有）：</p><ul>
<li>
<p>Unraid 网页 → <strong>Apps（Community Applications）</strong> → 搜索 <code>docker compose manager</code> → 安装；</p>
</li>
<li>
<p>装完在 <strong>插件</strong> 页面能看到它，点开就是 Compose 管理界面。</p>
</li>
</ul><p><strong>新建 stack</strong>：点 <code>ADD NEW STACK</code> → 名字填 <code>immich</code> → 点进齿轮 → <code>EDIT STACK</code> → 选 <code>COMPOSE FILE</code>，把下面这份 <strong>完整可用的 <code>docker-compose.yml</code></strong>（按需进行修改）粘贴进去：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>name: immich</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>services:</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>immich-server:</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>container_name: immich_server</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>volumes:</span></div></div><div><div><div>8</div></div><div><span><span>      </span></span><span>- ${UPLOAD_LOCATION}:/data                 # 上传目录（在 .env 里定义）</span></div></div><div><div><div>9</div></div><div><span><span>      </span></span><span>- /etc/localtime:/etc/localtime:ro</span></div></div><div><div><div>10</div></div><div><span><span>      </span></span><span>- /mnt/user/backup-photos:/mnt/nas_photos:ro   # 外部库：挂 rsync 同步下来的照片</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>env_file:</span></div></div><div><div><div>12</div></div><div><span><span>      </span></span><span>- .env</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>ports:</span></div></div><div><div><div>14</div></div><div><span><span>      </span></span><span>- '2283:2283'</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>depends_on:</span></div></div><div><div><div>16</div></div><div><span><span>      </span></span><span>- redis</span></div></div><div><div><div>17</div></div><div><span><span>      </span></span><span>- database</span></div></div><div><div><div>18</div></div><div><span><span>    </span></span><span>restart: always</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span><span>  </span></span><span>immich-machine-learning:</span></div></div><div><div><div>21</div></div><div><span><span>    </span></span><span>container_name: immich_machine_learning</span></div></div><div><div><div>22</div></div><div><span><span>    </span></span><span>image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}</span></div></div><div><div><div>23</div></div><div><span><span>    </span></span><span># 想用核显加速（i5-12400 有 UHD 730），改成下面三行，见 7.5：</span></div></div><div><div><div>24</div></div><div><span><span>    </span></span><span>#   image: ghcr.io/immich-app/immich-machine-learning:release-openvino</span></div></div><div><div><div>25</div></div><div><span><span>    </span></span><span>#   devices: [ "/dev/dri:/dev/dri" ]</span></div></div><div><div><div>26</div></div><div><span><span>    </span></span><span>#   device_cgroup_rules: [ 'c 189:* rmw' ]</span></div></div><div><div><div>27</div></div><div><span><span>    </span></span><span>volumes:</span></div></div><div><div><div>28</div></div><div><span><span>      </span></span><span>- model-cache:/cache</span></div></div><div><div><div>29</div></div><div><span><span>    </span></span><span>env_file:</span></div></div><div><div><div>30</div></div><div><span><span>      </span></span><span>- .env</span></div></div><div><div><div>31</div></div><div><span><span>    </span></span><span>restart: always</span></div></div><div><div><div>32</div></div><div>
</div></div><div><div><div>33</div></div><div><span><span>  </span></span><span>redis:</span></div></div><div><div><div>34</div></div><div><span><span>    </span></span><span>container_name: immich_redis</span></div></div><div><div><div>35</div></div><div><span><span>    </span></span><span>image: docker.io/valkey/valkey:9</span></div></div><div><div><div>36</div></div><div><span><span>    </span></span><span>volumes:</span></div></div><div><div><div>37</div></div><div><span><span>      </span></span><span>- /mnt/user/appdata/immich/redis:/data     # redis 持久化（否则重启丢任务队列）</span></div></div><div><div><div>38</div></div><div><span><span>    </span></span><span>restart: always</span></div></div><div><div><div>39</div></div><div>
</div></div><div><div><div>40</div></div><div><span><span>  </span></span><span>database:</span></div></div><div><div><div>41</div></div><div><span><span>    </span></span><span>container_name: immich_postgres</span></div></div><div><div><div>42</div></div><div><span><span>    </span></span><span>image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0</span></div></div><div><div><div>43</div></div><div><span><span>    </span></span><span>environment:</span></div></div><div><div><div>44</div></div><div><span><span>      </span></span><span>POSTGRES_PASSWORD: ${DB_PASSWORD}</span></div></div><div><div><div>45</div></div><div><span><span>      </span></span><span>POSTGRES_USER: ${DB_USERNAME}</span></div></div><div><div><div>46</div></div><div><span><span>      </span></span><span>POSTGRES_DB: ${DB_DATABASE_NAME}</span></div></div><div><div><div>47</div></div><div><span><span>      </span></span><span>POSTGRES_INITDB_ARGS: '--data-checksums'</span></div></div><div><div><div>48</div></div><div><span><span>    </span></span><span>volumes:</span></div></div><div><div><div>49</div></div><div><span><span>      </span></span><span>- ${DB_DATA_LOCATION}:/var/lib/postgresql/data   # 必须落 SSD，见 7.2 的坑</span></div></div><div><div><div>50</div></div><div><span><span>    </span></span><span>shm_size: 128mb</span></div></div><div><div><div>51</div></div><div><span><span>    </span></span><span>restart: always</span></div></div><div><div><div>52</div></div><div>
</div></div><div><div><div>53</div></div><div><span>volumes:</span></div></div><div><div><div>54</div></div><div><span><span>  </span></span><span>model-cache:</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>配套的 <code>.env</code>：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># 上传照片的存储位置（unRAID 的用户共享路径）</span></div></div><div><div><div>2</div></div><div><span>UPLOAD_LOCATION=/mnt/user/appdata/immich/photo/</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 数据库存储位置：必须是 SSD cache 盘（见 7.2 的坑）</span></div></div><div><div><div>5</div></div><div><span>DB_DATA_LOCATION=/mnt/cache/appdata/immich/db</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span># Immich 版本（固定主版本，避免滚动升级出兼容问题）</span></div></div><div><div><div>8</div></div><div><span>IMMICH_VERSION=v3</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span># postgres 密码：改成你自己的强密码</span></div></div><div><div><div>11</div></div><div><span>DB_PASSWORD=your-strong-password</span></div></div><div><div><div>12</div></div><div><span>DB_USERNAME=postgres</span></div></div><div><div><div>13</div></div><div><span>DB_DATABASE_NAME=immich</span></div></div><div><div><div>14</div></div><div>
</div></div><div><div><div>15</div></div><div><span># 国内必加：模型下载走 hf-mirror 镜像（见 7.4.1）</span></div></div><div><div><div>16</div></div><div><span>HF_ENDPOINT=https://hf-mirror.com</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>几个要点：</p><ul>
<li>
<p><strong>数据库路径用变量 <code>DB_DATA_LOCATION</code></strong>，统一在 <code>.env</code> 里改，别在 compose 里硬编码（避免 <code>.env</code> 和 compose 两处路径不一致的坑）；</p>
</li>
<li>
<p><strong>外部库挂载</strong> <code>/mnt/user/backup-photos:/mnt/nas_photos:ro</code>，把 rsync 拉下来的照片只读挂进容器；</p>
</li>
<li>
<p><strong><code>HF_ENDPOINT</code></strong> 国内必加；</p>
</li>
<li>
<p><strong><code>IMMICH_VERSION</code> 固定主版本</strong>（如 <code>v3</code>），不要用会滚动的 <code>release</code>，避免升级踩兼容坑。</p>
</li>
</ul><p><strong>启动</strong>：填完 compose 和 env，回到 stack 页面点 <code>COMPOSE UP</code>，等镜像拉取完成（第一次会拉几个 GB）。</p><p><strong>首次初始化（第一次打开）</strong>：</p><ol>
<li>
<p>浏览器访问 <code>http://unraid-ip:2283</code>；</p>
</li>
<li>
<p>第一次会进入 <strong>创建管理员</strong> 页面，填邮箱 + 密码（这就是你的 Immich 管理员账号，记牢）；</p>
</li>
<li>
<p>进入后就是正式界面了。</p>
</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/Pasted%20image%2020260910234759.png" alt="Pasted image 20260910234759" /><figcaption>Pasted image 20260910234759</figcaption></figure><p></p></section><section><h3>7.2 postgres 必须落在真实 SSD 上<a href="#72-postgres-必须落在真实-ssd-上"><span>#</span></a></h3><p><code>compose.yml</code> 里 database 的挂载要特别注意：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>database:</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>volumes:</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>- /mnt/cache/appdata/immich/db:/var/lib/postgresql/data</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>问题出在 <code>/mnt/cache</code> 这个路径</strong>：它是 unRAID 的 cache 池（SSD）挂载点。如果你没配 SSD cache 盘，这个目录根本不存在——Docker 挂载不存在的路径时会自动创建它，<strong>创建在 unRAID 的根文件系统里，而根文件系统是内存</strong>。于是 postgres 数据全写进内存，一重启就清零，Immich 就显示「重新安装」，人脸识别、标签全没了。</p><p><strong>修复</strong>：给 unRAID 加一块 SSD 做 cache 池（postgres 本就该在 SSD），或退而求其次把 DB 落到阵列持久化目录。核心原则：<strong>postgres 数据必须落在一个真实、持久的磁盘上</strong>。</p></section><section><h3>7.3 用「外部库」管理照片<a href="#73-用外部库管理照片"><span>#</span></a></h3><p>照片已经在 <code>/mnt/user/backup-photos/</code> 了，Immich 不用重新上传，直接挂成外部库只做索引。在 <code>compose.yml</code> 的 <code>immich-server</code> 服务里加一个只读挂载：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>immich-server:</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>volumes:</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>- /mnt/user/backup-photos:/mnt/nas_photos:ro</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>改完 <code>docker compose up -d</code> 重启，然后在 Immich 后台：<strong>管理 → 外部库 → 创建外部库 → 导入路径填 <code>/mnt/nas_photos</code></strong>。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/Pasted%20image%2020260910235033.png" alt="Pasted image 20260910235033" /><figcaption>Pasted image 20260910235033</figcaption></figure><p></p><blockquote><p>外部库是<strong>只读索引</strong>：Immich 不改动照片原件，只建数据库索引。照片在 <code>/mnt/user/backup-photos/</code>，索引在 postgres——这也再次说明 postgres 必须持久化，否则索引每次重建。</p></blockquote></section><section><h3>7.4 开启人脸识别<a href="#74-开启人脸识别"><span>#</span></a></h3><p>人脸识别<strong>默认就是开启的</strong>，由 <code>immich-machine-learning</code> 容器承担，不需要改任何配置。但外部库的照片不会自动全部处理，需要手动触发，而且<strong>顺序很关键：先检测、后识别</strong>。</p><ol>
<li>
<p>先扫描外部库：<strong>管理 → 外部库 → 你的库 → 扫描（Scan）</strong>，让照片进库；</p>
</li>
<li>
<p><strong>管理 → 任务（Jobs）→ 人脸检测（Face Detection）</strong>，点右侧 <strong>全部（All）</strong>；</p>
</li>
<li>
<p>等检测跑完（Jobs 页有进度条），再点 <strong>人脸识别（Facial Recognition）</strong> 的 <strong>全部（All）</strong>；</p>
</li>
<li>
<p>全部跑完后，到 <strong>探索（Explore）→ 人物（People）</strong>，给聚类出的人脸命名，之后 Immich 会自动归类同名的人。</p>
</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/Pasted%20image%2020260910235128.png" alt="Pasted image 20260910235128" /><figcaption>Pasted image 20260910235128</figcaption></figure><p></p><blockquote><p><strong>为什么「人脸识别显示 0」？</strong> 因为人脸识别依赖人脸检测先跑——检测没跑，识别队列永远是 0；而照片没 scan 进库，检测又无从谈起。所以卡在 0 时，从「外部库有没有扫描」往上查。</p></blockquote><section><h4>7.4.1 国内必踩的坑：模型下载失败<a href="#741-国内必踩的坑模型下载失败"><span>#</span></a></h4><p>人脸识别依赖的 <code>buffalo_l</code> 模型（以及智能搜索的 CLIP 模型）默认从 <strong>HuggingFace</strong> 下载，国内直连不通，会出现典型的死循环：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>Downloading detection model 'buffalo_l' ... This may take a while.</span></div></div><div><div><div>2</div></div><div><span>Failed to load detection model 'buffalo_l'. Clearing cache.</span></div></div><div><div><div>3</div></div><div><span>Attempted to clear cache for model 'buffalo_l', but cache directory does not exist</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>解决：在 <code>.env</code> 里加一行，把模型下载源切到国内镜像</strong>：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>HF_ENDPOINT=https://hf-mirror.com</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>然后重启 ML 容器：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>docker compose up -d immich-machine-learning</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>重启后再看日志，出现 <code>Fetching ... 100%</code> 和 <code>Loading detection model 'buffalo_l' to memory</code> 就说明下载成功、可以正常识别了。</p><p><strong>成功的标志</strong>（加了 <code>HF_ENDPOINT</code> 后，日志从「下载失败」变成「下载成功」）：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>Downloading detection model 'buffalo_l' ... This may take a while.</span></div></div><div><div><div>2</div></div><div><span>Fetching 4 files: 100%|██████████| 4/4 [00:06&lt;00:00, 1.60s/it]</span></div></div><div><div><div>3</div></div><div><span>Loading detection model 'buffalo_l' to memory</span></div></div><div><div><div>4</div></div><div><span>Loading recognition model 'buffalo_l' to memory</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>关键看 <code>Fetching ... 100%</code>（下载成功）和 <code>Loading ... to memory</code>（加载成功）——之前失败时是 <code>Failed to load ... Clearing cache</code>。</p></section></section><section><h3>7.5 硬件加速（可选）：用核显 OpenVINO<a href="#75-硬件加速可选用核显-openvino"><span>#</span></a></h3><p>默认用 CPU 跑，几万张照片会偏慢。i5-12400 自带 UHD 730 核显，可改成 OpenVINO 加速——<strong>前提是核显没被其他虚拟机直通占用</strong>。</p><p>先确认核显可用：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>ls /dev/dri        # 能看到 renderD128 之类即说明核显可用</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>改 compose（⚠️ unRAID 上 <code>device_cgroup_rules</code> 这行必须加，否则容器访问不到 <code>/dev/dri</code>）：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>immich-machine-learning:</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>image: ghcr.io/immich-app/immich-machine-learning:release-openvino</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>devices:</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>- /dev/dri:/dev/dri</span></div></div><div><div><div>5</div></div><div><span><span>  </span></span><span>device_cgroup_rules:</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>- 'c 189:* rmw'</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>改完拉新镜像并重启：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>docker compose pull immich-machine-learning</span></div></div><div><div><div>2</div></div><div><span>docker compose up -d immich-machine-learning</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>怎么确认用上了核显？</strong> 看 ML 日志的 execution provider：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>docker logs immich_machine_learning 2&gt;&amp;1 | grep -i "execution provider"</span></div></div></code></pre><div><div></div><div></div></div></figure></div><ul>
<li>
<p><code>CPUExecutionProvider</code> → 还在用 CPU</p>
</li>
<li>
<p><code>OpenVINOExecutionProvider</code> → 核显生效 ✅</p>
</li>
</ul><p></p><figure><img src="http://imgbed.leihub.cn/img/cdf7a42ecd93498004a39237eadbab59.png" alt="cdf7a42ecd93498004a39237eadbab59" /><figcaption>cdf7a42ecd93498004a39237eadbab59</figcaption></figure><p></p><p><strong>成功的标志</strong>：日志里 <code>OpenVINOExecutionProvider</code> 排在第一位（CPU 只作为 fallback 排第二），说明核显已接管推理：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>Setting execution providers to ['OpenVINOExecutionProvider', 'CPUExecutionProvider'], in descending order of preference</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>对比改造前（纯 CPU）：<code>['CPUExecutionProvider']</code> —— 前后一字之差，就是核显是否生效的分水岭。</p><blockquote><p><code>device_cgroup_rules: 'c 189:* rmw'</code> 是给容器开放 <code>/dev/dri</code>（字符设备 189）的读写权限。unRAID 的 Docker 默认 cgroup 限制较严，漏了这行即使挂载了 <code>/dev/dri</code> 也访问不到——这是 unRAID 上特有的坑。</p></blockquote></section><section><h3>7.6 其他几个实用配置<a href="#76-其他几个实用配置"><span>#</span></a></h3><ul>
<li><strong>redis 持久化</strong>：官方 compose 的 redis 默认没挂数据卷，重启会丢任务队列，建议加一行：</li>
</ul><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>    </span></span><span>redis:</span></div></div><div><div><div>2</div></div><div><span><span>      </span></span><span>volumes:</span></div></div><div><div><div>3</div></div><div><span><span>        </span></span><span>- /mnt/user/appdata/immich/redis:/data</span></div></div></code></pre><div><div></div><div></div></div></figure></div><ul>
<li>
<p><strong>最小识别人脸数</strong>：默认 <code>3</code>，即同一个人至少要出现 3 张脸才会被建为「人物」。若某人照片少被隐藏，可在 <strong>管理 → 设置 → 机器学习 → 人脸识别</strong> 里调低。</p>
</li>
<li>
<p><strong>改参数 vs 换模型</strong>：只改检测阈值，重跑「人脸识别-全部」即可；换了识别模型，则要重跑「人脸检测-全部」。</p>
</li>
<li>
<p><strong>双胞胎/相似脸</strong>：可在人脸识别设置里调低「最大识别距离」来区分。</p>
</li>
</ul></section><section><h3>7.7 全功能模型清单：env 不用加任何模型配置<a href="#77-全功能模型清单env-不用加任何模型配置"><span>#</span></a></h3><p>Immich 的机器学习功能<strong>默认全部开启</strong>，模型会自动下载，<strong>不需要在 <code>.env</code> 里写模型名</strong>（唯一要加的就是 7.4.1 的 <code>HF_ENDPOINT</code>）。各功能对应模型：</p>

<table><thead><tr><th>功能</th><th>模型</th><th>需要动吗</th></tr></thead><tbody><tr><td>人脸识别</td><td><code>buffalo_l</code></td><td>❌ 默认够用</td></tr><tr><td>智能搜索（自然语言搜图）</td><td><code>ViT-B-32__openai</code>（默认）</td><td>⚠️ 中文建议换</td></tr><tr><td>OCR 文字识别</td><td><code>PP-OCRv5_mobile</code></td><td>❌ 自动加载</td></tr><tr><td>重复检测</td><td>复用 CLIP</td><td>❌</td></tr><tr><td>反向地理编码</td><td>GeoNames 库（非 ML）</td><td>❌</td></tr></tbody></table><p><strong>唯一建议动的：中文智能搜索换模型</strong>。默认 <code>ViT-B-32__openai</code> 偏英文，中文搜图（如「海边的日落」「春节鞭炮」）效果差，建议换成多语言的 XLM-Roberta 系列。</p><p>操作（在 UI 改，不是 env）：<strong>管理 → 设置 → 机器学习设置 → 智能搜索 → 模型名称</strong>里粘贴：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>XLM-Roberta-Base-ViT-B-32__laion5b_s13b_b90k</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>保存后到 Jobs 页点「智能搜索 → 全部」重新建索引。内存够可上更准的 <code>XLM-Roberta-Large-ViT-H-14__frozen_laion5b_s13b_b90k</code>，但更吃内存（32G 还要跑 Windows VM 的话，先用 Base 版）。</p><blockquote><p>⚠️ 网上常见的 <code>CLIP_VISUAL_MODEL_NAME</code> 等 env 变量是 <strong>MT Photos</strong>（另一个相册软件）的，不是 Immich。Immich 的模型一律在后台 UI 里改。</p></blockquote><hr /><p><a name="八"></a></p></section></section>
<section><h2>八、常见问题排查（FAQ）<a href="#八常见问题排查faq"><span>#</span></a></h2>

<table><thead><tr><th>问题</th><th>原因</th><th>解决</th></tr></thead><tbody><tr><td>群晖上 telnet 命令不存在</td><td>DSM 没有 telnet 客户端</td><td>用 <code>bash -c 'cat &lt; /dev/null &gt; /dev/tcp/ip/port'</code> 测端口</td></tr><tr><td>测端口显示”不通”其实是通的</td><td><code>cat &lt;/dev/tcp</code> 会等 EOF 被 timeout 误杀</td><td>换成 <code>cat &lt; /dev/null &gt; /dev/tcp/...</code></td></tr><tr><td>SSH 免密一直 <code>Permission denied</code></td><td>DSM 家目录 ACL 覆盖了 chmod</td><td>用 <code>synoacltool -del</code> 删 ACL，见 4.3</td></tr><tr><td>SSH 连上但 <code>Could not chdir to home</code></td><td>家目录服务没开</td><td>用户与群组 → 高级 → 启用家目录服务</td></tr><tr><td>rsync 报 <code>service disabled (code 52)</code></td><td>rsync 服务没开</td><td>文件服务 → rsync → 启用</td></tr><tr><td>Immich 重启显示”重新安装”</td><td>postgres 挂到了 <code>/mnt/cache</code>（无 SSD 时落内存）</td><td>DB 改到真实持久盘，见 7.2</td></tr><tr><td>人脸识别显示 0</td><td>照片没 scan 进库，或人脸检测没先跑</td><td>先扫描外部库，再「先检测后识别」，见 7.4</td></tr><tr><td>日志报 <code>Failed to load model</code> / 人脸检测一直失败</td><td>模型从 HuggingFace 下载失败（国内不通）</td><td><code>.env</code> 加 <code>HF_ENDPOINT=https://hf-mirror.com</code>，见 7.4.1</td></tr><tr><td>人脸识别跑完但 People 里人很少</td><td>最小识别人脸数默认 3，人出现不足 3 张被隐藏</td><td>调低最小识别人脸数，见 7.6</td></tr><tr><td>备份读到 <code>Permission denied</code></td><td>backup 账号读不到别人的文件</td><td>群晖配 sudoers + <code>--rsync-path="sudo rsync"</code></td></tr><tr><td><code>docker compose up</code> 报 <code>Invalid container name</code></td><td>把镜像名写进了 <code>container_name</code> 字段（镜像名含 <code>/</code> 和 <code>:</code>，不能当容器名）</td><td>检查 compose：<code>container_name</code> 只填容器名，<code>image</code> 才填 <code>ghcr.io/...</code> 镜像名，见 7.1</td></tr></tbody></table><p><a name="总结"></a></p></section>
<section><h2>总结<a href="#总结"><span>#</span></a></h2><p>折腾了这么一圈，总算把「群晖相册 → unRAID 备份」这条路走通了。最大的意外收获是 Immich——它有全平台客户端，用下来比 Synology Photos（DS Photos）顺手不少，尤其是后者看照片地图时经常崩溃的问题，在 Immich 这边完全不存在。</p><p>所以我现在是这么分工的：<strong>上传和同步交给 Synology Photos</strong>，白嫖它的 QuickConnect 远程能力；<strong>照片的处理、查看交给 Immich</strong>，人脸识别、智能搜索都在这边跑。两者各干各擅长的，互补着用。</p><p>整套方案从组网到备份再到相册搭建，全部配置和踩过的坑都写在上面了，照着做基本能一次到位。如果你也有异地备份照片的需求，不妨试试这套组合，应该不会让你失望。</p></section>
<section><h2>参考<a href="#参考"><span>#</span></a></h2><ol>
<li><a href="https://immich.app/" target="_blank">Immich</a></li>
<li><a href="https://kb.synology.cn/zh-cn/DSM/help/DSM/AdminCenter/file_rsync?version=7" target="_blank">rsync | DSM - Synology 知识中心</a></li>
<li><a href="https://ca.unraid.net/apps/unraid-rsync-1q5v71x1vub5v5" target="_blank">Unraid Rsync 适用于Unraid</a></li>
<li><a href="https://cloud.tencent.com/developer/article/1903535" target="_blank">使用hyper backup与rsync将数据备份到unraid-腾讯云开发者社区-腾讯云</a></li>
<li><a href="https://wiki.slarker.me/unraid/immich_ai_model.html" target="_blank">Immich 智能搜索 - 支持中文的 CLIP 大模型 | 一起玩 NAS!</a></li>
<li><a href="https://www.himiku.com/archives/immich.html" target="_blank">immich：从零开始，自建 NAS 相册 - 初之音</a></li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/1052/</id>
      <title type="text">西上东下：梵净山雾中徒步记</title>
      <published>2026-09-06T11:56:48.000Z</published>
      <updated>2026-09-06T11:59:05.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/1052/"/>
      <summary type="text">朋友嚷嚷了一年的梵净山，最近终于找到了爬山窗口，做足了攻略的我们，直接选择来一波特种兵爬梵净山。 一、周五晚上10点，株洲站出发 我们几个都是从株洲出发的，火车是晚上的卧铺车，10 点出发，第二天凌晨 5:40 到铜仁。一张硬卧 138 块</summary>
      <content type="html"><![CDATA[<p>朋友嚷嚷了一年的梵净山，最近终于找到了爬山窗口，做足了攻略的我们，直接选择来一波特种兵爬梵净山。</p>
<section><h3>一、周五晚上10点，株洲站出发<a href="#一周五晚上10点株洲站出发"><span>#</span></a></h3><p>我们几个都是从株洲出发的，火车是晚上的卧铺车，10 点出发，第二天凌晨 5&lt;40&gt; 到铜仁。一张硬卧 138 块，直接把住宿和一程高铁钱都省下来了。</p><p>不过我们还是有点高估自己的睡觉质量，在卧铺上，我才堪堪睡了 30 分钟，第二天全靠一杯魔爪提神。</p><p>凌晨出站的时候天还黑着，铜仁的空气凉得舒服。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/321a6f3400668b3be0cd70285dd69d47.jpg" alt="321a6f3400668b3be0cd70285dd69d47|340" /><figcaption>321a6f3400668b3be0cd70285dd69d47|340</figcaption></figure><p></p><p><strong>梵净山有两个门</strong>：东线在江口县，主流游客走这里，索道上下、轻松；西线在印江县，山门叫护国寺，从护国寺到徒步起点需要坐景交车上山，然后徒步上去。</p><p>我们选择的是西上东下线，从西门徒步上到金顶，再在东线坐索道下山。西线相对东线便宜一些，但交通不太方便，推荐提前约好顺风车，不然临时打车会非常贵。我们提前一周联系了一个顺风车师傅，这趟顺风车花了 200 出头，几个人平摊下来还好。</p><p>在去西线的路上，我们还遇到了一群黔金丝猴，听说这种”牢底坐穿兽”只有贵州才有。
</p><figure><img src="http://imgbed.leihub.cn/img/90d57470071ade615606893b2f001258.jpg" alt="90d57470071ade615606893b2f001258|351" /><figcaption>90d57470071ade615606893b2f001258|351</figcaption></figure><p></p><p>西线盘山公路非常绕，本来就没休息好的我，直接被绕晕车了，这还没开始爬，人就已经半血了。闷头坐了 2 个多小时车，到西线山门的时候已经 8 点。</p></section>
<section><h3>二、西线徒步<a href="#二西线徒步"><span>#</span></a></h3><p><strong>门票 + 景交车 + 东线下行索道一共 190 元</strong>（这是西上东下的标准买法，从山门坐景交车到棉絮岭徒步起点，回程从东线索道下山）。</p><p><strong>为什么要选西线而不是东线索道？</strong> 因为它沿途是原始杜鹃林和阔叶林，台阶大多埋在树影里，绿得发亮。我们这个时间（9 月初）花早就没了，但可以想象：4 月杜鹃满开的时候这条路会是什么样。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/a45cf3e6059f43a44ee1a2bdf56c86dc.jpg" alt="a45cf3e6059f43a44ee1a2bdf56c86dc|354" /><figcaption>a45cf3e6059f43a44ee1a2bdf56c86dc|354</figcaption></figure><p></p><p>棉絮岭起步不久，就看到了<strong>万米睡佛</strong>——这是西线专属的一个景点，在观景台上远眺，远处起伏的山脊线刚好构成一尊绵延万米的卧佛轮廓。这是走东门看不到的补偿。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/893b4892242351aff8a9be918825ea06.jpg" alt="893b4892242351aff8a9be918825ea06|353" /><figcaption>893b4892242351aff8a9be918825ea06|353</figcaption></figure><p></p><p>接着是黑巷子、十月怀胎树、剪刀峡、拜佛台……每个名字都不一样。台阶湿漉漉的，风穿过树梢，一路上都非常凉爽，怪不得徒步都推荐来西线呢。</p><blockquote><p>建议在保存红云金顶的预约二维码，不用到普渡广场，在路上就可以预约红云金顶，我是走了半路上才可以，搭子的手机刚进进去再棉絮岭就可以预约了。
</p><figure><img src="http://imgbed.leihub.cn/img/5404eb80b92d02738efa96139dfa36f1.jpg" alt="5404eb80b92d02738efa96139dfa36f1|362" /><figcaption>5404eb80b92d02738efa96139dfa36f1|362</figcaption></figure><p></p></blockquote></section>
<section><h3>三、普渡广场，300 号的红云金顶<a href="#三普渡广场300-号的红云金顶"><span>#</span></a></h3><p><strong>10&lt;00&gt; 不到，我们就到了普渡广场</strong>。这是山顶的核心枢纽，去红云金顶、老金顶、蘑菇石都要在这里分叉。</p><p>我们从西线过来，首先会经过老金顶和蘑菇石，因为红云金顶太火爆了、还需要预约，所以我们选择直冲红云金顶，后面回头再来老金顶。</p><p>因为我们来得比较早，取号的时候才 300 号，红云金顶都还没开始叫号排队，我们直接上去就行。</p><p>红云金顶在一座独立的尖峰上，山体陡峭，要靠铁链手抓脚踩。下半段还算稳，到中段开始，真正只容一人通过，两边是悬空。
</p><figure><img src="http://imgbed.leihub.cn/img/06c2bbdf1864a1cb44f249f0006f97f7.jpg" alt="06c2bbdf1864a1cb44f249f0006f97f7|250" /><figcaption>06c2bbdf1864a1cb44f249f0006f97f7|250</figcaption></figure><p></p><p>登顶的那一刻，金顶被云雾包着，时隐时现。远处的山尖像漂浮的小岛。风是真的大，把衣服吹得噼啪响。
</p><figure><img src="http://imgbed.leihub.cn/img/f1ad08a13af69c6e43c042e5a2bbaba0.jpg" alt="f1ad08a13af69c6e43c042e5a2bbaba0|282" /><figcaption>f1ad08a13af69c6e43c042e5a2bbaba0|282</figcaption></figure><p></p></section>
<section><h3>四、老金顶与蘑菇石，大部队来了<a href="#四老金顶与蘑菇石大部队来了"><span>#</span></a></h3><p><strong>从红云金顶下来，已经 11 点左右</strong>，这时候大部队陆续上山。</p><p>我们原路返回普渡广场，往老金顶方向走。<strong>老金顶比红云金顶海拔高一点（2493 米）</strong>，但坡相对缓，有一段需要手脚并用的险路。</p><p><strong>老金顶上堵得水泄不通</strong>。人一多，游客挤成一锅粥卡在窄台阶上，险段还有人停下来自拍——台阶本来就只够一人通行，一人自拍，全员堵车。</p><p>蘑菇石离老金顶不远，一块 14 亿年的巨石，立在另一块石头上，看似随时要倒，就是不倒——梵净山的 logo。拍照要排队，但至少脚下稳。
</p><figure><img src="http://imgbed.leihub.cn/img/82d9418cf26b3ffa854372dfbb93b319.jpg" alt="82d9418cf26b3ffa854372dfbb93b319|243" /><figcaption>82d9418cf26b3ffa854372dfbb93b319|243</figcaption></figure><p></p><p>整个老金顶 + 蘑菇石，我们花了将近 1 个小时，到 12&lt;30&gt; 左右才回到普渡广场。雾散了一点，我们找准机会，才拍到了云雾中的红云金顶。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/a3eb243e05e9adf8a1ccb0dd975b4838.jpg" alt="a3eb243e05e9adf8a1ccb0dd975b4838|244" /><figcaption>a3eb243e05e9adf8a1ccb0dd975b4838|244</figcaption></figure><p></p></section>
<section><h3>五、坐东线下行索道，回铜仁<a href="#五坐东线下行索道回铜仁"><span>#</span></a></h3><p>下午一点多从普渡广场出发，沿着指示牌走一段木栈道，就到了<strong>东线下行索道</strong>，然后转景区公交车到景区门口，已经是下午两点多了。景区门口有不少拉客的司机，拼车 35 块一个人，可以直接到铜仁站。
</p><figure><img src="http://imgbed.leihub.cn/img/3e01b0aad36d5674e49c30b5ef05802b.jpg" alt="3e01b0aad36d5674e49c30b5ef05802b|290" /><figcaption>3e01b0aad36d5674e49c30b5ef05802b|290</figcaption></figure><p></p></section>
<section><h3>六、铜仁美食：施秉全牛自助<a href="#六铜仁美食施秉全牛自助"><span>#</span></a></h3><p>从梵净山下来，我们立马买了回长沙的高铁票，但铜仁回长沙的高铁只有晚上 19&lt;30&gt; 那一趟，还有四五个小时，这下不得不去铜仁觅个食了。</p><p>各种社交平台刷了一遍，最后选了家老字号——施秉全牛馆，自助 55 一位，牛肉随便吃。兄弟几个一听到”牛肉随便吃”就走不动道了，直接拍板。</p><figure><img src="http://imgbed.leihub.cn/img/3a1e3aaa22c1c02fee2f896b661e72a1.jpg" alt="3a1e3aaa22c1c02fee2f896b661e72a1|282" /><figcaption>3a1e3aaa22c1c02fee2f896b661e72a1|282</figcaption></figure><p></p><p>我们吃的是酸汤锅底加干锅牛肉。酸汤锅底放了山胡椒油，我个人是一点也顶不住，味道只能说中规中矩；干锅牛肉稍微咸了点，但对于刚爬完山、出了一身汗的我来说刚刚好。</p><p>如果这顿是 100 元的自助，完全不值；但它 55 一个人，我只能说完全没毛病。</p></section>
<section><h3>七、费用<a href="#七费用"><span>#</span></a></h3><p>总共算了一下出行费用，不算饮食，而且我们也没有住宿：</p><ul>
<li>
<p>株洲→铜仁卧铺：~138元</p>
</li>
<li>
<p>铜仁→梵净山西线顺风车/拼车：~200/3=66（往返，平摊）</p>
</li>
<li>
<p>山顶门票 + 景交车 + 东线下行索道：190元</p>
</li>
<li>
<p>梵净山东线→铜仁站：~35元</p>
</li>
<li>
<p>铜仁→长沙回程：~184元</p>
</li>
</ul><p>加起来 ~613 元，没超预算，纯特种兵出行，连住宿都免了。</p></section>
<section><h3>八、总结<a href="#八总结"><span>#</span></a></h3><p><strong>1. 西线 vs 东线怎么选？</strong></p><ul>
<li>
<p>带老人小孩、想舒服：东线，索道上下（贵一些，大概 264 一整套）</p>
</li>
<li>
<p>朋友组队、想徒步、原生态：西线徒步上 + 东线索道下（这次我们走的路线，爬升约800米，全程下来4个小时）
</p><figure><img src="http://imgbed.leihub.cn/img/7d9aaf3d716d21f1c138bda119e7ae00.jpg" alt="7d9aaf3d716d21f1c138bda119e7ae00|297" /><figcaption>7d9aaf3d716d21f1c138bda119e7ae00|297</figcaption></figure><p></p>
</li>
<li>
<p>纯徒步，不上金顶：东线徒步，全程爬升1600米，时间上会非常赶，到时候红云金顶排队会非常严重，而且可能赶上下山索道、景交车高峰期，会比较折磨。</p>
</li>
</ul><p><strong>2. 红云金顶怎么免排队？</strong></p><p>进山后直接扫码预约，不一定要到普渡广场，有时候老远就能预约到了。如果你到达比较早，每天<strong>前 500 人直接上、不用等叫号</strong>。超过 500 号要在原地等叫号。</p><p><strong>3. 西线专属景点：万米睡佛</strong></p><p>只有走西线的徒步客能看到。在棉絮岭观景台。<strong>东线的游客看不到</strong>——这一点作为西线的精神补偿还算值。</p><p><strong>4. 装备清单（雾天尤其重要）</strong></p><ul>
<li>
<p>防滑运动鞋（湿石很滑）</p>
</li>
<li>
<p>薄手套（抓铁链、雾天铁链冰凉）</p>
</li>
<li>
<p>冲锋衣（山顶比山下低 6-8℃）</p>
</li>
<li>
<p>一次性雨衣（雾天飘的水珠跟下雨一样）</p>
</li>
</ul><p><strong>5. 关于猴子</strong></p><p>山下到山门盘山路上，如果停着车等人，或者经过有树有水的地方，<strong>留意一下树梢</strong>。梵净山的黔金丝猴是国家一级保护动物，运气好能碰上，<strong>但别喂、别追、别下车</strong>。</p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/1044/</id>
      <title type="text">NotionNext 个人博客搭建教程：腾讯云 EdgeOne 部署</title>
      <published>2026-06-13T06:26:59.000Z</published>
      <updated>2026-08-10T10:30:22.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/1044/"/>
      <summary type="text">前言 目前主流的博客搭建方案可大致分为两类，且各有局限：一类是以 WordPress 为代表的动态博客系统，依赖独立服务器运行，运维与硬件成本较高；另一类是以 Hexo 为代表的静态博客框架，采用本地 Markdown 编写，无实时预览能力</summary>
      <content type="html"><![CDATA[<section><h2>前言<a href="#前言"><span>#</span></a></h2><p>目前主流的博客搭建方案可大致分为两类，且各有局限：一类是以 WordPress 为代表的动态博客系统，依赖独立服务器运行，运维与硬件成本较高；另一类是以 Hexo 为代表的静态博客框架，采用本地 Markdown 编写，无实时预览能力，无法在编辑阶段直观确认最终呈现效果，且内容更新需手动执行构建部署流程，操作链路较长。</p><p>NotionNext 恰好填补了两类方案之间的空白。它以 Notion 作为内容生产端，完整保留了所见即所得的块级编辑体验与强大的数据库管理能力，创作者可专注于内容本身，无需在编辑与预览间反复切换；同时通过 Next.js 将 Notion 内容渲染为独立的静态博客站点，支持多平台托管部署，兼顾了部署灵活性与运维轻量化。</p><p>基于这套方案，本文介绍，如何通过NotionNext，将个人博客部署到<strong>腾讯云 EdgeOne Pages和</strong>Vercel上。</p><p><strong>前置准备</strong>：Notion 账号、GitHub 账号、腾讯云账号（已实名认证）、备案域名（可选）</p><hr /></section>
<section><h2>一、创建 Notion 内容页<a href="#一创建-notion-内容页"><span>#</span></a></h2><section><h3>1. 复制官方模板<a href="#1-复制官方模板"><span>#</span></a></h3><p>打开 <a href="https://www.notion.so/02ab3b8678004aa69e9e415905ef32a5?pvs=21" target="_blank">NotionNext官方配置模板</a>，点击页面右上角 <strong>Duplicate</strong>，将模板复制到自己的 Notion 工作区。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/NotionNext%E5%AE%98%E6%96%B9%E9%85%8D%E7%BD%AE%E6%A8%A1%E6%9D%BF.png" alt="NotionNext官方配置模板" /><figcaption>NotionNext官方配置模板</figcaption></figure><p></p></section><section><h3>2. 获取页面 ID<a href="#2-获取页面-id"><span>#</span></a></h3><ol>
<li>打开复制后的配置页面，依次点击右上角 <strong>Share → Publish → 开启 Share to web</strong>，复制页面共享链接。</li>
<li>提取规则：链接中连续 32 位的字母数字串即为页面 ID，需剔除 <code>?v=</code>、<code>?pvs=</code> 及之后的所有参数。
<ul>
<li>示例： <code>https://www.notion.so/tanghh/02ab3b8678004aa69e9e415905ef32a5?v=b7eb...</code></li>
<li>页面 ID：<code>02ab3b8678004aa69e9e415905ef32a5</code></li>
</ul>
</li>
<li>关键提醒：必须开启公开分享，否则站点无法拉取 Notion 数据。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/%E5%85%AC%E5%BC%80%E5%88%86%E4%BA%AB.png" alt="公开分享" /><figcaption>公开分享</figcaption></figure><p></p><hr /></section></section>
<section><h2>二、复刻项目源码<a href="#二复刻项目源码"><span>#</span></a></h2><ol>
<li>打开 NotionNext GitHub 官方仓库，点击右上角 <strong>Fork</strong>，将项目完整复刻到自己的 GitHub 账号下。</li>
<li>后续所有部署、配置修改均基于你自己的仓库完成，支持版本管理和个性化二次开发。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/Fork.png" alt="Fork" /><figcaption>Fork</figcaption></figure><p></p><hr /></section>
<section><h2>三、腾讯云 EdgeOne 部署<a href="#三腾讯云-edgeone-部署"><span>#</span></a></h2><section><h3>1. 进入 Makers控制台<a href="#1-进入-makers控制台"><span>#</span></a></h3><p>登录腾讯云控制台，搜索「边缘安全加速平台 EO」，左侧导航选择「Makers」，点击「创建项目」。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/%E8%BE%B9%E7%BC%98%E5%AE%89%E5%85%A8%E5%8A%A0%E9%80%9F%E5%B9%B3%E5%8F%B0%20EO.png" alt="边缘安全加速平台 EO" /><figcaption>边缘安全加速平台 EO</figcaption></figure><p></p></section><section><h3>2. 导入 Git 仓库<a href="#2-导入-git-仓库"><span>#</span></a></h3><ol>
<li>选择「导入 Git 仓库」，完成 GitHub 账号授权，建议仅授权指定的 NotionNext 仓库。</li>
<li>仓库选择上一步 Fork 的项目，生产分支选择 <code>main</code>。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/%E7%94%9F%E4%BA%A7%E5%88%86%E6%94%AF.png" alt="生产分支" /><figcaption>生产分支</figcaption></figure><p></p></section><section><h3>3. 构建配置（核心步骤）<a href="#3-构建配置核心步骤"><span>#</span></a></h3><p>系统会自动检测项目的框架，并且预填写构建命令</p><ol>
<li>构建命令请使用静态导出：<code>yarn export</code>。若托管面板模板仍显示 <code>npm run build</code> / <code>npm run export</code>，请按仓库习惯改为 Yarn。前者是动态站点，后者是静态。</li>
<li><code>项目名称</code>要修改一下，名称长度必须为5到63个字符，只能包含小写字母、数字和连字符。</li>
<li>环境变量中添加您的<code>NOTION_PAGE_ID</code></li>
</ol><blockquote><p>补充说明：静态部署后，Notion 内容更新需重新触发构建才能同步到站点。</p></blockquote><p></p><figure><img src="http://imgbed.leihub.cn/img/%E6%9E%84%E5%BB%BA%E9%85%8D%E7%BD%AE.png" alt="构建配置" /><figcaption>构建配置</figcaption></figure><p></p></section><section><h3>4. 启动部署<a href="#4-启动部署"><span>#</span></a></h3><ol>
<li>确认配置无误，点击「开始部署」，首次构建约 3-5 分钟。</li>
<li>部署成功后，系统分配默认访问域名，可直接打开验证站点效果。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/%E5%BC%80%E5%A7%8B%E9%83%A8%E7%BD%B2.png" alt="开始部署" /><figcaption>开始部署</figcaption></figure><p></p></section><section><h3>5. 绑定自定义域名（可选）<a href="#5-绑定自定义域名可选"><span>#</span></a></h3><ol>
<li>前提：域名已完成工信部 ICP 备案。</li>
<li>操作路径：项目设置 → 域名管理 → 添加自定义域名，按提示在域名服务商处添加 CNAME 解析记录。</li>
<li>解析生效后系统自动签发 SSL 证书，默认开启 HTTPS 访问。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/%E7%BB%91%E5%AE%9A%E8%87%AA%E5%AE%9A%E4%B9%89%E5%9F%9F%E5%90%8D.png" alt="绑定自定义域名" /><figcaption>绑定自定义域名</figcaption></figure><p></p><hr /></section></section>
<section><h2>四、备选方案：Vercel 一键部署<a href="#四备选方案vercel-一键部署"><span>#</span></a></h2><p>适用场景：海外读者为主，或需要 Notion 内容实时自动同步。</p><ol>
<li>Vercel 官网使用 GitHub 账号登录。</li>
<li>导入 Fork 的 NotionNext 仓库，框架会自动识别为 Next.js。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/Vercel.png" alt="Vercel" /><figcaption>Vercel</figcaption></figure><p></p><ol>
<li>添加环境变量 <code>NOTION_PAGE_ID</code>，点击 Deploy 即可完成部署。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/Deploy%20.png" alt="Deploy " /><figcaption>Deploy </figcaption></figure><p></p><ol>
<li>优势：支持 ISR 增量静态再生，Notion 修改内容后数分钟内自动同步，无需手动重建。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/vercelNotion.png" alt="vercelNotion" /><figcaption>vercelNotion</figcaption></figure><p></p><hr /></section>
<section><h2>五、站点基础配置<a href="#五站点基础配置"><span>#</span></a></h2><section><h3>1. 发布文章<a href="#1-发布文章"><span>#</span></a></h3><p>在 Notion 数据库中新增一行：</p><ul>
<li><code>type</code> 选择 <code>Post</code>（普通博客文章）</li>
<li><code>status</code> 设为 <code>Published</code>（公开可见）</li>
<li>填写标题、分类、标签、摘要后，点击进入页面，即可用 Notion 原生块编辑器撰写内容。</li>
</ul><p></p><figure><img src="http://imgbed.leihub.cn/img/Notion%20%E6%95%B0%E6%8D%AE%E5%BA%93.png" alt="Notion 数据库" /><figcaption>Notion 数据库</figcaption></figure><p></p></section><section><h3>2. 主题与菜单<a href="#2-主题与菜单"><span>#</span></a></h3><ul>
<li><strong>主题切换</strong>：新增 <code>Config</code> 类型条目，配置名填 <code>THEME</code>，配置值为主题文件夹名（如 next、heo、matery）。</li>
<li><strong>导航菜单</strong>：<code>type</code> 选 <code>Menu</code> 为一级菜单，选 <code>SubMenu</code> 为二级子菜单，<code>slug</code> 字段填写跳转路径。</li>
<li>配置优先级：Notion 内配置 &gt; 项目本地 <code>blog.config.js</code> 文件。</li>
</ul></section><section><h3>3. 内容更新规则<a href="#3-内容更新规则"><span>#</span></a></h3><ul>
<li>EdgeOne 静态部署：Notion 修改内容后，需在 EdgeOne 控制台手动触发重新部署，站点才会同步更新。</li>
</ul><p></p><figure><img src="http://imgbed.leihub.cn/img/EdgeOne%20%E6%8E%A7%E5%88%B6%E5%8F%B0%E6%89%8B%E5%8A%A8%E8%A7%A6%E5%8F%91%E9%87%8D%E6%96%B0%E9%83%A8%E7%BD%B2.png" alt="EdgeOne 控制台手动触发重新部署" /><figcaption>EdgeOne 控制台手动触发重新部署</figcaption></figure><p></p><ul>
<li>Vercel 部署：默认开启增量缓存，无需手动操作，数分钟内自动同步。</li>
</ul><hr /><p>搭建的博客首页样式如图所示</p><p></p><figure><img src="http://imgbed.leihub.cn/img/%E5%8D%9A%E5%AE%A2%E9%A6%96%E9%A1%B5%E6%A0%B7%E5%BC%8F.png" alt="博客首页样式" /><figcaption>博客首页样式</figcaption></figure><p></p></section></section>
<section><h2>六、常见问题<a href="#六常见问题"><span>#</span></a></h2><ol>
<li><strong>站点不显示文章</strong>
<ul>
<li>检查页面 ID 是否准确，Notion 页面是否开启公开分享。</li>
<li>确认文章 <code>status</code> 为 <code>Published</code>。</li>
</ul>
</li>
<li><strong>EdgeOne 构建失败</strong>
<ul>
<li>确认构建命令为 <code>npm run export</code>。</li>
<li>可添加环境变量 <code>NODE_VERSION=18</code> 指定 Node 版本，清空构建缓存后重试。</li>
</ul>
</li>
<li><strong>国内访问加载慢</strong>
<ul>
<li>建议替换谷歌字体为国内源，图片资源改用国内图床。</li>
<li>在 EdgeOne 控制台配置缓存规则，提升静态资源命中效率。</li>
</ul>
</li>
</ol></section>
<section><h2>总结<a href="#总结"><span>#</span></a></h2><p>总的来说，这套 Notion + NotionNext 的建站方案，最大的好处就是把「写内容」和「搭网站」拆得特别舒服。你不用像用 WordPress 那样操心服务器运维，也不用像用 Hexo 那样在本地编辑器和最终部署效果之间反复横跳 —— 平时写文章就正常用 Notion，排版、分类、插代码嵌图片都所见即所得，写完发布顺手就能同步到网站上，门槛低了很多。</p><p>对国内用户来说，部署到腾讯云 EdgeOne 是性价比很高的选择，国内访问速度稳，个人博客用免费额度基本就够；如果想图省事一键搭建，或者主要面向海外读者，Vercel 方案也完全能用。</p></section>
<section><h1>📎 参考文章<a href="#-参考文章"><span>#</span></a></h1><ul>
<li><a href="https://notionnext.tangly1024.com/user-guide/start-here" target="_blank">从这里开始 | NotionNext 使用说明</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/1921844392844568499" target="_blank">(77 封私信 / 80 条消息) 如何用Notion搭建个人博客网站？ - 知乎</a></li>
<li><a href="https://blog.csdn.net/C_JackForme/article/details/140280730" target="_blank">基于NotionNext的个人网站|博客搭建与部署实例教程-CSDN博客</a></li>
</ul></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/1041/</id>
      <title type="text">五一萍乡自驾游｜4天游玩全记录</title>
      <published>2026-05-04T16:37:18.000Z</published>
      <updated>2026-05-07T16:39:22.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/1041/"/>
      <summary type="text">五一不想挤人山人海的热门景区，和朋友果断冲萍乡自驾游！四天三晚玩遍孽龙洞、竹筏、反穿武功山，有好玩到封神的项目，也有巨踩雷的景点和美食，还有自驾专属大坑！全程真实无滤镜，新手直接抄作业，避坑省钱两不误✨ ✨出行省钱小技巧 出发前专门囤了株洲</summary>
      <content type="html"><![CDATA[<p>五一不想挤人山人海的热门景区，和朋友果断冲<strong>萍乡自驾游</strong>！四天三晚玩遍孽龙洞、竹筏、反穿武功山，有好玩到封神的项目，也有巨踩雷的景点和美食，还有自驾专属大坑！全程真实无滤镜，新手直接抄作业，避坑省钱两不误✨</p>
<img src="http://imgbed.leihub.cn/img/%E9%87%91%E9%A1%B6%E6%89%93%E5%8D%A1.jpg" />
<section><h2>✨出行省钱小技巧<a href="#出行省钱小技巧"><span>#</span></a></h2><p>出发前专门囤了<strong>株洲文旅惠民卡</strong>！抖音入手只要100块，真的巨划算！不光能玩遍株洲本地文旅项目，萍乡超多景点也能通用抵扣，五一出游直接省下一大笔门票钱，自驾周边游必入！</p><img src="http://imgbed.leihub.cn/img/%E6%96%87%E6%97%85%E5%8D%A1.jpg" /></section>
<section><h2>📅四天三晚完整行程实况<a href="#四天三晚完整行程实况"><span>#</span></a></h2><section><h3>Day1 5.2｜打卡天下第一洞·孽龙洞<a href="#day1-52打卡天下第一洞孽龙洞"><span>#</span></a></h3><p>第一天主打轻松休闲，自驾直奔<strong>萍乡孽龙洞</strong>！号称“天下第一洞”，网上名气超大，实际逛完真心觉得期望值拉太高了。</p><p>整体就是很常规的溶洞景观，石笋、石幔这些溶洞标配景色都有，没有特别惊艳的亮点。景区步道全程超长，足足四五公里，慢慢逛走完要3个小时左右，全程一直在走路，逛到后面纯纯审美疲劳，普通游客可去可不去，性价比一般。</p><img src="http://imgbed.leihub.cn/img/%E5%AD%BD%E9%BE%99%E6%B4%9E.jpg" /></section><section><h3>Day2 5.3｜治愈竹筏+超嗨游乐项目<a href="#day2-53治愈竹筏超嗨游乐项目"><span>#</span></a></h3><p>上午慢悠悠打卡<strong>十里竹筏</strong>！这一站真的很惊喜，完全是小众治愈秘境。四周青山环绕，溪水清澈透亮，山清水秀氛围感拉满，吹着山间清风坐竹筏超舒服，人少景美，很适合拍照打卡，放松散心超合适。</p><img src="http://imgbed.leihub.cn/img/%E5%8D%81%E9%87%8C%E7%AB%B9%E7%AD%8F.jpg" /><p>下午直接冲武功山山脚，解锁两大游乐项目：<strong>滑草+越野车</strong>！</p><p>滑草项目性价比超高，套餐里包含射箭、水滑等多个小项目，一票通玩，趣味性很足，老少皆宜，玩得超尽兴。</p><img src="http://imgbed.leihub.cn/img/%E6%BB%91%E8%8D%89.jpg" /><p>重点夸爆<strong>山地越野车</strong>！绝对是本次旅途<strong>最佳项目No.1</strong>！全程颠簸刺激，山路弯道超多，油门踩到底的快乐谁懂！自由度很高，可玩性拉满，玩完还意犹未尽，来萍乡一定要冲！</p><img src="http://imgbed.leihub.cn/img/%E8%B6%8A%E9%87%8E.jpg" /><p>玩完所有项目，晚上直接驱车赶往<strong>龙山村</strong>入住，为第二天反穿武功山提前占位。</p></section><section><h3>Day3 5.4｜武功山二刷反穿！<a href="#day3-54武功山二刷反穿"><span>#</span></a></h3><p>这天是我<strong>二刷武功山反穿路线</strong>！去年9月就挑战过一次完整版武功山反穿，全程12小时暴走20公里，当时就整理了超详细的路线解析、徒步装备、食宿避坑完整攻略，没看过首次反穿细节的朋友可以先补课👉<a href="/archives/946/">武功山一日反穿完整版攻略</a>！</p><p>本以为有第一次的徒步经验，五一二刷肯定能轻松拿捏，结果完全翻车！平时工作日、淡季徒步和五一旺季徒步，体验感天差地别，累度直接翻倍，还踩了自驾停车的致命大坑，今天就好好跟大家聊聊两次反穿的真实差别，给旺季爬山的朋友避大雷！</p><img src="http://imgbed.leihub.cn/img/%E7%88%AC%E5%B1%B1%E5%87%BA%E5%8F%91.jpg" /><p>依旧是早上<strong>6点准时起床摸黑出发</strong>，和第一次淡季空旷的山路完全不同，五一山上人山人海，全程走走停停。同样是龙山村反穿金顶的路线，全程20公里徒步、12小时超长续航，从清晨走到傍晚，硬生生熬到晚上6点才登顶金顶。下山人流拥堵严重，折腾到晚上8点才下到索道口，排队等索道直接排到夜里10点，对比第一次淡季不用排队、畅通无阻，五一旺季爬山真的折磨加倍！</p><img src="http://imgbed.leihub.cn/img/%E4%BA%BA.jpg" /><p>这里必须给所有自驾游客<strong>掏心窝避坑忠告</strong>！！！</p><p>千万别把车停龙山村！！！我们自驾车停在龙山村，下山在游客中心，距离超远，深夜下山还要额外打车折返取车，又累又麻烦，心态直接崩了。</p><p><strong>正确自驾操作（沿用首次反穿靠谱经验）</strong>：之前9月反穿，我们就是车停<strong>武功山游客中心</strong>，打车去龙山村起步，下山直达停车场，全程顺畅不折腾。结果这次五一偷懒换了停车方式，直接踩雷！真心建议所有自驾党，无脑照搬这个正确路线，千万别乱改！下山直接到游客中心开车，完美避开深夜折返跑路，省力又省心！</p></section></section>
<section><h2>🏨三晚住宿真实测评（平价+实景）<a href="#三晚住宿真实测评平价实景"><span>#</span></a></h2><p>全程三晚住宿，性价比、体验感参差不齐，真实分享给大家：</p><p><strong>第一晚｜芦溪县城 礼萍宾馆</strong></p><p>性价比直接封神！！两个标间才花200块，人均超级便宜，临时过渡住一晚完全够用，干净整洁，预算党闭眼冲不亏哈哈哈。</p><p><strong>第二晚｜龙山村 龙门山庄</strong></p><p>靠近武功山徒步起点，位置绝佳，主打一个方便徒步，周边配套齐全，爬山前落脚首选。</p><p><strong>第三晚｜归隐栖心酒店</strong></p><p>环境安静舒适，设施比较新，暴走爬山后住这里休整，休息体验感很不错。</p></section>
<section><h2>🍜全程美食真实吐槽｜无滤镜实况<a href="#全程美食真实吐槽无滤镜实况"><span>#</span></a></h2><p>萍乡美食有惊喜也有踩雷，全部真实口感分享：</p><p><strong>Day1午餐｜大掌柜家常菜</strong></p><p>真心踩大雷！味道很普通，关键是超级辣，不能吃辣的慎入！最离谱的是空心菜都没炒熟，口感巨差，整体体验很一般，不推荐。</p><p><strong>Day1晚餐｜昭萍宴</strong></p><p>中规中矩的网红店，没有惊艳的味道，整体平平无奇，吃完没什么记忆点，可吃可不吃。</p><p><strong>Day2午餐｜8号餐厅（全场最佳）</strong></p><p>整趟旅途最满意的一餐！直接封神yyds！招牌<strong>莲花血鸭</strong>正宗地道，香辣入味，越吃越上头，我们直接吃到过瘾，来萍乡必吃！</p><img src="http://imgbed.leihub.cn/img/%E7%BE%8E%E9%A3%9F.jpg" /><p><strong>Day2晚餐｜本地炒粉</strong></p><p>玩累了随便找店解决，本地特色炒粉，味道家常，饱腹刚刚好。</p><p><strong>Day3早餐｜龙门山庄炒粉</strong></p><p>15元一碗的农家炒粉，性价比尚可，简单吃完补充体力，开启暴走爬山模式。</p><p><strong>Day4晚餐｜季季红火锅</strong></p><p>旅途收尾整顿好的！爬山累瘫后炫一顿火锅，治愈所有疲惫，完美收官本次萍乡之行。</p></section>
<section><h2>💥总结碎碎念<a href="#总结碎碎念"><span>#</span></a></h2><p>这次萍乡四天自驾，属于<strong>一半惊喜一半踩坑</strong>！也是我时隔大半年二刷武功山反穿，两次体验反差真的超大！淡季徒步人少路顺、体验感拉满，五一旺季人挤人、排队崩溃，还踩了自驾停车大坑。整体来说，十里竹筏、山地越野车、8号餐厅莲花血鸭完全值得冲，孽龙洞性价比一般。虽然两次反穿都累到腿废，但武功山的草甸全景、山野风光永远让人着迷，每次登顶都有不一样的治愈感！</p><p>最最重要的就是自驾停车避坑！听劝！千万别复刻我们折返取车的悲惨经历！</p><img src="http://imgbed.leihub.cn/img/%E9%9B%86%E4%BD%93%E6%89%93%E5%8D%A1.jpg" /></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/1038/</id>
      <title type="text">2026黄山两日游｜株洲出发，黄山两日20公里爬山记录</title>
      <published>2026-04-17T16:06:21.000Z</published>
      <updated>2026-05-07T16:40:12.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/1038/"/>
      <summary type="text">从株洲出发特种兵刷完黄山两日线！全程暴走20公里，日出、云海、天都峰、西海大峡谷全打卡✨ 所有路线、交通、踩坑点都是亲测实况，不用到处翻攻略了，新手直接抄作业就行！ 一、全程交通｜超详细换乘 我们的路线：株洲→长沙→黄山北站→黄山景区，全程</summary>
      <content type="html"><![CDATA[<p>从株洲出发特种兵刷完黄山两日线！全程暴走20公里，日出、云海、天都峰、西海大峡谷全打卡✨ 所有路线、交通、踩坑点都是亲测实况，不用到处翻攻略了，新手直接抄作业就行！</p>
<img src="http://imgbed.leihub.cn/img/1f97759b903264025cbe413f3f96f85e.jpg" alt="1f97759b903264025cbe413f3f96f85e" />
<section><h2>一、全程交通｜超详细换乘<a href="#一全程交通超详细换乘"><span>#</span></a></h2><p>我们的路线：<strong>株洲→长沙→黄山北站→黄山景区</strong>，全程公共交通，不想自驾的朋友完全可以这么走，省事又省钱。</p><img src="http://imgbed.leihub.cn/img/%E7%81%AB%E8%BD%A6.png" /><section><h3>1、高铁出行<a href="#1高铁出行"><span>#</span></a></h3><p>我们提前一晚从株洲去长沙落脚，第二天早上7点坐高铁直达黄山北，车程大概6小时，下午1点左右到站，时间刚好衔接登山，不早不晚刚刚好。</p></section><section><h3>2、黄山北站→慈光阁<a href="#2黄山北站慈光阁"><span>#</span></a></h3><p>出站不用打车！直接打开<strong>黄山旅游官方小程序</strong>买景区班车票，车程一小时左右，直接送到慈光阁入口，班次很多，完全不用慌。</p></section><section><h3>3、景区内部接驳小细节<a href="#3景区内部接驳小细节"><span>#</span></a></h3><p>到慈光阁之后分两种上山方式，大家看自己体力选就行：</p><ul>
<li><strong>步行上山</strong>：不用额外花钱，但要坐5分钟免费景区班车才能到真正的步行入口！别傻乎乎直接原地走，会走错路。</li>
<li><strong>索道上山</strong>：直接坐玉屏索道，适合体力一般、不想太累、赶时间的朋友。</li>
</ul></section><section><h3>4、返程超级大坑（很多人踩雷）<a href="#4返程超级大坑很多人踩雷"><span>#</span></a></h3><p>我们是云谷索道下山，返程买票一定要注意！两个路段用的是不同小程序，千万别搞错：</p><ul>
<li>
<p>云谷寺→汤口换乘中心：<strong>黄山旅游官方小程序</strong>买票</p>
<img src="http://imgbed.leihub.cn/img/%E9%BB%84%E5%B1%B1%E5%B0%8F%E7%A8%8B%E5%BA%8F.png" />
</li>
<li>
<p>换乘中心→黄山北站：<strong>中交出行小程序</strong>买票！官方小程序买不了！现场排队巨多人，千万别临时买！</p>
</li>
</ul><img src="http://imgbed.leihub.cn/img/%E4%B8%AD%E4%BA%A4.png" /><p>✨小提醒：班车有运营时间，下午尽量早点下山，别卡点赶末班车，真的会焦虑！</p></section></section>
<section><h2>二、两日行程实况｜20公里暴走累瘫但巨值！<a href="#二两日行程实况20公里暴走累瘫但巨值"><span>#</span></a></h2><img src="http://imgbed.leihub.cn/img/%E8%A1%8C%E7%A8%8B.png" /><section><h3>Day1 周六｜冲天都峰、看日落、住白云宾馆<a href="#day1-周六冲天都峰看日落住白云宾馆"><span>#</span></a></h3><p>✅ <strong>前一晚</strong>：株洲出发到长沙，住在高铁站旁边，第二天早起赶车超级方便，不用慌慌张张。</p><p>✅ <strong>早上7点高铁</strong>：长沙出发直奔黄山，时间卡得刚刚好。</p><p>✅ <strong>下午1点进慈光阁</strong>：这里重点提醒！<strong>天都峰下午2&lt;30就停止检票&gt;</strong>！我们到的时候时间特别赶，全程小跑不敢停。刚进山的路超级友好，坡度很缓，一路上都是树，还有小溪流水，风吹着全是草木清香，完全是轻松热身的状态，走起来特别舒服。</p><img src="http://imgbed.leihub.cn/img/%E6%85%88%E5%85%89%E9%98%81.jpg" /><p>✅ <strong>天都峰攀爬实况（全程心惊胆战）</strong>：走完热身路段，从新道口进去就是天都峰硬核路段，难度直接翻倍！好多阶梯几乎90度垂直，全程必须抓着铁链慢慢挪，真的步步惊心。中途会经过一线天，最吓人的就是鲫鱼背，短短十几米，最窄的地方只能一个人过，两边都是悬空的，恐高的朋友真的会腿软。</p><img src="http://imgbed.leihub.cn/img/%E9%B2%AB%E9%B1%BC%E8%83%8C.jpg" /><p>咬牙登顶之后，一路走到玉屏峰，打卡标志性的千年迎客松，现场看真的超有氛围感。慢慢往光明顶方向走，傍晚刚好遇上山间日落，漫天余晖真的太治愈了！不过爬完整个人累到不行，双腿巨酸。而且山顶信号超级差，我的小米手环全程没记录到徒步轨迹，白白暴走一天，真的有点可惜。</p><img src="http://imgbed.leihub.cn/img/%E8%BF%8E%E5%AE%A2%E6%9D%BE.jpg" /><p>✅ <strong>住宿：白云宾馆</strong>：好不容易抢到的标间，1500一晚，说实话真的肉疼，钱包直接被掏空！但不得不说山顶位置真的绝，看完日落走路就能到，不用折腾。酒店福利也很贴心，<strong>免费借看日出的棉服、头灯，还含第二天早餐</strong>，不用自己背厚重衣服，这点真的救大命。休整一晚，准备凌晨冲日出！</p></section><section><h3>Day2 周天｜凌晨追日出、暴走西海大峡谷、圆满下山<a href="#day2-周天凌晨追日出暴走西海大峡谷圆满下山"><span>#</span></a></h3><p>✅ <strong>凌晨4点冲光明顶</strong>：为了看日出真的拼了！四点直接起床，空腹摸黑上山，靠着酒店借的头灯照明。到山顶的时候已经挤满人了，赶紧抢占位置蹲日出。亲眼看着太阳从云海里面慢慢升起来，金光铺满整座山谷，那一刻真的觉得早起、累全都值了！</p><img src="http://imgbed.leihub.cn/img/%E6%97%A5%E5%87%BA.jpg" /><p>✅ <strong>意外收获：绝美流动云海</strong>：看完日出准备走，回头突然看到大片流动的云海！云雾绕着群山飘来飘去，仙气满满。别人说看黄山风景“八分饱”是最好的状态，这次真的被风景喂饱了，运气直接拉满！</p><img src="http://imgbed.leihub.cn/img/%E4%BA%91%E6%B5%B7.jpg" /><p>✅ <strong>早上6点早餐休整</strong>：看完云海回酒店吃早餐，狠狠补充体力，因为接下来的路才是最虐的！</p><p>✅ <strong>徒步西海大峡谷（9.5公里纯暴走）</strong>：休整完直接冲西海大峡谷！全程9.5公里，前一天爬完天都峰，我的膝盖和腿已经完全肌无力了，但还是坚持全程徒步，没坐小火车。</p><p>这条路真的巨虐！先一路陡坡下到海拔1000米的谷底，峡谷风景确实震撼，视野超级开阔。但下得有多爽，爬上来就有多累！全程高强度爬坡，中途还遇到超窄超陡的小鲫鱼背路段，必须小心翼翼慢慢走，走完整个人直接累瘫，但景色真的绝美。</p><img src="http://imgbed.leihub.cn/img/%E8%A5%BF%E6%B5%B7%E5%A4%A7%E5%B3%A1%E8%B0%B7.jpg" /><p>✅<strong>两日20公里圆满收官</strong>：艰难走出西海大峡谷，经过北海景区，最后走到云谷索道路口下山。整整两天，累计暴走<strong>20公里</strong>！</p><p>真心觉得黄山又险又美，虽然全程腿废、钱包也空，但亲眼看到了日出、云海、奇松、峡谷，所有疲惫全部抵消，这趟旅程真的超值得！</p><img src="http://imgbed.leihub.cn/img/%E8%BD%A8%E8%BF%B9.jpg" /></section></section>
<section><h2>三、重点避坑注意事项<a href="#三重点避坑注意事项"><span>#</span></a></h2><section><h3>1、黄山门票一定要提前抢<a href="#1黄山门票一定要提前抢"><span>#</span></a></h3><p>黄山门票真的超级紧张！每天只放3万张，周末、旺季基本秒空。我当时买的时候都已经只能候补了，差点没票进山，大家一定别临时抱佛脚，提前3-5天蹲票！</p></section><section><h3>2、天都峰预约比门票更卷！<a href="#2天都峰预约比门票更卷"><span>#</span></a></h3><p>划重点！<strong>先买黄山门票，才能预约天都峰</strong>，预约是免费的，但名额极少，一天只放3000个！必须提前三四天预约，纯纯手慢无。我同行的小伙伴就没约上，全程没能登顶天都峰，真的巨遗憾！</p><img src="http://imgbed.leihub.cn/img/%E5%A4%A9%E9%83%BD%E5%B3%B0%E9%A2%84%E7%BA%A6.jpg" /></section><section><h3>3、山顶住宿真心贵<a href="#3山顶住宿真心贵"><span>#</span></a></h3><p>山顶酒店普遍溢价严重，想看日出图方便，就选白云宾馆、光明顶附近，位置最好；想省钱的朋友可以住山下汤口镇民宿，性价比高很多。</p></section></section>
<section><h2>四、总结<a href="#四总结"><span>#</span></a></h2><p>这条两日路线还挺适合株洲、长沙周边周末短途出游。行程紧凑但不瞎赶路，黄山核心美景全部打卡到位。只要提前抢好门票和约好天都峰，新手也能轻松玩转！</p><img src="http://imgbed.leihub.cn/img/%E5%B0%8F%E9%B2%AB%E9%B1%BC%E8%83%8C.jpg" /></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/997/</id>
      <title type="text">阿雷的2025年个人年终总结</title>
      <published>2026-01-26T15:26:56.000Z</published>
      <updated>2026-03-07T16:52:56.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/997/"/>
      <summary type="text">引言：致匆匆又充实的2025 时间过得是真快啊，一眨眼2025年就没了，又到了每年必做的总结环节～ 今年最意外的就是换了个部门，比起2024年，工作强度真的降了不少，总算把上一年攒下的疲惫给缓过来了。也正因为不那么忙了，我才有多余的时间享受</summary>
      <content type="html"><![CDATA[<section><h1>引言：致匆匆又充实的2025<a href="#引言致匆匆又充实的2025"><span>#</span></a></h1><p>时间过得是真快啊，一眨眼2025年就没了，又到了每年必做的总结环节～ 今年最意外的就是换了个部门，比起2024年，工作强度真的降了不少，总算把上一年攒下的疲惫给缓过来了。也正因为不那么忙了，我才有多余的时间享受下班生活，重新捡回了羽毛球，开启我的“羽毛球复建计划”，还意外入了户外徒步的坑。最近这半年，基本保持着两三周一山的节奏，对于我们这种天天久坐的打工人来说，徒步真的就是救命良药，爬完浑身都通透了！</p></section>
<section><h1>一、生活：简单而纯粹<a href="#一生活简单而纯粹"><span>#</span></a></h1><p>2025年生活主打一个简单纯粹，住公司宿舍，两点一线（公司→宿舍），没有复杂的琐事，也没完成去年定下的脱单小目标😂 日常下班回去，要么打打球放松身心，要么玩会儿游戏解压，平淡却也充实，除此之外，还有几个值得纪念的小瞬间。</p><p>1）提车时刻：2025年最值得纪念的小事就是我终于提车辣，在爸妈千呼万唤的催促下，我终于拥有了自己的小车，出行不用打车看城铁颜色了，偶尔开车出去兜兜风，去周边徒徒步，解锁了新的生活形态~</p><img src="http://imgbed.leihub.cn/img/image-20260126221256971.png" alt="image-20260126221256971" /><p>2）厂BA回忆：今年公司组队参加了厂BA，一闯进淘汰赛，就拉着我们去当啦啦队，也算正式体验了一把现场篮球观赛的快乐！可惜我一到场，公司球队就输了，真的太扎心了so sad。</p><img src="http://imgbed.leihub.cn/img/03520ffb74068621f078671423042f30.jpg" alt="03520ffb74068621f078671423042f30" /><p>3）湘超狂热粉日常：作为实打实的足球迷，今年湘超一开始举办，我就全程蹲守赛事！只要能抢到票，每一场比赛都不会缺席，可最大的难题就是抢票太难了，忍不住吐槽一句：湘超的票到底是谁在抢啊😭 株洲队常规赛发挥超稳，可惜最后淘汰赛状态拉胯，完全没打出我理想中的水平，真的有点遗憾。</p><img src="http://imgbed.leihub.cn/img/a710679aa485a4dd86319f49a3012726.jpg" alt="a710679aa485a4dd86319f49a3012726" /><p>4）KPL线下初体验：虽然我不怎么看KPL，王者荣耀也弃坑好久了。这次KPL季后赛，被龙哥硬拉着去看狼队比赛——我之前常线上看LPL，从来没去过线下观赛，也算曲线救国，补齐了没看过电竞现场的遗憾。没想到重庆狼队在不被看好的情况下，一路逆袭杀进鸟巢决赛，可惜最后惜败，没能见证夺冠，有点小可惜。</p><img src="http://imgbed.leihub.cn/img/81b2b51b91eba89a494613e0045b491e.jpg" alt="81b2b51b91eba89a494613e0045b491e" /></section>
<section><h1>二、2025年度游戏回顾：快乐就好<a href="#二2025年度游戏回顾快乐就好"><span>#</span></a></h1><p>2025年我的精力主要放在户外运动上，游戏上花的时间比往年少了很多，除了朋友拉着联机开黑，平时几乎不主动上线，主打一个劳逸结合，用游戏缓解上班带来的疲惫，不沉迷、不内耗，快乐就好～</p><p>1）三角洲行动：今年上半年一度玩得特别上头，可深入玩下去后，彻底感受到了策划的深深恶意😭 游戏里养了一堆工作室，还一个劲打压普通玩家的游戏生态，对外挂更是放任不管，我这种鱼塘局都能遇到一堆外挂，举报了也不封号。经历几次策划“不做人”的操作后，我彻底对这款游戏无感，下半年就果断弃坑了。</p><img src="http://imgbed.leihub.cn/img/image-20260126192856983.png" alt="image-20260126192856983" /><p>2）英雄联盟：我本来就是个玩了好几年的大乱斗咸鱼玩家，之前已经有点玩腻了，上号频率越来越低。没想到今年策划搞了个roguelike模式的海克斯大乱斗，直接把大乱斗的随机性和趣味性拉满！年底连着玩了一个月海克斯大乱斗，真的玩爽了，瑞天帝、双刀流薇恩、一板一眼杰斯，哪怕是抑郁症过来，玩上几局都得笑出声😂</p><img src="http://imgbed.leihub.cn/img/image-20260126193707359.png" alt="image-20260126193707359" /><p>3）崩坏星穹铁道：崩铁算是我今年游戏里的意外惊喜！本来我都处于半退坑状态了，结果周年庆抽奖时，居然靠狗运抽到了一本纪念册设定集——别人都得满勤做任务才能拿到，我这个常年不满勤的人居然抽中了，当时开心到起飞～</p><img src="http://imgbed.leihub.cn/img/b76864c0c5195dbdd036bf8ec1b269f1.jpg" alt="b76864c0c5195dbdd036bf8ec1b269f1" /><p>4）赛尔号：这波真的是爷青回！之前因为忘记密码，尝试了好多次都没能找回米米号，本来都不抱希望了，大概是淘米快撑不住了？今年账号找回变得异常简单，只需要提交一些简单的验证材料，居然真的把童年的账号找回来了！上号第一件事就冲了个年费，不为别的，就为了弥补自己曾经逝去的童年回忆。</p><img src="http://imgbed.leihub.cn/img/4a49f9be67706e9696344152cae7ac88.jpg" alt="4a49f9be67706e9696344152cae7ac88" /><p>今年大部分精力都放在户外徒步和运动上，游戏时间减少其实也是件好事。毕竟上班对着电脑，下班玩游戏还是对着电脑，对眼睛和腰背都不太友好，非必要确实要尽量减少电脑游戏时间，但要说戒掉游戏，那是不可能的～ 游戏依旧是我忙碌生活里，不可或缺的解压小方式。</p></section>
<section><h1>三、运动：步履不停，在热爱里找回活力<a href="#三运动步履不停在热爱里找回活力"><span>#</span></a></h1><p>去年一年深陷工作忙碌，每天5点吃完晚饭就回工位继续加班，完全没有保持任何运动量，久而久之，体重直接飙升了10斤。当体重秤上的数字变得刺眼，我才真正意识到问题的严重性，于是2025年，我开始有意识地控制体重、坚持运动，把更多精力放在了自己的身体上，也慢慢找回了活力满满的状态～</p><img src="http://imgbed.leihub.cn/img/06d6def763bec89d6ef09658c2ca85e3.jpg" alt="06d6def763bec89d6ef09658c2ca85e3" /><p>**羽毛球：**今年最大的收获之一，就是重新捡回了羽毛球这项运动。慢慢凑起了几个固定的球搭子，默契十足，每周二、四、六下班，我们都会第一时间冲去羽毛球场，卸下一天的工作疲惫，酣畅淋漓打一场球。这一年下来，羽毛球技巧确实有了长足进步，但说实话，依旧没摸到入门的门槛，失误率还是很高，反手要么打不过渡球，要么根本打不到后场，短板十分明显。</p><p>身边也有人建议我请个私教系统学习，但我觉得没必要太过较真，没有请私教，就和球搭子们随意打、开心打，哪怕进步慢一点也没关系。运动的初衷本就是放松和解压，不用追求专业水准，能在挥洒汗水中收获快乐，就足够了。</p><img src="http://imgbed.leihub.cn/img/082052a4d44a4eed817f75b937a5484f.jpg" alt="082052a4d44a4eed817f75b937a5484f" /><p>**减肥：**运动之外，饮食控制也提上了日程。我给自己制定了简单易坚持的饮食计划：早午餐以牛奶咖啡搭配全麦面包、玉米或鸡蛋为主，清淡又顶饱；中午在公司食堂就餐，尽量避开高脂肪、高热量的食物，多吃蔬菜和豆制品，保证营养均衡。</p><p>在不打羽毛球的日子里，我就去公司健身房爬坡一小时，不追求高强度运动，只坚持有氧运动，慢慢燃烧脂肪。经过一段时间的坚持，体重也在一点点稳步下降，虽然还没达到预期目标，但我知道，减肥是一场持久战，“革命尚未成功，同志仍需努力”。2026年，我的小目标是把体重控制到55kg，继续加油！</p><img src="http://imgbed.leihub.cn/img/5673da3a0229273446d0c519b89b42ad.jpg" alt="5673da3a0229273446d0c519b89b42ad" /><p>**徒步：**我对徒步和旅游做了个简单的划分：省内的爬山都归为徒步，省外的出行则算旅游。今年一旦打开了徒步这个“开关”，就彻底停不下来了，和几个徒步搭子更是一拍即合，一到周末就嚷嚷着要去爬个山，要是一周不爬山，就浑身不自在，感觉身上有蚂蚁在爬哈哈哈，妥妥的爬山上瘾体质～</p><img src="http://imgbed.leihub.cn/img/89ffe46e208e2c5b01b58e3a1c9406be.jpg" alt="89ffe46e208e2c5b01b58e3a1c9406be" /><p>1）我的徒步之旅，是从老朋友衡山开始的。今年和兄弟们一起，连续爬了两次衡山，一次走常规路线，一次抄了近道——曾国藩古道。能明显感觉到，经过三个月的运动锻炼，我的体能提升了不少，第二次爬山的速度比第一次快了很多，也轻松了很多，那种循序渐进的进步，真的很有成就感。</p><img src="http://imgbed.leihub.cn/img/a82997666b0421e6b335113060b8214e.jpg" alt="a82997666b0421e6b335113060b8214e" /><p>2）后来入坑了两步路APP，开始尝试走野路子，现在想想还想吐槽一句：这到底是谁在两步路上传的路线啊哈哈哈哈哈！汉王陵-谷山-尖山三穿，直接把我走懵了，尤其是尖山那段，全程都是野路子，需要钻树林、爬陡坡，我们几个人全程骂骂咧咧，累得气喘吁吁，但走完之后，又有种征服困难的快感。</p><img src="http://imgbed.leihub.cn/img/d69f9115ea71a82eb4f52386f7420cfe.jpg" alt="d69f9115ea71a82eb4f52386f7420cfe" /><p>3）狮峰山环线：狮峰山的环线整体不算累，但最后一段路真的让我印象深刻——全程特别滑，我至少滑了十多次，最后裤子上沾满了灰尘，狼狈又好笑。要知道，我当时穿的还是迪卡侬MH500的徒步鞋，防滑效果已经不算差了，真不敢想象，要是穿普通运动鞋来，得滑成什么样。</p><img src="http://imgbed.leihub.cn/img/48528cde579f8370bea435b73b3bd423.jpg" alt="48528cde579f8370bea435b73b3bd423" /><p>4）黑麋峰环线：黑麋峰环线相较于之前爬的山，距离更远一些，从株洲开车过去都要一个多小时。这条环线会途经两个森林公园，从黑麋峰森林公园出发，转到北山森林公园，最后再折回黑麋峰，好在全程路程不算长，我们很轻松就走完了。不过有个特别气人的小插曲：当时我用action4录制徒步视频，不小心调成了1/8倍速，导致全程都没有录到声音，给我气的半死。</p><img src="http://imgbed.leihub.cn/img/8a9da66899b037747f5e28981736df75.jpg" alt="8a9da66899b037747f5e28981736df75" /><p>5）九郎山环线：九郎山算是我们的徒步老朋友了，经典环线几乎没有任何难度，谁让株洲50公里以内，好玩的山就没几座呢～ 2025年的徒步收尾，就交给了九郎山。这里必须提醒一句：上九郎山千万不要开车，尤其是周末，堵车堵到怀疑人生。</p><img src="http://imgbed.leihub.cn/img/a1dfd5bcd73f5ebe97ecf559b199202b.jpg" alt="a1dfd5bcd73f5ebe97ecf559b199202b" /><p>回望2025年，户外徒步和羽毛球运动，填满了我的业余生活。去年的充实，全是工作赋予的；而今年的充实，是运动和热爱赋予的。2026年，我会继续保持运动的热情，达成更多运动量，成功把体重降下来，争取把湖南周围的山，都爬个遍，解锁更多徒步新路线～</p></section>
<section><h1>四、旅游：步履所至，皆为风景<a href="#四旅游步履所至皆为风景"><span>#</span></a></h1><p>1） 北京｜3月匆忙的出差之旅：新年的第一个出行地点没想到是北京，周末突然接到电话要求到北京出差，一下子就把我可怜的周末给占用了。完成工作后，怎么能错过利用有限时间“公费旅游”的机会呢？毕竟是祖国壮丽的首都呀哈哈～ 上次来北京已经逛过故宫，这次就重点打卡了天坛，感受京城的厚重底蕴，也算不辜负这趟匆忙的出差。</p><img src="http://imgbed.leihub.cn/img/26bdc8f6c5ff60cf0054e5eaa457b2b4.jpg" alt="26bdc8f6c5ff60cf0054e5eaa457b2b4" /><p>2）武汉｜5月重温旧时光：趁着超哥5月婚礼，我终于回了一趟武汉。再次踏上这片熟悉的土地，心中满是物是人非的感慨——以前住的宿舍，现在居然改成了酒店，周围一圈发展得像CBD一样，我都快认不出，这还是当年那个老破小的鱼区吗？刚提车就开车去了武汉，两天一起开了1000多公里，还在路上就被交警电话警告疲劳驾驶了。</p><img src="http://imgbed.leihub.cn/img/075ddff1febfebfa4fb51aecd692f698.jpg" alt="075ddff1febfebfa4fb51aecd692f698" /><p>3）宜昌、恩施｜8月高温假，带着爸妈的自驾游：提车后的第二次出省出行，选在了高温假，趁着假期，带着爸妈一起自驾游，主打一个“走到哪玩到哪”，轻松自在，也好好陪了陪爸妈。</p><p>我们先去了宜昌：第一天直奔长江边，看看江边的夜景，吹吹宜昌的晚风，第二天上午游清江画廊，绿水如翡翠，下午打卡三峡大瀑布，穿瀑体验超级刺激。宜昌的最后一天，欣赏了震撼的大国工程—两坝一峡。</p><img src="http://imgbed.leihub.cn/img/73fb57270229aa6022e129caa45ece6c.jpg" alt="73fb57270229aa6022e129caa45ece6c" /><p>告别宜昌，我们又去恩施玩了两天：第一天逛了恩施大峡谷，为了照顾爸妈的体力只走了地缝，两边岩壁直直的，还有小瀑布，看着就像原神稻妻的无想仞狭间哈哈哈。第二天去腾龙洞，不愧是亚洲最大溶洞，洞顶高到看不见头，传说能装1000万人，里面的表演也超好看。</p><img src="http://imgbed.leihub.cn/img/930a61064668abd4cc5d0de5717c1a64.jpg" alt="930a61064668abd4cc5d0de5717c1a64" /><p>这次湖北之行开了两千多公里，回去直接累趴，在家躺了一天才缓过来。</p><p>4）桂林｜8月部门团建：刚去了宜昌，隔一周部门又组织去桂林，首先去古东景区爬瀑布，算是一个比较新奇的体验。然后是漓江冠岩，溶洞灯光土得像KTV，10分钟就想溜。漓江竹筏赶上雨天，漓江水浑得不行，让我对此次旅程有点失望。</p><img src="http://imgbed.leihub.cn/img/47deb7907a4f1bfdad4189c52e206f56.jpg" alt="47deb7907a4f1bfdad4189c52e206f56" /><p>5）武功山｜9月首次高强度徒步挑战：之前高温假的时候，我已经正穿过一次武功山，而9月，朋友又拉着我去武功山反穿，这也是我的第一次高强度户外徒步挑战。全程爬了整整12个小时，累到怀疑人生，中途无数次想放弃，但当登上山顶，看到连绵起伏的绿色草甸，吹着山间的风，所有的疲惫都烟消云散，那一刻，觉得所有的坚持都值得。</p><img src="http://imgbed.leihub.cn/img/001ef8f41e35f11763e9a969ac2bf7a2.jpg" alt="001ef8f41e35f11763e9a969ac2bf7a2" /><p>6）佛山、深圳｜9月第二次出差，解锁岭南风味：又是一次突击出差，9月这次来到了祖国的南方，和同学一起逛了佛山的清辉园、渔人码头。然后去了一趟深圳，不仅吃了正宗的广式早茶，粥底火锅、仙庙烧鸡、桑拿鸡，每一样都让人回味无穷，最后还去深圳湾逛了一圈，吹着海风，放松身心，这趟出差，也算吃喝玩乐两不误。</p><img src="http://imgbed.leihub.cn/img/603bd4db33b6d1313a926d5cfa87cf34.jpg" alt="603bd4db33b6d1313a926d5cfa87cf34" /><p>7）天堂在左，雨崩在右 | 国庆徒步之旅：作为一名户外新手，今年国庆被同事“拐”去雨崩，5 天 4 夜的行程，尼农+冰湖+神瀑，一共徒步了50公里，有高反的狼狈、徒步的极限，也有星空下的青旅和冰瀑前的震撼。</p><img src="http://imgbed.leihub.cn/img/627c76c86003bf0e60fad0cafe7f8237.jpg" alt="627c76c86003bf0e60fad0cafe7f8237" /><p>8）三清山-10月特种兵一日游，速通大环线：周末朋友拉着去三清山徒步，走的大环线，本来想着预计花两天慢慢爬，整体难度不高，结果我们 6 小时就把大环线刷完了，为了节省时间下山就扛着火车跑回湖南了哈哈哈，纯爬山。</p><img src="http://imgbed.leihub.cn/img/f1401da33ac26e497d61f37eb844c2b4.jpg" alt="f1401da33ac26e497d61f37eb844c2b4" /><p>9）白鹤洲｜12月年底观鸟之旅，解锁新体验：年底的时候，鄱阳湖白鹤洲观鸟在小红书上特别火，我也跟着凑了个热闹，拉着朋友一起，开启了一场“高雅”的观鸟之旅。观鸟还是得带专业设备，在场都是超长的”炮筒“，我一个小手机完全拍不清，还在白鹤洲上还给我冻得不轻哈哈哈哈。</p><img src="http://imgbed.leihub.cn/img/f5b6e00f44b3e47ae8d14d9e441ffdcb.jpg" alt="f5b6e00f44b3e47ae8d14d9e441ffdcb" /><p>2025年去了不少地方，比如美丽的雨崩，艰难的武功山，冻死人的白鹤洲，速通的三清山，还有许多没来得及去的地方，2026年想进一步解锁，比如南太行、麦理浩径，峨眉山、黄山。。。这么多美丽的河山还等着我去探索。</p></section>
<section><h1>五、工作：慢慢沉淀成长<a href="#五工作慢慢沉淀成长"><span>#</span></a></h1><p>今年是我转正后的第二年，已经正式开始主管项目。由于上半年在原部门工作、下半年调整部门，全年仅主管了3个项目，同时参与了多个不同系列的电机设计项目，在实践中慢慢沉淀、逐步成长，也清晰认识到自身的优势与不足，收获满满。</p><section><h2>主管项目<a href="#主管项目"><span>#</span></a></h2><p>1）发电机项目：这是我独立主管的第一款电机项目，项目基于现有电磁平台进行衍生设计，通过这个项目，我在电机总体结构、电磁方案、尺寸链设计以及与客户对接外形需求等方面，都获得了长足进步，也奠定了后续主管项目的基础。</p><p>2）飞轮电机项目：项目整体难度不大，电磁方案由客户主导设计，我们主要负责定转子施工设计，大部分精力都投入到与客户的沟通对接中。也正是这个项目，让我意识到自身沟通能力还有提升空间，有时与客户沟通常做无用功，一些返工、工艺优化相关的沟通处理，消耗了较多时间和精力。</p><p>3）高速电机项目：基于现有电机的设计，更新轴承配置方案，主要精力内部沟通，图纸很快完成下发，但电机试制的进度太慢了，年底才做完制造，现在还没开始做试验。</p></section><section><h2>参与项目<a href="#参与项目"><span>#</span></a></h2><p><strong>1、高速系列项目</strong></p><p>1）公司组建新项目组时，我被纳入其中，在项目组中，我主要负责机械仿真和图纸绘制，也借此学会了高速转子动力学计算、薄壁件屈曲失稳仿真，对机械计算有了更深入的认识和掌握。</p><p>2）同时，还参与了小型高速气浮电机项目，这是我第一次接触气浮轴承相关电机设计，虽未深入参与核心设计，但也初步了解了气浮轴承的相关知识，算是意外收获。</p><p><strong>2、船用电机系列项目</strong></p><p>全年参与了多个不同功率级别船用电机的图纸绘制和机械仿真工作，核心难点集中在绝缘设计上。这几套图纸前前后后修改了三四版，反复调整优化，着实花费了不少功夫，也让我在细节把控上得到了锻炼。</p><p><strong>3、磁浮电机系列项目</strong></p><p>1）参与了大型高速永磁电机项目，负责磁浮轴承及轴承座的设计，这是我第一次接触磁浮轴承相关设计，好在有主管的耐心指导，最终顺利完成了一整套磁浮轴承的图纸绘制；后续还参与了一款磁浮轴承高速电机的转子绘制，也算完整接触了磁浮轴承定转子的设计流程。</p><p>2）此外，还初步参与了一个飞轮电机项目，负责部分零部件强度校核和转子动力学计算，虽仅参与前期工作，最终未采用我的设计方案，但也有效提升了自身的仿真能力。</p><p>4、<strong>常规电机项目</strong></p><p>参与了多个项目电机的图纸绘制和校核工作，有个项目给我敲响了警钟——项目评审时流于形式，未仔细校核实物与图纸的一致性，部分尺寸未经严谨思考就做出让步，后续出现了出线设计不合理、尺寸偏差等问题，导致零部件返工，多次熬夜处理后续整改工作，深刻体会到细节严谨的重要性。</p></section><section><h2>存在的不足与反思<a href="#存在的不足与反思"><span>#</span></a></h2><p>存在的不足主要还是在沟通方面吧，与同事、领导、客户的沟通存在效率低下的情况，这个能够进一步提升的话，可以大大改进个人的工作效率。</p><p>负责和参与项目时，也不够细心和耐心，往往是急于完成任务，急急忙忙的做完，在图纸校核和评审的时候常常暴露出一堆问题，反过来有严重影响自己的工作效率。</p></section><section><h2>工作中的小感悟<a href="#工作中的小感悟"><span>#</span></a></h2><p>全年通过主管和参与各类项目，专业能力得到了显著提升：熟练掌握了电机图纸绘制、机械仿真相关技能，新增了高速转子动力学计算、薄壁件仿真、磁浮轴承设计等相关经验，对不同类型、不同用途电机的设计思路、核心难点，有了更全面的认识。</p><p>后续工作规划的话，还是先把高速电机、机械仿真这一块吃透，然后逐步了解电磁方面的知识，努力成为一名电机设计的“全栈工程师“吧。</p></section></section>
<section><h1>六、全年回望与2026期许<a href="#六全年回望与2026期许"><span>#</span></a></h1><p>2025年这一年，过得挺充实，也挺有意义。工作上，从跟着别人做项目，到自己独立管项目，慢慢成长，专业能力也在提升；生活上，简单又自在，提了车、解锁了新生活，运动和旅游填满了业余时间，游戏也玩得开心，整体收获满满。</p><p>2026年，希望生活上顺顺利利，坚持运动减体重，多爬几座山、多去几个地方，慢慢变好，不辜负美好时光。</p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/995/</id>
      <title type="text">2026 元旦宜春行：万载烟花盛会与明月山冬日徒步记</title>
      <published>2026-01-13T17:01:23.000Z</published>
      <updated>2026-03-08T03:49:19.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/995/"/>
      <summary type="text">一、烟花晚会 2026 年元旦的快乐，始于好朋友鱼包哥的邀请 —— 他是万载人，之前跟我们炫耀老家是 “中国花炮之乡”，这次恰逢万载县烟花爆竹总商会 30 周年庆典，直接喊我们来免费看大型焰火晚会，还说有明星助阵！ 晚会在龙湖公园开阔地带举</summary>
      <content type="html"><![CDATA[<section><h2>一、烟花晚会<a href="#一烟花晚会"><span>#</span></a></h2><p>2026 年元旦的快乐，始于好朋友鱼包哥的邀请 —— 他是万载人，之前跟我们炫耀老家是 “中国花炮之乡”，这次恰逢万载县烟花爆竹总商会 30 周年庆典，直接喊我们来免费看大型焰火晚会，还说有明星助阵！</p><img src="http://imgbed.leihub.cn/img/IMG_20260101_213851.jpg" alt="IMG_20260101_213851" /><p>晚会在龙湖公园开阔地带举办，天黑后花炮秀暖场，色彩、造型都拿捏到位，不愧是花炮之乡，比春节自购烟花震撼百倍，我举着手机拍全程，内存都告急了。</p><img src="http://imgbed.leihub.cn/img/IMG_20260101_204225.jpg" alt="IMG_20260101_204225" /><p>更惊喜的是有戴羽彤、游鸿明、江映蓉等明星献唱，我直接被戴羽彤圈粉，真人颜值能打，散场就冲去微博关注，循环《来迟》《孤独颂歌》停不下来。</p><img src="http://imgbed.leihub.cn/img/IMG_20260101_202320.jpg" alt="IMG_20260101_202320" /><p>本计划次日宅家补觉，可晚会送了免费明月山门票，不薅这羊毛太亏，当即拍板：冲明月山，主打一个说走就走！</p></section>
<section><h2>二、开局即 “波折”<a href="#二开局即-波折"><span>#</span></a></h2><p>元旦假期的明月山人气爆棚！中午 12 点多赶到景区，停车场入口早已堵成长龙，广播循环播报 “车位已满”。无奈之下，我们只能把车停在景区外临时停车场，顶着零度寒风步行 1 公里冲向游客中心。</p><p>刚出发就瞥见山顶雾凇皑皑，没做攻略的特种兵式爬山，竟撞上这般美景，幸运值直接拉满。谁知才爬 2000 级台阶，就被半山腰工作人员拦下 —— 因云谷深处路段结冰，景区禁止步行登山，只能缆车上山且中站不下客。我们和其他游客软磨硬泡，最终录下自愿担责的免责视频，才得以继续进山。</p></section>
<section><h2>三、爬山初体验<a href="#三爬山初体验"><span>#</span></a></h2><p>元旦穿了加绒冲锋衣配秋衣，本以为山里天寒，结果爬山不到二十分钟就浑身发热，后背的汗把衣服浸得透湿。赶到第一个休息平台，我赶紧扒掉加绒内衬，脱衣瞬间，身上的热气撞上冷空气，都开始冒白烟了。</p><p>刚收拾好衣服抬头望，瞬间被惊艳到 —— 远处山峰裹着厚厚一层雾凇，阳光穿透云层洒下来，冰棱折射出细碎的光，宛如闯进了童话仙境。此前只在图片里见过雾凇，亲眼所见时，连呼吸都不自觉放轻，生怕惊扰了这片如梦似幻的景致。</p><img src="http://imgbed.leihub.cn/img/IMG_20260102_134639.jpg" alt="IMG_20260102_134639" /></section>
<section><h2>四、6381 级台阶<a href="#四6381-级台阶"><span>#</span></a></h2><p>明月山的登山道全是石阶，全程大概 7000 级，我们最终爬到山顶走了 6381 级，每一步都算数（也都累到算数）！后来才知道，其实明月山有三条路线可选，大家可以按需选择：</p><ul>
<li>懒人轻松线（4-5h）：景区大门→观光车（10 元）→缆车上行（80 元）→山顶观光车（15 元）→青云栈道→月亮湖→缆车下行（70 元），全程几乎不用爬，适合家庭和怕累星人，3100 米悬空栈道 + 云海直接打卡。</li>
<li><strong>经典徒步线（6-7h）</strong>：景区大门→徒步至五叠泉瀑布群（2h）→缆车中站→登顶→青云栈道→返程，能看 119 米云谷飞瀑 + 鱼鳞瀑，层峦叠嶂超治愈，我们走的就是这个路线。</li>
<li>硬核穿越线（2 天 1 夜）：明月山→高山小火车（30 元）→羊狮慕→徒步栈道→宿山顶帐篷，能解锁日出星空 + 两景区秘境，户外爱好者可以冲。</li>
</ul><img src="http://imgbed.leihub.cn/img/image-20260114005221663.png" alt="image-20260114005221663" /><img src="http://imgbed.leihub.cn/img/image-20260114005231306.png" alt="image-20260114005231306" /><p>我们走的就是经典徒步线的路段，登山初期的路段毫无压力。路面基本没有冰雪覆盖，石阶平整好走，沿途伴着小桥流水，偶尔还能看见山泉从冰缝里汩汩冒出来，清澈得能见底。</p><img src="http://imgbed.leihub.cn/img/IMG_20260102_141315.jpg" alt="IMG_20260102_141315" /><p>越往上走，石阶上的冰雪就越厚，原本轻松的散步模式直接切换成小心翼翼的防滑模式。景区很贴心，在结冰严重的地方铺了麦麸增加摩擦力，但每一步还是得稳着来。行至鱼鳞铺时，因为一路暴走，大脑早就过载，眼镜片上蒙了厚厚一层雾气，眼前一片模糊。不过沿途总能看到工作人员拿着铲子扫雪除冰，零下几度的天气里，真的要给这群守护者狠狠点个赞！</p><img src="http://imgbed.leihub.cn/img/IMG_20260102_145911.jpg" alt="IMG_20260102_145911" /><p>再往后的路段，石阶上的冰雪已经积得有些厚了，只能亦步亦趋慢慢挪。朋友兴致勃勃地想帮我拍张雪地登山照，催着我笑一个，可我累得连嘴角都扯不动，完全笑不出来。</p></section>
<section><h2>五、登顶：云海 雪山 蓝天<a href="#五登顶云海-雪山-蓝天"><span>#</span></a></h2><p>从山脚到山顶，我们足足走了 3 小时。快到山顶时，余光瞥见缆车从头顶掠过，抬头望去，阳光穿透云雾，天空澄澈得像被水洗过一般，白雪覆盖的群山在阳光下泛着耀眼银光，之前积攒的疲惫瞬间烟消云散。</p><img src="http://imgbed.leihub.cn/img/mmexport1767424260552.jpg" alt="mmexport1767424260552" /><p>终于登顶虎背界，站在观景台的那一刻，才算真正读懂 “无限风光在险峰”：远处云海翻涌不息，近处雾凇洁白无瑕，更神奇的是能清晰看到冷空气被明月山阻隔的界限 —— 一边云雾缭绕如仙境，一边晴空万里见苍穹，这般震撼根本无法用语言形容！</p><img src="http://imgbed.leihub.cn/img/IMG_20260102_160031.jpg" alt="IMG_20260102_160031" /><p>山顶的风大得惊人，气温怕是降到了零下，没待多久，头发就结了一层白霜，用手一摸硬邦邦的。山顶还有个人工雪场，不少人在里面滑雪玩闹，可惜我们没带装备，不然真想下场体验一番，有计划来的朋友可别错过这个乐趣！</p><img src="http://imgbed.leihub.cn/img/IMG_20260102_155014.jpg" alt="IMG_20260102_155014" /></section>
<section><h2>六、青云栈道 + 明月湖<a href="#六青云栈道--明月湖"><span>#</span></a></h2><p>到了山顶，后面的路线就是围绕山顶绕一圈，小圈三四公里的样子，大圈就是往明月山庄走，途径青云栈道，最到到达明月湖，回到出发点，全场六七公里的样子。我们选择的是大圈路线。</p><img src="http://imgbed.leihub.cn/img/IMG_20260102_171223.jpg" alt="IMG_20260102_171223" /><p>青云栈道总长约 3 公里，悬在百米悬崖上，走在上面有种 “悬空” 的感觉，给我一种三清山的栈道的即视感。栈道旁的悬崖上挂满了冰挂，脚下是翻滚的云海，偶尔有风吹过，云雾流动的速度肉眼可见，仿佛在仙境中漫步。</p><img src="http://imgbed.leihub.cn/img/mmexport1767424332608.jpg" alt="mmexport1767424332608" /><p>从栈道走出来，就能看到山顶的明月湖，高山湖泊超静谧，我们去的时候刚好是晴天，湖面倒映着蓝天白云和雪山，随手一拍都是壁纸级别的照片。</p><img src="http://imgbed.leihub.cn/img/IMG_20260102_171131.jpg" alt="IMG_20260102_171131" /></section>
<section><h2>七、下山 “噩梦”<a href="#七下山-噩梦"><span>#</span></a></h2><p>快乐总是转瞬即逝，下午 5 点赶到索道上站准备下山，一进候车室直接傻眼 —— 小小的空间里挤得水泄不通。</p><p>元旦的山里天黑得格外快，气温也越来越低。之前把棉内衬脱了，排队时人挤人根本没空间穿，我们只能在队伍里冻得瑟瑟发抖，靠原地跺脚勉强取暖。</p><p>熬到 7 点半终于坐上缆车时，天已经彻底黑透了。下了缆车还得步行 1 公里回停车场，坐进车里的那一刻，全身骨头都在抗议，双腿软得站都站不稳。</p></section>
<section><h2>八、万载攻略<a href="#八万载攻略"><span>#</span></a></h2><section><h3>1. 万载烟花晚会打卡指南<a href="#1-万载烟花晚会打卡指南"><span>#</span></a></h3><ul>
<li>举办契机：关注万载县烟花爆竹总商会相关活动，周年庆典、春节等节点大概率会有大型焰火晚会，偶尔会有明星助阵；</li>
<li>门票福利：部分晚会会联动周边景区送福利（比如我这次的明月山免费票），关注官方公众号或本地朋友消息，能蹲到羊毛；</li>
</ul></section><section><h3>2. 明月山门票福利 &amp; 费用<a href="#2-明月山门票福利--费用"><span>#</span></a></h3><ul>
<li>常规门票 90 元 / 人。</li>
<li>索道往返 150 元（单程上 80 下 70），观光车 10 元 / 次，山顶观光车 15 元 / 次，高山小火车 30 元 / 人，可根据路线按需购买。</li>
</ul></section><section><h3>3. 路线选择<a href="#3-路线选择"><span>#</span></a></h3><ul>
<li>懒人党：直接冲懒人轻松线，全程少走路，美景不打折；</li>
<li>徒步党：经典徒步线能看瀑布群，风景更丰富，预留 6-7 小时足够；</li>
<li>户外党：硬核穿越线需要 2 天 1 夜，记得提前订山顶帐篷，下载离线地图。</li>
</ul></section><section><h3>4. 交通建议<a href="#4-交通建议"><span>#</span></a></h3><ul>
<li>万载→明月山：自驾约 1.5 小时，路况良好；</li>
<li>明月山交通：自驾节假日尽量早8点到景区，避免停车远。</li>
</ul></section><section><h3>5. 万载美食<a href="#5-万载美食"><span>#</span></a></h3><section><h5>（1）花园汤包店<a href="#1花园汤包店"><span>#</span></a></h5><p>鱼包哥强推的花园汤包店，真没踩坑！这老店的汤包绝了，皮薄薄的，咬开一口汤汁直接飙出来，肉馅鲜得很，一点不腻。我们一人狂炫两屉，再配一碗本地炒粉，扎粉炒得油滋滋的，酱香十足，嗦起来贼过瘾，最后吃得扶墙出，肚子圆滚滚的才罢休。</p><img src="http://imgbed.leihub.cn/img/IMG_20260102_094555.jpg" alt="IMG_20260102_094555" /></section><section><h5>（2）百岁我家酸菜鱼<a href="#2百岁我家酸菜鱼"><span>#</span></a></h5><p>晚餐冲了百岁我家酸菜鱼，黑鱼是现杀的，片得薄薄的，吃起来又鲜又筋道。牛蹄也炖得烂乎乎的，一抿就脱骨，酸笋贼下饭，凤爪滑溜溜的吸满了汤汁，味道都挺顶。就是这辣度太猛了，辣到头皮发麻（此处无图）。</p></section></section></section>
<section><h2>总结<a href="#总结"><span>#</span></a></h2><p>这趟元旦之旅，真的把 “惊喜” 拉满了 —— 本来只是冲着朋友的邀请去看烟花，没想到被明星和烟花双重圈粉，还意外解锁了明月山的冬日仙境。有时候旅行的意义，不在于计划多完美，而在于这些不期而遇的美好和波折。</p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/990/</id>
      <title type="text">折腾记录：2025 WordPress 搭建 + 迁移全攻略，Docker / 宝塔 / 插件多方案任选</title>
      <published>2025-11-22T11:10:04.000Z</published>
      <updated>2026-03-08T03:57:35.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/990/"/>
      <summary type="text">一、前言 作为用 WordPress 写了四年博客的老用户，之前分享过不少主题配置、插件推荐的内容，很多朋友问过我怎么安装和迁移 WordPress，毕竟不管是新手入门还是换服务器，这两个都是刚需操作。今天就把我实际用过的几种安装方式和迁移</summary>
      <content type="html"><![CDATA[<section><h2>一、前言<a href="#一前言"><span>#</span></a></h2><p>作为用 WordPress 写了四年博客的老用户，之前分享过不少主题配置、插件推荐的内容，很多朋友问过我怎么安装和迁移 WordPress，毕竟不管是新手入门还是换服务器，这两个都是刚需操作。今天就把我实际用过的几种安装方式和迁移方法整理出来，全是自己踩坑后的实战经验，新手也能跟着走。</p><p>虽然现在有 Hexo、Hugo 这些静态博客，但我还是偏爱 WordPress，主要是因为：</p><ul>
<li>可视化后台，不用懂代码也能管理，写文章、换主题都方便；</li>
<li>插件生态太丰富，想要的功能（统计、评论管理、SEO 优化）基本都有；</li>
<li>可扩展性强，支持自定义代码、二次开发，后期想加功能也不限制；</li>
<li>数据存在自己手里，不用担心平台跑路，迁移也灵活。</li>
</ul><p>如果你是新手，想快速搭建个人博客；或者像我一样，需要长期维护、经常更新内容，WordPress 绝对是首选。</p></section>
<section><h2>二、WordPress 安装：两种主流方式，按需选择<a href="#二wordpress-安装两种主流方式按需选择"><span>#</span></a></h2><section><h3>（一）Docker 安装：适合技术用户，环境隔离不冲突<a href="#一docker-安装适合技术用户环境隔离不冲突"><span>#</span></a></h3><p>我自己的博客就是用 Docker 搭的，优点是环境隔离，不会和服务器上其他软件冲突，迁移也方便。</p><section><h4>1. 准备工作<a href="#1-准备工作"><span>#</span></a></h4><p>先创建一个专属目录，我习惯放在～/docker/wordpress，统一管理配置和数据：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>work</span><span>=</span><span>~/docker/wordpress</span><span> &amp;&amp; </span><span>mkdir</span><span> </span><span>-p</span><span> </span><span>$work</span><span> &amp;&amp; </span><span>cd</span><span> </span><span>$work</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>然后开放端口，我选的是 18080，避免和其他服务冲突，防火墙命令安排上：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># Ubuntu/Debian用ufw防火墙</span></div></div><div><div><div>2</div></div><div><span>sudo</span><span> </span><span>ufw</span><span> </span><span>allow</span><span> </span><span>18080/tcp</span><span> </span><span>comment</span><span> </span><span>'WordPress'</span><span> &amp;&amp; </span><span>sudo</span><span> </span><span>ufw</span><span> </span><span>reload</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># CentOS用firewalld</span></div></div><div><div><div>5</div></div><div><span># sudo firewall-cmd --add-port=18080/tcp --permanent &amp;&amp; sudo firewall-cmd --reload</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section><section><h4>2. 编写 docker-compose.yml<a href="#2-编写-docker-composeyml"><span>#</span></a></h4><p>新建 docker-compose.yml 文件，直接复制下面的配置，注意两个坑：</p><ul>
<li>如果你用的是 arm 架构的服务器，把<code>mysql:5.7</code>改成<code>mysql:oracle</code>，不然会报错；</li>
<li>数据库密码和用户密码一定要改复杂点，别用默认的，我这里只是示例。</li>
</ul><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>---</span></div></div><div><div><div>2</div></div><div><span>version</span><span>: </span><span>'3.0'</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span>services</span><span>:</span></div></div><div><div><div>5</div></div><div><span>  </span><span>db</span><span>:</span></div></div><div><div><div>6</div></div><div><span>    </span><span>image</span><span>: </span><span>mysql:5.7</span><span> </span><span># arm架构的机器请将mysql:5.7改为mysql:oracle</span></div></div><div><div><div>7</div></div><div><span>    </span><span>container_name</span><span>: </span><span>wordpress-db</span></div></div><div><div><div>8</div></div><div><span>    </span><span>restart</span><span>: </span><span>unless-stopped</span></div></div><div><div><div>9</div></div><div><span>    </span><span># command: --max-binlog-size=200M --expire-logs-days=2 # 使用mysql 8.0的小伙伴建议使用</span></div></div><div><div><div>10</div></div><div><span>    </span><span>environment</span><span>:</span></div></div><div><div><div>11</div></div><div><span>      </span><span>MYSQL_ROOT_PASSWORD</span><span>: </span><span>rootpassword</span><span> </span><span># 按需修改</span></div></div><div><div><div>12</div></div><div><span>      </span><span>MYSQL_DATABASE</span><span>: </span><span>wordpress</span></div></div><div><div><div>13</div></div><div><span>      </span><span>MYSQL_USER</span><span>: </span><span>wordpress</span></div></div><div><div><div>14</div></div><div><span>      </span><span>MYSQL_PASSWORD</span><span>: </span><span>yourpassword</span><span> </span><span># 按需修改</span></div></div><div><div><div>15</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>16</div></div><div><span><span>      </span></span><span>- </span><span>'./db:/var/lib/mysql'</span></div></div><div><div><div>17</div></div><div><span>    </span><span>networks</span><span>:</span></div></div><div><div><div>18</div></div><div><span><span>      </span></span><span>- </span><span>default</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span>  </span><span>app</span><span>:</span></div></div><div><div><div>21</div></div><div><span>    </span><span>image</span><span>: </span><span>wordpress:latest</span></div></div><div><div><div>22</div></div><div><span>    </span><span>container_name</span><span>: </span><span>wordpress-app</span></div></div><div><div><div>23</div></div><div><span>    </span><span>restart</span><span>: </span><span>unless-stopped</span></div></div><div><div><div>24</div></div><div><span>    </span><span>ports</span><span>:</span></div></div><div><div><div>25</div></div><div><span><span>      </span></span><span>- </span><span>18080:80</span><span>  </span><span># 按需修改。与防火墙开放端口一致。</span></div></div><div><div><div>26</div></div><div><span>    </span><span>environment</span><span>:</span></div></div><div><div><div>27</div></div><div><span>      </span><span>WORDPRESS_DB_HOST</span><span>: </span><span>db</span></div></div><div><div><div>28</div></div><div><span>      </span><span>WORDPRESS_DB_NAME</span><span>: </span><span>wordpress</span></div></div><div><div><div>29</div></div><div><span>      </span><span>WORDPRESS_DB_USER</span><span>: </span><span>wordpress</span></div></div><div><div><div>30</div></div><div><span>      </span><span>WORDPRESS_DB_PASSWORD</span><span>: </span><span>yourpassword</span><span> </span><span># 按需修改</span></div></div><div><div><div>31</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>32</div></div><div><span><span>      </span></span><span>- </span><span>'./app:/var/www/html'</span></div></div><div><div><div>33</div></div><div><span>    </span><span>links</span><span>:</span></div></div><div><div><div>34</div></div><div><span><span>      </span></span><span>- </span><span>db:db</span></div></div><div><div><div>35</div></div><div><span>    </span><span>depends_on</span><span>:</span></div></div><div><div><div>36</div></div><div><span><span>      </span></span><span>- </span><span>redis</span></div></div><div><div><div>37</div></div><div><span><span>      </span></span><span>- </span><span>db</span></div></div><div><div><div>38</div></div><div><span>    </span><span>networks</span><span>:</span></div></div><div><div><div>39</div></div><div><span><span>      </span></span><span>- </span><span>default</span></div></div><div><div><div>40</div></div><div>
</div></div><div><div><div>41</div></div><div><span>  </span><span>redis</span><span>:</span></div></div><div><div><div>42</div></div><div><span>    </span><span>image</span><span>: </span><span>redis:alpine</span></div></div><div><div><div>43</div></div><div><span>    </span><span>container_name</span><span>: </span><span>wordpress-redis</span></div></div><div><div><div>44</div></div><div><span>    </span><span>restart</span><span>: </span><span>unless-stopped</span></div></div><div><div><div>45</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>46</div></div><div><span><span>      </span></span><span>- </span><span>./redis-data:/data</span></div></div><div><div><div>47</div></div><div><span>    </span><span>networks</span><span>:</span></div></div><div><div><div>48</div></div><div><span><span>      </span></span><span>- </span><span>default</span></div></div><div><div><div>49</div></div><div>
</div></div><div><div><div>50</div></div><div><span>networks</span><span>:</span></div></div><div><div><div>51</div></div><div><span>  </span><span>default</span><span>:</span></div></div><div><div><div>52</div></div><div><span>    </span><span>name</span><span>: </span><span>wordpress</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h4>3. 启动服务，完成初始化<a href="#3-启动服务完成初始化"><span>#</span></a></h4><p>配置文件写完，直接后台启动就行：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 开启服务</span></div></div><div><div><div>2</div></div><div><span>cd</span><span> </span><span>$work</span><span> &amp;&amp; </span><span>docker-compose</span><span> </span><span>up</span><span> </span><span>-d</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>启动后用<code>docker ps</code>看看状态，只要 db、app、redis 三个容器都是 Up，就说明成功了。接下来访问<code>http://服务器IP:18080</code>，就能进入 WordPress 安装向导：</p><ul>
<li>选择简体中文；</li>
<li>填写数据库信息（和 docker-compose.yml 里的一致）；</li>
<li>设置博客标题、管理员账号密码，完成安装。</li>
</ul><p>最后可以用 Nginx 或 NPM 做反向代理，绑定域名<code>yournewdomain.com</code>并配置 HTTPS，我之前用宝塔面板配置的，步骤很简单，新建站点，反向代理到 127.0.0.1&lt;18080&gt; 就行。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251030005605605.png" alt="image-20220427090856986" /><figcaption>image-20220427090856986</figcaption></figure><p></p><p>设置完成后直接登陆：<code>https://yournewdomain.com</code></p></section></section><section><h3>（二）宝塔一键安装：新手首选，10 分钟搞定<a href="#二宝塔一键安装新手首选10-分钟搞定"><span>#</span></a></h3><p>如果不想折腾 Docker，宝塔面板的一键安装绝对是新手福音，不用写配置文件，点点鼠标就好。</p><section><h4>1. 准备工作<a href="#1-准备工作-1"><span>#</span></a></h4><p>先在服务器上安装宝塔面板，然后登录面板，安装 PHP（推荐 7.4 或 8.0 版本）、MySQL、Nginx 这些环境，面板会自动安装，不用手动操作。</p><p>宝塔中集成了不少网站部署的一键脚本，只需要进行简单的设置，就可以完成复杂网页的部署，比如 wordpress 个人博客、discuz 论坛等。</p></section><section><h4>2. 一键部署 WordPress<a href="#2-一键部署-wordpress"><span>#</span></a></h4><ol>
<li>点击左侧 “网站”→“添加站点”，输入你的域名，选择 “一键部署”；</li>
<li>在模板里选择 “WordPress”，设置数据库账号密码（自动生成也可以，记得保存好）；</li>
<li>点击 “提交”，宝塔会自动下载 WordPress 源码、创建数据库，全程不用管；</li>
<li>部署完成后，访问你的域名，就能进入安装向导，和 Docker 安装的后续步骤一样。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829220309288.png" alt="image-20230829220309288" /><figcaption>image-20230829220309288</figcaption></figure><p></p><p>完成配置后，点击提交，过一会就会自动拉取 wordpress 源代码进行部署，通过点击弹窗中的访问站点即可访问网站服务。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829220843006.png" alt="image-20230829220843006" /><figcaption>image-20230829220843006</figcaption></figure><p></p><p>访问网址进入 wordpress 网站页面，开始 wordpress 的初始化配置，选择语言为简体中文</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829220924786.png" alt="image-20230829220924786" /><figcaption>image-20230829220924786</figcaption></figure><p></p><p>点击继续，下一步进行数据库绑定，将网站创建中一起创建的数据库名、用户名和密码填入栏中，其他的保持默认就行，点击提交。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829221010866.png" alt="image-20230829221010866" /><figcaption>image-20230829221010866</figcaption></figure><p></p><p>完成数据库配置，进入网站信息设置页面，标题、用户名、密码、电子邮箱等信息自行修改，然后点击安装 Wordpress 进行部署。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829221234926.png" alt="image-20230829221234926" /><figcaption>image-20230829221234926</figcaption></figure><p></p><p>完成部署后，通过上一步自己设置的用户名和密码就可以登录服务器后台，假设博客地址为 <code>https://yournewdomain.com</code>，博客后台的登录网址为 <code>https://yournewdomain.com/wp-admin</code>。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829221507291.png" alt="image-20230829221507291" /><figcaption>image-20230829221507291</figcaption></figure><p></p><p>登录后，进入 WordPress 后台界面，如图所示。</p><p>搭建成功，可以自定义自己的模块、插件、等等配置了。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829221548159.png" alt="image-20230829221548159" /><figcaption>image-20230829221548159</figcaption></figure><p></p><p>宝塔的好处是自动配置了 Nginx 反向代理和 HTTPS，不用自己动手，后期管理文件、数据库也方便，适合不懂技术的新手。</p></section></section></section>
<section><h2>三、WordPress 迁移：四种方法，覆盖不同场景<a href="#三wordpress-迁移四种方法覆盖不同场景"><span>#</span></a></h2><p>博客用久了，难免会遇到换服务器、换域名的情况，迁移就成了刚需。我试过几种迁移方法，各有优劣，大家根据自己的情况选。</p><section><h3>1.手动迁移：适合技术用户，灵活度高<a href="#1手动迁移适合技术用户灵活度高"><span>#</span></a></h3><p>手动迁移比较麻烦，但灵活度高，适合需要自定义备份内容的用户，步骤如下：</p><ol>
<li><strong>备份数据库</strong>：用 phpMyAdmin 登录原服务器数据库，选择 WordPress 对应的数据库，点击 “导出”，选择 SQL 格式，下载备份文件；</li>
<li><strong>备份博客文件</strong>：用 FTP 工具连接原服务器，下载<code>/var/www/html</code>目录下的所有文件（主题、插件、上传的图片都在这里）；</li>
<li><strong>恢复数据库</strong>：在新服务器上创建同名数据库，用 phpMyAdmin 导入备份的 SQL 文件；</li>
<li><strong>恢复博客文件</strong>：用 FTP 工具把备份的文件上传到新服务器的站点目录；</li>
<li><strong>修改配置文件</strong>：打开<code>wp-config.php</code>，修改数据库账号密码，和新服务器一致；</li>
<li><strong>替换旧域名</strong>：如果换了域名，用 Better Search Replace 插件批量替换数据库里的旧域名，避免链接失效。</li>
</ol></section><section><h3>2. 宝塔面板迁移：新手友好，可视化操作<a href="#2-宝塔面板迁移新手友好可视化操作"><span>#</span></a></h3><p>如果用的是宝塔面板，迁移也很简单，还支持定时备份到云存储，比如腾讯云 COS、阿里云 OSS，异地备份更安全。</p><section><h4>1. 定时备份（推荐提前设置）<a href="#1-定时备份推荐提前设置"><span>#</span></a></h4><ol>
<li>点击左侧 “计划任务”→“添加任务”，选择 “网站备份”；</li>
<li>选择要备份的网站和数据库，备份周期选每月一次（或每周），远程存储选腾讯云 COS（我用的这个，稳定）；</li>
<li>填写 COS 的 AccessKey、SecretKey、存储桶，保存后就会自动备份，还能保留 3 份历史备份，不怕备份文件丢失。</li>
</ol><p>我同时备份wordpress的目录和数据库，每月执行一次，备份到腾讯云COS，保留3份。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251122124728596.png" alt="image-20251122124728596" /><figcaption>image-20251122124728596</figcaption></figure><p></p><p>如下图所示，目录和数据库分别备份到相应的文件夹。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251122125106449.png" alt="image-20251122125106449" /><figcaption>image-20251122125106449</figcaption></figure><p></p></section><section><h4>2. 还原迁移<a href="#2-还原迁移"><span>#</span></a></h4><p>如果你需要还原站点了，使用宝塔面板比较简单，分两步就行了，上传数据库和导入数据库文件即可。</p><section><h5>导入数据库<a href="#导入数据库"><span>#</span></a></h5><p>首先在宝塔面板选择添加数据库，完成命名和密码设置，点击导入备份，从本地上传之前备份的压缩包，导入后就会显示在下方，这样并没有完成，还要点击导入，才会实现解压压缩包数据，完成对新数据库的覆盖，这样就完成数据库的还原了，还是非常简单的。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251122125532422.png" alt="image-20251122125532422" /><figcaption>image-20251122125532422</figcaption></figure><p></p></section><section><h5>上传站点文件<a href="#上传站点文件"><span>#</span></a></h5><p>接下来就是上传站点文件，首先通过宝塔面板创建一个新的PHP站点。填入你的站点域名和目录。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251122125954486.png" alt="image-20251122125954486" /><figcaption>image-20251122125954486</figcaption></figure><p></p><p>来到站点目录，删除默认创建的站点文件，将之前备份的站点压缩包文件上传。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251122130327895.png" alt="image-20251122130327895" /><figcaption>image-20251122130327895</figcaption></figure><p></p><p>解压到网站目录</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251122131621494.png" alt="image-20251122131621494" /><figcaption>image-20251122131621494</figcaption></figure><p></p><p>将解压的文件移动到站点目录里，这样就完成了站点文件迁移。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251122132319118.png" alt="image-20251122132319118" /><figcaption>image-20251122132319118</figcaption></figure><p></p></section><section><h5>注意事项<a href="#注意事项"><span>#</span></a></h5><section><h6>修改配置文件<a href="#修改配置文件"><span>#</span></a></h6><p>不过这样还没完成配置，还要更改下博客的数据库和站点配置文件。因为数据库我们是重新创建的，名字和密码可能会不一样（你也可以设置成一样的），所以需要重新配置。</p><p>打开目录下解压的wp-config.php的文件，修改这一段代码</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>define</span><span><span>(</span><span> </span></span><span>'DB_NAME'</span><span><span>,</span><span> </span></span><span>'yourdbname'</span><span><span> </span><span>);  </span></span><span>#修改成你的数据库名字</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>/** Database username */</span></div></div><div><div><div>4</div></div><div><span>define</span><span><span>(</span><span> </span></span><span>'DB_USER'</span><span><span>,</span><span> </span></span><span>'yourdbname'</span><span><span> </span><span>);  </span></span><span>#修改成你的数据库用户名字</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span>/** Database password */</span></div></div><div><div><div>7</div></div><div><span>define</span><span><span>(</span><span> </span></span><span>'DB_PASSWORD'</span><span><span>,</span><span> </span></span><span>'yourdbpassword'</span><span><span> </span><span>);  </span></span><span>#修改成你的数据库密码</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>/** Database hostname */</span></div></div><div><div><div>10</div></div><div><span>define</span><span><span>(</span><span> </span></span><span>'DB_HOST'</span><span><span>,</span><span> </span></span><span>'localhost'</span><span><span> </span><span>);</span></span></div></div><div><div><div>11</div></div><div>
</div></div><div><div><div>12</div></div><div><span>/** Database charset to use in creating database tables. */</span></div></div><div><div><div>13</div></div><div><span>define</span><span><span>(</span><span> </span></span><span>'DB_CHARSET'</span><span><span>,</span><span> </span></span><span>'utf8mb4'</span><span><span> </span><span>);</span></span></div></div><div><div><div>14</div></div><div>
</div></div><div><div><div>15</div></div><div><span>/** The database collate type. Don't change this if in doubt. */</span></div></div><div><div><div>16</div></div><div><span>define</span><span><span>(</span><span> </span></span><span>'DB_COLLATE'</span><span><span>,</span><span> </span></span><span>''</span><span><span> </span><span>);</span></span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>注意你迁移前后的博客域名注意要一致，否则会无法访问站点，这就是wordpress的痛点了，他要求只能通过一个站点域名访问wordpress站点，如果不一样，就要在配置文件里修改一下。在wp-config.php文件最后加上这一段代码。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>define</span><span>(</span><span>'WP_HOME'</span><span><span>,</span><span> </span></span><span>'http://yournewdomain.com'</span><span>);    </span><span>#修改成你的站点域名</span></div></div><div><div><div>2</div></div><div><span>define</span><span>(</span><span>'WP_SITEURL'</span><span><span>,</span><span> </span></span><span>'http://yournewdomain.com'</span><span>);  </span><span>#修改成你的站点域名</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section><section><h6>修改站点地址<a href="#修改站点地址"><span>#</span></a></h6><p>完成这样后，就可以访问你迁移后的wordpress站点了。不过这样简单的修改域名只是让你可以访问站点，还存在一些问题，毕竟WordPress更换域名不是简单把DNS改一下那么轻松，它涉及数据库、缓存、搜索引擎设置、重定向等多个层面。</p><p>进入站点后，进入后台的：设置 &gt; 常规 &gt; WordPress地址(URL) &amp; 站点地址(URL)</p><p>确保这两个都改为新域名，点击保存后网站会立即跳转。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251122135544291.png" alt="image-20251122135544291" /><figcaption>image-20251122135544291</figcaption></figure><p></p></section><section><h6>批量替换数据库中的旧域名<a href="#批量替换数据库中的旧域名"><span>#</span></a></h6><p><strong>Better Search Replace</strong> 是一个可以<strong>对WordPress<a href="https://www.wpdaxue.com/tag/%E6%95%B0%E6%8D%AE%E5%BA%93" target="_blank">数据库</a>进行搜索和替换</strong>的插件，比如你网站更换域名，或者你需要一次性更换邮箱设置（可能在不同的选项都用到了这个邮箱），等等，通过 Better Search Replace 插件就可以非常方便地实现。</p><p>可以在后台 <em>插件 -&gt; 安装插件</em> 界面，搜索 Better Search Replace 进行在线安装，或者<a href="https://wordpress.org/plugins/better-search-replace/" target="_blank">到这里下载 Better Search Replace </a>后手动安装插件。</p><p>启用插件以后，就可以在 <em>工具 – Better Search Replace</em> 进入插件界面。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251122162643026.png" alt="image-20251122162643026" /><figcaption>image-20251122162643026</figcaption></figure><p></p><p>假设原来网址为 <code>http://localhost</code>，线上的网址为 <code>http://yournewdomain.com</code> ，那我们就可以按照下面的步骤操作。</p><ol>
<li>先备份下你的数据库</li>
<li>在 搜索 字段，输入你要查找的内容，这里输入 <code>http://localhost</code></li>
<li>在 替换为 字段，输入 <code>http://yournewdomain.com</code></li>
<li>选择数据库表，全选所有数据表</li>
<li>要真正替换数据，就取消“作为尝试运行”那个选项</li>
<li>点击“运行搜索/替换”按钮就开始执行了</li>
</ol><p>如果在运行过程中，提示执行方面的错误，可以尝试切换到下图的设置标签，减少“最大页面大小”的值，保存后再去试试。</p><p>这样就完成wordpress站点的迁移了。</p></section></section></section></section><section><h3>3.Docker 迁移：最简单，推荐技术用户<a href="#3docker-迁移最简单推荐技术用户"><span>#</span></a></h3><p>如果你的 WordPress 是用 Docker 搭的，迁移简直不要太方便！因为我们在 docker-compose.yml 里已经把博客文件和数据库都做了持久化映射，迁移步骤就两步：</p><ol>
<li><strong>备份数据</strong>：把原服务器上<code>~/docker/wordpress</code>目录下的<code>db</code>（数据库）、<code>app</code>（博客文件）、<code>redis-data</code>（缓存）三个文件夹打包备份，下载到本地；</li>
<li><strong>恢复数据</strong>：在新服务器上创建同样的目录<code>~/docker/wordpress</code>，把备份的三个文件夹上传过去，然后重新运行<code>docker-compose up -d</code>，搞定！</li>
</ol><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span> </span><span>services</span><span>:</span></div></div><div><div><div>2</div></div><div><span>  </span><span>db</span><span>:</span></div></div><div><div><div>3</div></div><div><span>    </span><span>...</span></div></div><div><div><div>4</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>5</div></div><div><span><span>      </span></span><span>- </span><span>'./db:/var/lib/mysql'</span></div></div><div><div><div>6</div></div><div><span>    </span><span>...</span></div></div><div><div><div>7</div></div><div><span>  </span><span>app</span><span>:</span></div></div><div><div><div>8</div></div><div><span>    </span><span>...</span></div></div><div><div><div>9</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>10</div></div><div><span><span>      </span></span><span>- </span><span>'./app:/var/www/html'</span></div></div><div><div><div>11</div></div><div><span>    </span><span>...</span></div></div><div><div><div>12</div></div><div><span>  </span><span>redis</span><span>:</span></div></div><div><div><div>13</div></div><div><span>    </span><span>...</span></div></div><div><div><div>14</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>15</div></div><div><span><span>      </span></span><span>- </span><span>./redis-data:/data</span></div></div><div><div><div>16</div></div><div><span>    </span><span>...</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>这种方法不用改配置文件，数据完全一致，我换服务器的时候就是这么迁的，全程不到 10 分钟。</p></section><section><h3>4.使用插件迁移<a href="#4使用插件迁移"><span>#</span></a></h3><p>如果既不用 Docker 也不用宝塔，用插件迁移是最方便的，我推荐 WPvivid Backup，免费功能完全够用，还支持远程存储。</p><section><h4>1. 安装插件<a href="#1-安装插件"><span>#</span></a></h4><p>在 WordPress 后台 “插件”→“安装插件”，搜索 “WPvivid Backup”，安装并启用。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251030004616779.png" alt="image-20251030004616779" /><figcaption>image-20251030004616779</figcaption></figure><p></p></section><section><h4>2. 备份原站点<a href="#2-备份原站点"><span>#</span></a></h4><ol>
<li>点击左侧 “WPvivid Backup”→“备份与恢复”，选择 “数据库 + 文件”，点击 “立即备份”；</li>
<li>备份完成后，点击 “下载” 把备份文件保存到本地，或者配置远程存储，自动上传备份文件。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251030004751895.png" alt="wpvivid备份与恢复" /><figcaption>wpvivid备份与恢复</figcaption></figure><p></p><section><h5>计划<a href="#计划"><span>#</span></a></h5><p>勾选“启用备份计划”，时间为“每天”，文件选择“数据库+文件(WordPress文件)”，保存修改即可。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251030004839880.png" alt="wpvivid自动备份计划" /><figcaption>wpvivid自动备份计划</figcaption></figure><p></p><p>建议将备份文件发送到远程存储，步骤见下方“远程存储”设置。</p></section><section><h5>远程存储<a href="#远程存储"><span>#</span></a></h5><p>远程存储是重点，也是一定要配置的功能！</p><p>WPvivid支持使用 Google Drive 、Dropbox 、oneDrive 、Amazon S3 、DigitalOcean Spaces 、 FTP 等方式配置远程存储。</p><p>前几种网盘国内的网络都无法访问或者不太稳定，这里推荐自己搭建FTP进行远程存储。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251030005118658.png" alt="image-20251030005118658" /><figcaption>image-20251030005118658</figcaption></figure><p></p><p>配置远程存储成功后，点击上方“计划”，勾选“启用备份计划”与“发送文件到远程存储”；点击“设置”，勾选“上传到远程存储后，将备份存储在本机”，保存修改即可。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251030005157614.png" alt="启用自动备份计划" /><figcaption>启用自动备份计划</figcaption></figure><p></p></section></section><section><h4>3. 恢复新站点<a href="#3-恢复新站点"><span>#</span></a></h4><ol>
<li>在新服务器上搭建好空白的 WordPress（用 Docker 或宝塔都可以）；</li>
<li>同样安装 WPvivid Backup 插件，点击 “备份与恢复”→“上传”，上传之前备份的文件；</li>
<li>点击 “还原”，等待还原完成，新站点就和原站点一模一样了，包括账号密码、主题插件。</li>
</ol><p>这种方法适合新手，不用操作服务器文件，全程在 WordPress 后台完成，缺点是备份文件大的话，上传下载比较慢。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251030005411398.png" alt="wpvivid数据恢复演示" /><figcaption>wpvivid数据恢复演示</figcaption></figure><p></p></section></section></section>
<section><h2>四、WordPress 插件推荐<a href="#四wordpress-插件推荐"><span>#</span></a></h2><p>安装好 WordPress 后，这些插件一定要装，能提升博客功能和体验：</p><ol>
<li><strong>Akismet Anti-Spam</strong>：反垃圾评论神器，能自动拦截大部分垃圾评论，不用手动删除；</li>
<li><strong>WP Mail SMTP</strong>：解决 WordPress 默认邮件发送失败的问题，配置 SMTP 后，评论通知、密码找回邮件都能正常发送；</li>
<li><strong>WP Statistics</strong>：网站访问统计，能看到访问量、访客来源、热门文章，比第三方统计工具更隐私；</li>
<li><strong>Better Search Replace</strong>：批量替换数据库内容，换域名、改网站标题都能用；</li>
<li><strong>Simple Local Avatars</strong>：自定义用户头像，不用依赖 Gravatar，国内访问更快；</li>
<li><strong>WP Githuber MD</strong>：Markdown 编辑器，写技术博客必备，支持代码高亮、数学公式；</li>
<li><strong>Redis Object Cache</strong>：Redis 缓存插件，和我们 Docker 配置里的 Redis 配合，能大幅提升博客加载速度。</li>
</ol></section>
<section><h2>五、总结<a href="#五总结"><span>#</span></a></h2><ul>
<li><strong>新手入门</strong>：优先选宝塔一键安装，简单快捷，后期管理方便；</li>
<li><strong>技术用户</strong>：选 Docker 安装，环境隔离，迁移方便，适合长期维护；</li>
<li><strong>迁移场景</strong>：Docker 用户用目录备份迁移，新手用宝塔用户用面板备份，按需选择。</li>
</ul><p>WordPress 搭建和迁移看着复杂，其实实操一遍就会了，我第一次迁移的时候折腾了半天，现在换服务器半小时就能搞定。如果大家在操作过程中遇到问题，比如 Docker 启动失败、迁移后链接失效，可以留言问我，我会尽量帮忙解答～</p></section>
<section><h2>参考<a href="#参考"><span>#</span></a></h2><ol>
<li><a href="https://www.wpdaxue.com/wordpress-change-domain-name.html" target="_blank">如何更换WordPress网站域名 – WordPress大学</a></li>
<li><a href="https://blognas.hwb0307.com/linux/docker/238" target="_blank">Docker系列 WordPress系列 搭建WordPress个人博客 - Bensz</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/12402242114" target="_blank">(19 封私信 / 81 条消息) 零基础WordPress建站教程：WP安装、主题插件、SEO一网打尽 - 知乎</a></li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/978/</id>
      <title type="text">Uptime Kuma 2025最新Docker部署教程，轻量高效监控网站连通性</title>
      <published>2025-11-16T03:16:16.000Z</published>
      <updated>2026-03-08T03:59:58.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/978/"/>
      <summary type="text">一、前言 作为一名业余时间维护个人网站博主，有时候遇到网站宕机几小时才发现，访客流失不说，搜索引擎收录还可能受影响。之前试过Uptime Robot、Pingdom等工具，最终被开源免费、功能全、颜值高的Uptime Kuma圈粉。今天就把</summary>
      <content type="html"><![CDATA[<section><h1>一、前言<a href="#一前言"><span>#</span></a></h1><p>作为一名业余时间维护个人网站博主，有时候遇到网站宕机几小时才发现，访客流失不说，搜索引擎收录还可能受影响。之前试过Uptime Robot、Pingdom等工具，最终被<strong>开源免费、功能全、颜值高</strong>的Uptime Kuma圈粉。今天就把2025年最新的Docker部署方案整理出来，从环境准备到反向代理，新手也能一步到位。</p><p>在说部署前，先聊聊它的核心优势——毕竟监控工具那么多，选对才不浪费服务器资源：</p><ul>
<li><strong>开源无限制</strong>：对比Uptime Robot免费版仅支持50个监控项，Kuma无任何功能锁，监控100个网站也不收费；</li>
<li><strong>监控类型全</strong>：除了HTTP(s)网站，还支持TCP端口、Ping、DNS、数据库（MySQL/Redis）、Docker容器等20+监控场景；</li>
<li><strong>实时预警快</strong>：支持SMTP邮件、Telegram、钉钉、企业微信等30+通知方式，宕机10秒内就能收到提醒；</li>
<li><strong>可视化直观</strong>：自带响应时间曲线图、状态热力图，故障历史一目了然，不用查日志猜问题；</li>
<li><strong>轻量省资源</strong>：Docker容器启动后仅占50MB内存，比同类工具省70%资源，低配服务器也能跑。</li>
</ul><p>放一张我网站的状态页面截图，健康状态、响应时间清晰可见，颜值还不错哦。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251113005153562.png" alt="image-20251113005153562" /><figcaption>image-20251113005153562</figcaption></figure><p></p></section>
<section><h1>二、准备工作<a href="#二准备工作"><span>#</span></a></h1><p>Kuma的部署门槛极低，只要服务器能跑Docker，基本零障碍。先确认以下3个条件：：</p><ul>
<li>已安装 Docker 和 Docker Compose</li>
<li>有公网 IP（或本地服务器用于测试）</li>
<li>开放目标端口（默认 13001，可自定义）</li>
</ul><p>为了方便后续管理配置和数据备份，建议创建独立工作目录（我习惯把工具都放~/opt目录下，统一管理）：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>cd</span><span> </span><span>~</span></div></div><div><div><div>2</div></div><div><span>mkdir</span><span> </span><span>-p</span><span> </span><span>~/opt/uptime-kuma</span></div></div><div><div><div>3</div></div><div><span>cd</span><span> </span><span>~/opt/uptime-kuma</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>接下来开放端口，这里分两种场景，根据你的服务器防火墙类型选：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 场景1：用ufw防火墙（Ubuntu/Debian），开放13001端口</span></div></div><div><div><div>2</div></div><div><span>sudo</span><span> </span><span>ufw</span><span> </span><span>allow</span><span> </span><span>13001/tcp</span><span> </span><span>comment</span><span> </span><span>'Uptime Kuma监控服务'</span><span> &amp;&amp; </span><span>sudo</span><span> </span><span>ufw</span><span> </span><span>reload</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 场景2：用firewalld防火墙（CentOS/RHEL）</span></div></div><div><div><div>5</div></div><div><span>sudo</span><span> </span><span>firewall-cmd</span><span> </span><span>--add-port=13001/tcp</span><span> </span><span>--permanent</span><span> &amp;&amp; </span><span>sudo</span><span> </span><span>firewall-cmd</span><span> </span><span>--reload</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><blockquote><p>注意：如果是云服务器（阿里云/腾讯云），还要在控制台的“安全组”里开放13001端口，否则外部无法访问。</p></blockquote></section>
<section><h1>三、Docker Compose部署<a href="#三docker-compose部署"><span>#</span></a></h1><p>Uptime Kuma的Docker配置极其简洁，核心就是“镜像+数据卷+端口映射”。</p><p>在~/opt/uptime-kuma目录下新建docker-compose.yml文件，直接复制以下配置：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>version</span><span>: </span><span>'3.3'</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>services</span><span>:</span></div></div><div><div><div>4</div></div><div><span>  </span><span>uptime-kuma</span><span>:</span></div></div><div><div><div>5</div></div><div><span>    </span><span># 推荐用镜像源，拉取速度快（国外服务器可换louislam/uptime-kuma:2）</span></div></div><div><div><div>6</div></div><div><span>    </span><span>image</span><span>: </span><span>docker2.leitool.top/louislam/uptime-kuma:2</span></div></div><div><div><div>7</div></div><div><span>    </span><span>restart</span><span>: </span><span>unless-stopped</span><span>  </span><span># 异常自动重启，保障服务稳定</span></div></div><div><div><div>8</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>9</div></div><div><span>      </span><span># 数据持久化：将容器内数据映射到宿主机，删除容器也不丢数据</span></div></div><div><div><div>10</div></div><div><span><span>      </span></span><span>- </span><span>./data:/app/data</span></div></div><div><div><div>11</div></div><div><span>    </span><span>ports</span><span>:</span></div></div><div><div><div>12</div></div><div><span>      </span><span># 主机端口:容器端口（容器内默认3001，主机端口可自定义）</span></div></div><div><div><div>13</div></div><div><span><span>      </span></span><span>- </span><span>"13001:3001"</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>配置完成后，执行启动命令，Docker会自动拉取镜像并创建容器：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 后台启动服务（-d表示 detached 模式）</span></div></div><div><div><div>2</div></div><div><span>docker-compose</span><span> </span><span>up</span><span> </span><span>-d</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 查看容器运行状态（出现Up说明启动成功）</span></div></div><div><div><div>5</div></div><div><span>docker</span><span> </span><span>ps</span></div></div><div><div><div>6</div></div><div><span># 若启动失败，查看日志排查问题</span></div></div><div><div><div>7</div></div><div><span>docker-compose</span><span> </span><span>logs</span><span> </span><span>-f</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>使用 <code>docker ps</code> 命令检查容器是否创建成功。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251112232938100.png" alt="image-20251112232938100" /><figcaption>image-20251112232938100</figcaption></figure><p></p><section><h2>四、首次配置：监控项添加<a href="#四首次配置监控项添加"><span>#</span></a></h2><section><h3>4.1 配置引导<a href="#41-配置引导"><span>#</span></a></h3><p>打开浏览器访问“服务器IP&lt;13001&gt;”，就能进入Uptime Kuma的安装引导页面，全程可视化操作，非常简单。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251112233158904.png" alt="image-20251112233158904" /><figcaption>image-20251112233158904</figcaption></figure><p></p><p>Uptime Kuma 2.0版本最大的升级就是支持MariaDB数据库，对比旧版本的SQLite，两者区别很明显，根据需求选。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251112233403365.png" alt="image-20251112233403365" /><figcaption>image-20251112233403365</figcaption></figure><p></p><p><strong>创建管理员账号</strong>：数据库配置后，设置用户名和密码（建议密码包含大小写+数字，避免被暴力破解），点击“Create”完成初始化：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251112234919428.png" alt="image-20251112234919428" /><figcaption>image-20251112234919428</figcaption></figure><p></p><p>自动跳转进入 Uptime Kuma 仪盘表</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251112235137679.png" alt="image-20251112235137679" /><figcaption>image-20251112235137679</figcaption></figure><p></p></section><section><h3>4.2 监控项配置<a href="#42-监控项配置"><span>#</span></a></h3><ol>
<li><strong>添加第一个监控项</strong>：进入仪表盘后，点击右上角“+ Add Monitor”，重点配置这几个参数： Monitor Type：选“HTTP(s)”（监控网站用这个）；</li>
<li>显示名称：自定义名称（比如“我的个人博客”）；</li>
<li>URL：填写网站完整地址（如<a href="https://blog.example.com%EF%BC%89%EF%BC%9B" target="_blank">https://blog.example.com）；</a></li>
<li>Heartbeat Interval：心跳间隔，默认60秒，我建议改成180秒（减少误报，也能降低服务器请求压力）；</li>
<li>Max Retries：重试次数，默认3次，保留即可。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251112235339076.png" alt="image-20251112235339076" /><figcaption>image-20251112235339076</figcaption></figure><p></p></section><section><h3>4.3 通知方式：宕机报警<a href="#43-通知方式宕机报警"><span>#</span></a></h3><p>监控的核心是“出问题能及时知道”，Uptime Kuma支持30+通知方式，我推荐使用<strong>SMTP邮件（通用）</strong>：填写邮箱SMTP服务器信息（比如QQ邮箱用smtp.qq.com，端口465），测试成功后，网站宕机就会收到邮件提醒：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251112235750240.png" alt="image-20251112235750240" /><figcaption>image-20251112235750240</figcaption></figure><p></p></section></section></section>
<section><h1>五、状态页面<a href="#五状态页面"><span>#</span></a></h1><p>正常监控时的响应状态可视化：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251113000314827.png" alt="image-20251113000314827" /><figcaption>image-20251113000314827</figcaption></figure><p></p><p>状态页面可以把所有监控项整理成一个公开页面，方便访客查看网站状态（比如“status.example.com”）。创建步骤：</p><ol>
<li>点击左侧“Status Pages”→“+ Add Status Page”；</li>
<li>设置页面名称、URL路径（比如“website”，访问地址就是Istatus.example.com/websit）；</li>
<li>保存后就能通过链接访问状态页面了。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251113000655060.png" alt="image-20251113000655060" /><figcaption>image-20251113000655060</figcaption></figure><p></p><p>我配置的状态页面长这样，能自定义展示顺序和分组：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251113010812792.png" alt="image-20251113010812792" /><figcaption>image-20251113010812792</figcaption></figure><p></p></section>
<section><h1>六、反向代理<a href="#六反向代理"><span>#</span></a></h1><p>直接通过<code>IP:端口</code>访问不够美观，且缺乏 HTTPS 安全层。我们可以用 Nginx（或 Caddy、Apache）做反向代理，绑定域名并配置 SSL。</p><blockquote><p>与其他 Web 应用程序不同，Uptime Kuma 基于 WebSocket。您需要另外两个标头**“Upgrade”<strong>和</strong>“Connection”**才能反向代理 WebSocket。</p><p>请阅读 wiki 了解更多信息：<a href="https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy" target="_blank">https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy</a></p></blockquote><p>先在域名解析平台（如阿里云、Cloudflare）将域名（如<code>umami.example.com</code>）解析到服务器 IP。</p><section><h3>6.1 NPM<a href="#61-npm"><span>#</span></a></h3><p>NPM图形化操作，无需写配置文件，适合新手：</p><ol>
<li>在NPM中添加“Proxy Host”，填写域名（如kuma.example.com）；</li>
<li>Scheme选“http”，Forward Hostname/IP填“127.0.0.1”，Forward Port填“13001”；</li>
<li>勾选“WebSockets Support”（关键！否则监控数据无法实时更新）；</li>
<li>进入“SSL”标签，申请Let’s Encrypt证书，开启强制HTTPS。</li>
</ol></section><section><h3>6.2 Nginx<a href="#62-nginx"><span>#</span></a></h3><p>如果是Nginx，根据官网的描述，要添加以下代码：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>  </span><span>location</span><span> / {</span></div></div><div><div><div>2</div></div><div><span>   <span> </span></span><span>proxy_set_header </span><span>  X-Real-IP $</span><span>remote_addr</span><span>;</span></div></div><div><div><div>3</div></div><div><span>   <span> </span></span><span>proxy_set_header </span><span>  X-Forwarded-For $</span><span>proxy_add_x_forwarded_for</span><span>;</span></div></div><div><div><div>4</div></div><div><span>   <span> </span></span><span>proxy_set_header </span><span>  Host $</span><span>host</span><span>;</span></div></div><div><div><div>5</div></div><div><span>   <span> </span></span><span>proxy_pass </span><span>        http://localhost:3001/;</span></div></div><div><div><div>6</div></div><div><span>   <span> </span></span><span>proxy_http_version </span><span>1.1</span><span>;</span></div></div><div><div><div>7</div></div><div><span>   <span> </span></span><span>proxy_set_header </span><span>  Upgrade $</span><span>http_upgrade</span><span>;</span></div></div><div><div><div>8</div></div><div><span>   <span> </span></span><span>proxy_set_header </span><span>  Connection </span><span>"upgrade"</span><span>;</span></div></div><div><div><div>9</div></div><div><span><span>  </span></span><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>6.3 群晖NAS<a href="#63-群晖nas"><span>#</span></a></h3><p>如果把Kuma部署在群晖NAS上，用系统自带的反向代理即可：</p><ol>
<li>
<p>打开群晖“控制面板”→“登录门户”→“高级”→“反向代理”；</p>
</li>
<li>
<p>点击“新增”，填写来源（域名、端口443）和目标（群晖本地IP、端口13001）：</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251113004508066.png" alt="image-20251113004508066" /><figcaption>image-20251113004508066</figcaption></figure><p></p>
</li>
<li>
<p>切换到“自定义标题”，点击“创建”→选择“Websockets”，自动填充所需头信息：</p>
</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251113004551420.png" alt="image-20251113004551420" /><figcaption>image-20251113004551420</figcaption></figure><p></p><p>这样就可以通过域名访问Uptime-kumaf服务了。</p></section></section>
<section><h1>七、腾讯云EdgeOne配置<a href="#七腾讯云edgeone配置"><span>#</span></a></h1><p>我把Kuma部署在内网群晖里，没有公网IPv4，所以用腾讯云EdgeOne实现IPv6转IPv4，让纯IPv4环境也能访问，步骤如下：</p><ol>
<li><strong>IPv6域名解析</strong>：用DDNS-go工具，将域名（如kuma.example.com）解析到群晖的本地IPv6地址。</li>
<li><strong>EdgeOne配置</strong>：在腾讯云EdgeOne控制台，添加站点并选择“开启IPv6访问”，将加速域名指向刚才的IPv6域名；</li>
<li><strong>验证访问</strong>：通过EdgeOne分配的加速域名（如uptime.example.com），纯IPv4网络也能访问内网的Kuma服务了。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251113001344020.png" alt="image-20251113001344020" /><figcaption>image-20251113001344020</figcaption></figure><p></p><p>#八、小结</p><p>作为用了Uptime Robot 免费版2年的老用户，最近用上了Uptime kuma，部署轻量易上手，监控数据实时性和通知可靠性都经得起考验。</p><p>如果你有多个网站、服务器或API服务，花10分钟部署Uptime Kuma，就能彻底告别“被动发现故障”的尴尬。</p></section>
<section><h1>参考<a href="#参考"><span>#</span></a></h1><ol>
<li><a href="https://cloud.tencent.com/developer/article/2419591" target="_blank">Uptime Kuma的部署与简单使用-腾讯云开发者社区-腾讯云</a></li>
<li><a href="https://blognas.hwb0307.com/linux/docker/4939" target="_blank">Docker系列 Uptime Kuma监测网站连通性 - Bensz</a></li>
<li><a href="https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy" target="_blank">Reverse Proxy · louislam/uptime-kuma Wiki</a></li>
<li><a href="https://github.com/louislam/uptime-kuma/wiki" target="_blank">Home · louislam/uptime-kuma Wiki</a></li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/983/</id>
      <title type="text">Docker 部署 Chevereto 个人图床，搭配 EdgeOne 实现免费公网访问</title>
      <published>2025-11-14T13:47:16.000Z</published>
      <updated>2026-03-08T04:12:30.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/983/"/>
      <summary type="text">前言 之前一直用腾讯云 COS 存博客图片，之前也写过一篇博文来介绍typora+picgo+cos+cdn搭建个人写作环境 - 阿雷的小窝，每月虽然花不了多少钱，但总觉得被厂商绑着，而且流量多了之后费用也不少。之前也试过 Lsky这些图床</summary>
      <content type="html"><![CDATA[<section><h1>前言<a href="#前言"><span>#</span></a></h1><p>之前一直用腾讯云 COS 存博客图片，之前也写过一篇博文来介绍<a href="/archives/798/">typora+picgo+cos+cdn搭建个人写作环境 - 阿雷的小窝</a>，每月虽然花不了多少钱，但总觉得被厂商绑着，而且流量多了之后费用也不少。之前也试过 Lsky这些图床，要么功能不全，要么界面用着不舒服，后来因为内网穿透不稳定，就搁置了个人图床的想法。</p><p>前阵子发现腾讯云 EdgeOne 有免费套餐，不限流量还能做 IPv6 转 IPv4，这不正好解决了我内网群晖没法公网访问的问题。果断决定折腾一波 Chevereto，毕竟之前就听说它开源免费，功能还全，这次正好趁着 EdgeOne 的车，搭个专属图床试试水。</p><p>废话少说，直接开干！</p></section>
<section><h1>准备工作<a href="#准备工作"><span>#</span></a></h1><p><code>chevereto</code>部署门槛相较于之前介绍的软件要高一些，其实也没什么复杂的，就是提前把环境弄好，省得等下部署的时候手忙脚乱：</p><ul>
<li>已安装 Docker 和 Docker Compose</li>
<li>有公网 IP（或本地服务器用于测试）</li>
<li>开放目标端口（默认 38080，可自定义）</li>
</ul><p>然后是目录规划，我习惯把所有工具都放在～/opt 目录下，统一管理，找起来方便。这次也不例外，新建了 chevereto 的专属目录，还分了 database（存数据库）、storage（存图片）：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>cd</span><span> </span><span>~</span></div></div><div><div><div>2</div></div><div><span>mkdir</span><span> </span><span>-p</span><span> </span><span>~/opt/chevereto</span></div></div><div><div><div>3</div></div><div><span>mkdir</span><span> </span><span>-p</span><span> </span><span>~/opt/chevereto/database</span></div></div><div><div><div>4</div></div><div><span>mkdir</span><span> </span><span>-p</span><span> </span><span>~/opt/chevereto/storage</span></div></div><div><div><div>5</div></div><div><span>cd</span><span> </span><span>~/opt/chevereto</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>接下来要开放端口，我选的是 38080，避免和其他服务冲突。这里分两种场景，根据你的服务器防火墙类型选：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 场景1：用ufw防火墙（Ubuntu/Debian），开放13001端口</span></div></div><div><div><div>2</div></div><div><span>sudo</span><span> </span><span>ufw</span><span> </span><span>allow</span><span> </span><span>38080/tcp</span><span> </span><span>comment</span><span> </span><span>'chevereto'</span><span> &amp;&amp; </span><span>sudo</span><span> </span><span>ufw</span><span> </span><span>reload</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 场景2：用firewalld防火墙（CentOS/RHEL）</span></div></div><div><div><div>5</div></div><div><span>sudo</span><span> </span><span>firewall-cmd</span><span> </span><span>--add-port=38080/tcp</span><span> </span><span>--permanent</span><span> &amp;&amp; </span><span>sudo</span><span> </span><span>firewall-cmd</span><span> </span><span>--reload</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><blockquote><p>注意：如果是云服务器（阿里云/腾讯云），还要在控制台的“安全组”里开放38080端口，否则外部无法访问。</p></blockquote></section>
<section><h1>docker compose部署<a href="#docker-compose部署"><span>#</span></a></h1><p>如果你使用的是付费版本Chevereto图床，需要自己下载付费版本的代码库，然后自己通过docker进行构建，因为我使用的是免费版本（直接在官网下载就行），如果你使用的付费版本可以参考一下官网上介绍的付费版的镜像构建<a href="https://v4-docs.chevereto.com/guides/docker/#advantages" target="_blank">Install Chevereto on Docker | Chevereto V4 Docs</a>。</p><p>接着，在<code>~/opt/chevereto</code>文件夹中建立一个文件<code>php.ini</code>：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>upload_max_filesize = 100M</span></div></div><div><div><div>2</div></div><div><span>post_max_size = 100M</span></div></div><div><div><div>3</div></div><div><span>memory_limit = 3072M</span></div></div><div><div><div>4</div></div><div><span>max_execution_tim = 180</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>接着，在<code>~/opt/chevereto</code>文件夹中建立一个文件<code>docker-compose.yml</code>：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>services</span><span>:</span></div></div><div><div><div>2</div></div><div><span>  </span><span>database</span><span>:</span></div></div><div><div><div>3</div></div><div><span>    </span><span>image</span><span>: </span><span>docker.m.daocloud.io/mariadb:jammy</span></div></div><div><div><div>4</div></div><div><span>    </span><span>networks</span><span>:</span></div></div><div><div><div>5</div></div><div><span><span>      </span></span><span>- </span><span>chevereto</span></div></div><div><div><div>6</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>7</div></div><div><span><span>      </span></span><span>- </span><span>./database:/var/lib/mysql:rw</span></div></div><div><div><div>8</div></div><div><span>    </span><span>restart</span><span>: </span><span>always</span></div></div><div><div><div>9</div></div><div><span>    </span><span>environment</span><span>:</span></div></div><div><div><div>10</div></div><div><span>      </span><span>MYSQL_ROOT_PASSWORD</span><span>: </span><span>password</span></div></div><div><div><div>11</div></div><div><span>      </span><span>MYSQL_DATABASE</span><span>: </span><span>chevereto</span></div></div><div><div><div>12</div></div><div><span>      </span><span>MYSQL_USER</span><span>: </span><span>chevereto</span></div></div><div><div><div>13</div></div><div><span>      </span><span>MYSQL_PASSWORD</span><span>: </span><span>user_database_password</span></div></div><div><div><div>14</div></div><div>
</div></div><div><div><div>15</div></div><div><span>  </span><span>php</span><span>:</span></div></div><div><div><div>16</div></div><div><span>    </span><span>image</span><span>: </span><span>chevereto/chevereto:latest</span><span> </span><span># tweak with target image to run</span></div></div><div><div><div>17</div></div><div><span>    </span><span>networks</span><span>:</span></div></div><div><div><div>18</div></div><div><span><span>      </span></span><span>- </span><span>chevereto</span></div></div><div><div><div>19</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>20</div></div><div><span><span>      </span></span><span>- </span><span>./storage:/var/www/html/images/:rw</span></div></div><div><div><div>21</div></div><div><span><span>      </span></span><span>- </span><span>./storage/content:/var/www/html/content:rw</span></div></div><div><div><div>22</div></div><div><span><span>      </span></span><span>- </span><span>./storage/routes:/var/www/html/app/routes:rw</span></div></div><div><div><div>23</div></div><div><span><span>      </span></span><span>- </span><span>./storage/php.ini:/usr/local/etc/php/php.ini:ro</span></div></div><div><div><div>24</div></div><div><span>      </span><span># - app:/var/www/html/ # uncomment when using CHEVERETO_SERVICING=server</span></div></div><div><div><div>25</div></div><div><span>    </span><span>restart</span><span>: </span><span>always</span></div></div><div><div><div>26</div></div><div><span>    </span><span>depends_on</span><span>:</span></div></div><div><div><div>27</div></div><div><span><span>      </span></span><span>- </span><span>database</span></div></div><div><div><div>28</div></div><div><span>    </span><span>ports</span><span>:</span></div></div><div><div><div>29</div></div><div><span><span>      </span></span><span>- </span><span>38080:80</span></div></div><div><div><div>30</div></div><div><span>    </span><span>environment</span><span>:</span></div></div><div><div><div>31</div></div><div><span>      </span><span>CHEVERETO_DB_HOST</span><span>: </span><span>database</span></div></div><div><div><div>32</div></div><div><span>      </span><span>CHEVERETO_DB_USER</span><span>: </span><span>chevereto</span></div></div><div><div><div>33</div></div><div><span>      </span><span>CHEVERETO_DB_PASS</span><span>: </span><span>user_database_password</span></div></div><div><div><div>34</div></div><div><span>      </span><span>CHEVERETO_DB_PORT</span><span>: </span><span>3306</span></div></div><div><div><div>35</div></div><div><span>      </span><span>CHEVERETO_DB_NAME</span><span>: </span><span>chevereto</span></div></div><div><div><div>36</div></div><div><span>      </span><span>CHEVERETO_HOSTNAME</span><span>: </span><span>chevereto.leiting2020.top</span></div></div><div><div><div>37</div></div><div><span>      </span><span>CHEVERETO_HOSTNAME_PATH</span><span>: </span><span>/</span></div></div><div><div><div>38</div></div><div><span>      </span><span>CHEVERETO_HTTPS</span><span>: </span><span>0</span></div></div><div><div><div>39</div></div><div><span>      </span><span>CHEVERETO_MAX_POST_SIZE</span><span>: </span><span>2G</span></div></div><div><div><div>40</div></div><div><span>      </span><span>CHEVERETO_MAX_UPLOAD_SIZE</span><span>: </span><span>2G</span></div></div><div><div><div>41</div></div><div><span>      </span><span>#CHEVERETO_SERVICING: server # uncomment to enable application filesystem upgrades</span></div></div><div><div><div>42</div></div><div>
</div></div><div><div><div>43</div></div><div><span>networks</span><span>:</span></div></div><div><div><div>44</div></div><div><span>  </span><span>chevereto</span><span>:</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>配置完成后，执行启动命令，Docker会自动拉取镜像并创建容器：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 后台启动服务（-d表示 detached 模式）</span></div></div><div><div><div>2</div></div><div><span>docker-compose</span><span> </span><span>up</span><span> </span><span>-d</span></div></div><div><div><div>3</div></div><div><span># 查看容器运行状态（出现Up说明启动成功）</span></div></div><div><div><div>4</div></div><div><span>docker</span><span> </span><span>ps</span></div></div><div><div><div>5</div></div><div><span># 若启动失败，查看日志排查问题</span></div></div><div><div><div>6</div></div><div><span>docker-compose</span><span> </span><span>logs</span><span> </span><span>-f</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>使用 <code>docker ps</code> 命令检查容器是否创建成功。</p></section>
<section><h1>初始化chevereto<a href="#初始化chevereto"><span>#</span></a></h1><p>我是把 Chevereto 部署在群晖 NAS 上的，直接用 IP&lt;38080&gt; 访问太丑了，还没 HTTPS，所以得整个反向代理。群晖用户直接在Web Staion里弄就行。</p><p>如果是其他系统可以通过NPM/nginx进行配置。将域名反向代理到docker compose.yml中配置的 <code>CHEVERETO_HOSTNAME</code>域名。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251114203432238.png" alt="image-20251114203432238" /><figcaption>image-20251114203432238</figcaption></figure><p></p><p>然后就是 EdgeOne 的配置，解决内网没有公网 IPv4 的问题。我用了 DDNS-go 工具，把域名解析到群晖的 IPv6 地址，然后在 EdgeOne 控制台添加站点，源站填解析好的 IPv6 域名，开启 IPv6 回源和 HTTPS 免费证书。这样一来，纯 IPv4 网络也能通过域名访问我的图床了，还能享受 EdgeOne 的加速和防护，关键是免费不限流量，还是挺香的。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251114203919276.png" alt="image-20251114203919276" /><figcaption>image-20251114203919276</figcaption></figure><p></p><p>完成相关配置后，访问你在docker compose.yml中配置的 <code>CHEVERETO_HOSTNAME</code>域名即可。会自动转到安装界面，会自动跳转到 Chevereto 的安装界面，一步步来就行：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251114002737430.png" alt="image-20251114002737430" /><figcaption>image-20251114002737430</figcaption></figure><p></p><p>自己填好相关信息就可以完成登陆了。直接登陆，后台就是这样：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251114005044602.png" alt="image-20251114005044602" /><figcaption>image-20251114005044602</figcaption></figure><p></p><p>登录后台后，第一件事就是把语言改成中文，在 Settings→Language 里选 Chinese (Simplified)，保存后页面就变成中文了，看着舒服多了。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251114203555475.png" alt="image-20251114203555475" /><figcaption>image-20251114203555475</figcaption></figure><p></p><p>到这里，我们就完成chevereto的安装了。</p></section>
<section><h1>上传图片<a href="#上传图片"><span>#</span></a></h1><p>上传图片很简单，在任意界面都可以看到右上方有一个<code>上传</code>按钮，可以直接浏览本地图片进行上传。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251114204416091.png" alt="image-20251114204416091" /><figcaption>image-20251114204416091</figcaption></figure><p></p><p>Chevereto 的上传方式特别多，我最常用的是拖拽和剪贴板粘贴：</p><ul>
<li>写博客的时候，直接把本地图片拖拽到图床页面，自动上传；</li>
<li>微信、QQ 截图后，按 Ctrl+V 就能直接粘贴上传，不用保存本地，太省时间了。</li>
</ul><p>上传完成后，会自动弹出各种格式的链接，我写博客常用 Markdown 格式，直接复制粘贴到 Typora 里就行，不用再手动处理图片路径了。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251114204757084.png" alt="image-20251114204757084" /><figcaption>image-20251114204757084</figcaption></figure><p></p><p>双击图片还能查看详情，比如上传时间、大小、分辨率，还能生成不同尺寸的链接，功能挺全的。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251114205144849.png" alt="image-20251114205144849" /><figcaption>image-20251114205144849</figcaption></figure><p></p></section>
<section><h1>小结<a href="#小结"><span>#</span></a></h1><p>用了一段时间，Chevereto 整体挺稳定的，没出什么幺蛾子。搭配 EdgeOne 之后，不仅不用花钱买存储和流量，还解决了公网访问的问题，写博客上传图片的效率也提高了不少。后续我打算研究一下把图片同步到腾讯云 COS  做双备份，这样更安全，到时候再写一篇记录。</p><p>如果你也经常写博客，或者需要存很多图片，不想被第三方图床限制，真心推荐试试这个组合，折腾一次，后续能省不少事。</p></section>
<section><h1>参考<a href="#参考"><span>#</span></a></h1><ol>
<li><a href="https://v4-docs.chevereto.com/guides/docker/" target="_blank">Install Chevereto on Docker | Chevereto V4 Docs</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/627917691" target="_blank">(17 封私信 / 80 条消息) 使用Docker安装 Chevereto V4 搭建自己的图床 - 知乎</a></li>
<li><a href="https://blognas.hwb0307.com/linux/docker/485" target="_blank">Docker系列 搭建个人图床chevereto - Bensz</a></li>
<li><a href="https://blog.tangwudi.com/technology/docker7628/" target="_blank">docker系列 使用docker基于chevereto搭建属于自己的图床 - 无敌的个人博客</a></li>
<li><a href="https://mikublog.com/tech/1607" target="_blank">调教Chevereto（三）——给Chevereto图床上全套腾讯云服务 – MikuBlog</a></li>
<li><a href="https://www.howie6879.com/post/2022/05_pic-url-solution/" target="_blank">我的图床解决方案，超详细！ | 老胡的储物柜</a></li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/951/</id>
      <title type="text">自建网站访问数据统计工具: umami  Docker 部署全指南</title>
      <published>2025-11-09T15:32:20.000Z</published>
      <updated>2026-03-08T04:14:21.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/951/"/>
      <summary type="text">前言 如果你跟我一样，既想清楚知道自己的网站有多少人看、从哪来，又不想把用户数据拱手交给第三方，更受不了那些动辄弹出 “同意追踪” 的繁琐流程 —— 那 Umami 这工具，你大概率会喜欢。 它不搞花里胡哨，只把访问量、来源渠道、设备类型这</summary>
      <content type="html"><![CDATA[<section><h1>前言<a href="#前言"><span>#</span></a></h1><p>如果你跟我一样，既想清楚知道自己的网站有多少人看、从哪来，又不想把用户数据拱手交给第三方，更受不了那些动辄弹出 “同意追踪” 的繁琐流程 —— 那 Umami 这工具，你大概率会喜欢。</p><p>它不搞花里胡哨，只把访问量、来源渠道、设备类型这些核心数据摆得明明白白，一个页面全看清。关键是能自己部署，数据握在手里，开源免费还不折腾。</p><p>如果你想直观感受它的界面，可以访问官方 Demo：<a href="https://cloud.umami.is/analytics/eu/share/LGazGOecbDtaIwDr" target="_blank">Umami Demo</a>，核心数据看板如下：</p><img src="http://imgbed.leihub.cn/img/image-20251109172150130.png" alt="image-20251109172150130" /><p>实时流量监控更是精准到秒，能清晰看到当前访客的浏览行为：</p><img src="http://imgbed.leihub.cn/img/image-20251109161657477.png" alt="image-20251109161657477" /><p>接下来，我们就用 Docker 快速部署一套属于自己的 Umami。</p></section>
<section><h1>准备工作<a href="#准备工作"><span>#</span></a></h1><p>在开始部署前，先确认你的服务器满足以下条件：</p><ul>
<li>已安装 Docker 和 Docker Compose（如果未安装，可参考文末的补充命令）</li>
<li>有公网 IP（或本地服务器用于测试）</li>
<li>开放目标端口（默认 3000，可自定义）</li>
</ul><p>为了方便管理 Umami 的配置和数据，我们先创建一个独立的工作目录：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>cd</span><span> </span><span>~</span></div></div><div><div><div>2</div></div><div><span>mkdir</span><span> </span><span>-p</span><span> </span><span>~/opt/umami</span></div></div><div><div><div>3</div></div><div><span>cd</span><span> </span><span>~/opt/umami</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>如果需要通过服务器 IP 直接访问（非反向代理场景），需开放端口（以 3000 为例）：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>sudo</span><span> </span><span>ufw</span><span> </span><span>allow</span><span> </span><span>3000/tcp</span><span> </span><span>comment</span><span> </span><span>'umami'</span><span> &amp;&amp; </span><span>sudo</span><span> </span><span>ufw</span><span> </span><span>reload</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section>
<section><h1>配置yml文件<a href="#配置yml文件"><span>#</span></a></h1><p>Umami 需要依赖数据库存储数据（支持 PostgreSQL 或 MySQL，这里以 PostgreSQL 为例），我们用 docker-compose 统一管理应用和数据库容器。</p><p>在<code>~/opt/umami</code>目录下，新建<code>docker-compose.yml</code>文件，将以下内容复制到文件中：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>---</span></div></div><div><div><div>2</div></div><div><span>version</span><span>: </span><span>'3'</span></div></div><div><div><div>3</div></div><div><span>services</span><span>:</span></div></div><div><div><div>4</div></div><div><span>umami</span><span>:</span></div></div><div><div><div>5</div></div><div><span>  </span><span># 使用Umami官方最新镜像</span></div></div><div><div><div>6</div></div><div><span>  </span><span>image</span><span>: </span><span>ghcr.io/umami-software/umami:latest</span></div></div><div><div><div>7</div></div><div><span>  </span><span># 端口映射（左侧为服务器端口，右侧为容器内端口，可自定义左侧）</span></div></div><div><div><div>8</div></div><div><span>  </span><span>ports</span><span>:</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>- </span><span>"3000:3000"</span></div></div><div><div><div>10</div></div><div><span>  </span><span>environment</span><span>:</span></div></div><div><div><div>11</div></div><div><span>    </span><span># 数据库连接地址（格式：数据库类型://用户名:密码@数据库容器名:端口/数据库名）</span></div></div><div><div><div>12</div></div><div><span>    </span><span>DATABASE_URL</span><span>: </span><span>postgresql://umami:umamipassword@db:5432/umami</span></div></div><div><div><div>13</div></div><div><span>    </span><span># 数据库类型（postgresql或mysql）</span></div></div><div><div><div>14</div></div><div><span>    </span><span>DATABASE_TYPE</span><span>: </span><span>postgresql</span></div></div><div><div><div>15</div></div><div><span>    </span><span># 用于加密数据的随机字符串</span></div></div><div><div><div>16</div></div><div><span>    </span><span>HASH_SALT</span><span>: </span><span>your-random-string-here-123456</span></div></div><div><div><div>17</div></div><div><span>  </span><span># 依赖数据库容器，确保数据库先启动</span></div></div><div><div><div>18</div></div><div><span>  </span><span>depends_on</span><span>:</span></div></div><div><div><div>19</div></div><div><span><span>    </span></span><span>- </span><span>db</span></div></div><div><div><div>20</div></div><div><span>  </span><span># 自动重启</span></div></div><div><div><div>21</div></div><div><span>  </span><span>restart</span><span>: </span><span>always</span></div></div><div><div><div>22</div></div><div><span>  </span><span>networks</span><span>:</span></div></div><div><div><div>23</div></div><div><span><span>    </span></span><span>- </span><span>default</span></div></div><div><div><div>24</div></div><div>
</div></div><div><div><div>25</div></div><div><span>db</span><span>:</span></div></div><div><div><div>26</div></div><div><span>  </span><span># PostgreSQL镜像（15版本稳定，alpine版本体积更小）</span></div></div><div><div><div>27</div></div><div><span>  </span><span>image</span><span>: </span><span>ghcr.io/postgres:15-alpine</span></div></div><div><div><div>28</div></div><div><span>  </span><span>environment</span><span>:</span></div></div><div><div><div>29</div></div><div><span>    </span><span># 数据库名（建议保持默认）</span></div></div><div><div><div>30</div></div><div><span>    </span><span>POSTGRES_DB</span><span>: </span><span>umami</span></div></div><div><div><div>31</div></div><div><span>    </span><span># 数据库用户名（建议保持默认）</span></div></div><div><div><div>32</div></div><div><span>    </span><span>POSTGRES_USER</span><span>: </span><span>umami</span></div></div><div><div><div>33</div></div><div><span>    </span><span># 数据库密码（按需修改）</span></div></div><div><div><div>34</div></div><div><span>    </span><span>POSTGRES_PASSWORD</span><span>: </span><span>umamipassword</span></div></div><div><div><div>35</div></div><div><span>  </span><span>volumes</span><span>:</span></div></div><div><div><div>36</div></div><div><span>    </span><span># 映射数据目录到本地（确保数据持久化，重启容器不丢失）</span></div></div><div><div><div>37</div></div><div><span><span>    </span></span><span>- </span><span>./data:/var/lib/postgresql/data</span></div></div><div><div><div>38</div></div><div><span>  </span><span>restart</span><span>: </span><span>always</span></div></div><div><div><div>39</div></div><div><span>  </span><span>networks</span><span>:</span></div></div><div><div><div>40</div></div><div><span><span>    </span></span><span>- </span><span>default</span></div></div><div><div><div>41</div></div><div>
</div></div><div><div><div>42</div></div><div><span>networks</span><span>:</span></div></div><div><div><div>43</div></div><div><span>default</span><span>:</span></div></div><div><div><div>44</div></div><div><span>  </span><span># 自定义网络名称，避免与其他容器冲突</span></div></div><div><div><div>45</div></div><div><span>  </span><span>name</span><span>: </span><span>umami</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>所有配置完成后，启动容器：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>docker-compose</span><span> </span><span>up</span><span> </span><span>-d</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>启动成功后，可检查容器状态：</p><p>如果输出中<code>app</code>和<code>db</code>的状态都是<code>Up</code>，说明部署成功！</p><img src="http://imgbed.leihub.cn/img/image-20251109164335656.png" /></section>
<section><h1>反向代理<a href="#反向代理"><span>#</span></a></h1><p>直接通过<code>IP:端口</code>访问不够美观，且缺乏 HTTPS 安全层。我们可以用 Nginx（或 Caddy、Apache）做反向代理，绑定域名并配置 SSL。</p><section><h4>步骤 1：解析域名<a href="#步骤-1解析域名"><span>#</span></a></h4><p>先在域名解析平台（如阿里云、Cloudflare）将域名（如<code>umami.example.com</code>）解析到服务器 IP。</p></section><section><h4>步骤 2：Nginx 反向代理配置<a href="#步骤-2nginx-反向代理配置"><span>#</span></a></h4><p>在 Nginx 配置文件中添加以下内容。反代配置如下图所示：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>server</span></div></div><div><div><div>2</div></div><div><span>{</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>listen </span><span>80</span><span>;</span></div></div><div><div><div>4</div></div><div><span> <span> </span></span><span>listen </span><span>443</span><span> ssl http2;</span></div></div><div><div><div>5</div></div><div><span>   <span> </span></span><span>server_name </span><span>umami.example.com;</span></div></div><div><div><div>6</div></div><div><span>   <span> </span></span><span>root </span><span>/www/wwwroot/umami.example.com;</span></div></div><div><div><div>7</div></div><div><span>    </span><span>if</span><span> ($</span><span>server_port</span><span> !~ 443){</span></div></div><div><div><div>8</div></div><div><span>        </span><span>rewrite</span><span> </span><span>^(/.*)$</span><span> https://$</span><span>host</span><span>$</span><span>1</span><span> </span><span>permanent</span><span>;</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>    </span><span>####################</span></div></div><div><div><div>12</div></div><div><span>    </span><span># 其他配置</span></div></div><div><div><div>13</div></div><div><span>    </span><span>####################</span></div></div><div><div><div>14</div></div><div>
</div></div><div><div><div>15</div></div><div><span>    </span><span># 反代配置</span></div></div><div><div><div>16</div></div><div><span>    </span><span>location</span><span> ^~ </span><span>/   </span><span>{</span></div></div><div><div><div>17</div></div><div><span>   <span> </span></span><span>proxy_pass </span><span>http://127.0.0.1:3000;</span></div></div><div><div><div>18</div></div><div><span>   <span> </span></span><span>proxy_set_header </span><span>Host $</span><span>host</span><span>;</span></div></div><div><div><div>19</div></div><div><span>   <span> </span></span><span>proxy_set_header </span><span>X-Real-IP $</span><span>remote_addr</span><span>;</span></div></div><div><div><div>20</div></div><div><span>   <span> </span></span><span>proxy_set_header </span><span>X-Forwarded-For $</span><span>proxy_add_x_forwarded_for</span><span>;</span></div></div><div><div><div>21</div></div><div><span>   <span> </span></span><span>proxy_set_header </span><span>X-Forwarded-Proto $</span><span>scheme</span><span>;</span></div></div><div><div><div>22</div></div><div><span>   <span> </span></span><span>proxy_set_header </span><span>REMOTE-HOST $</span><span>remote_addr</span><span>;</span></div></div><div><div><div>23</div></div><div><span>   <span> </span></span><span>add_header </span><span>X-Cache $</span><span>upstream_cache_status</span><span>;</span></div></div><div><div><div>24</div></div><div><span>    </span><span># 缓存</span></div></div><div><div><div>25</div></div><div><span>   <span> </span></span><span>add_header </span><span>Cache-Control no-cache;</span></div></div><div><div><div>26</div></div><div><span>   <span> </span></span><span>expires </span><span>12h</span><span>;</span></div></div><div><div><div>27</div></div><div><span><span>  </span></span><span>}</span></div></div><div><div><div>28</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>如果用宝塔面板，操作更简单：在 “网站” 中添加站点，绑定域名后，在 “反向代理” 中设置目标 URL 为<code>http://127.0.0.1:3000</code>即可：</p><img src="http://imgbed.leihub.cn/img/image-20251109165236275.png" alt="image-20251109165236275" /></section><section><h4>步骤 3：首次登录：初始化设置<a href="#步骤-3首次登录初始化设置"><span>#</span></a></h4><p>访问你的域名（如<code>https://umami.example.com</code>），使用默认账号登录：</p><ul>
<li>用户名：<code>admin</code></li>
<li>密码：<code>umami</code></li>
</ul><p><strong>重要！</strong> 登录后第一件事：修改默认密码！进入 “设置”→“个人资料”，更新密码为强密码，避免被他人登录。</p><img src="http://imgbed.leihub.cn/img/image-20251109164821166.png" alt="image-20251109164821166" /></section></section>
<section><h1>使用方法<a href="#使用方法"><span>#</span></a></h1><section><h4>步骤 1：添加被统计网站<a href="#步骤-1添加被统计网站"><span>#</span></a></h4><p>进入后台，修改成简体中文后，添加一个网站：</p><img src="http://imgbed.leihub.cn/img/image-20251109165849806.png" alt="image-20251109165849806" /></section><section><h4>步骤 2：获取跟踪代码<a href="#步骤-2获取跟踪代码"><span>#</span></a></h4><p>添加网站后，点击网站右侧的 “编辑”→“跟踪代码”，复制生成的脚本：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>script</span><span> </span><span>defer</span><span> </span><span>src</span><span>=</span><span>"http://umami.leiting2020.top/script.js"</span><span> </span><span>data-website-id</span><span>=</span><span>"4c3c5b19-7a47-4dd6-ab0f-2542f91fa56a"</span><span>&gt;&lt;/</span><span>script</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><img src="http://imgbed.leihub.cn/img/image-20251109170124631.png" alt="image-20251109170124631" /></section><section><h4>步骤 3：安装跟踪代码到网站<a href="#步骤-3安装跟踪代码到网站"><span>#</span></a></h4><p>将跟踪代码添加到需要统计的网站中，具体位置因平台而异：</p><ul>
<li><strong>WordPress</strong>：在 “外观”→“主题文件编辑器”→“header.php”，粘贴到<code>&lt;head&gt;</code>标签内</li>
<li><strong>Hexo</strong>：在主题的<code>_config.yml</code>中找到 “自定义脚本” 配置项进行配置即可</li>
<li><strong>静态 HTML</strong>：直接粘贴到<code>&lt;head&gt;</code>标签内</li>
</ul><p>以 WordPress 为例，添加位置如下：</p><img src="http://imgbed.leihub.cn/img/image-20251109171346232.png" alt="image-20251109171346232" /><p>对于本博客使用的Argon主题来说，在页头或者页尾脚本中，添加这一段跟踪代码即可，  添加后保存Argon设置即可生效。</p><img src="http://imgbed.leihub.cn/img/image-20251109170842022.png" alt="image-20251109170842022" /><p><strong>为什么放<code>&lt;head&gt;</code>里？</strong> 因为<code>&lt;head&gt;</code>是网页加载时优先解析的部分，能确保跟踪代码尽早执行，避免遗漏短时间访问（如用户刚打开页面就关闭）。</p></section></section>
<section><h1>Umami 核心功能：能统计哪些数据？<a href="#umami-核心功能能统计哪些数据"><span>#</span></a></h1><p>部署完成后，等待 10-30 分钟（数据有延迟），就能在后台看到详细统计了，核心数据包括：</p><ul>
<li><strong>访问概览</strong>：访问量（ visitors ）、浏览量（ pageviews ）、平均访问时长、跳出率</li>
<li><strong>实时数据</strong>：当前在线人数、正在浏览的页面、访客 IP（匿名化）、设备信息</li>
<li><strong>页面分析</strong>：各页面的访问次数、停留时间、入口 / 出口页面</li>
<li><strong>访客分析</strong>：设备类型（手机 / 电脑 / 平板）、操作系统、浏览器</li>
<li><strong>来源分析</strong>：访客从哪个网站 / 搜索引擎跳转而来（支持识别 Google、百度、必应等）</li>
<li><strong>地理位置</strong>：访客所在国家 / 地区（基于 IP，非精确定位）</li>
</ul><img src="http://imgbed.leihub.cn/img/image-20251109174745725.png" alt="image-20251109174745725" /></section>
<section><h1>小结<a href="#小结"><span>#</span></a></h1><p>Umami 作为一款轻量、隐私友好的自建统计工具，完美平衡了功能与简洁性。通过本文的 Docker 部署教程，你可以在 10 分钟内搭建一套属于自己的网站分析系统，摆脱对第三方工具的依赖。</p></section>
<section><h1>参考<a href="#参考"><span>#</span></a></h1><ul>
<li><a href="https://github.com/umami-software/umami/tree/master" target="_blank">umami-software/umami: Umami is a modern, privacy-focused alternative to Google Analytics.</a></li>
<li><a href="https://www.eallion.com/umami/" target="_blank">Umami Docker 部署及优化 · eallion’s Blog</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/610262462" target="_blank">(12 封私信 / 80 条消息) 网站流量分析工具——Umami - 知乎</a></li>
<li><a href="https://blognas.hwb0307.com/linux/docker/661" target="_blank">Docker系列 通过umami监控网站流量 - Bensz</a></li>
</ul></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/941/</id>
      <title type="text">三清山徒步游记｜特种兵一日游</title>
      <published>2025-11-02T08:51:50.000Z</published>
      <updated>2026-03-08T04:16:01.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/941/"/>
      <summary type="text">周末朋友拉着去三清山徒步，本来想着预计花两天慢慢爬，结果我们 6 小时就把大环线刷完了。赶紧整理了这份攻略，给大家讲一下交通、路线、食宿的经验，给大家参考一下，少走冤枉路～ 交通 我们一行人从湖南株洲出发，实际用时一天，其他更远地方的游客可</summary>
      <content type="html"><![CDATA[<p>周末朋友拉着去三清山徒步，本来想着预计花两天慢慢爬，结果我们 6 小时就把大环线刷完了。赶紧整理了这份攻略，给大家讲一下交通、路线、食宿的经验，给大家参考一下，少走冤枉路～</p>
<img src="http://imgbed.leihub.cn/img/2e23466865e539234d1e30aaccf97861.jpg" alt="2e23466865e539234d1e30aaccf97861" />
<section><h2>交通<a href="#交通"><span>#</span></a></h2><p>我们一行人从湖南株洲出发，实际用时一天，其他更远地方的游客可根据当地车次情况自行考虑一个周末的时间是否足够。</p><p>✅ 高铁：快是快，但就是交通费有点肉疼，占了总花费的大头</p><p>✅ 卧铺火车：想省点钱的朋友可选这个，能省一半多，穷游党冲</p><img src="http://imgbed.leihub.cn/img/0d71cd1940b62e892d76bda42b693ad4.jpg" alt="0d71cd1940b62e892d76bda42b693ad4" /><p>从上饶站下车后，可乘坐班车或者出租车前往三清山，我们下火车是晚上九点半了，这个时候班车已经停运了，只能选择网约车前往，费用为140元（120元+20元高速费），三人出行，均价40+/人，也不算贵，出租车会走一截高速，约1个多小时就能到达目的地，比班车节约很多时间。</p><img src="http://imgbed.leihub.cn/img/4d46fd87a92a91e6a3bdbd6fc3ab386b.jpg" alt="4d46fd87a92a91e6a3bdbd6fc3ab386b" /></section>
<section><h2>路线规划<a href="#路线规划"><span>#</span></a></h2><p>三清山的地图如下图所示，一共有三处上山点，分别是金沙、外双溪以及港首。徒步上山必选<strong>外双溪</strong>，另外即使需要索道上山建议也选择外双溪，当天早上我们到达的时候（7点半）都没什么人，不用排队。而<strong>金沙</strong>那边旅游团特别多，人满为患。路线一共有三种，分别是小圈、中圈和大圈路线。</p><p><strong>小圈（蓝线）</strong>：入门版体验小圈路线，也是人最多的路线，特别多的老年团走这条线，人满为患。从<strong>金沙索道上山</strong>→巨蟒栈道→神陀峰→巨蟒出山→东方女神→女神栈道→<strong>金沙索道下山</strong>，用时<strong>2-3小时</strong>，比较轻松，经过核心景点，适合带小孩和老人、时间紧张的家庭。</p><p><strong>中圈（蓝线+橙线）</strong>：<strong>金沙索道上山</strong>→巨蟒栈道→神驼峰→巨蟒出山→东方女神→杜鹃谷→玉台→马头石→遥望主峰→玉女开怀→连升三级→生死恋→一线天→神龙戏松→东南沿海栈道→遥望天门群峰→遥望万寿园→<strong>金沙索道下山</strong>，用时<strong>4-5小时</strong>。</p><p><strong>大圈（蓝线+橙线+红线）</strong>：<strong>外双溪索道上山</strong>→天门山庄→老道拜月→犀牛石→日上山庄→玉兔奔月→福寿门→禹皇顶→秀峰→三龙出海→巨蟒出山→东方女神→杜鹃谷→玉台→马头石→玉女开怀→遥望主峰→连升三级→生死恋→一线天→神龙戏松→摩崖石刻→万寿园→牛背石→蒲牢鸣天→彭祖祝寿→<strong>外双溪索道下山</strong>。<strong>用时5-6小时</strong>，适合徒步达人、追求全景的游客，最好带好干粮和登山杖。</p><img src="http://imgbed.leihub.cn/img/3a7ac551ebd1134eb50e504e2d0641b4.png" alt="3a7ac551ebd1134eb50e504e2d0641b4" /><p>如果想要走大环线，推荐从外双溪索道上下，外双溪索道人比较少，旺季都不会排队很久。这个索道附近的景色很美，一下索道就可以看到绝美群峰，最经典的巨蟒出山和女神峰，走到禹皇顶和西海岸、阳光海岸都可以看到，不必执著于金沙索道上下。<strong>体力好比较推荐从外双溪上下，走到三清宫往返全程大概五六个小时！</strong></p><img src="http://imgbed.leihub.cn/img/a284f3a26e008db21eb429e7bd4018d0.jpg" alt="a284f3a26e008db21eb429e7bd4018d0" /><p>当时做路径规划的时候，考虑一天爬完，大环线全程也有16公里左右，而索道在下午五点就会关，为了防止夜晚下山的风险，选择了索道上下行。结果高估了整体登山的难度，很多人说外双溪费腿要爬山，实际就是索道出来后左拐走西海岸绕大圈，只有30分钟是爬山，剩下的全程都是平路或者下坡路。一点都不累，不要低估自己。</p><img src="http://imgbed.leihub.cn/img/3136020e4c1f2f0b35bf73340c3be652.jpg" alt="3136020e4c1f2f0b35bf73340c3be652" /><p>我们算是正常速度，从七点半开始爬，不到六个小时就完成了大环线同时还坐了索道下行。本来预留在山下住一晚的，结果一点多就到山下了，一看时间当天还能坐火车回湖南，就当天买票扛着火车回去了，也算是一次特种兵出行了。PS：如果当时没高估整体的难度，说不定还可以放弃索道上下行，徒步上山，如果采用步行估计用时2小时左右，下山约40分钟，那样更有挑战性一点，估计要多花3-4个小时，应该能在太阳下山前到达山下。</p><img src="http://imgbed.leihub.cn/img/81c6a65a0d5c2196541cf93d925d40e0.jpg" alt="81c6a65a0d5c2196541cf93d925d40e0" /></section>
<section><h2>饮食住宿消费<a href="#饮食住宿消费"><span>#</span></a></h2><p>在美团上看外双溪游客中心那一块的民宿，便宜的民宿卫生条件比较差，都推荐希尔顿，但一个标间就要五六百，太贵了。所以选择住在离游客中心6公里远的一家民宿，一百多一晚上，加卫生条件还不错，民宿老板还提供往返游客中心的接送服务，性价比还不错。</p><img src="http://imgbed.leihub.cn/img/b0bacdf721fbea5d62046cef4b6e967f.jpg" alt="b0bacdf721fbea5d62046cef4b6e967f" /><p>登山过程需要的水和食物最好提前准备。因为我们是坐索道上下行，准备了一些能量胶和士力架、三明治和鸡蛋。整体的体力消耗不算很大，行前准备的能量胶和士力架都没派上用场。</p><p>我们早上在民宿老板家里吃的早饭，一碗粉15，虽然说贵了点，但是味道还不错。</p><p>中午在山上吃的，因为消耗不大，啃了点三明治和鸡蛋就够了。</p><p>因为下山时间比较早，所以晚餐直接选择回长沙吃了。PS：同行伙伴一直念叨着上饶的鸡腿好吃，我们一起在上饶站花15大洋买了个大鸡腿，结果踩了大雷，又辣又难吃，我还被迫在火车站花8块大洋买瓶牛奶来压住辣味。</p><img src="http://imgbed.leihub.cn/img/e3d6218cb02a808fa84db44ef18e3fc2.jpg" alt="e3d6218cb02a808fa84db44ef18e3fc2" /></section>
<section><h2>天气与景观<a href="#天气与景观"><span>#</span></a></h2><ol>
<li>必看的景点 &amp; 天气​</li>
</ol><ul>
<li>
<p>核心景点：巨蟒出山、女神峰、禹皇顶、西海岸、阳光海岸，从外双溪索道走都能看到</p>
</li>
<li>
<p>最好选晴天去！我们去的时候天气好，能见度高，看山峰超震撼</p>
</li>
<li>
<p>不过有点小遗憾 —— 没碰到云雾绕山的 “仙山” 样子，想蹲云海的朋友可以提前看天气预报</p>
<img src="http://imgbed.leihub.cn/img/eaf926b341b0e1e6846099361de6ea64.jpg" alt="eaf926b341b0e1e6846099361de6ea64" />
</li>
</ul><ol>
<li>这些要注意</li>
</ol><ul>
<li>
<p>景区有些岔路口的指示牌不清不楚，我还走错了路，本来应该在玉台那穿过小卖铺网上走，结果没看到岔路，直接往下走了，绕了一大圈。。。在关键路口最好看一下高德地图，免得走冤枉路。</p>
</li>
<li>
<p>一线天那地方游客特别多，容易堵，尽量错峰过去</p>
</li>
</ul><img src="http://imgbed.leihub.cn/img/684765684becf77bc2b1eb1e780a3aa4.jpg" alt="684765684becf77bc2b1eb1e780a3aa4" /></section>
<section><h2>总结<a href="#总结"><span>#</span></a></h2><section><h3>费用明细<a href="#费用明细"><span>#</span></a></h3><ul>
<li>交通：株洲来回上饶的高铁票≈300x2元；上饶站来回三清山出租车≈50x2元；</li>
<li>门票：门票+上下行索道：245元；</li>
<li>住宿：住宿：180/3=60元；</li>
</ul><p>总花费1000元左右，大头是高铁费用，如果转成卧铺火车，估计能节省一大半费用。</p><p>三清山风景是真的美，一日特种兵徒步完全没问题！希望这份攻略能够帮到你。</p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/936/</id>
      <title type="text">EasyTier 私有虚拟网络搭建全流程</title>
      <published>2025-10-26T16:22:39.000Z</published>
      <updated>2026-03-08T04:26:19.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/936/"/>
      <summary type="text">EasyTier 私有虚拟网络搭建全流程 EasyTier简介 在国内复杂的网络环境中，内网穿透和异地组网始终是个棘手问题。之前折腾过 Zerotier、Tailscale 等工具的朋友可能深有体会，网络通畅时，P2P 直连体验流畅。可一旦</summary>
      <content type="html"><![CDATA[<section><h1><strong>EasyTier 私有虚拟网络搭建全流程</strong><a href="#easytier-私有虚拟网络搭建全流程"><span>#</span></a></h1><section><h2>EasyTier简介<a href="#easytier简介"><span>#</span></a></h2><p>在国内复杂的网络环境中，内网穿透和异地组网始终是个棘手问题。之前折腾过 Zerotier、Tailscale 等工具的朋友可能深有体会，网络通畅时，P2P 直连体验流畅。可一旦遇到 NAT 复杂或网络波动，就不得不依赖国外中继服务器 —— 延迟飙升、速度骤降几乎成了常态。</p><p>最近接触到了国内的一个开源穿透软件EasyTier ，EasyTier是一个简单、安全、去中心化的内网穿透 SD-WAN 方案，使用 Rust 语言实现。它实现了零拷贝和全链路高性能，性能与主流组网软件相当。EasyTier 支持跨平台运行，包括 MacOS/Linux/Windows/FreeBSD/Android，未来还将支持 iOS。可执行文件静态链接，部署简单。</p></section><section><h2>EasyTier的特点<a href="#easytier的特点"><span>#</span></a></h2><ul>
<li><strong>去中心化</strong>：无需依赖中心化服务，节点平等且独立。</li>
<li><strong>安全</strong>：支持利用 WireGuard 加密通信，也支持 AES-GCM 加密保护中转流量。</li>
<li><strong>高性能</strong>：全链路零拷贝，性能与主流组网软件相当。</li>
<li><strong>跨平台</strong>：支持 MacOS/Linux/Windows/FreeBSD/Android，未来将支持 iOS。</li>
<li><strong>无公网 IP 组网</strong>：支持利用共享的公网节点组网。</li>
<li><strong>NAT 穿透</strong>：支持基于 UDP 的 NAT 穿透，在复杂的网络环境下也能建立稳定的连接。</li>
<li><strong>子网代理（点对网）</strong>：节点可以将可访问的网段作为虚拟网暴露给其他节点，允许其他节点通过这些节点访问子网。</li>
<li><strong>智能路由</strong>：根据流量智能选择链路，减少延迟，提高吞吐量。</li>
<li><strong>TCP 支持</strong>：在 UDP 受限的情况下，通过并发 TCP 链接提供可靠的数据传输，优化性能。</li>
<li><strong>高可用性</strong>：支持多路径和在检测到高丢包率或网络错误时切换到健康路径。</li>
<li><strong>IPV6 支持</strong>：支持利用 IPV6 组网。</li>
</ul></section><section><h2>安装(docker-compose)<a href="#安装docker-compose"><span>#</span></a></h2><section><h3>服务端配置<a href="#服务端配置"><span>#</span></a></h3><p>创建配置目录</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>sudo </span><span>mkdir</span><span> -p /opt/easytier</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>创建一个<code>docker-compose.yml</code>和<code>config.yaml</code>文件：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>vim /opt/easytier/docker-compose.yml</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><code>docker-compose.yml</code>填入以下内容（注意<code>#</code>号标注相关提示）：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>services:</span></div></div><div><div><div>2</div></div><div><span>  </span><span># 可选：自动更新镜像的watchtower</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>watchtower:</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>image: containrrr/watchtower:latest</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>container_name: easytier-watchtower</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>restart: unless-stopped</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>environment:</span></div></div><div><div><div>8</div></div><div><span><span>      </span></span><span>- TZ=Asia/Shanghai</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>volumes:</span></div></div><div><div><div>10</div></div><div><span><span>      </span></span><span>- /var/run/docker.sock:/var/run/docker.sock</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>command: --interval 3600 --cleanup --label-enable</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>  </span><span># easytier服务端</span></div></div><div><div><div>14</div></div><div><span><span>  </span></span><span>easytier-server:</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>image: easytier/easytier:latest  # 国内：m.daocloud.io/docker.io/easytier/easytier:latest</span></div></div><div><div><div>16</div></div><div><span><span>    </span></span><span>container_name: easytier-server</span></div></div><div><div><div>17</div></div><div><span><span>    </span></span><span>hostname: easytier-server  # 与配置文件中hostname一致</span></div></div><div><div><div>18</div></div><div><span><span>    </span></span><span>labels:</span></div></div><div><div><div>19</div></div><div><span><span>      </span></span><span>com.centurylinklabs.watchtower.enable: </span><span>'true'</span><span>  # 允许watchtower更新</span></div></div><div><div><div>20</div></div><div><span><span>    </span></span><span>restart: unless-stopped</span></div></div><div><div><div>21</div></div><div><span><span>    </span></span><span>network_mode: host  # 必须用host模式，确保端口监听正常</span></div></div><div><div><div>22</div></div><div><span><span>    </span></span><span>cap_add:</span></div></div><div><div><div>23</div></div><div><span><span>      </span></span><span>- NET_ADMIN  # 允许网络配置（如创建tun设备）</span></div></div><div><div><div>24</div></div><div><span><span>      </span></span><span>- NET_RAW</span></div></div><div><div><div>25</div></div><div><span><span>    </span></span><span>environment:</span></div></div><div><div><div>26</div></div><div><span><span>      </span></span><span>- TZ=Asia/Shanghai</span></div></div><div><div><div>27</div></div><div><span><span>    </span></span><span>devices:</span></div></div><div><div><div>28</div></div><div><span><span>      </span></span><span>- /dev/net/tun:/dev/net/tun  # 提供WireGuard隧道支持</span></div></div><div><div><div>29</div></div><div><span><span>    </span></span><span>volumes:</span></div></div><div><div><div>30</div></div><div><span><span>      </span></span><span>- /opt/easytier:/root  # 挂载配置目录到容器内/root</span></div></div><div><div><div>31</div></div><div><span><span>      </span></span><span>- /etc/machine-id:/etc/machine-id:ro  # 保持机器标识一致</span></div></div><div><div><div>32</div></div><div><span><span>    </span></span><span>command: --config-file /root/config.yaml  # 加载配置文件</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p><code>config.yaml</code>文件输入以下核心配置文件内容</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># 服务端基础信息（唯一标识）</span></div></div><div><div><div>2</div></div><div><span>hostname = "easytier-server"</span><span>  </span><span># 服务端主机名（自定义，需唯一）</span></div></div><div><div><div>3</div></div><div><span>instance_name = "primary-server"</span><span>  </span><span># 实例名称（区分多个服务端）</span></div></div><div><div><div>4</div></div><div><span>instance_id = "f47ac10b-58cc-4372-a567-0e02b2c3d479"</span><span>  </span><span># 标准UUID（必填，需唯一，生成方法见下方）</span></div></div><div><div><div>5</div></div><div><span>ipv4 = "10.126.126.1/24"</span><span>  </span><span># 虚拟网络IP（建议用网段首个IP，如.1）</span></div></div><div><div><div>6</div></div><div><span>dhcp = false</span><span>  </span><span># 服务端固定IP，关闭DHCP</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span># 监听端口（客户端通过这些端口连接）</span></div></div><div><div><div>9</div></div><div><span>listeners = [</span></div></div><div><div><div>10</div></div><div><span>    </span><span>"tcp://0.0.0.0:11010"</span><span>,  </span><span># TCP协议监听（推荐客户端优先使用）</span></div></div><div><div><div>11</div></div><div><span>    </span><span>"udp://0.0.0.0:11010"</span><span>,  </span><span># UDP协议监听</span></div></div><div><div><div>12</div></div><div><span>    </span><span>"wg://0.0.0.0:11011"</span><span>    </span><span># WireGuard加密协议监听（需tun设备支持）</span></div></div><div><div><div>13</div></div><div><span>]</span></div></div><div><div><div>14</div></div><div>
</div></div><div><div><div>15</div></div><div><span># RPC端口（0表示随机分配，服务端无需固定）</span></div></div><div><div><div>16</div></div><div><span>rpc_portal = "0.0.0.0:0"</span></div></div><div><div><div>17</div></div><div>
</div></div><div><div><div>18</div></div><div><span># 网络标识（客户端必须完全匹配才能加入网络）</span></div></div><div><div><div>19</div></div><div><span>[</span><span>network_identity</span><span>]</span></div></div><div><div><div>20</div></div><div><span>network_name = "my-easytier-network"</span><span>  </span><span># 网络名称（自定义，如公司/项目名）</span></div></div><div><div><div>21</div></div><div><span>network_secret = "your-secure-secret-123"</span><span>  </span><span># 网络密钥（类似密码，建议复杂字符串）</span></div></div><div><div><div>22</div></div><div>
</div></div><div><div><div>23</div></div><div><span># 服务端无需配置[[peer]]（客户端会主动连接服务端）</span></div></div><div><div><div>24</div></div><div><span># 若多服务端集群，可在此添加其他服务端的uri（如"tcp://server2-ip:11010"）</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>在当前目录下，运行代码直接编排容器上线即可：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 启动容器</span></div></div><div><div><div>2</div></div><div><span>docker-compose up -d</span></div></div><div><div><div>3</div></div><div><span># 查看日志（确认启动成功）</span></div></div><div><div><div>4</div></div><div><span>docker logs -f easytier-server</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>开放防火墙端口</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 开放TCP/UDP 11010和WireGuard 11011端口</span></div></div><div><div><div>2</div></div><div><span>sudo ufw allow 11010/tcp</span></div></div><div><div><div>3</div></div><div><span>sudo ufw allow 11010/udp</span></div></div><div><div><div>4</div></div><div><span>sudo ufw allow 11011/udp</span></div></div><div><div><div>5</div></div><div><span>sudo ufw reload</span></div></div><div><div><div>6</div></div><div><span># 若用云服务器（如阿里云/腾讯云），需在安全组中同步开放上述端口</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>客户端配置<a href="#客户端配置"><span>#</span></a></h3><p>客户端需连接服务端加入虚拟网络，配置核心是匹配服务端的网络标识，并指定服务端的连接地址。</p><p>安装配置文件<code>docker-compose.yml</code>与服务端一致，只需要修改和<code>config.yaml</code>文件</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># 客户端基础信息（唯一标识）</span></div></div><div><div><div>2</div></div><div><span>hostname = "client-pc-01"</span><span>  </span><span># 客户端主机名（自定义，需唯一）</span></div></div><div><div><div>3</div></div><div><span>instance_name = "office-client"</span><span>  </span><span># 实例名称（区分多个客户端）</span></div></div><div><div><div>4</div></div><div><span>instance_id = "a1b2c3d4-5678-4f5e-8a9b-0c1d2e3f4a5b"</span><span>  </span><span># 客户端唯一UUID（与服务端不同）</span></div></div><div><div><div>5</div></div><div><span>ipv4 = "10.126.126.2/24"</span><span>  </span><span># 虚拟网络IP（与服务端同一网段，如.2、.3等）</span></div></div><div><div><div>6</div></div><div><span>dhcp = false</span><span>  </span><span># 客户端固定IP</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span># 客户端无需开放监听（若需被其他节点主动连接，可添加监听端口）</span></div></div><div><div><div>9</div></div><div><span>listeners = []</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span># RPC端口（随机分配）</span></div></div><div><div><div>12</div></div><div><span>rpc_portal = "0.0.0.0:0"</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span># 网络标识（必须与服务端完全一致）</span></div></div><div><div><div>15</div></div><div><span>[</span><span>network_identity</span><span>]</span></div></div><div><div><div>16</div></div><div><span>network_name = "my-easytier-network"</span><span>  </span><span># 与服务端network_name相同</span></div></div><div><div><div>17</div></div><div><span>network_secret = "your-secure-secret-123"</span><span>  </span><span># 与服务端network_secret相同</span></div></div><div><div><div>18</div></div><div>
</div></div><div><div><div>19</div></div><div><span># 需连接的服务端地址（至少填写服务端的TCP/UDP地址）</span></div></div><div><div><div>20</div></div><div><span>[[</span><span>peer</span><span>]]</span></div></div><div><div><div>21</div></div><div><span>uri = "tcp://服务端公网IP:11010"</span><span>  </span><span># 替换为服务端的公网IP或域名</span></div></div><div><div><div>22</div></div><div>
</div></div><div><div><div>23</div></div><div><span>[[</span><span>peer</span><span>]]</span></div></div><div><div><div>24</div></div><div><span>uri = "udp://服务端公网IP:11010"</span><span>  </span><span># 可选，提高连接稳定性</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h3>客户端验证<a href="#客户端验证"><span>#</span></a></h3><p>日志中出现以下信息说明连接成功：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>successfully connected to peer: tcp://服务端IP:11010</span></div></div><div><div><div>2</div></div><div><span>virtual network ip assigned: 10.126.126.2</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>测试虚拟网络通信，客户端执行<code>ping 10.126.126.1</code>（服务端虚拟 IP），能 ping 通则说明网络互通。</p><p>使用 <code>easytier-cli peer</code> 查看子网中的节点信息：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>easytier-cli</span><span> </span><span>peer</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>输出示例：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251026235557438.png" alt="image-20251026235557438" /><figcaption>image-20251026235557438</figcaption></figure><p></p><p>使用 <code>easytier-cli route</code> 查看子网中的路由信息：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>easytier-cli</span><span> </span><span>route</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>输出示例：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251026235726258.png" alt="image-20251026235726258" /><figcaption>image-20251026235726258</figcaption></figure><p></p><p>使用 <code>easytier-cli node</code> 查看本节点的信息：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>easytier-cli</span><span> </span><span>node</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>输出示例：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251026235758346.png" alt="image-20251026235758346" /><figcaption>image-20251026235758346</figcaption></figure><p></p><p>这是windows下gui的配置情况</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251026235149588.png" alt="image-20251026235149588" /><figcaption>image-20251026235149588</figcaption></figure><p></p></section></section><section><h2>关闭转发<a href="#关闭转发"><span>#</span></a></h2><p>默认情况下，Easytier 的每个节点都允许为其他虚拟网提供转发服务，即使已加入一个虚拟网。若需改变此行为，可通过 <code>--relay-whitelist</code> 参数限定可转发的网络白名单（空格分隔的通配符列表）。当列表为空时，则不会为所有其他网络提供转发服务。例如：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>easytier-core</span><span> </span><span>--relay-whitelist</span><span> </span><span>relay-all</span><span> </span><span>--relay-all-peer-rpc</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>只需设置参考白名单为空，同时仅允许转发 RPC 流量即可。</p></section><section><h2>小结<a href="#小结"><span>#</span></a></h2><p>用了一段时间了，从实际用下来的感受看，EasyTier 最关键的好处就是 ——<strong>特别适配咱们国内的网络环境</strong>。不管是面对复杂的 NAT 网络，穿透成功率，还是用 WireGuard 加密传输的速度和稳定性，都比那些依赖国外中继服务器的工具稳一些。</p><p>而且它是去中心化的 P2P 方案，不用怕单个服务器挂了整个网络就崩了，节点之间直接连接，还能最大程度减少延迟。另外它还支持多平台，不同设备组网特别方便。不管是个人异地办公、家里设备互联，还是小团队做内网穿透，都很合适。</p><p>感兴趣的小伙伴不妨来试试 EasyTier。</p></section><section><h2>参考<a href="#参考"><span>#</span></a></h2><ol>
<li><a href="https://easytier.cn/guide/network/quick-networking.html" target="_blank">快速组网 | EasyTier - 简单、安全、去中心化的异地组网方案</a></li>
</ol></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/933/</id>
      <title type="text">wordpress遇到的小问题记录</title>
      <published>2025-10-20T13:58:17.000Z</published>
      <updated>2026-03-08T04:24:59.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/933/"/>
      <summary type="text">这篇文章用于记录wordpress配置中遇到的小问题，当作自己的错题本来用了。 1、伪静态配置问题 报错现象 当我迁移完博客时，发现迁移后的博客首页可以访问，但是博客下面的文章，比如/archives/908/这样的链接就会报404错误。 </summary>
      <content type="html"><![CDATA[<p>这篇文章用于记录wordpress配置中遇到的小问题，当作自己的错题本来用了。</p>
<section><h2>1、伪静态配置问题<a href="#1伪静态配置问题"><span>#</span></a></h2><section><h3>报错现象<a href="#报错现象"><span>#</span></a></h3><p>当我迁移完博客时，发现迁移后的博客首页可以访问，但是博客下面的文章，比如/archives/908/这样的链接就会报404错误。</p><img src="http://imgbed.leihub.cn/img/image-20251026213113444.png" alt="image-20251026213113444" /><p>如果我在wordpress固定链接里设置为朴素型链接，比如<a href="https://blog.leihub.cn/?p=123%E8%BF%99%E6%A0%B7%E5%B0%B1%E6%B2%A1%E9%97%AE%E9%A2%98">https://blog.leihub.cn/?p=123这样就没问题</a></p><p>在网上搜了一遍，初步推测是<strong>伪静态规则未正确配置</strong> 导致的。</p><p>因为<strong>朴素型链接（<code>?p=123</code>）<strong>是 WordPress 默认的「查询字符串形式」，本质是</strong>动态 URL</strong>。它的结构是 <code>域名/index.php?p=123</code>（浏览器会省略 <code>index.php</code>，直接显示 <code>?p=123</code>）。服务器收到这种请求时，会默认将 <code>?p=123</code> 作为参数传递给网站根目录的 <code>index.php</code> 处理（因为 URL 中包含 <code>?</code> 符号，服务器知道这是动态参数，需要交给 PHP 解析）。所以无论有没有伪静态规则，服务器都能正确找到 <code>index.php</code> 并处理请求，因此不会报错。</p><p>因为 WordPress 的 <strong>数字型链接</strong>（如 <code>/archives/908</code>）属于自定义固定链接，这种格式是「静态化 URL」，服务器收到这种请求时，默认逻辑是：<strong>查找是否存在对应的物理文件或目录</strong>，但实际上，<code>/archives/908</code> 并不是真实的文件 / 目录，而是 WordPress 为了美观和 SEO 设计的「虚拟路径」，真正处理请求的还是 <code>index.php</code>。需要服务器通过重写规则（Rewrite）将请求转发到 <code>index.php</code> 处理，否则服务器会认为该链接对应的文件不存在，从而返回 「404 Not Found」错误。</p><img src="http://imgbed.leihub.cn/img/image-20251026213317811.png" alt="image-20251026213317811" /></section><section><h3>解决方法<a href="#解决方法"><span>#</span></a></h3><p>解决方法就是按之前提到的步骤，为 Nginx 配置正确的 rewrite 规则，或为 Apache 配置正确的 <code>.htaccess</code> 文件，确保虚拟路径能被转发到 <code>index.php</code>。</p><section><h4><strong>Nginx</strong><a href="#nginx"><span>#</span></a></h4><p>因为我使用的是宝塔面板，可以直接使用宝塔的默认模板进行配置，相对简单一点。</p><p>手动配置 Nginx 的伪静态规则：</p><ul>
<li>登录宝塔面板 → 左侧「网站」→ 找到你的 WordPress 站点，点击「设置」→「伪静态」。</li>
<li>在伪静态设置页面，下拉选择「WordPress」模板（宝塔已预设好规则），点击「保存」。</li>
</ul><img src="http://imgbed.leihub.cn/img/image-20251026214106006.png" alt="image-20251026214106006" /><ul>
<li>若没有「WordPress」模板，手动粘贴以下规则：</li>
</ul><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>location</span><span> / {</span></div></div><div><div><div>2</div></div><div><span>   <span> </span></span><span>try_files </span><span>$</span><span>uri</span><span> $</span><span>uri</span><span>/ /index.php?$</span><span>args</span><span>;</span></div></div><div><div><div>3</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure></div><ul>
<li>保存后，重启 Nginx 服务（宝塔「软件商店」→ 找到 Nginx → 点击「重启」）。</li>
</ul><p>设置好伪静态规则后，博客就可以正常访问了。</p><img src="http://imgbed.leihub.cn/img/image-20251026214432664.png" alt="image-20251026214432664" /></section><section><h4><strong>Apache</strong><a href="#apache"><span>#</span></a></h4><p>因为我没用<strong>Apache</strong>，这里就简单贴一下网上描述的解决方法供大家参考。</p><p>Apache 依赖网站根目录下的 <code>.htaccess</code> 文件实现重写，若文件缺失或权限不足会导致 404：</p><ul>
<li>
<p>宝塔面板 →「网站」→ 你的站点 →「文件」，进入网站根目录（如 <code>/www/wwwroot/你的域名</code>）。</p>
</li>
<li>
<p>确认是否存在<code>.htaccess</code>文件。</p>
<ul>
<li>
<p>若不存在：新建一个 <code>.htaccess</code> 文件，粘贴以下内容：</p>
</li>
<li>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># BEGIN WordPress</span></div></div><div><div><div>2</div></div><div><span>&lt;IfModule </span><span>mod_rewrite.c</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span>RewriteEngine</span><span> On</span></div></div><div><div><div>4</div></div><div><span>RewriteBase</span><span> /</span></div></div><div><div><div>5</div></div><div><span>RewriteRule</span><span> </span><span>^index\.php$</span><span> </span><span>-</span><span> [L]</span></div></div><div><div><div>6</div></div><div><span>RewriteCond</span><span> </span><span>%{REQUEST_FILENAME}</span><span> </span><span>!-f</span></div></div><div><div><div>7</div></div><div><span>RewriteCond</span><span> </span><span>%{REQUEST_FILENAME}</span><span> </span><span>!-d</span></div></div><div><div><div>8</div></div><div><span>RewriteRule</span><span> </span><span>.</span><span> </span><span>/index.php</span><span> [L]</span></div></div><div><div><div>9</div></div><div><span>&lt;/IfModule&gt;</span></div></div><div><div><div>10</div></div><div><span># END WordPress</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p>若存在：检查内容是否与上面一致，不一致则替换。</p>
</li>
<li>
<p>设置文件权限：右键 <code>.htaccess</code> →「权限」，设置为 <code>644</code>（所有者读写，其他只读），确保 Apache 能读取该文件。</p>
</li>
<li>
<p>宝塔「软件商店」→ 找到 Apache → 点击「设置」→「模块」，检查 <code>rewrite</code> 模块是否已勾选（默认已启用，若未勾选则勾选后重启 Apache）。</p>
</li>
</ul>
</li>
</ul></section></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/908/</id>
      <title type="text">天堂在左，雨崩在右｜2025 国庆中秋雨崩徒步全记录</title>
      <published>2025-10-11T18:00:36.000Z</published>
      <updated>2026-03-08T04:28:31.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/908/"/>
      <summary type="text">作为一名户外新手，今年国庆被同事 “拐” 去雨崩时，我连 “雨崩” 两个字都没听过 —— 直到在小红书刷到满屏的梅里雪山、原始村落，才知道这是户外圈公认的 “新手入坑圣地”。5 天 4 夜的行程里，有高反的狼狈、徒步的极限，也有星空下的青旅</summary>
      <content type="html"><![CDATA[<p>作为一名户外新手，今年国庆被同事 “拐” 去雨崩时，我连 “雨崩” 两个字都没听过 —— 直到在小红书刷到满屏的梅里雪山、原始村落，才知道这是户外圈公认的 “新手入坑圣地”。5 天 4 夜的行程里，有高反的狼狈、徒步的极限，也有星空下的青旅和冰瀑前的震撼，整理成这篇攻略，希望能帮到同样想出发的你～</p>
<section><h2>目录<a href="#目录"><span>#</span></a></h2><ol>
<li>Day1：株洲→香格里拉｜赶路 + 高反初体验</li>
<li>Day2：香格里拉→尼农→雨崩｜14 公里徒步 + 雨夜进山</li>
<li>Day3：雨崩冰湖线｜最累的 14 公里</li>
<li>Day4：雨崩神瀑线｜最轻松的 “公园级” 徒步</li>
<li>Day5：雨崩→株洲｜极限赶车日</li>
<li>全程费用 + 新手必备清单</li>
</ol><section><h3>Day1：株洲→香格里拉｜赶路 + 高反初体验<a href="#day1株洲香格里拉赶路--高反初体验"><span>#</span></a></h3><p><strong>核心行程</strong>：株洲→长沙黄花机场→昆明长水机场→昆明站→香格里拉站
10 月 3 号的行程从 “凌晨 4 点起床” 开始 —— 为了赶 6&lt;55&gt; 长沙飞昆明的早班机，我的搭子差点迟到，最后 5 分钟冲进机场。</p><ul>
<li>
<p><strong>长沙→昆明</strong>：飞行 1.5 小时，落地长水机场后，去昆明站的公交选「919 路机场专线」，20 分钟一班，车程 40 分钟，票价 15 元，比打车省一半钱；</p>
<img src="http://imgbed.leihub.cn/img/IMG_20251003_071759.jpg" alt="IMG_20251003_071759" />
</li>
<li>
<p><strong>昆明中转 3 小时</strong>：我们去了昆明站旁的「万达广场云山雀」，现切的菌子刺身配芥末，鲜到跺脚！怕肠胃不适的朋友可以选菌子火锅，更稳妥；</p>
<img src="http://imgbed.leihub.cn/img/mmexport1759468479219.jpg" alt="昆明菌子刺身——国庆雨崩行中转美食" />
</li>
<li>
<p><strong>昆明→香格里拉</strong>：5 小时火车（C字头，国庆建议提前 15 天抢票！我们回程没抢到坐票，全程无座累到懵），傍晚 6 点到香格里拉站时，我突然心率飙升 —— 高反来了！</p>
<img src="http://imgbed.leihub.cn/img/IMG_20251003_183125_1.jpg" alt="香格里拉站傍晚景色——国庆雨崩行第一站" />
</li>
</ul><p><strong>高原反应</strong>：</p><ol>
<li>香格里拉海拔 3300 米，刚到别跑跳！我们提前订了「含接站的酒店」（避免走路加重高反），到酒店后只敢慢走找吃的，结果走 50 米就气喘，嘴唇发绀（发紫）；</li>
<li>当晚没洗澡（高反时洗澡易缺氧），休息一晚上后，第二天早上明显好转；</li>
</ol></section><section><h3>Day2：香格里拉→尼农→雨崩｜14 公里徒步 + 雨夜进山<a href="#day2香格里拉尼农雨崩14-公里徒步--雨夜进山"><span>#</span></a></h3><p><strong>核心行程</strong>：香格里拉租车→金沙江打卡→梅里雪山售票→尼农徒步入口→下雨崩→上雨崩</p><p>早上 8 点在香格里拉打了个了皮卡上尼龙，把行李箱寄在司机家。</p><ul>
<li>
<p><strong>香格里拉→尼农</strong>：4 小时车程，会经过海拔 4200 米的垭口，我轻微高反（头晕）；中途会路过「金沙江大拐弯观景台」（免费），红军长征途经地，拍照超有意义，建议停留 10 分钟打卡；</p>
<img src="http://imgbed.leihub.cn/img/IMG_20251004_100048.jpg" alt="香格里拉到尼农必经：金沙江大拐弯，缅怀先烈的同时别忘拍全景" />
</li>
<li>
<p><strong>梅里雪山门票</strong>：2025 年价格是 55 元 / 人，无需提前预约，但国庆人多，拍照别太久！我们因为在售票处沉迷拍雪山，让同行美女和司机等了 20 分钟，直接导致后续赶夜路；</p>
<img src="http://imgbed.leihub.cn/img/mmexport1759588660487.jpg" alt="梅里雪山景区打卡" />
<img src="http://imgbed.leihub.cn/img/mmexport1759834541096.jpg" alt="梅里雪山门票打卡" />
</li>
<li>
<p><strong>尼农→下雨崩徒步</strong>：中午 12 点开始，14 公里山路 + 1000 米爬升，刚走 1 小时就下雨（国庆雨崩多雨！必带「防水徒步鞋 + 轻便雨衣」，登山杖能省 30% 体力）。</p>
</li>
</ul><p>6 小时后，我们在晚上 6 点终于到下雨崩，又冷又累，随便吃了饭，再往上雨崩时，我体力彻底透支，选了当地皮卡代步（80 元 / 人，单程，晚上只有皮卡能走）。</p><img src="http://imgbed.leihub.cn/img/mmexport1759588750245.jpg" alt="徒步的狼狈墨阳" /><p><strong>住宿推荐</strong>：「德钦帕萨青旅」（床位 350 元 / 晚），新床位很干净，有公共客厅能烤火，我在雨崩 4 晚里，这晚睡得最香！提醒：刚到雨崩别洗澡，高反会加重，擦身即可。
</p></section><section><h3>Day3：雨崩冰湖线｜最累的 14 公里<a href="#day3雨崩冰湖线最累的-14-公里"><span>#</span></a></h3><p><strong>核心行程</strong>：上雨崩→冰湖观景台→大本营→绝望坡→冰湖→下撤</p><p>冰湖线是雨崩经典路线，来回 14 公里 + 800 米爬升，前一天下雨后，山路全是泥（穿「防水徒步鞋」！我看到有人穿运动鞋，鞋底全是泥，走一步滑一步）。作为 “娇弱男孩”，我走 50 米就要停，高反又犯了（头痛 + 喘气），靠「慢慢走」缓解。</p><img src="http://imgbed.leihub.cn/img/mmexport1759674941148.jpg" alt="冰湖线雨后泥泞路，穿防水鞋+登山杖是刚需，不然太费脚" /><ul>
<li>
<p><strong>观景台不是终点</strong>：爬 3个小时到冰湖观景台时，别以为快到了！后面还要下陡坡、再爬 “绝望坡” ，全是碎石，建议手脚并用，别抬头看，盯着脚下走）；</p>
<img src="http://imgbed.leihub.cn/img/mmexport1759674343511.jpg" alt="mmexport1759674343511" />
</li>
<li>
<p><strong>冰湖打卡</strong>：终于到冰湖时，我高反加重，只拍了 5 分钟就撤（冰湖海拔 3800 米）；</p>
<img src="http://imgbed.leihub.cn/img/IMG_20251005_160703.jpg" alt="冰湖超冷！建议速战速决，高反严重别硬撑，安全第一" />
</li>
<li>
<p><strong>下撤选骡子</strong>：傍晚 4 点开始下撤，天快黑了，山路更滑，我实在走不动，在大本营租了骡子（555 元 / 人，单程，只能到上雨崩，国庆要排队，建议提前和向导说）。</p>
</li>
</ul><p><strong>避坑提醒</strong>：冰湖线到了大本营才有补给站，一定要带够水（2L）和干粮（巧克力、能量棒），别指望中途买东西！</p></section><section><h3>Day4：雨崩神瀑线｜最轻松的 “公园级” 徒步<a href="#day4雨崩神瀑线最轻松的-公园级-徒步"><span>#</span></a></h3><p><strong>核心行程</strong>：下雨崩→神瀑→下撤</p><p>神瀑线是雨崩最轻松的路线！全程水泥路，爬升平缓，像逛公园，我们早上 9 点出发，边走边拍，一点都不累。</p><ul>
<li>
<p><strong>路况 &amp; 补给</strong>：水泥路很好走，穿普通运动鞋也可，中途有 2 个补给站（卖泡面、热饮，15-20 元 / 份）；</p>
<img src="http://imgbed.leihub.cn/img/mmexport1759758834787.jpg" alt="雨崩神瀑线水泥路——新手友好路线" />
</li>
<li>
<p><strong>拍摄</strong>：到达冰瀑下，是真的很冷，但是挡不住美女们美丽冻人的心，顶着冰瀑水也要去瀑布下出片，respect！</p>
<img src="http://imgbed.leihub.cn/img/mmexport1759758928795.jpg" alt="神瀑下" />
</li>
</ul><p>我们在神瀑拍了超多短视频，下午 3 点就下撤了，是整个行程最快乐的一天～

从神瀑下撤也比较简答，也是时间最充裕的一天，全程唱歌下撤，哈哈，最快乐的一天。</p></section><section><h3>Day5：雨崩→株洲｜极限赶车日<a href="#day5雨崩株洲极限赶车日"><span>#</span></a></h3><p><strong>核心行程</strong>：下雨崩→尼农（皮卡+步行）→香格里拉→昆明→长沙→株洲</p><p>为了保护膝盖，我选了 “皮卡到尼农半程 + 步行下撤”，结果踩了大坑：</p><ul>
<li><strong>等皮卡超久</strong>：早上 8 点去等皮卡，国庆人太多，半小时只走 20 人，最后被迫坐皮卡后备箱（超颠！同行不高反的朋友都被摇得头晕）；</li>
<li><strong>行李寄存问题</strong>：之前把行李寄在司机家，到尼农时已经 1 点，司机还想等其他人，我们直接加价 150 元让他先走，又火急火燎让司机家人送行李到尼农；</li>
<li><strong>赶车时间卡得死死的</strong>：尼农→香格里拉 4 小时，香格里拉→昆明火车 5 小时（无座），昆明→长沙飞机 2.5 小时，最后到株洲已经凌晨 3 点，累到倒头就睡。</li>
</ul><p><strong>赶车攻略</strong>：雨崩返程建议预留至少 2 小时缓冲时间，别像我们一样卡着点走，万一堵车就惨了！</p><img src="http://imgbed.leihub.cn/img/wx_camera_1759849156728.jpg" alt="赶飞机" /></section><section><h3>全程总结：费用 + 新手必备清单<a href="#全程总结费用--新手必备清单"><span>#</span></a></h3><section><h4>1. 费用明细（人均）<a href="#1-费用明细人均"><span>#</span></a></h4><ul>
<li>交通：株洲→长沙→昆明→香格里拉（飞机 + 火车）≈1200 元；雨崩内皮卡 + 骡子≈630 元；返程≈1300 元；</li>
<li>住宿：香格里拉酒店≈150 元，雨崩青旅 3 晚≈1000 元；</li>
<li>门票：梅里雪山 55 元；</li>
<li>餐饮：每天≈100 元（5 天≈500 元）；</li>
<li>其他：氧气瓶≈50 元；</li>
<li>总计：≈5000 元（国庆旺季价格，淡季能省 500-800 元）。</li>
</ul></section><section><h4>2. 新手必备清单<a href="#2-新手必备清单"><span>#</span></a></h4><ul>
<li><strong>高反用品</strong>：氧气瓶（可以去景区买，还有很多人没用完白送的哈哈）、葡萄糖水；</li>
<li><strong>徒步装备</strong>：防水徒步鞋、轻便雨衣、登山杖、速干衣裤、冲锋衣/冲锋裤（冰湖 / 神瀑用）；</li>
<li><strong>其他</strong>：保温杯（装热水）、能量零食、防晒霜 + 墨镜（高原紫外线强）、充电宝。</li>
</ul></section><section><h4>3. 最后碎碎念<a href="#3-最后碎碎念"><span>#</span></a></h4><p>这是我第一次高海拔徒步，虽然有高反的狼狈、赶车的匆忙，但看到梅里雪山的那一刻，所有累都值了。如果你也是户外新手，别害怕高反和徒步难度，雨崩会用最原始的美景治愈你～</p></section></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/946/</id>
      <title type="text">武功山一日反穿攻略｜交通+路线+食宿指南</title>
      <published>2025-09-07T11:39:09.000Z</published>
      <updated>2026-03-08T04:29:17.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/946/"/>
      <summary type="text">之前高温假带家人正穿过武功山（当时还写了游记👉2024 高温假自驾游 - 阿雷的小窝），那时候怕爸妈累，选的索道上山。最近刷小红书，反穿武功山火得不行，同事一约，我就冲了 —— 这可是我第一次高强度户外徒步，全程又爽又虐，赶紧整理攻略给想试</summary>
      <content type="html"><![CDATA[<p>之前高温假带家人正穿过武功山（当时还写了游记👉<a href="/archives/834/">2024 高温假自驾游 - 阿雷的小窝</a>），那时候怕爸妈累，选的索道上山。最近刷小红书，反穿武功山火得不行，同事一约，我就冲了 —— 这可是我第一次高强度户外徒步，全程又爽又虐，赶紧整理攻略给想试的朋友。</p>
<section><h2>🚗 交通攻略<a href="#-交通攻略"><span>#</span></a></h2><p>我们选的周末自驾，9 月 5 日周五下班就走，从株洲到武功山才一百多公里，两个小时就到了，比高铁还灵活。</p><img src="http://imgbed.leihub.cn/img/6b33a6cd00cb0effa953248902005b2d.jpg" alt="自驾路线" /><p>​                                          <em>图：从株洲自驾到武功山的路上，俩小时就到～</em></p><p>因为反穿是从龙山村出发，而下山是下到正面的游客中心，所以我们是选择开车到武功山游客中心，车停在游客中心停车场，然后打车到龙山村。晚上住在龙山村的民宿，价格还算不错。</p><img src="http://imgbed.leihub.cn/img/6e86051bef9ba5e23e72d15a83cb42c8.jpg" alt="龙山村民宿" /><p>​                                                  <em>图：住的龙山村民宿，主打一个便宜～</em></p><p>这是游玩路线，反穿不用买门票！只交 10 块钱卫生费就行，这波血赚</p><img src="http://imgbed.leihub.cn/img/image-20251102181944188.png" alt="反穿路线图" /><p>​                                           <em>图：我们走的反穿路线，10 块卫生费就能走，标好存图！</em></p></section>
<section><h2>🛤️ 徒步全程：20 公里 12 小时<a href="#️-徒步全程20-公里-12-小时"><span>#</span></a></h2><section><h4>1. 起点（6&lt;10&gt;）：龙山村→木马坳（开始就上强度）<a href="#1-起点6龙山村木马坳开始就上强度"><span>#</span></a></h4><p>上来就是持续爬升！全是山路，没一丁点平路，龙山村（560m）到木马坳（1470m）快 1000 米海拔差。</p><img src="http://imgbed.leihub.cn/img/f88c44e92ec188046f92a1b944110261.jpg" alt="龙山村出发" /><p>​                                                     <em>图：6 点 10 分从龙山村出发，一开始还挺兴奋～</em></p><p>我衣服直接湿透，谁懂啊！路上有人刚爬第一个山头就喊 “10 块钱的山爬够了”，当时还笑人家，爬完才知道人家多明智！</p><img src="http://imgbed.leihub.cn/img/7f17b6c71c07a4ab8bb7a4f02c32574f.jpg" alt="木马坳爬升" /><p>​                                                 <em>图：爬木马坳的路，全是爬升，腿都在抖～</em></p></section><section><h4>2. 缓冲段：木马坳→发云界（终于能喘口气）<a href="#2-缓冲段木马坳发云界终于能喘口气"><span>#</span></a></h4><p>这段相对平坦，爬升强度低，能好好恢复体力，建议在这多歇会儿，后面更累。</p><p>草甸开始慢慢多起来，随手拍都好看，心情能缓和不少。</p><img src="http://imgbed.leihub.cn/img/5f05480618012dd43458180e98ab6b5a.jpg" alt="发云界平路" /><p>​                                          <em>图：木马坳到发云界的平路，终于不用一直爬了～</em></p></section><section><h4>3. 折磨段：发云界→千丈岩（上上下下太搞心态）<a href="#3-折磨段发云界千丈岩上上下下太搞心态"><span>#</span></a></h4><p>全是 “爬上又爬下”！刚费老劲登上一个山，马上要走下去，循环往复</p><p>唯一安慰：武功山的草甸太绝了，连绵一片，看着心情能好点，不然真的想放弃</p><img src="http://imgbed.leihub.cn/img/bcecaf1fb1955e695b0837feb2a13a65.jpg" alt="千丈岩草甸" /><p>​                                  <em>图：发云界到千丈岩的草甸，美是真的美，累也是真的累～</em></p></section><section><h4>4. 错觉段：好汉坡（以为快结束？想多了）<a href="#4-错觉段好汉坡以为快结束想多了"><span>#</span></a></h4><p>爬完好汉坡，我们还嘻嘻哈哈拍照，觉得 “也就这样”，结果后面才知道，这只是热身！</p><blockquote><p>提醒：别在这浪费太多时间拍照，后面的绝望坡才是真 BOSS</p></blockquote><img src="http://imgbed.leihub.cn/img/d316923ced4d6ec76d28f826fbbb9dd8.jpg" alt="好汉坡打卡" /><p>​                                               <em>图：爬完好汉坡嘚瑟拍照，现在看太天真了～</em></p></section><section><h4>5. BOSS 段：绝望坡（名字没骗人，真绝望）<a href="#5-boss-段绝望坡名字没骗人真绝望"><span>#</span></a></h4><p>一堆人在坡下打卡，爬了才懂为啥叫 “绝望”：强度不算最高，但前面体力耗太多了</p><p>最搞心态的是：每次以为到顶了，前面又冒一个坡，来来回回两三次，我当时真想坐地上不走了</p><img src="http://imgbed.leihub.cn/img/79910c533dfe71ef27175ac0096e88ff.jpg" alt="绝望坡" /><p>​                                          <em>图：绝望坡下面全是打卡的人，谁知道上去有多虐～</em></p></section><section><h4>6. 休整段：绝望坡→观音宕（有厕所，能歇脚）<a href="#6-休整段绝望坡观音宕有厕所能歇脚"><span>#</span></a></h4><p>这段整体平坦，有景区公共厕所，建议在这简单休息，补充点能量</p><p>很多人会在这扎帐篷，分两天爬的朋友可以在这住，第二天去金顶看日出</p><img src="http://imgbed.leihub.cn/img/c3f6872a9f6c0dc731722f48e02029e6.jpg" alt="观音宕休整" /><p>​                                                <em>图：观音宕的休息区，有厕所，能好好歇会儿</em></p></section><section><h4>7. 冲刺前：观音宕→吊马桩（修整！补体力）<a href="#7-冲刺前观音宕吊马桩修整补体力"><span>#</span></a></h4><p>吊马桩是大型休整平台，能在这吃晚饭，我们当时垫了点肚子的，吃完才有力气冲金顶</p><img src="http://imgbed.leihub.cn/img/d46d92bd3ec8fbf0fa54f361bc197717.jpg" alt="吊马桩平台" /><p>​                                                                <em>图：吊马桩休整平台</em></p></section><section><h4>8. 终段：吊马桩→金顶（最后 1 小时，咬咬牙！）<a href="#8-终段吊马桩金顶最后-1-小时咬咬牙"><span>#</span></a></h4><p>还要 1 小时爬升，是对体能和心理的双重考验，当时全靠 “马上到顶” 的信念撑着</p><img src="http://imgbed.leihub.cn/img/527e8b04a42f82f05621853001768d80.jpg" alt="金顶爬升" /><p>​                                                                                     <em>图 金顶</em></p></section><section><h4>9. 下撤：金顶→中庵索道（下撤超伤膝盖）<a href="#9-下撤金顶中庵索道下撤超伤膝盖"><span>#</span></a></h4><p>到金顶时已经太晚了，金顶索道已经关门，只能去中庵索道，而且夜爬上山的人越来越多，下山只能一步一步挪。</p><p>全是台阶，超伤膝盖！我当时腿都软了，全靠扶着栏杆走，还好赶上了最后一班索道</p><img src="http://imgbed.leihub.cn/img/738d090dc066e533a774d86012d65e3f.jpg" alt="金顶下撤" /><p>​                                                               <em>图：下撤的台阶</em></p></section></section>
<section><h2>🍚 食宿<a href="#-食宿"><span>#</span></a></h2><section><h4>1. 避坑！老萍巷莲花血鸭（游客中心旁）<a href="#1-避坑老萍巷莲花血鸭游客中心旁"><span>#</span></a></h4><p>到达武功山游客中心的时候已经是晚上了，当时又累又饿不想再找其他店吃饭了，直接选择在游客中心旁边的老萍巷莲花血鸭吃，看到美团评论最多，好评也不少，然后就踩了个大坑，菜量又少又贵，几个人均价吃了100元/人，还没吃饱，大家可以避雷一下。</p><img src="http://imgbed.leihub.cn/img/906e75d21c1d1e86e243f0cb93326e6f.jpg" alt="906e75d21c1d1e86e243f0cb93326e6f" /><p>​                                                   <em>图：就是这家老萍巷莲花血鸭，贵还不好吃</em></p></section><section><h4>2. 推荐！200 元家庭套房<a href="#2-推荐200-元家庭套房"><span>#</span></a></h4><p>劳累了一天，腿也软了，不敢开车回株洲，选择在武功山这边休息一个晚上。因为第一天没睡好，我们决定睡一个好一点的民宿，犒劳一下自己。这个民宿还不错，自驾游的朋友可以来着，住的200元一个的家庭套房，有两个一米八的大床，空间有40平，算是住过性价比比较高的民宿了。就是离游客中心有个两公里，得开车前往。</p><img src="http://imgbed.leihub.cn/img/90900134195e775cde56d8e4aa9397eb.jpg" alt="90900134195e775cde56d8e4aa9397eb" /><p>​                                                              <em>图：住的家庭套房，200 块太值了</em></p></section><section><h4>3. 必吃！8 号餐厅（花涧里游客中心）<a href="#3-必吃8-号餐厅花涧里游客中心"><span>#</span></a></h4><p>前一天随便找了个餐厅踩了雷，第二天特意选了个去年吃过的餐厅-8号餐厅，口味很不错，性价比也不错，直接给哥们几个吃撑了。这里比较推荐大家去吃，在武功山花溅里游客中心里。</p><img src="http://imgbed.leihub.cn/img/6b8d310b2015a5c14e777c03c7185c5d.jpg" alt="8号餐厅" /><p>​                                                                       <em>图：8 号餐厅</em></p></section></section>
<section><h2>总结<a href="#总结"><span>#</span></a></h2><section><h4>全程耗时<a href="#全程耗时"><span>#</span></a></h4><p>早上 6 点出发，晚上 6 点多下撤，整整 12 小时，手表还没电了（只记录到观音宕），贴一个同行的伙伴的轨迹做参考。</p><img src="http://imgbed.leihub.cn/img/a9dd55751d06779e1ec2aa20d0ca2199.jpg" alt="a9dd55751d06779e1ec2aa20d0ca2199" /></section><section><h4>徒步建议<a href="#徒步建议"><span>#</span></a></h4><ol>
<li>
<p>体力门槛：至少有运动基础或徒步经验再试！20 多公里 + 2200 米爬升，没基础真的会崩溃。</p>
</li>
<li>
<p>装备精简：反穿路线成熟，补给点多，山上矿泉水 10 块 / 瓶、饮料 15 块 / 瓶，宁愿买也别自己背，省力气。</p>
</li>
<li>
<p>随时补充电解质：一共吃了四五包电解质胶+两瓶电解制水。</p>
</li>
<li>
<p>注意防晒：发云界后出太阳，我没及时补防晒，脖子和手全晒伤了。</p>
</li>
<li>
<p>离线地图：部分地方没信号，有手表的提前下离线地图。</p>
</li>
</ol><p>武功山反穿真的很考验人，但看到草甸和金顶的那一刻，又觉得值了！</p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/896/</id>
      <title type="text">WordPress 备份：WPVivid 还原失败 / 卡住 83%？5 步解决 WordPress 备份还原难题</title>
      <published>2025-08-27T12:17:04.000Z</published>
      <updated>2026-03-08T04:31:57.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/896/"/>
      <summary type="text">不少人常常选择WordPress搭建个人博客，而博客备份与还原是核心操作，而 WPVivid 是目前主流的 WordPress 备份插件之一。但不少用户在使用 WPVivid 还原时，会遇到各种问题 —— 比如频繁卡在 83% 不动，或直接</summary>
      <content type="html"><![CDATA[<p>不少人常常选择WordPress搭建个人博客，而博客备份与还原是核心操作，而 WPVivid 是目前主流的 WordPress 备份插件之一。但不少用户在使用 WPVivid 还原时，会遇到各种问题 —— 比如<strong>频繁卡在 83% 不动</strong>，或直接提示 “还原失败”，导致网站无法正常恢复。本文结合官方建议与实战经验，详细拆解 WPVivid 还原失败的解决思路，带你通过 5 个步骤完成网站还原，同时附上关键的 “手动拆分备份包” 教程，覆盖从基础设置到进阶操作的全场景。</p>
<img src="http://imgbed.leihub.cn/img/dd32f59.png" alt="WPVivid还原失败常见场景（如卡住83%）" />
<section><h2>一、为什么 WPVivid 还原会失败？<a href="#一为什么-wpvivid-还原会失败"><span>#</span></a></h2><p>在使用 WPVivid 还原时，“进度卡住”“插件 / 核心文件还原无响应”“数据库导入失败” 是最常见的问题。根据 WPVivid 官方论坛反馈及实战排查，核心原因集中在<strong>服务器配置不匹配</strong>和<strong>备份包处理逻辑冲突</strong>，具体包括：</p><ul>
<li>PHP 执行时间过短（默认 30 秒），无法处理大型备份文件（尤其超过 1GB 的包）</li>
<li>服务器内存不足（低于 128M），导致大文件解压 / 传输时中断</li>
<li>备份包体积超过服务器 “上传文件大小限制”（常见限制 200MB-500MB）</li>
<li>分卷备份包缺失（如 part002.zip 丢失）或备份文件损坏</li>
<li>服务器 PHP 版本过低（低于 7.4），与 WPVivid 新功能不兼容</li>
</ul><blockquote><p>提示：即使你之前用 WPVivid 成功还原过，也可能因 “服务器环境更新（如 PHP 版本升级）”“备份包体积增大（如新增大量图片）” 再次遇到问题。</p></blockquote></section>
<section><h2>二、还原前必做：3 项准备工作<a href="#二还原前必做3-项准备工作"><span>#</span></a></h2><p>在开始还原操作前，先做好以下检查，可减少 80% 的失败概率：</p><ol>
<li>
<p><strong>备份当前站点（关键！）</strong>
无论原站点是否能访问，先备份当前的数据库（用 phpMyAdmin 导出）和文件（用 FTP 下载 wp-content 目录），防止还原失误导致现有数据丢失。</p>
</li>
<li>
<p><strong>验证备份包完整性</strong></p>
<ul>
<li>若为单文件备份：右键检查文件大小是否与备份时一致，避免下载中断导致文件损坏；</li>
<li>若为分卷备份（如 part001.zip、part002.zip）：确保所有分卷齐全，且文件名连续（无缺号）。
<img src="http://imgbed.leihub.cn/img/image-20250827124514489.png" alt="WPVivid分卷备份包完整性检查示例" /></li>
</ul>
</li>
<li>
<p><strong>准备工具与确认服务器配置</strong>
提前装好必备工具，并检查服务器是否满足最低要求：</p>

<table><thead><tr><th>类别</th><th>具体要求</th></tr></thead><tbody><tr><td>必备工具</td><td>7-Zip/WinRAR（解压备份包）、VSCode / 记事本（修改 JSON 文件）、FileZilla（FTP 工具）</td></tr><tr><td>服务器配置</td><td>PHP 版本≥7.4、PHP 执行时间≥300 秒、内存限制≥256M、上传文件大小≥备份包单文件体积</td></tr><tr><td>特殊场景处理</td><td>若原站点无法访问（如白屏），需先安装全新 WordPress + 激活 WPVivid 插件</td></tr></tbody></table>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250827124612311.png" alt="image-20250827124612311" /><figcaption>image-20250827124612311</figcaption></figure><p></p>
</li>
</ol></section>
<section><h2>三、5 步解决 WPVivid 还原失败问题<a href="#三5-步解决-wpvivid-还原失败问题"><span>#</span></a></h2><section><h3>步骤一：优化 WPVivid 设置<a href="#步骤一优化-wpvivid-设置"><span>#</span></a></h3><p>还原失败的首要原因是 “默认设置不匹配服务器配置”，先通过调整设置创造合适的还原环境：</p><ol>
<li>登录 WordPress 后台，进入「WPVivid Backup」→「设置」→「高级设置」；</li>
<li>重点修改 3 个参数（直接影响还原成功率）：
<ul>
<li><strong>PHP 执行超时时间</strong>：从默认 30 秒改为 300 秒（5 分钟），若备份包超过 2GB 可改为 600 秒；</li>
<li><strong>备份分块大小</strong>：从默认 100MB/200MB 改为 50MB（服务器配置低则设为 20MB），减少单次处理压力；</li>
<li>勾选「启用还原断点续传」（WPVivid 2.0 + 版本默认开启，老版本需手动勾选）；</li>
</ul>
</li>
<li>点击「保存更改」，刷新页面确认设置生效。<img src="http://imgbed.leihub.cn/img/image-20250827195943574.png" alt="WPVivid高级设置调整界面（延长PHP执行时间+减小分块）" /></li>
</ol><blockquote><p>注意：若无法进入后台，先装全新 WordPress+WPVivid，再按上述步骤设置（新插件默认无数据，不影响后续还原）。</p></blockquote></section><section><h3>步骤二：看懂 WPVivid 备份包结构（手动还原的前提）<a href="#步骤二看懂-wpvivid-备份包结构手动还原的前提"><span>#</span></a></h3><p>WPVivid 备份包包含多个 “独立组件”，拆分后分别还原可避免 “单包过大导致卡住”。解压备份包后，典型结构如下：</p><img src="http://imgbed.leihub.cn/img/image-20250827125356635.png" alt="WPVivid备份包解压后的文件结构" /><p>其中<strong>wpvivid_package_info.json</strong>是核心文件 —— 它记录了备份包的组成的信息，用 VSCode 打开后，可看到备份包含的所有组件（如核心文件、主题、数据库等）：<img src="http://imgbed.leihub.cn/img/image-20250827125313373.png" alt="WPVivid备份包JSON文件内容（记录组件信息）" /></p><p>一个完整的 WPVivid 备份包，通常包含 6 类核心组件：</p><ul>
<li><code>backup_core.zip</code>：WordPress 核心文件（wp-admin、wp-includes 目录）；</li>
<li><code>backup_themes.zip</code>：主题文件（wp-content/themes）；</li>
<li><code>backup_plugins.zip</code>：插件文件（wp-content/plugins）；</li>
<li><code>backup_uploads.zip</code>：媒体文件（wp-content/uploads，含图片、视频）；</li>
<li><code>backup_content.zip</code>：wp-content 目录下的其他文件（如自定义文件夹）；</li>
<li><code>backup_db.zip</code>：数据库备份（内含.sql 或.sql.gz 文件）。</li>
</ul></section><section><h3>步骤三：拆分备份包（核心操作！减小还原复杂度）<a href="#步骤三拆分备份包核心操作减小还原复杂度"><span>#</span></a></h3><p>当完整备份包还原卡住时，“拆分组件单独还原” 是最高效的解决方案，分两步操作：</p><section><h4>1. 合并分卷备份（若有分卷）<a href="#1-合并分卷备份若有分卷"><span>#</span></a></h4><p>若你的备份是分卷形式（如 part001.zip、part002.zip），先合并为完整包：</p><ul>
<li>将所有分卷文件放在<strong>同一个文件夹</strong>（确保无缺号，如 part001 到 part003 都齐全）；</li>
<li>右键点击「part001.zip」→ 选择「7-Zip/WinRAR → 解压到当前文件夹」（工具会自动合并所有分卷）；</li>
<li>解压完成后，得到完整的备份文件夹（或独立的 6 个组件 ZIP 包）。</li>
</ul></section><section><h4>2. 拆分核心组件<a href="#2-拆分核心组件"><span>#</span></a></h4><ul>
<li>若解压后是 “独立组件包”（如 backup_core.zip、backup_themes.zip）：直接分类存放即可；</li>
<li>若解压后是 “完整站点文件夹”（含 wp-config.php、wp-admin 等）：手动按 “核心 / 主题 / 插件” 分类打包 —— 比如将 wp-content/themes 文件夹压缩为<code>themes.zip</code>，wp-admin+wp-includes 压缩为<code>core.zip</code>。</li>
</ul></section></section><section><h3>步骤四：修改 JSON 文件（创建组件还原包）<a href="#步骤四修改-json-文件创建组件还原包"><span>#</span></a></h3><p>WPVivid 还原时会读取 JSON 文件识别组件，需为每个拆分的组件创建 “专属 JSON 文件”，确保还原时只加载单个组件：</p><ol>
<li>
<p>复制原始的<code>wpvivid_package_info.json</code>文件，为每个组件创建副本 —— 如命名为<code>core_info.json</code>（对应核心文件）、<code>themes_info.json</code>（对应主题）；</p>
</li>
<li>
<p>用 VSCode 打开副本 JSON 文件，删除<code>child_file</code>数组中 “非当前组件” 的条目，只保留目标组件的记录。</p>
<p>示例：创建 “主题还原包” 时，JSON 文件只保留主题相关条目：</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>{</span></div></div><div><div><div>2</div></div><div><span>    </span><span>"has_child"</span><span>: </span><span>1</span><span>,</span></div></div><div><div><div>3</div></div><div><span>    </span><span>"home_url"</span><span>: </span><span>"https:</span><span>\/\/</span><span>blog.leihub.cn"</span><span>,</span></div></div><div><div><div>4</div></div><div><span>    </span><span>"root_flag"</span><span>: </span><span>"custom"</span><span>,</span></div></div><div><div><div>5</div></div><div><span>    </span><span>"php_version"</span><span>: </span><span>"8.2.28"</span><span>,</span></div></div><div><div><div>6</div></div><div><span>    </span><span>"mysql_version"</span><span>: </span><span>"5.7.44"</span><span>,</span></div></div><div><div><div>7</div></div><div><span>    </span><span>"wp_version"</span><span>: </span><span>"6.8.2"</span><span>,</span></div></div><div><div><div>8</div></div><div><span>    </span><span>"child_file"</span><span>: {</span></div></div><div><div><div>9</div></div><div><span>        </span><span>"blog.leihub.cn_wpvivid-1bff5dbd0b25b_2025-08-26-20-23_backup_themes.zip"</span><span>: {}</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>},</span></div></div><div><div><div>11</div></div><div><span>    </span><span>"file"</span><span>: </span><span>"blog.leihub.cn_wpvivid-1bff5dbd0b25b_2025-08-26-20-23_backup_all.part001.zip"</span></div></div><div><div><div>12</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
</li>
<li>
<p>将 “修改后的 JSON 文件” 与 “对应的组件 ZIP 包” 选中，压缩为新的 ZIP 包（如<code>themes_restore.zip</code>）—— 还原时上传这个新包即可。</p>
</li>
</ol><img src="http://imgbed.leihub.cn/img/image-20250827125814304.png" alt="WPVivid组件还原包创建示例（JSON+组件ZIP压缩）" /></section><section><h3>步骤五：按顺序手动还原（关键！避免组件冲突）<a href="#步骤五按顺序手动还原关键避免组件冲突"><span>#</span></a></h3><p>还原顺序直接影响成功率，需按 “从基础到核心” 的逻辑执行 —— 先确保 WordPress 框架正常，再还原数据，具体步骤：</p><ol>
<li>
<p><strong>第一步：还原核心文件（core）</strong>
进入 WPVivid 后台「还原」→ 上传「core_restore.zip」→ 点击「还原」→ 等待 “还原成功” 提示（核心文件是基础，先确保 wp-admin 能正常访问）。</p>
</li>
<li>
<p><strong>第二步：还原主题（themes）和插件（plugins）</strong>
分别上传「themes_restore.zip」和「plugins_restore.zip」，逐个还原（顺序可互换）。</p>
<blockquote><p>注意：若插件数量多（如超过 50 个），还原可能耗时 10-20 分钟，耐心等待，不要刷新页面。</p></blockquote>
</li>
<li>
<p><strong>第三步：还原上传文件（uploads）和其他内容（content）</strong>
上传「uploads_restore.zip」和「content_restore.zip」，这部分多为图片 / 视频，体积可能较大，需确保服务器内存≥256M。</p>
</li>
<li>
<p><strong>第四步：还原数据库（database）</strong>
最后上传「db_restore.zip」还原数据库（数据库是核心数据，放在最后可避免前期文件操作覆盖数据）。</p>
<blockquote><p>必做：还原前先通过 WPVivid「数据库备份」功能，备份目标站点当前数据库，防止数据覆盖错误。</p></blockquote>
</li>
</ol><img src="http://imgbed.leihub.cn/img/image-20250827195751201.png" alt="WPVivid分组件还原操作界面" /><blockquote><p>重要提示：每一步还原都要等页面明确显示 “还原成功” 后再进行下一步，中途刷新 / 关闭浏览器会导致文件损坏，甚至站点白屏。</p></blockquote></section></section>
<section><h2>四、还原时的避坑指南（解决 “卡住 / 超时” 问题）<a href="#四还原时的避坑指南解决-卡住--超时-问题"><span>#</span></a></h2><ol>
<li><strong>禁止中途操作</strong>
还原时不要：刷新页面、关闭浏览器、点击 “取消”、重启服务器 PHP/MySQL——WPVivid 还原在后台运行，页面仅显示进度，强行中断会导致 “文件残缺”。</li>
<li><strong>判断还原状态的 2 个方法</strong>
<ul>
<li>成功：页面提示 “还原成功”，或收到 WPVivid 邮件通知（需提前在「设置」中开启 “还原通知”）；</li>
<li>失败：页面显示具体错误（如 “PHP 内存溢出”“数据库连接失败”），直接根据错误提示排查（如联系主机商增加内存）。</li>
</ul>
</li>
<li><strong>超时无响应的处理</strong>
若进度卡在某百分比（如 83%）超过 30 分钟，且服务器 CPU / 内存已降至正常水平，说明还原已中断：
<ul>
<li>第一步：联系主机商获取「PHP 错误日志」，查看是否有 “memory_limit exhausted”（内存不足）或 “max_execution_time exceeded”（执行时间不足）；</li>
<li>第二步：通过 FTP 删除 WPVivid 临时文件（路径：<code>wp-content/wpvividbackups/temp/</code>），避免残留文件干扰；</li>
<li>第三步：将组件包再拆分更小（如将 uploads 拆分为 “uploads_2023.zip”“uploads_2024.zip”），重新尝试还原。</li>
</ul>
</li>
</ol></section>
<section><h2>总结：WPVivid 手动还原的 3 个关键要点<a href="#总结wpvivid-手动还原的-3-个关键要点"><span>#</span></a></h2><ol>
<li><strong>环境优先</strong>：先优化 WPVivid 设置（延长执行时间、减小分块），再检查服务器配置，避免 “基础问题导致失败”；</li>
<li><strong>拆分核心</strong>：遇到大文件卡住时，按 “核心→主题 / 插件→上传文件→数据库” 拆分还原，降低单次处理压力；</li>
<li><strong>日志排查</strong>：若还原失败，优先查看 PHP 错误日志 —— 日志中的 “内存 / 时间” 提示，是解决问题的直接线索。</li>
</ol><p>如果按上述步骤仍无法解决，可收集 3 类信息联系官方支持（<code>support@wpvivid.com</code>）：① PHP 错误日志；② 备份包的 JSON 文件内容；③ 还原时的错误截图，官方通常会在 1-2 个工作日内回复。</p><p>希望本文能帮你解决 WPVivid 还原难题！如果觉得有用，欢迎分享给需要的 WordPress 用户；若你有其他还原经验，也欢迎在评论区留言交流～</p></section>
<section><h2>参考资料<a href="#参考资料"><span>#</span></a></h2><ol>
<li><a href="https://sammystuart.blog/wpvivid-backup-restore-failed/#google_vignette" target="_blank">WPvivid backup 還原失敗｜非常規處理方式 - SammyStuart</a></li>
<li><a href="https://wordpress.org/support/topic/back-up-is-stuck-at-83/" target="_blank">Back up is stuck at 83% | WordPress.org</a></li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/903/</id>
      <title type="text">足迹2025：比亚迪汉 L EV 湖北自驾实测（8 月版） 宜昌 + 恩施景点推荐，桂林避坑</title>
      <published>2025-08-24T13:13:18.000Z</published>
      <updated>2026-03-08T04:30:23.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/903/"/>
      <summary type="text">家人们谁懂啊！今年 8 月我直接把 “旅行” 焊在身上了 ——8 天高温假陪爸妈自驾湖北，刚歇脚又跟部门去桂林疗养，中间还被同事拽着要反穿武功山… 整个月脚不沾家，一半快乐到飞起，一半气到心梗！今天把干货捋清楚，想暑假去这俩地的，照着看准没</summary>
      <content type="html"><![CDATA[<p>家人们谁懂啊！今年 8 月我直接把 “旅行” 焊在身上了 ——8 天高温假陪爸妈自驾湖北，刚歇脚又跟部门去桂林疗养，中间还被同事拽着要反穿武功山… 整个月脚不沾家，一半快乐到飞起，一半气到心梗！今天把干货捋清楚，想暑假去这俩地的，照着看准没错～</p>
<section><h2>一、湖北自驾：爽到不想走，这些干货必看！<a href="#一湖北自驾爽到不想走这些干货必看"><span>#</span></a></h2><section><h3>1. 先薅羊毛！这张年卡能省一大笔<a href="#1-先薅羊毛这张年卡能省一大笔"><span>#</span></a></h3><p>听我的！去湖北自驾一定要办「湖北省旅游年卡」，官方卖 300 块，闲鱼搜 “湖北旅游年卡”，265 块就能拿下正规的兑换码。100 多个景点免门票，我光玩三峡大瀑布 + 腾龙洞就回本了，后面去的景点全是 “白嫖”，超香！</p><img src="http://imgbed.leihub.cn/img/cef42112b868d7acbf18dda9c1b0cf9.jpg" alt="2025湖北省旅游年卡" /></section><section><h3>2. 比亚迪汉 L EV 自驾实测：电车也能放心跑<a href="#2-比亚迪汉-l-ev-自驾实测电车也能放心跑"><span>#</span></a></h3><p>我 5 月提的汉 L EV，到出发前都跑 5000 公里了，本来还担心电车自驾麻烦，结果湖北高速充电桩多到离谱！满电开空调 + 导航，跑 500 公里没问题，中途在景区区补电，双枪快充 10 分钟就从 30% 到 80%，上个厕所就充满了，完全没续航焦虑～</p><img src="http://imgbed.leihub.cn/img/37966003229138a867ff2d676622200.jpg" alt="比亚迪汉L EV湖北自驾充电" /></section><section><h3>3. 宜昌 3 天玩透：每处都踩在爽点上<a href="#3-宜昌-3-天玩透每处都踩在爽点上"><span>#</span></a></h3><ul>
<li>
<p><strong>Day1：看看江边的夜景，吹吹宜昌的晚风</strong>
第一天到宜昌，放下行李就冲长江边！傍晚的江风超舒服，夷陵长江大桥的灯亮起来后，整个江面都闪闪闪的。我随手拍了张照，还不小心把旁边小姐姐拍进去了，别说，氛围感直接拉满～</p>
<img src="http://imgbed.leihub.cn/img/888006062143b82d93f71645ef8039b.jpg" alt="宜昌长江边夜景" />
</li>
<li>
<p><strong>Day2：十里画廊看 “翡翠水”，拍照烂也出片</strong>
第二天上午去十里画廊，那水绿得像块会动的翡翠！我拍照技术烂到抠脚，但架不住景美啊，随便举手机都好看。</p>
<img src="http://imgbed.leihub.cn/img/7a6c552b02aa9367c87d9dcc0ce39ae.jpg" alt="宜昌十里画廊绿水" />
</li>
<li>
<p><strong>Day2 下午：三峡大瀑布穿瀑，没拍着美女亏大了</strong>
下午去三峡大瀑布，最后那段要穿瀑布底！水花砸在身上超刺激，但我忘带防水手机套了，眼睁睁看小姐姐们被淋湿后超好看，没拍着太亏了（狗头）。你们去一定要在景区门口租 10 块钱的手机防水套。</p>
<img src="http://imgbed.leihub.cn/img/8d2fc04211302d6284562c7938defa6.jpg" alt="三峡大瀑布穿瀑" />
</li>
<li>
<p><strong>Day3：两坝一峡坐 “电梯船”，防晒一定要做好</strong>
第三天玩两坝一峡，坐游船穿葛洲坝、西陵峡，那个升船机绝了！船跟坐电梯似的不断上升，甲板上全是 “哇” 声。但 8 月太阳太毒了，感觉都要晒中暑啦，一定要穿冰袖戴宽檐帽，不然能晒掉一层皮！</p>
<img src="http://imgbed.leihub.cn/img/6be3ec4c228db06c17f2a3ed005d6da.jpg" alt="三峡大坝" />
</li>
</ul></section><section><h3>4.恩施 2 天：地缝像原神场景，溶洞超震撼<a href="#4恩施-2-天地缝像原神场景溶洞超震撼"><span>#</span></a></h3><ul>
<li>
<p><strong>恩施大峡谷：陪爸妈只逛地缝，也够爽</strong>
大峡谷全程走下来要七八个小时，陪爸妈就只逛了地缝，没有去七星寨那边。那地缝太震撼了，两边岩壁直愣愣的，中间还有小瀑布，我一看就想起《原神》稻妻的无想仞狭间（狗头）。建议坐观光电梯上去，30 块钱省劲儿，不然最后的台阶太累了～</p>
<img src="http://imgbed.leihub.cn/img/a3a7edbe4393a04c24feabcc1ee3188.jpg" alt="恩施大峡谷地缝" />
</li>
<li>
<p><strong>腾龙洞：亚洲最大溶洞，能装 1000 万人？</strong>
最后去腾龙洞，号称亚洲最大，进去才知道啥叫 “能装 1000 万人”，洞顶高得看不到头！但入口人挤人，建议早 9 点前到。洞内 12 度左右，记得带件薄外套，洞内还有表演，超好看！</p>
<img src="http://imgbed.leihub.cn/img/16ab4f9ce7991215d9c41e429bd69ac.jpg" alt="腾龙洞入口" />
<img src="http://imgbed.leihub.cn/img/10a6d34aa5fb8a8aeaa7292d0a562a1.jpg" alt="腾龙洞表演" />
</li>
</ul><p>最后，湖北之行这样就结束了，一波开了两千多公里，直接给我累趴了，在家直接躺了一天（咸鱼躺）。</p></section></section>
<section><h2>二、桂林跟团：有一次踩坑之旅<a href="#二桂林跟团有一次踩坑之旅"><span>#</span></a></h2><p>隔了一周部门组织去桂林辽阳，我去年去过一次，也踩了不少坑，本不想去，但想着 “不去亏一年” 还是去了，结果还被影响到心情！</p><ul>
<li>
<p><strong>古东景区：爬瀑布好玩，但草鞋磨脚到哭</strong>
第一个去古东景区，爬瀑布挺刺激的，要抓着铁链往上走。但景区给的草鞋硬得像纸板，我走完全程脚磨的够呛！最后还在景区花35买了个洞洞鞋穿。</p>
<img src="http://imgbed.leihub.cn/img/34866617a4791f6b480fad2813ca2bc.jpg" alt="桂林古东景区爬瀑布" />
</li>
<li>
<p><strong>漓江冠岩 + 竹筏：溶洞土，江水浑，全是失望</strong>
然后去漓江冠岩，那溶洞灯光土得像 KTV，进去逛 10 分钟就想走。从溶洞出来就去漓江坐竹筏，可惜这几天下雨，漓江水很浑浊，一点也不清澈！</p>
<img src="http://imgbed.leihub.cn/img/8f15cc93c47fb8fc539d205364a2e66.jpg" alt="漓江冠岩溶洞" />
<img src="http://imgbed.leihub.cn/img/f74e758ac3356510c473bafca87a934.jpg" alt="漓江竹筏" />
</li>
<li>
<p><strong>兴坪码头游轮：升级的沙发，救不了套路</strong>
游轮确实比去年豪华（沙发软乎），但全程被导游催着 “去甲板拍照”（其实是为了推销 花钱的打印照）。最后去 “少数民族古寨”，实则是银器购物点，不买就被导游甩脸子；返程时推销 “天价特产”，团里花了 1000 多，还被地域黑 “湖南团抠门”…</p>
<img src="http://imgbed.leihub.cn/img/e540c38ceebdd9130b8cbe7b03ea7ee.jpg" alt="e540c38ceebdd9130b8cbe7b03ea7ee" />
<img src="http://imgbed.leihub.cn/img/a814f92800af19f7423915b671b8cdf.jpg" alt="桂林" />
<h2>总结：湖北值得 N 刷，桂林建议自由行<a href="#总结湖北值得-n-刷桂林建议自由行"><span>#</span></a></h2>
<p>湖北的山水是 “野生的治愈”，自驾的自由 + 年卡的实惠，让每一步都很舒服；桂林的山水本是神作，却被跟团套路毁了体验 —— 如果去桂林，一定要选自由行，直奔遇龙河竹筏 + 龙脊梯田，别让导游毁了你的美好心情。</p>
</li>
</ul></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/956/</id>
      <title type="text">Nextcloud 部署教程：Docker 搭建私有云盘，数据隐私自己掌控</title>
      <published>2025-07-10T12:02:31.000Z</published>
      <updated>2026-03-08T04:38:05.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/956/"/>
      <summary type="text">前言 厌倦了百度云的限速、阿里云的存储付费，又担心手机相册、工作文件存在第三方平台的隐私泄露风险？那 Nextcloud 绝对是你的理想选择。 它是一款开源免费、功能全能的私有云盘解决方案，既能部署在个人服务器、NAS（如群晖、威联通）上，</summary>
      <content type="html"><![CDATA[<section><h1>前言<a href="#前言"><span>#</span></a></h1><p>厌倦了百度云的限速、阿里云的存储付费，又担心手机相册、工作文件存在第三方平台的隐私泄露风险？那 Nextcloud 绝对是你的理想选择。</p><p>它是一款<strong>开源免费、功能全能</strong>的私有云盘解决方案，既能部署在个人服务器、NAS（如群晖、威联通）上，也支持多端同步（Windows、Mac、手机、网页），文件存储、共享、备份一站式搞定。</p><p>和第三方网盘比，Nextcloud 的优势肉眼可见：</p><ul>
<li>数据完全私有：存在自己的设备上，不经过第三方服务器，隐私零风险</li>
<li>无限速无广告：上传下载速度取决于自己的带宽，没有隐藏消费</li>
<li>拓展性极强：支持插件扩展（如相册管理、办公协作、视频预览、密码管理器）</li>
<li>多场景适配：家庭文件共享、个人数据备份、小型团队协作都能用</li>
</ul><p>如果你想摆脱第三方网盘的束缚，用 Docker 快速搭建一套属于自己的私有云盘，跟着这篇教程做，新手也能轻松上手！</p></section>
<section><h1>准备工作<a href="#准备工作"><span>#</span></a></h1><p>在开始部署前，先确认你的设备满足以下条件：</p><ul>
<li>已安装 Docker 和 Docker Compose</li>
<li>服务器 / NAS 有足够存储空间（建议至少 10GB，根据存储需求调整）</li>
<li>开放目标端口（默认 28080，可自定义）</li>
</ul><p>为了方便管理配置和数据，先创建独立的工作目录：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 自定义路径，可修改为自己习惯的目录</span></div></div><div><div><div>2</div></div><div><span>mkdir</span><span> </span><span>-p</span><span> </span><span>~/docker/nextcloud</span></div></div><div><div><div>3</div></div><div><span># 进入目录</span></div></div><div><div><div>4</div></div><div><span>cd</span><span> </span><span>~/docker/nextcloud</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>需要开放 Nextcloud 的访问端口（28080）和 Redis 缓存端口（6379）：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 开放28080端口（Nextcloud访问）</span></div></div><div><div><div>2</div></div><div><span>sudo</span><span> </span><span>ufw</span><span> </span><span>allow</span><span> </span><span>28080/tcp</span><span> </span><span>comment</span><span> </span><span>'nextcloud访问端口'</span><span> &amp;&amp; </span><span>sudo</span><span> </span><span>ufw</span><span> </span><span>reload</span></div></div><div><div><div>3</div></div><div><span># 开放6379端口（Redis缓存，可选，容器内部通信可省略）</span></div></div><div><div><div>4</div></div><div><span>sudo</span><span> </span><span>ufw</span><span> </span><span>allow</span><span> </span><span>6379/tcp</span><span> </span><span>comment</span><span> </span><span>'nextcloud Redis缓存'</span><span> &amp;&amp; </span><span>sudo</span><span> </span><span>ufw</span><span> </span><span>reload</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>官方提供两种主流镜像，根据需求选择：</p><ul>
<li>基础镜像（<code>nextcloud:latest</code>）：基于 Apache，仅包含核心功能，体积小、部署快，适合普通用户</li>
<li>完整镜像（需自行构建）：包含 ffmpeg、ImageMagick 等工具，支持视频预览、图片处理等高级功能，适合有多媒体存储需求的用户</li>
</ul><p>完整镜像构建参考：<a href="https://github.com/nextcloud/docker/tree/master/.examples/dockerfiles/full/apache" target="_blank">Nextcloud 官方完整镜像示例</a>，按文档执行<code>docker build</code>即可。</p></section>
<section><h1>Docker Compose部署服务<a href="#docker-compose部署服务"><span>#</span></a></h1><p>在<code>~/docker/nextcloud</code>目录下创建配置文件：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>vim</span><span> </span><span>docker-compose.yml</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>以下配置使用 DaoCloud 镜像加速，避免国内拉取镜像缓慢，关键参数已标注说明：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>services</span><span>:</span></div></div><div><div><div>2</div></div><div><span>  </span><span># 数据库容器（MariaDB，兼容MySQL）</span></div></div><div><div><div>3</div></div><div><span>  </span><span>db</span><span>:</span></div></div><div><div><div>4</div></div><div><span>    </span><span>image</span><span>: </span><span>docker.m.daocloud.io/mariadb:latest</span></div></div><div><div><div>5</div></div><div><span>    </span><span>restart</span><span>: </span><span>always</span><span>  </span><span># 自动重启</span></div></div><div><div><div>6</div></div><div><span>    </span><span># 数据库核心参数，确保Nextcloud兼容</span></div></div><div><div><div>7</div></div><div><span>    </span><span>command</span><span>: </span><span>--transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW</span></div></div><div><div><div>8</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>9</div></div><div><span><span>      </span></span><span>- </span><span>./db:/var/lib/mysql</span><span>  </span><span># 数据持久化到本地，容器重启不丢失</span></div></div><div><div><div>10</div></div><div><span>    </span><span>environment</span><span>:</span></div></div><div><div><div>11</div></div><div><span><span>      </span></span><span>- </span><span>MYSQL_ROOT_PASSWORD=nextcloud_password_root</span><span>  </span><span># 数据库root密码，需修改（禁止含$字符）</span></div></div><div><div><div>12</div></div><div><span><span>      </span></span><span>- </span><span>MYSQL_PASSWORD=nextcloud_password</span><span>  </span><span># Nextcloud数据库用户密码，需修改（禁止含$字符）</span></div></div><div><div><div>13</div></div><div><span><span>      </span></span><span>- </span><span>MYSQL_DATABASE=nextcloud</span><span>  </span><span># 数据库名，建议默认</span></div></div><div><div><div>14</div></div><div><span><span>      </span></span><span>- </span><span>MYSQL_USER=nextcloud</span><span>  </span><span># 数据库用户，建议默认</span></div></div><div><div><div>15</div></div><div><span>    </span><span>networks</span><span>:</span></div></div><div><div><div>16</div></div><div><span><span>      </span></span><span>- </span><span>default</span></div></div><div><div><div>17</div></div><div>
</div></div><div><div><div>18</div></div><div><span>  </span><span># Redis缓存容器（提升Nextcloud访问速度）</span></div></div><div><div><div>19</div></div><div><span>  </span><span>cache</span><span>:</span></div></div><div><div><div>20</div></div><div><span>    </span><span>image</span><span>: </span><span>docker.m.daocloud.io/redis</span></div></div><div><div><div>21</div></div><div><span>    </span><span>restart</span><span>: </span><span>unless-stopped</span></div></div><div><div><div>22</div></div><div><span>    </span><span>expose</span><span>:</span></div></div><div><div><div>23</div></div><div><span><span>      </span></span><span>- </span><span>"6379"</span><span>  </span><span># 容器内部暴露端口，无需映射到主机</span></div></div><div><div><div>24</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>25</div></div><div><span><span>      </span></span><span>- </span><span>./cache:/data</span><span>  </span><span># 缓存数据持久化</span></div></div><div><div><div>26</div></div><div><span>    </span><span>command</span><span>: </span><span>redis-server --requirepass 'redis_password'</span><span>  </span><span># Redis密码，需修改（禁止含$字符）</span></div></div><div><div><div>27</div></div><div><span>    </span><span>networks</span><span>:</span></div></div><div><div><div>28</div></div><div><span><span>      </span></span><span>- </span><span>default</span></div></div><div><div><div>29</div></div><div>
</div></div><div><div><div>30</div></div><div><span>  </span><span># Nextcloud应用容器</span></div></div><div><div><div>31</div></div><div><span>  </span><span>app</span><span>:</span></div></div><div><div><div>32</div></div><div><span>    </span><span>image</span><span>: </span><span>docker.m.daocloud.io/nextcloud</span></div></div><div><div><div>33</div></div><div><span>    </span><span>restart</span><span>: </span><span>always</span></div></div><div><div><div>34</div></div><div><span>    </span><span>ports</span><span>:</span></div></div><div><div><div>35</div></div><div><span><span>      </span></span><span>- </span><span>28080:80</span><span>  </span><span># 端口映射（主机:容器），28080可自定义</span></div></div><div><div><div>36</div></div><div><span>    </span><span>links</span><span>:</span></div></div><div><div><div>37</div></div><div><span><span>      </span></span><span>- </span><span>db</span><span>  </span><span># 关联数据库容器</span></div></div><div><div><div>38</div></div><div><span><span>      </span></span><span>- </span><span>cache</span><span>  </span><span># 关联Redis缓存容器</span></div></div><div><div><div>39</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>40</div></div><div><span><span>      </span></span><span>- </span><span>./app:/var/www/html</span><span>  </span><span># 应用配置和文件存储目录</span></div></div><div><div><div>41</div></div><div><span>    </span><span>environment</span><span>:</span></div></div><div><div><div>42</div></div><div><span><span>      </span></span><span>- </span><span>MYSQL_PASSWORD=nextcloud_password</span><span>  </span><span># 与数据库的MYSQL_PASSWORD一致</span></div></div><div><div><div>43</div></div><div><span><span>      </span></span><span>- </span><span>MYSQL_DATABASE=nextcloud</span></div></div><div><div><div>44</div></div><div><span><span>      </span></span><span>- </span><span>MYSQL_USER=nextcloud</span></div></div><div><div><div>45</div></div><div><span><span>      </span></span><span>- </span><span>MYSQL_HOST=db</span><span>  </span><span># 数据库容器名称</span></div></div><div><div><div>46</div></div><div><span>    </span><span>networks</span><span>:</span></div></div><div><div><div>47</div></div><div><span><span>      </span></span><span>- </span><span>default</span></div></div><div><div><div>48</div></div><div>
</div></div><div><div><div>49</div></div><div><span># 自定义网络，隔离容器环境</span></div></div><div><div><div>50</div></div><div><span>networks</span><span>:</span></div></div><div><div><div>51</div></div><div><span>  </span><span>default</span><span>:</span></div></div><div><div><div>52</div></div><div><span>    </span><span>name</span><span>: </span><span>nextcloud</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><ul>
<li>所有密码（<code>MYSQL_ROOT_PASSWORD</code>、<code>MYSQL_PASSWORD</code>、<code>redis_password</code>）需修改为复杂密码，禁止包含<code>$</code>字符，否则会导致配置失效。</li>
<li>端口映射：若 28080 端口已被占用，可修改为其他端口（如<code>28081:80</code>）。</li>
<li>存储目录：<code>./db</code>、<code>./app</code>、<code>./cache</code>分别对应数据库、应用文件、缓存数据，建议确保目录有足够权限（可执行<code>chmod 775 ./*</code>临时授权）。</li>
</ul><p>保存配置文件后，执行以下命令启动容器：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 后台启动服务</span></div></div><div><div><div>2</div></div><div><span>docker-compose</span><span> </span><span>up</span><span> </span><span>-d</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>启动成功后，检查容器状态（确保<code>app</code>、<code>db</code>、<code>cache</code>均为<code>Up</code>状态）：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251030235357852.png" alt="image-20251030235357852" /><figcaption>image-20251030235357852</figcaption></figure><p></p></section>
<section><h1>反向代理：用域名访问并启用 HTTPS<a href="#反向代理用域名访问并启用-https"><span>#</span></a></h1><p>部署成功后，在浏览器中输入 <strong>NAS_IP&lt;28080&gt;</strong> 即可进行访问。直接通过<code>IP:端口</code>访问不够安全，也不便于记忆，建议配置反向代理，绑定域名并启用 HTTPS。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251110001826714.png" alt="image-20251110001826714" /><figcaption>image-20251110001826714</figcaption></figure><p></p><p>在域名托管商（如阿里云、腾讯云）将域名（如<code>nextcloud.example.com</code>）解析到服务器 IP。</p><p>可以通过宝塔面板/NPM等工具对域名反向代理，将域名反向代理到本地的28080端口，将本地服务暴露到域名上，这样就可以通过域名访问本地的<code>nextcloud</code>服务。</p><p>如果将 Nextcloud 部署在群晖 NAS 上，可通过 Web Station 快速配置反向代理：</p><p>部署 Nextcloud 时，勾选 “通过 Web Station 设置网页门户”：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251110183352495.png" alt="image-20251110183352495" /><figcaption>image-20251110183352495</figcaption></figure><p></p><p>群晖会自动创建网页服务，绑定 28080 端口：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251110183604846.png" alt="image-20251110183604846" /><figcaption>image-20251110183604846</figcaption></figure><p></p><p>接下来，在网页服务门户界面，选择新增网页门户，选择上一步创建的网页服务，<code>门户类型</code>选择<code>基于名称</code>，<code>主机名</code>就填之前解析好域名<code>nextcloud.example.com</code>。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251110183727971.png" alt="image-20251110183727971" /><figcaption>image-20251110183727971</figcaption></figure><p></p><p>这一步的操作和NPM/nginx原理上是一样的，不过是群晖将其集成到可视化界面Web Station里了。</p></section>
<section><h1>关键配置：解决 “不信任域名” 问题<a href="#关键配置解决-不信任域名-问题"><span>#</span></a></h1><p>配置反向代理后，直接访问域名可能会出现 “不被信任的域名” 提示，需修改 Nextcloud 的配置文件授权域名。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251110122138897.png" alt="image-20251110122138897" /><figcaption>image-20251110122138897</figcaption></figure><p></p><p>配置文件路径为：<code>~/docker/nextcloud/app/config/config.php</code>（群晖 NAS 路径需对应 Docker 挂载目录）。</p><p>编辑文件，添加域名到<code>trusted_domains</code>数组，并补充 HTTPS 相关配置：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>'trusted_domains'</span><span> =&gt;</span></div></div><div><div><div>2</div></div><div><span>array</span><span> (</span></div></div><div><div><div>3</div></div><div><span>    </span><span>0</span><span> =&gt; </span><span>'192.168.1.100:28080'</span><span>,  </span><span># 服务器/NAS内网IP+端口</span></div></div><div><div><div>4</div></div><div><span>    </span><span>1</span><span> =&gt; </span><span>'nextcloud.example.com'</span><span>,  </span><span># 你的域名</span></div></div><div><div><div>5</div></div><div><span>),</span></div></div><div><div><div>6</div></div><div><span>'datadirectory'</span><span> =&gt; </span><span>'/var/www/html/data'</span><span>,</span></div></div><div><div><div>7</div></div><div><span>'dbtype'</span><span> =&gt; </span><span>'mysql'</span><span>,</span></div></div><div><div><div>8</div></div><div><span>'version'</span><span> =&gt; </span><span>'32.0.1.2'</span><span>,</span></div></div><div><div><div>9</div></div><div><span>'overwritehost'</span><span> =&gt; </span><span>'nextcloud.example.com'</span><span>,  </span><span># 域名</span></div></div><div><div><div>10</div></div><div><span>'overwriteprotocol'</span><span> =&gt; </span><span>'https'</span><span>,  </span><span># 强制HTTPS</span></div></div><div><div><div>11</div></div><div><span>'overwrite.cli.url'</span><span> =&gt; </span><span>'https://nextcloud.example.com'</span><span>,  </span><span># 完整域名</span></div></div><div><div><div>12</div></div><div><span>'redis'</span><span> =&gt; </span><span>array</span><span>(  </span><span># 启用Redis缓存（提升性能）</span></div></div><div><div><div>13</div></div><div><span>    </span><span>'host'</span><span> =&gt; </span><span>'cache'</span><span>,</span></div></div><div><div><div>14</div></div><div><span>    </span><span>'port'</span><span> =&gt; </span><span>6379</span><span>,</span></div></div><div><div><div>15</div></div><div><span>    </span><span>'password'</span><span> =&gt; </span><span>'redis_password'</span><span>,  </span><span># 与docker-compose中的Redis密码一致</span></div></div><div><div><div>16</div></div><div><span>),</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>修改配置后，重启容器使配置生效。这样就可以通过<code>nextcloud.example.com</code>域名访问<strong>Nextcloud服务</strong>了。</p><p>进入初始化页面，第一次登录需要设置管理员账号和密码（建议强密码，保管好）。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251110122720183.png" alt="image-20251110122720183" /><figcaption>image-20251110122720183</figcaption></figure><p></p><p>设置完成后初始化需要的时间较长，耐心等待后进入主界面，如下图所示，这样就完成安装了。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20251110122814759.png" alt="image-20251110122814759" /><figcaption>image-20251110122814759</figcaption></figure><p></p></section>
<section><h1>公网访问：无公网 IPv4？IPv6 转 IPv4 方案（可选）<a href="#公网访问无公网-ipv4ipv6-转-ipv4-方案可选"><span>#</span></a></h1><p>很多家庭宽带只有 IPv6，无法在 IPv4 网络（如公共场所 WiFi）访问内网 Nextcloud，推荐用腾讯云 EdgeOne 或 Cloudflare 实现 IPv6-IPv4 转发。</p><p>我这里选择使用腾讯云的EdgeOne的CDN服务进行IPV6-IPV4的转发，效果和cloudflare的cdn是类似的，我用腾讯云的EdgeOne服务单纯是为了国内访问快一点，cloudflare提供的免费cdn在国内有时还是挺卡的。这里可以参考我之前的一篇文章<a href="/archives/899/">2025最新版：基于腾讯云EdgeOne 的 IPv6 内网穿透指南（无公网 IPv4 也能实现博客 + 图床公网访问） - 阿雷的小窝</a>。</p><p>这里需要使用到两个域名，第一个域名<code>synology.example.com</code>，用于DDNS-GO指向本地的IPV6地址。第二个域名<code>nextcloud.example.com</code>，为我们配置反向代理的域名。</p><ol>
<li><strong>配置 DDNS-GO</strong>：将动态 IPv6 地址绑定到域名（如<code>synology.example.com</code>），确保内网服务可通过固定域名访问。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250827213619933.png" alt="ddns-go IPv6 配置界面" /><figcaption>ddns-go IPv6 配置界面</figcaption></figure><p></p><p>用两个域名的原因是腾讯云EdgeOne设置回源时，需要填IP地址或者域名，而群晖的IPV6地址是动态的，设置地址显然不行，只能曲线救国通过回源DDNS-GO设置的域名来实现，这样就实现了外网无ipv6也能访问本地的<code>nextcloud</code>服务。</p><ol>
<li><strong>配置腾讯云 EdgeOne</strong>：</li>
</ol><ul>
<li>源站类型选择 “域名”，填写 DDNS 绑定的域名（<code>synology.example.com</code>）。</li>
<li>开启 “IPv6 回源” 和 HTTPS，实现 IPv6-IPv4 转换。</li>
</ul><p></p><figure><img src="http://imgbed.leihub.cn/img/1756304019975.png" alt="腾讯云 EO 源站配置界面" /><figcaption>腾讯云 EO 源站配置界面</figcaption></figure><p></p><ol>
<li><strong>访问方式</strong>：通过 Nextcloud 域名（<code>nextcloud.example.com</code>）即可在任何网络访问，CDN 还能提升访问速度。</li>
</ol></section>
<section><h1>小结<a href="#小结"><span>#</span></a></h1><p>Nextcloud 作为开源私有云盘的标杆，不仅解决了第三方网盘的隐私和限速问题，还能通过插件拓展功能。无论是家庭文件共享、个人数据备份，还是小型团队协作，都能完美适配。</p><p>通过 Docker 部署，简化了环境配置；配合反向代理和 CDN，实现了公网安全访问。按照本文步骤，你也能拥有一套数据完全可控、使用无限制的私有云盘服务！</p></section>
<section><h1>参考<a href="#参考"><span>#</span></a></h1><ol>
<li><a href="https://nextcloud.com/" target="_blank">Nextcloud - Open source content collaboration platform</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/686950702" target="_blank">(10 封私信 / 80 条消息) 个人网盘来了！Nextcloud AIO保姆级部署攻略 - 知乎</a></li>
<li><a href="https://blognas.hwb0307.com/linux/docker/234" target="_blank">Docker系列 搭建个人云盘服务nextcloud - Bensz</a></li>
<li><a href="/archives/899/">基于腾讯云 EdgeOne 的 IPv6 内网穿透指南 - 阿雷的小窝</a></li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/899/</id>
      <title type="text">2025最新版：基于腾讯云EdgeOne 的 IPv6 内网穿透指南（无公网 IPv4 也能实现博客 + 图床公网访问）</title>
      <published>2025-06-27T16:54:58.000Z</published>
      <updated>2026-03-08T04:45:00.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/899/"/>
      <summary type="text">2025最新版：基于腾讯云EdgeOne 的 IPv6 内网穿透指南（无公网 IPv4 也能实现博客 + 图床公网访问） 作为一个喜欢折腾的宅，在本地搭建了 WordPress 博客和 Chevereto 图床等服务，想在外随时访问需要进行</summary>
      <content type="html"><![CDATA[<section><h1>2025最新版：基于腾讯云EdgeOne 的 IPv6 内网穿透指南（无公网 IPv4 也能实现博客 + 图床公网访问）<a href="#2025最新版基于腾讯云edgeone-的-ipv6-内网穿透指南无公网-ipv4-也能实现博客--图床公网访问"><span>#</span></a></h1><p>作为一个喜欢折腾的宅，在本地搭建了 WordPress 博客和 Chevereto 图床等服务，想在外随时访问需要进行<strong>内网穿透</strong>。之前也陆续使用过zerotier、FRP、cloudflare等服务，像家庭宽带只有 <strong>IPv6 公网地址</strong>，IPv4 还是内网，直接用 IPv6 访问又只能在支持 IPv6 的环境用，兼容性太差。</p><p>试了 zerotier、FRP（配置复杂）、花生壳（限速且贵）、Cloudflare 免费版（国内访问慢），直到发现<strong>腾讯云边缘计算 EO（EdgeOne）</strong> ：9.9 元 / 月含 50GB 流量，还支持 IPv6 源站，搭配<strong>DDNS 动态域名解析</strong>，终于实现低成本穿透。今天分享完整方案，新手跟着步骤也能做。</p><ul>
<li>
<section><h4>一、先搞懂：为什么腾讯云 EO+IPv6 方案能行？<a href="#一先搞懂为什么腾讯云-eoipv6-方案能行"><span>#</span></a></h4><p>在动手前，先理清核心逻辑，没有公网IPv4，为什么IPv6+EO能实现穿透？</p><p>家庭宽带IPv6本身是公网地址，我们这个方法选择EO充当“IPv4转IPv6桥梁”，接收IPv4用户请求并转发到本地服务，同时解决IPv6地址动态变化（靠DDNS）和兼容性问题。</p><ol>
<li>家庭宽带的 “痛点”
现在多数家庭宽带已支持 IPv6（找运营商开通，光猫路由器开启 IPv6 即可），但两个问题拦住多数人：</li>
</ol><ul>
<li><strong>IPv6 地址是动态的</strong>（每次重启路由器会变），没法直接绑定域名；</li>
<li>多数用户设备仍用 IPv4（手机 4G、公司网络），直接访问 IPv6 服务会失败。</li>
</ul><ol>
<li>所需的工具</li>
</ol><ul>
<li><strong>DDNS（动态域名解析）</strong>：解决 IPv6 地址动态变化问题，把 “变化的 IPv6” 和 “固定域名” 绑定（比如让<code>local.mydomain.com</code>始终指向家里的 IPv6），是<strong>IPv6 穿透的核心前提</strong>。</li>
<li><strong>腾讯云 EO</strong>：相当于 “中间桥梁”—— 接收 IPv4 用户的访问请求，转发到 IPv6 本地服务，同时提供 CDN 加速（国内节点，比 Cloudflare 快）和流量控制（50GB 足够个人用），是<strong>无公网 IPv4 穿透的关键工具</strong>。</li>
<li><strong>双域名设计</strong>：一个域名（A 域名）绑本地 IPv6（靠 DDNS），一个域名（B 域名）做 EO 加速入口，解决 EO 不能直接绑动态 IPv6 的问题。</li>
</ul></section>
</li>
</ul><section><h3>二、方案架构：一张图看懂流量走向<a href="#二方案架构一张图看懂流量走向"><span>#</span></a></h3><p>整个穿透流程其实很简单，用文字画个架构图：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>                              </span></span><span>公网用户（IPv4/IPv6）</span></div></div><div><div><div>2</div></div><div><span><span>                                      </span></span><span>↓</span></div></div><div><div><div>3</div></div><div><span><span>                       </span></span><span>腾讯云EO（B域名：public.mydomain.com）</span></div></div><div><div><div>4</div></div><div><span><span>                                      </span></span><span>↓</span></div></div><div><div><div>5</div></div><div><span><span>                        </span></span><span>A域名（local.mydomain.com:80）</span></div></div><div><div><div>6</div></div><div><span><span>                                      </span></span><span>↓</span></div></div><div><div><div>7</div></div><div><span><span>                              </span></span><span>本地WordPress博客</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>简单说：用户访问 B 域名，EO 根据路径把请求转发到对应的本地服务，同时自动处理 IPv4 转 IPv6 的兼容问题。</p></section><section><h3>三、前置准备：这些东西要先备好<a href="#三前置准备这些东西要先备好"><span>#</span></a></h3><p>动手前先确认资源是否齐全，避免中途卡壳：</p><ol>
<li>
<p><strong>家庭 IPv6 环境</strong>：光猫、路由器开启 IPv6（登录路由器管理页，找 “IPv6 设置”，选 “原生 IPv6”），用ipconfig（Windows）或ifconfig（Linux）查本地 IPv6（开头通常是 240e、2409 等公网段）。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250827212955267.png" alt="路由器 IPv6 设置界面" /><figcaption>路由器 IPv6 设置界面</figcaption></figure><p></p>
</li>
<li>
<p><strong>两个域名</strong>：在阿里云、腾讯云等平台注册，比如用<a href="http://local.mydomain.com/" target="_blank">local.mydomain.com</a>（A 域名，绑本地 IPv6）和<a href="http://public.mydomain.com/" target="_blank">public.mydomain.com</a>（B 域名，EO 加速入口）。</p>
</li>
<li>
<p><strong>腾讯云账号</strong>：开通 “边缘计算 EO” 服务（搜 “EdgeOne” 就能找到，新用户有优惠，9.9 元 / 月的 “基础版” 足够），为主域名<a href="mydomain.com/">mydomain.com</a>购买一个9.9元的个人套餐，每月有50G流量，一般来说足够用了。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250827214756985.png" alt="腾讯云 EO 基础版套餐界面" /><figcaption>腾讯云 EO 基础版套餐界面</figcaption></figure><p></p>
</li>
<li>
<p><strong>本地服务</strong>：博客（我用 WordPress，部署在 80 端口）、图床（Chevereto，8080 端口），确保局域网内用 IPv6 能访问（比如用http://[240e:xxx:xxx]打开博客）。</p>
</li>
<li>
<p><strong>DDNS 工具</strong>：推荐开源的ddns-go（跨平台，图形化界面，新手友好）。</p>
</li>
</ol></section><section><h3>四、分步操作：从 0 到 1 实现穿透<a href="#四分步操作从-0-到-1-实现穿透"><span>#</span></a></h3><p>这部分是核心，每一步都附具体操作，跟着来就能成。DDNS的搭建可以看之前写的一篇文章：<a href="/archives/535/">DDNS+IPV6实现外网访问 - 阿雷的小窝</a></p><section><h4>第一步：配置 A 域名的 DDNS（让域名绑住动态 IPv6）<a href="#第一步配置-a-域名的-ddns让域名绑住动态-ipv6"><span>#</span></a></h4><p>目标：让<a href="http://local.mydomain.com/" target="_blank">local.mydomain.co</a><a href="http://local.mydomain.com/" target="_blank">m</a>始终指向家里的 IPv6，哪怕地址变了也能自动更新。</p><ol>
<li><strong>下载安装 ddns-go</strong>：</li>
</ol><ul>
<li>
<p>官网：<a href="https://github.com/jeessy2/ddns-go%EF%BC%8C%E6%A0%B9%E6%8D%AE%E7%B3%BB%E7%BB%9F%E4%B8%8B%E8%BD%BD%E5%AF%B9%E5%BA%94%E7%89%88%E6%9C%AC%EF%BC%88Windows" target="_blank">https://github.com/jeessy2/ddns-go，根据系统下载对应版本（Windows</a> 选 exe，Linux 选 amd64.deb）。</p>
</li>
<li>
<p>打开软件，默认端口 9876，浏览器访问<a href="http:/localhost:9876/">http://localhost&lt;987&gt;</a><a href="http://localhost:9876/" target="_blank">6</a>进入管理页。</p>
</li>
</ul><ol>
<li><strong>配置 DDNS 规则</strong>：</li>
</ol><ul>
<li>
<p>选择 “DNS 服务商”：比如你的域名在腾讯云，就选 “腾讯云 DNS”，然后去腾讯云控制台获取 “SecretId” 和 “SecretKey”（搜 “访问管理”→“API 密钥” 创建）。</p>
</li>
<li>
<p>DDNS类型选IPV6，通过网卡获取IP地址，填指向本地的域名（即<a href="http://local.mydomain.com/" target="_blank">local.mydomain.com</a>）；</p>
</li>
</ul><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250827213619933.png" alt="ddns-go IPv6 配置界面" /><figcaption>ddns-go IPv6 配置界面</figcaption></figure><p></p><ol>
<li><strong>测试验证</strong>：</li>
</ol><ul>
<li>
<p>保存配置后，看 ddns-go 日志是否显示 “更新成功”，每隔半小时会自动更新域名解析，确保指向本地IPV6地址。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250827220011735.png" alt="ddns-go 更新成功日志" /><figcaption>ddns-go 更新成功日志</figcaption></figure><p></p>
</li>
<li>
<p>打开 cmd（Windows）或终端（Linux），输入ping6 <a href="http://local.mydomain.com/" target="_blank">local.mydomain.com</a>，能 ping 通且 IP 和本地 通过ipconfig查询的IPv6 一致，说明 DDNS 配置好了。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250827214323679.png" alt="ping6 验证 DDNS 结果" /><figcaption>ping6 验证 DDNS 结果</figcaption></figure><p></p>
</li>
</ul></section><section><h4>第二步：创建腾讯云 EO 服务（B 域名做访问入口）<a href="#第二步创建腾讯云-eo-服务b-域名做访问入口"><span>#</span></a></h4><p>目标：让<a href="http://public.mydomain.com/" target="_blank">public.mydomain.co</a><a href="http://public.mydomain.com/" target="_blank">m</a>成为公网访问入口，同时转发请求到本地服务。</p><ol>
<li><strong>开通 EO 并新建加速域名</strong>：</li>
</ol><ul>
<li>
<p>登录腾讯云控制台，搜 “EdgeOne” 进入控制台，新建 “站点”（选 “网站加速”）。</p>
</li>
<li>
<p>输入加速域名：<a href="http://public.mydomain.com/" target="_blank">public.mydomain.com</a>，然后 “下一步”。</p>
</li>
</ul><ol>
<li><strong>关键：源站配置（IPv6 穿透核心）</strong>⚠️ <strong>核心提示</strong>：</li>
</ol><ul>
<li>源站类型必须选 “域名”（而非 IP），因为 IPv6 是动态的，选域名可通过 DDNS 自动更新</li>
<li>源站地址：填 A 域名<code>local.mydomain.com</code>；</li>
<li>端口与协议：按需修改；</li>
<li>IPv6 回源：必须开启（“协议设置”→勾选 “IPv6”），确保 EO 能访问 IPv6 源站；</li>
<li>为什么不直接选 IP：IPv6 地址会变，选 IP 会导致 EO 转发失败，选域名可通过 DDNS 自动同步最新 IPv6。</li>
</ul><p></p><figure><img src="http://imgbed.leihub.cn/img/1756304019975.png" alt="腾讯云 EO 源站配置界面" /><figcaption>腾讯云 EO 源站配置界面</figcaption></figure><p></p><ol>
<li><strong>配置 HTTPS（必须！现在公网访问都要安全）</strong>：</li>
</ol><ul>
<li>
<p>申请免费证书：EO 控制台→“SSL 证书”→“申请免费证书”→输入<code>public.mydomain.com</code>→选 “DNS 验证”（EO 自动加解析记录，无需手动操作）；</p>
</li>
<li>
<p>绑定证书：“加速域名”→“HTTPS 配置”→绑定证书→开启 “强制 HTTPS”（让 HTTP 请求自动转 HTTPS，避免浏览器提示 “不安全”）；</p>
</li>
<li>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250827233930932.png" alt="腾讯云 EO HTTPS 配置界面" /><figcaption>腾讯云 EO HTTPS 配置界面</figcaption></figure><p></p>
</li>
</ul></section><section><h4>第三步：测试验证（确保能正常访问）<a href="#第三步测试验证确保能正常访问"><span>#</span></a></h4><p>配置完一定要多场景测试，确保 IPv4/IPv6 环境都能访问。</p><p>我是用群晖的Web Station创建了一个网页在本地，反代到DDNS指向的 A 域名<a href="http://local.mydomain.com/" target="_blank">local.mydomain.com</a>；</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250828002409635.png" alt="群晖" /><figcaption>群晖</figcaption></figure><p></p><p>此时本地只有IPV6地址，在IPV4环境使用域名<a href="http://local.mydomain.com/" target="_blank">local.mydomain.com</a>是无法访问的。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250828002844016.png" alt="image-20250828002844016" /><figcaption>image-20250828002844016</figcaption></figure><p></p><p>通过腾讯云 EO 服务创建B 域名做访问入口后，既可以通过B域名<a href="https://public.mydomain.com%E8%AE%BF%E9%97%AE%E3%80%82" target="_blank">https://public.mydomain.com访问。</a></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250828002937064.png" alt="IPv4 访问 EO 域名成功界面" /><figcaption>IPv4 访问 EO 域名成功界面</figcaption></figure><p></p><p>腾讯云 EO 控制台有 “流量分析”，能看到每天用了多少流量，50GB 对个人来说真的够用（我每月博客 + 图床才用 5GB 左右）。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250828003146135.png" alt="腾讯云 EO 流量监控界面" /><figcaption>腾讯云 EO 流量监控界面</figcaption></figure><p></p></section></section><section><h3>五、总结<a href="#五总结"><span>#</span></a></h3><section><h4>1、 方案核心优势<a href="#1-方案核心优势"><span>#</span></a></h4><p>给大家算笔账，对比常见的穿透方案：</p>

<table><thead><tr><th>方案</th><th>月成本</th><th>流量限制</th><th>兼容性（IPv4/IPv6）</th><th>国内访问速度</th></tr></thead><tbody><tr><td>花生壳专业版</td><td>33元</td><td>无限制GB（2Mbps）</td><td>支持</td><td>一般</td></tr><tr><td>Cloudflare 免费版</td><td>0 元</td><td>无限制（但国内慢）</td><td>支持</td><td>慢（节点在国外）</td></tr><tr><td>腾讯云 EO 基础版</td><td>9.9 元</td><td>50GB</td><td>支持</td><td>快（国内节点）</td></tr></tbody></table><p>在国内内网穿透服务上，腾讯云 EO 的性价比还算可以 ——9.9 元既有国内加速，又有 50GB 流量，还支持 IPv6，完全满足个人需求。</p><p>按我个人使用：每月发 10 篇博客（每篇 5 张图，每张 1MB），每天 100 次访问，每月流量约 3-5GB，50GB 足够用，就算偶尔分享图片，也很难用完。</p><p>如果你和我一样，有本地服务公网访问的需求，且家庭宽带支持 IPv6，这个方案绝对值得试：</p><ul>
<li><strong>低成本</strong>：9.9 元 / 月含 50GB 国内流量，比花生壳专业版（398一年）性价比高；</li>
<li><strong>易操作</strong>：无需复杂命令，跟着步骤 1-2 小时搞定，新手友好；</li>
<li><strong>兼容性强</strong>：支持 IPv4/IPv6 双栈访问，手机 4G、公司网络、家里 WiFi 都能用；</li>
<li><strong>速度快</strong>：腾讯云国内边缘节点，比 Cloudflare 免费版（国外节点）访问速度快 3-5 倍。</li>
</ul></section><section><h4>2、注意安全防护<a href="#2注意安全防护"><span>#</span></a></h4><ul>
<li>
<p>本地服务别用默认密码：WordPress、图床的后台密码设复杂点，最好加两步验证；</p>
</li>
<li>
<p>别暴露敏感服务：比如数据库（MySQL）别开公网访问，只让本地服务连接；</p>
</li>
<li>
<p>EO 加访问控制：在 “安全防护”→“访问控制” 里，添加自己常用的 IP（比如公司 IP），限制其他 IP 访问后台（比如/blog/wp-admin）。</p>
</li>
</ul></section></section><section><h3>参考<a href="#参考"><span>#</span></a></h3><p><a href="https://cloud.tencent.com/document/product/1552/69826" target="_blank">边缘安全加速平台 EO 产品概述_腾讯云</a></p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/883/</id>
      <title type="text">阿雷的2024个人年终总结</title>
      <published>2025-03-01T15:07:49.000Z</published>
      <updated>2026-03-08T04:48:14.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/883/"/>
      <summary type="text">一、游戏 今年是工作转正的第一年，手头也逐渐宽裕，买游戏不像当时读书一样的纠结了，也有了更多的底气。今年在steam上入手了不少游戏，也逐步弃坑了一些游戏。 弃坑： 原神：应该说原神不是今年退坑的，是今年决定不玩了，原神是我最喜欢的一款游戏</summary>
      <content type="html"><![CDATA[<section><h3>一、游戏<a href="#一游戏"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>今年是工作转正的第一年，手头也逐渐宽裕，买游戏不像当时读书一样的纠结了，也有了更多的底气。今年在steam上入手了不少游戏，也逐步弃坑了一些游戏。</span></div></div></code></pre><div><div></div><div></div></div></figure></div><section><h4>弃坑：<a href="#弃坑"><span>#</span></a></h4><ol>
<li>
<p>原神：应该说原神不是今年退坑的，是今年决定不玩了，原神是我最喜欢的一款游戏，曾经非常入迷，深度沉迷于其人物、地图、剧情设计，但同时因为每天上限清每日任务、刷圣遗物、每周的深渊这些繁杂却又不得不刷的东西，感觉非常的劳累，在读书的时候还有非常多的空闲时间去肝，而工作之后，逐渐因为各种繁杂的事务渐渐的减少了游戏的登录，最后还是决定弃坑了。但是并不妨碍他在我心中的地位，我仍然认为他是我玩过最好玩的游戏。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/5a731ca2afca63fd86ca46292feb75f.jpg" alt="5a731ca2afca63fd86ca46292feb75f" /><figcaption>5a731ca2afca63fd86ca46292feb75f</figcaption></figure><p></p>
</li>
<li>
<p>崩坏星穹铁道：其人物美术、剧情设计都比较好，但与原神的退坑原因一致，其繁复的日常任务劝退了我。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/242fdbc8852eaed0ce2e3eb367f7c4e.jpg" alt="242fdbc8852eaed0ce2e3eb367f7c4e" /><figcaption>242fdbc8852eaed0ce2e3eb367f7c4e</figcaption></figure><p></p>
</li>
<li>
<p>绝区零：作为一款格斗游戏我个人觉得还不错，米家的几款游戏的退坑原因都基本一致。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/4eab53641cc3b368f01bec36e1a781c.jpg" alt="4eab53641cc3b368f01bec36e1a781c" /><figcaption>4eab53641cc3b368f01bec36e1a781c</figcaption></figure><p></p>
</li>
<li>
<p>英雄联盟：英雄联盟的设计师就是一坨屎，本来我早就作为一个养老玩家了，天天只有在那大乱斗，然后他瞎几把改大乱斗，乱搞平衡，特别影响游戏体验，往往一句游戏的胜负在随机英雄阶段就已经注定了，在高中、大学的时候，他是我最沉迷的游戏，但现在，我只能说他就是一坨屎。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301215359112.png" alt="image-20250301215359112" /><figcaption>image-20250301215359112</figcaption></figure><p></p>
</li>
<li>
<p>绝地求生：本来今年被同事带的一起玩PUBG了，刚刚玩的起劲，就到处遇到挂钩，太影响游戏体验了，还是排位，玩着玩着没什么游戏体验了，不弃坑留着干啥。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301215905967.png" alt="image-20250301215905967" /><figcaption>image-20250301215905967</figcaption></figure><p></p>
</li>
<li>
<p>CS2：这游戏没什么人陪着我玩了，而且玩的时候也经常打不过，就弃坑了。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301215920475.png" alt="image-20250301215920475" /><figcaption>image-20250301215920475</figcaption></figure><p></p>
</li>
</ol></section></section>
<section><h3>入坑\回坑：<a href="#入坑回坑"><span>#</span></a></h3><ol>
<li>
<p>三角洲行动：在同学的带动下，入坑了三角洲行动，其两个模式，一个是塔可夫类型，但是加上了守望先锋类似的技能组和职业，还有一个是战地模式。我主要玩塔可夫模式多，就一个字缝，但是缝的还不错，还挺喜欢玩的，有点上头。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301224953428.png" alt="image-20250301224953428" /><figcaption>image-20250301224953428</figcaption></figure><p></p>
</li>
<li>
<p>部落冲突：几个同学又拉着我回坑玩了，每天就上线几分钟打打部落战，也挺轻松，相对于米家游戏还是轻松挺多的。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/f24f1e7fdc95b0513a82f3c186f00c2.jpg" alt="f24f1e7fdc95b0513a82f3c186f00c2" /><figcaption>f24f1e7fdc95b0513a82f3c186f00c2</figcaption></figure><p></p>
</li>
<li>
<p>艾尔登法环：今年入坑的神作，画风、大地图设计和玩法体验，是我今年最喜欢的游戏之一，所以幽影树之影一出来我就买了，结果通关玩的一坨屎，怪物数值策划是拿脚填的，特别是最后的米塔恩，简直是我见过的技能组最花哨、攻击欲望最强烈的boss，说实话我这手残党都不知道如何能够通关，最后逼得我没办法，没有耐心陪米塔恩玩了，用顿戳流派通关了。只能说本体10分，dlc 6分。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301215934803.png" alt="image-20250301215934803" /><figcaption>image-20250301215934803</figcaption></figure><p></p>
</li>
<li>
<p>为了吾王：在同学的带领下一起玩了这个游戏，真的全看脸，玩了几条命都没能通关，运气成分较高，一气之下弃坑了。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301215953135.png" alt="image-20250301215953135" /><figcaption>image-20250301215953135</figcaption></figure><p></p>
</li>
<li>
<p>群星：P社游戏好玩是好玩，流程、游玩时间、游戏设计都非常庞大，经常一局游戏就要玩十几个小时，玩到现在，我竟然一局游戏都没结束过，打到中后期奠定胜局后就不想玩了，就是繁琐的地图填色，前期的探索、运营阶段更吸引人。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301220301565.png" alt="image-20250301220301565" /><figcaption>image-20250301220301565</figcaption></figure><p></p>
</li>
<li>
<p>文明6：文明6也是一款游戏，一个人一包烟，一局游戏玩一天，在工作后时间匆忙起来了，这种需要连续玩几个小时到十几个小时的游戏就玩的比较少了。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301220446607.png" alt="image-20250301220446607" /><figcaption>image-20250301220446607</figcaption></figure><p></p>
</li>
<li>
<p>怪物猎人：世界，游戏本体游玩起来整体难度尚可，进入冰原后难度完全不是一个等级，我这手残党只能全程摇人，但是因为用的公司网络，极度不稳定，经常摇过来的人还没打完就掉线了，今年最终也没通关这个游戏。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301220657259.png" alt="image-20250301220657259" /><figcaption>image-20250301220657259</figcaption></figure><p></p>
</li>
<li>
<p>黑神话：悟空，是今年国产游戏的一个亮点吧，这个游戏整体来说，加上国产化滤镜，我只能给个8分，游戏动作系统、剧情设计尚可，但是地图设计我认为还是属于二三线水平，真不如原神，各种空气墙，还是有盘丝洞那一章节，地图都要给我绕晕了，特别是最后一章的地图设计，简直堪称灾难，完全没有引导，也没有任何地标指引，找个boss找半天，直接拉低了我对这个游戏的评价。整体剧情也比较单薄，流程特别短，结局也只有两个，严格来说只有一个结局，而且这个结局在我看来也非常一般。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301221054562.png" alt="image-20250301221054562" /><figcaption>image-20250301221054562</figcaption></figure><p></p>
</li>
<li>
<p>幻兽帕鲁：这个游戏就一个字缝，嘿，但是你别说，他还缝的挺不错，和同学一起联机玩还挺有意思的。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301221158586.png" alt="image-20250301221158586" /><figcaption>image-20250301221158586</figcaption></figure><p></p>
</li>
<li>
<p>庄园领主：游戏设计比较细节，也比较真实，但是你不能一个半成品端出来就要卖我99吧？</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301221259719.png" alt="image-20250301221259719" /><figcaption>image-20250301221259719</figcaption></figure><p></p>
</li>
<li>
<p>帝国时代4：和同学一起玩了会帝国时代，已经找不回当时初中时，因为家里断网，只能玩玩单机帝国时代时候的感觉了。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301221410082.png" alt="image-20250301221410082" /><figcaption>image-20250301221410082</figcaption></figure><p></p>
</li>
<li>
<p>the way out：一款不错的短流程游戏，同事拉我一起玩，一下午就通关了。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301221453576.png" alt="image-20250301221453576" /><figcaption>image-20250301221453576</figcaption></figure><p></p>
</li>
<li>
<p>地平线5： 买来就没怎么玩，感觉可惜了。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301221623022.png" alt="image-20250301221623022" /><figcaption>image-20250301221623022</figcaption></figure><p></p>
</li>
<li>
<p>皇家女神异闻录5黄金版：都说P5天下第一，我就入手了，但是也没怎么玩。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301221723679.png" alt="image-20250301221723679" /><figcaption>image-20250301221723679</figcaption></figure><p></p>
</li>
<li>
<p>RAFT：和同学尝试了下这个游戏，还是太累的，需要一直的操作，鲨鱼会不停的破坏东西，需要不停的钓物资来修补船筏，目前还没引起我的兴趣。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301221855480.png" alt="image-20250301221855480" /><figcaption>image-20250301221855480</figcaption></figure><p></p>
</li>
</ol></section>
<section><h3>二、文章<a href="#二文章"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>今年没写什么文章，当时所预想的、计划的项目很多都因为繁忙的工作或者沉迷游戏搁浅了，也有可能就是单纯的懒，哈哈哈。</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section>
<section><h3><a href="https://blog.leihub.cn/archives/date/2024/12">12 月</a><a href="#12-月"><span>#</span></a></h3><p><a href="/archives/859/">开源多端同步笔记软件 - Joplin</a></p><p><a href="/archives/861/">忆外公</a></p></section>
<section><h3><a href="https://blog.leihub.cn/archives/date/2024/11">11 月</a><a href="#11-月"><span>#</span></a></h3><p><a href="/archives/878/">自建密码堡垒：手把手教你搭建企业级 Vaultwarden 密码管理器</a></p></section>
<section><h3><a href="https://blog.leihub.cn/archives/date/2024/10">10 月</a><a href="#10-月"><span>#</span></a></h3><p><a href="/archives/856/">足迹：桂林三日游</a></p></section>
<section><h3><a href="https://blog.leihub.cn/archives/date/2024/08">8 月</a><a href="#8-月"><span>#</span></a></h3><p><a href="/archives/834/">足迹：2024 高温假自驾游</a></p></section>
<section><h3><a href="https://blog.leihub.cn/archives/date/2024/07">7 月</a><a href="#7-月"><span>#</span></a></h3><p><a href="/archives/819/">搭建起我的第一口小草缸</a></p></section>
<section><h3><a href="https://blog.leihub.cn/archives/date/2024/06">6 月</a><a href="#6-月"><span>#</span></a></h3><p><a href="/archives/813/">基于 steamcmd+zerotier 搭建森林、未转变者、幻兽帕鲁等游戏服务器</a></p><p><a href="/archives/802/">Hexo + Serverless 免费部署属于自己的个人博客</a></p><p><a href="/archives/798/">typora+picgo+cos+cdn 搭建个人写作环境</a></p><p><a href="/archives/784/">足迹：端午长沙行</a></p><p><a href="/archives/717/">个人数据备份方案</a></p><p><a href="/archives/715/">聊天机器人（二）：chatgpt-on-wechat 与星火大模型 API 搭建微信聊天机器人</a></p></section>
<section><h3><a href="https://blog.leihub.cn/archives/date/2024/05">5 月</a><a href="#5-月"><span>#</span></a></h3><p><a href="/archives/711/">铝合金焊接知识（一）</a></p><p><a href="/archives/709/">新能源油冷电机（二）：特斯拉和比亚迪</a></p><p><a href="/archives/707/">新能源电机油冷方案（一）</a></p></section>
<section><h3>三、行迹<a href="#三行迹"><span>#</span></a></h3><ol>
<li>
<p>今年也很少出去玩，最多的就是和几个同事一起去长沙玩，因为比较近，一天就能来回，非常方便。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/c9e4ca73c02dbf0d5cc09e274b6f8b9.jpg" alt="c9e4ca73c02dbf0d5cc09e274b6f8b9" /><figcaption>c9e4ca73c02dbf0d5cc09e274b6f8b9</figcaption></figure><p></p>
</li>
<li>
<p>也尝试过钓鱼，在家里别人的鱼塘钓了一个一两斤的鱼，当时就膨胀了，买了装备就想着去湘江钓鱼，结果遇到大雨，好险差点滑到江里去了，半个身子都进江里，后面就再也没去钓过鱼了。</p>
</li>
</ol><p></p><figure><img src="https://imgbed.leihub.cn/img/68935658fe2e47dde91e6511ce2035a.jpg" alt="68935658fe2e47dde91e6511ce2035a" /><figcaption>68935658fe2e47dde91e6511ce2035a</figcaption></figure><p></p><ol>
<li>上半年还去东莞出了一次差，供应商加工有问题，去人家那挑别人毛病。</li>
</ol><p></p><figure><img src="https://imgbed.leihub.cn/img/dd7a7167ccb191d4767f5d96f18cd1f.jpg" alt="dd7a7167ccb191d4767f5d96f18cd1f" /><figcaption>dd7a7167ccb191d4767f5d96f18cd1f</figcaption></figure><p></p><ol>
<li>
<p>很快啊，我们这边吊完供应商，我们就飞去北京挨客户吊了啊，哈哈哈，相对于南方，感觉北方还是太萧条了，走在路上都没有绿色，全是一片灰蒙蒙的，污染也相对严重，还是自家好。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/4a0184f322301d0a9556d4a0be2bb4d.jpg" alt="4a0184f322301d0a9556d4a0be2bb4d" /><figcaption>4a0184f322301d0a9556d4a0be2bb4d</figcaption></figure><p></p>
</li>
<li>
<p>到了下班年的高温假，和家人凑了个假期一起出去游玩了，在湖南和江西的边界穿梭，什么神农谷、井冈山、武功山、株洲方特都玩了一圈，还是一个非常充实的假期。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/264a353a5048acc06285a6e542cd2ff.jpg" alt="264a353a5048acc06285a6e542cd2ff" /><figcaption>264a353a5048acc06285a6e542cd2ff</figcaption></figure><p></p>
</li>
<li>
<p>国庆假期就和同事一起凑了个旅游团，一起去桂林玩了一趟，说实话，游玩体验不是特别好，因为是旅游高峰期，真的全是人，看的不爽、吃的也不爽哈，下次出来要避着高峰假期哈。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/fb389946b76c98cb35a44e361198dc6.jpg" alt="fb389946b76c98cb35a44e361198dc6" /><figcaption>fb389946b76c98cb35a44e361198dc6</figcaption></figure><p></p>
</li>
</ol></section>
<section><h3>四、消费<a href="#四消费"><span>#</span></a></h3><p></p><figure><img src="https://imgbed.leihub.cn/img/feb54f7658a66d6474c626ac60ede2f.jpg" alt="feb54f7658a66d6474c626ac60ede2f" /><figcaption>feb54f7658a66d6474c626ac60ede2f</figcaption></figure><p></p><ol>
<li>
<p>去年的消费大头是吃饭，民以食为天哈哈，去年动不动就和同事出去聚餐，而且聚餐的消费还不低，一整年下来，画在吃饭上的钱都上两万了，今年在饮食的消费上还是需要谨慎一些了。</p>
</li>
<li>
<p>另外的消费大头就是给爸妈换了两个红米K70U手机，以及过年的人情往来消费。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/8198430eeddde3f9c36ba1e77393317.jpg" alt="8198430eeddde3f9c36ba1e77393317" /><figcaption>8198430eeddde3f9c36ba1e77393317</figcaption></figure><p></p>
</li>
<li>
<p>另一个就是为了偷懒，买了个小电驴哈哈，从宿舍到公司一共也就15分钟路程，我硬是买了个小电驴上下班，感觉今年走路都走的少了，体重都上去了好多。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/8d65569d8c9d1cbdef0d17c7e0899d6.jpg" alt="8d65569d8c9d1cbdef0d17c7e0899d6" /><figcaption>8d65569d8c9d1cbdef0d17c7e0899d6</figcaption></figure><p></p>
</li>
</ol></section>
<section><h3>五、影视<a href="#五影视"><span>#</span></a></h3><p>今年影视方面看得少，以往还经常看小片片看大片的电视剧或者电影解说，现在也看的少了。今年也就稍微看了几部国漫，例如牧神记、斗罗大陆二、吞噬星空这些。感觉影视方面还是看的少了，在2025年要多涉猎一点电影、电视剧和动漫了，不然都有点脱节了。</p></section>
<section><h3>六、工作<a href="#六工作"><span>#</span></a></h3><p>今年是转正的第一年，公司也给了挺多机会，深度参与了多个项目的图纸设计、仿真分析和技术交流工作。同时在进来的第一年就有机会主导一个项目，从全局的角度了解一款电机的设计制造，对个人的职业道路规划也有很大的帮助。</p><ul>
<li>
<p>承担多款电机的零部件设计及仿真分析，确保机械强度与可靠性‌。</p>
</li>
<li>
<p>完成高速电机的模态仿真与结构优化，解决高速动平衡与热稳定性问题‌。‌</p>
</li>
<li>
<p>主导低空经济领域大功率电机的转子设计与机械仿真，优化轴承装配方案‌。</p>
</li>
<li>
<p>参与兆瓦级电机的强度分析与结构统型，提升产品标准化水平‌。</p>
</li>
<li>
<p>完成多款电机的动力学仿真报告撰写，制定机座铸件技术规范‌。</p>
</li>
</ul></section>
<section><h3>总结<a href="#总结"><span>#</span></a></h3><p>总的来说，2024一年还是比较充实的，工作也逐渐忙起来了，空闲时间还是太少了，需要好好对时间进行管理，增加自己的游戏、运动时间，多多出去走走玩玩，丰富业余生活。也祝福自己能在新的一年能够脱单吧~</p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/873/</id>
      <title type="text">2025最新版：基于Cloudflare Tunnel的内网穿透实战指南</title>
      <published>2025-02-24T14:22:36.000Z</published>
      <updated>2026-03-08T04:46:47.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/873/"/>
      <summary type="text">这两年折腾内网穿透，基本把市面方案试了个遍： ‌FRP反向代理‌：靠学生优惠白嫖的腾讯云服务器（4核4G+6M带宽）确实香，但三年到期后续费直接翻倍。新买的2核2G云服务器做中继，转发网页服务勉强够用，但每年上千的续费账单实在肉疼‌。 ‌虚</summary>
      <content type="html"><![CDATA[<p>这两年折腾内网穿透，基本把市面方案试了个遍：</p>
<ol>
<li>‌<strong>FRP反向代理</strong>‌：靠学生优惠白嫖的腾讯云服务器（4核4G+6M带宽）确实香，但三年到期后续费直接翻倍。新买的2核2G云服务器做中继，转发网页服务勉强够用，但每年上千的续费账单实在肉疼‌。</li>
<li>‌<strong>虚拟局域网</strong>‌：Zerotier打洞成功率确实高，但每次知道服务器位于北美就心慌，生怕哪天断联；换成国人开发的Easytier后虽然数据走P2P更安全，但穿透率又掉回解放前——现在直接两条腿走路，两套方案互为备份‌24。</li>
<li>‌<strong>Cloudflare Tunnel</strong>‌：最近发现的宝藏方案，用托管在CF的域名就能把内网服务甩到公网。虽然节点在国外偶尔抽风，但胜在‌<strong>零成本+免备案+银行级加密</strong>‌，配个域名10分钟搞定，比FRP改配置重启服务省心十倍‌。‌</li>
</ol>
<p>这次重点讲Cloudflare Tunnel，就是看中它能把NAS低频访问的内网服务，用最低成本稳定暴露到外网。关键数据全程SSL加密，比自建FRP省了服务器钱还不用操心DDoS防护‌。</p>
<section><h4>‌<strong>一、前置准备</strong>‌<a href="#一前置准备"><span>#</span></a></h4><ol>
<li>
<p>‌<strong>域名与账号配置</strong>‌</p>
<ul>
<li>
<p>注册Cloudflare账号并完成邮箱验证（建议使用Gmail等国际邮箱）‌。</p>
</li>
<li>
<p>将已有域名托管至Cloudflare：进入域名注册商后台（如阿里云、华为云），将DNS服务器替换为Cloudflare提供的地址（例如<code>mike.ns.cloudflare.com</code>）‌。</p>
</li>
<li>
<p>‌<strong>绑定付款方式</strong>‌：支持国际信用卡、借记卡或PayPal，仅用于身份验证（支付金额为0元，服务免费）‌</p>
<img src="http://imgbed.leihub.cn/img/image-20250223141406253.png" alt="创建Cloudflare Zero Trust团队" />
</li>
</ul>
<p>确认是0元免费就可以继续支付了</p>
<img src="http://imgbed.leihub.cn/img/image-20250223141416641.png" alt="免费计划" />
<p>不添加付款方式不让下一步，你可以点Next后输入付款方式</p>
<img src="http://imgbed.leihub.cn/img/image-20250223141632849.png" alt="零元购" />
</li>
<li>
<p>‌<strong>内网环境要求</strong>‌</p>
<ul>
<li>确保被穿透设备（如NAS、Web服务器）支持Docker或本地客户端运行（推荐Linux系统或群晖DSM</li>
<li>开放设备互联网访问权限，检查防火墙是否放行Cloudflare客户端通信端口（如HTTP/80、HTTPS/443）‌</li>
</ul>
</li>
</ol></section>
<section><h4>‌<strong>二、创建Cloudflare Tunnel隧道</strong>‌<a href="#二创建cloudflare-tunnel隧道"><span>#</span></a></h4><ol>
<li>
<p>‌<strong>进入Zero Trust控制台</strong>‌</p>
<ul>
<li>登录Cloudflare控制台 → 左侧菜单点击 ‌<strong>Zero Trust</strong>‌ → 进入 ‌<strong>Networks &gt; Tunnels</strong>‌ ‌</li>
<li>首次使用需选择免费计划（Free Plan）‌</li>
</ul>
</li>
<li>
<p>‌<strong>新建隧道</strong>‌</p>
<ul>
<li>
<p>点击 ‌<strong>Create a tunnel</strong>‌ → 输入隧道名称（如<code>home-nas</code>）→ 保存‌</p>
</li>
<li>
<p>‌<strong>客户端安装</strong>‌：根据设备系统选择安装方式（推荐Docker），群晖可以通过矿神源第三方应用进行安装，本质上也是docker。</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># 拉取官方镜像</span></div></div><div><div><div>2</div></div><div><span>docker pull cloudflare/cloudflared:latest</span></div></div><div><div><div>3</div></div><div><span># 运行隧道（替换YOUR_TOKEN为实际令牌）</span></div></div><div><div><div>4</div></div><div><span>docker run -d cloudflare/cloudflared tunnel --no-autoupdate run --token YOUR_TOKEN</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
</li>
</ul>
</li>
</ol><img src="http://imgbed.leihub.cn/img/image-20250223141830474.png" alt="创建cloudflare tunnel" /><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>  </span></span><span>隧道类型选Cloudflared就可以，然后下一步</span></div></div></code></pre><div><div></div><div></div></div></figure></div><img src="http://imgbed.leihub.cn/img/image-20250223141912829.png" alt="选择隧道类型" /><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>  </span></span><span>创建隧道</span></div></div></code></pre><div><div></div><div></div></div></figure></div><img src="http://imgbed.leihub.cn/img/image-20250223141956222.png" alt="创建隧道" /><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>  </span></span><span>因为我们要在群晖的Docker下用所以选择Docker，你可以根据自己情况选择。在群晖第三方套件    中安装Cloudflare Tunnel，输入tocken安装进行连接，在下方就可以看到连接器了。</span></div></div></code></pre><div><div></div><div></div></div></figure></div><img src="http://imgbed.leihub.cn/img/image-20250223142317799.png" alt="选择连接方式" /></section>
<section><h4>‌**三、**配置公网访问规则<a href="#三配置公网访问规则"><span>#</span></a></h4><ol>
<li>
<p>‌<strong>域名映射与协议设置</strong></p>
<ul>
<li>在隧道详情页点击 ‌<strong>Configure Public Hostname</strong>‌ → 选择已托管的域名和子域名（如<code>blog.leitool.top</code>）</li>
<li>设置协议（HTTP/HTTPS）及内网服务地址，比如我的内网服务部署在本地群晖的8080端口上，内网服务地址就填<code>http://localhost:8080</code>。</li>
<li>支持路径映射（如将<code>/jellyfin</code>指向本地端口<code>8096</code>）‌</li>
<li>一个 Tunnel 中可以添加多条三级域名来跳转到不同的内网服务，在 Tunnel 页面的 Public Hostname 中新增即可。</li>
</ul>
</li>
<li>
<p>‌<strong>端口限制说明</strong>‌</p>
<ul>
<li>免费版仅支持部分HTTP/HTTPS端口（如80、443、2082等），需避免使用非常用端口‌</li>
</ul>
<p>这样配置好托管的域名和群晖的IP和端口就OK了</p>
</li>
</ol><img src="http://imgbed.leihub.cn/img/image-20250223142701535.png" alt="创建丑tunnel成功" /></section>
<section><h4>‌<strong>四、验证与访问</strong>‌<a href="#四验证与访问"><span>#</span></a></h4><ol>
<li>
<p>‌<strong>测试穿透服务</strong>‌</p>
<ul>
<li>
<p>通过浏览器访问配置的子域名（如<code>https://blog.leitool.top</code>），若显示内网服务页面则成功‌。</p>
<img src="http://imgbed.leihub.cn/img/image-20250224220147927.png" alt="内网穿透服务成功" />
</li>
<li>
<p>若失败，检查客户端日志或Cloudflare Tunnel状态‌</p>
</li>
</ul>
</li>
</ol></section>
<section><h4>五、为你的服务添加额外验证<a href="#五为你的服务添加额外验证"><span>#</span></a></h4><p>如果你觉得这种直接暴露内网服务的方式有较高的安全风险，我们还可以使用 Application 功能为服务添加额外的安全验证。</p><ol>
<li>
<p>点击 Application - Get started。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301163502956.png" alt="image-20250301163502956" /><figcaption>image-20250301163502956</figcaption></figure><p></p>
<p>2.选择自托管</p>
</li>
</ol><p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301163619757.png" alt="image-20250301163619757" /><figcaption>image-20250301163619757</figcaption></figure><p></p><ol>
<li>填写配置，<strong>注意 域名和子域名需要使用刚刚创建的 Tunnel 服务相同的域名配置</strong>。</li>
</ol><p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301163929962.png" alt="image-20250301163929962" /><figcaption>image-20250301163929962</figcaption></figure><p></p><ol>
<li>选择验证方式。填写 策略名称（任意）。在添加规则区域选择验证方式，示例图片中使用的是特定完整邮箱地址。你还可以选择使用指定的邮箱域名（如@gmail.com）验证、IP 地址范围等方式。</li>
</ol><p></p><figure><img src="https://imgbed.leihub.cn/img/image-20250301164101588.png" alt="image-20250301164101588" /><figcaption>image-20250301164101588</figcaption></figure><p></p><ol>
<li>完成添加</li>
<li>这样访问配置的子域名（如<code>https://blog.leitool.top</code>）可以看到网站多了一个验证页面，使用刚刚设置的域名邮箱来访问。</li>
</ol></section>
<section><h4><strong>六、总结与适用场景</strong>‌<a href="#六总结与适用场景"><span>#</span></a></h4><ul>
<li>‌<strong>核心优势</strong>‌：免费、无需公网IP、集成DDoS防护和HTTPS加密‌。</li>
<li>‌<strong>典型用途</strong>‌：
<ul>
<li>家庭NAS远程访问（如Jellyfin影音服务）‌。</li>
<li>自建GitLab、Nextcloud等Web服务公网暴露‌。</li>
<li>通过SSH/RDP隧道安全访问内网设备（需配置TCP协议映射）‌。</li>
</ul>
</li>
</ul></section>
<section><h4>七、参考<a href="#七参考"><span>#</span></a></h4><ol>
<li><a href="https://post.smzdm.com/p/aklp824e/" target="_blank">群晖搭建Cloudflare免费隧道穿透，无公网IP也能搞定！__什么值得买</a></li>
<li><a href="https://post.smzdm.com/p/admp85dn/" target="_blank">无需公网IP！CloudFlare Tunnel内网穿透实现内网访问_路由器_什么值得买</a></li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/867/</id>
      <title type="text">基于Cloudflare Workers的Docker镜像反向代理方案</title>
      <published>2025-02-23T04:31:20.000Z</published>
      <updated>2026-03-08T04:49:24.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/867/"/>
      <summary type="text">基于Cloudflare Workers的Docker镜像反向代理方案详解 ‌加速拉取‌：利用Cloudflare全球CDN节点缓存镜像，降低延迟。 ‌绕过限制‌：解决部分区域对Docker Hub的访问限制或限速问题。 ‌零服务器成本‌：</summary>
      <content type="html"><![CDATA[<section><h3>基于Cloudflare Workers的Docker镜像反向代理方案详解<a href="#基于cloudflare-workers的docker镜像反向代理方案详解"><span>#</span></a></h3><ol>
<li>‌<strong>加速拉取</strong>‌：利用Cloudflare全球CDN节点缓存镜像，降低延迟。</li>
<li>‌<strong>绕过限制</strong>‌：解决部分区域对Docker Hub的访问限制或限速问题。</li>
<li>‌<strong>零服务器成本</strong>‌：无需自建服务器，完全依赖Cloudflare免费额度。</li>
<li>‌<strong>灵活扩展</strong>‌：支持自定义缓存策略、请求过滤等高级功能。</li>
</ol><p><strong>适用场景</strong>‌：为Docker Hub等公共仓库提供加速镜像，绕过网络限制并提升拉取速度。</p><section><h5><strong>1. 域名与Cloudflare基础配置</strong>‌<a href="#1-域名与cloudflare基础配置"><span>#</span></a></h5><ul>
<li>
<p>‌<strong>域名托管</strong>‌
将用于镜像加速的域名（如 <code>mirror.example.com</code>）DNS解析托管至Cloudflare，确保代理状态为 ‌**Proxied（橙色云图标）**‌。</p>
</li>
<li>
<p>‌<strong>SSL/TLS设置</strong>‌</p>
<p>在Cloudflare控制台中：</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>plaintextCopy CodeSSL/TLS模式 → Full (Strict)</span></div></div><div><div><div>2</div></div><div><span>边缘证书 → 启用HSTS、最低TLS版本1.2</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p>‌**防火墙规则（可选）**‌
添加规则拦截高频请求IP或恶意爬虫（例：<code>http.request.uri.path contains "/v2/" &amp;&amp; cf.threat_score &gt; 5</code>）。</p>
</li>
</ul></section><section><h5>‌<strong>2. 编写并部署Cloudflare Worker</strong><a href="#2-编写并部署cloudflare-worker"><span>#</span></a></h5><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250223120851990.png" alt="image-20250223120851990" /><figcaption>image-20250223120851990</figcaption></figure><p></p><p>首先部署一个helloword。 注意：应用名称和你cloudflare用户名会影响访问的域名（cloudflare给你分配的）</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250223121033682.png" alt="image-20250223121033682" /><figcaption>image-20250223121033682</figcaption></figure><p></p><p>将下面代码复制到worker.js</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>/**</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>* Welcome to Cloudflare Workers! This is your first worker.</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>*</span></div></div><div><div><div>4</div></div><div><span><span> </span></span><span>* - Run "npm run dev" in your terminal to start a development server</span></div></div><div><div><div>5</div></div><div><span><span> </span></span><span>* - Open a browser tab at http://localhost:8787/ to see your worker in action</span></div></div><div><div><div>6</div></div><div><span><span> </span></span><span>* - Run "npm run deploy" to publish your worker</span></div></div><div><div><div>7</div></div><div><span><span> </span></span><span>*</span></div></div><div><div><div>8</div></div><div><span><span> </span></span><span>* Learn more at https://developers.cloudflare.com/workers/</span></div></div><div><div><div>9</div></div><div><span><span> </span></span><span>*/</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>// _worker.js</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>// Docker镜像仓库主机地址</span></div></div><div><div><div>14</div></div><div><span>let</span><span><span> </span><span>hub_host</span><span> </span></span><span>=</span><span> </span><span>'registry-1.docker.io'</span><span>;</span></div></div><div><div><div>15</div></div><div><span>// Docker认证服务器地址</span></div></div><div><div><div>16</div></div><div><span>const</span><span> </span><span>auth_url</span><span> </span><span>=</span><span> </span><span>'https://auth.docker.io'</span><span>;</span></div></div><div><div><div>17</div></div><div><span>// 自定义的工作服务器地址</span></div></div><div><div><div>18</div></div><div><span>let</span><span><span> </span><span>workers_url</span><span> </span></span><span>=</span><span> </span><span>'https://xxx/'</span><span>;</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span>let</span><span><span> </span><span>屏蔽爬虫UA</span><span> </span></span><span>=</span><span> [</span><span>'netcraft'</span><span>];</span></div></div><div><div><div>21</div></div><div>
</div></div><div><div><div>22</div></div><div><span>// 根据主机名选择对应的上游地址</span></div></div><div><div><div>23</div></div><div><span>function</span><span> </span><span>routeByHosts</span><span><span>(</span><span>host</span><span>) {</span></span></div></div><div><div><div>24</div></div><div><span>  </span><span>// 定义路由表</span></div></div><div><div><div>25</div></div><div><span>  </span><span>const</span><span> </span><span>routes</span><span> </span><span>=</span><span> {</span></div></div><div><div><div>26</div></div><div><span>    </span><span>// 生产环境</span></div></div><div><div><div>27</div></div><div><span>    </span><span>"quay"</span><span>:</span><span> </span><span>"quay.io"</span><span>,</span></div></div><div><div><div>28</div></div><div><span>    </span><span>"gcr"</span><span>:</span><span> </span><span>"gcr.io"</span><span>,</span></div></div><div><div><div>29</div></div><div><span>    </span><span>"k8s-gcr"</span><span>:</span><span> </span><span>"k8s.gcr.io"</span><span>,</span></div></div><div><div><div>30</div></div><div><span>    </span><span>"k8s"</span><span>:</span><span> </span><span>"registry.k8s.io"</span><span>,</span></div></div><div><div><div>31</div></div><div><span>    </span><span>"ghcr"</span><span>:</span><span> </span><span>"ghcr.io"</span><span>,</span></div></div><div><div><div>32</div></div><div><span>    </span><span>"cloudsmith"</span><span>:</span><span> </span><span>"docker.cloudsmith.io"</span><span>,</span></div></div><div><div><div>33</div></div><div><span>    </span><span>"nvcr"</span><span>:</span><span> </span><span>"nvcr.io"</span><span>,</span></div></div><div><div><div>34</div></div><div>
</div></div><div><div><div>35</div></div><div><span>    </span><span>// 测试环境</span></div></div><div><div><div>36</div></div><div><span>    </span><span>"test"</span><span>:</span><span> </span><span>"registry-1.docker.io"</span><span>,</span></div></div><div><div><div>37</div></div><div><span><span>  </span></span><span>};</span></div></div><div><div><div>38</div></div><div>
</div></div><div><div><div>39</div></div><div><span>  </span><span>if</span><span><span> (</span><span>host</span><span> </span></span><span>in</span><span><span> </span><span>routes</span><span>) </span></span><span>return</span><span><span> [ </span><span>routes</span><span>[</span><span>host</span><span>], </span></span><span>false</span><span> ];</span></div></div><div><div><div>40</div></div><div><span>  </span><span>else</span><span> </span><span>return</span><span><span> [ </span><span>hub_host</span><span>, </span></span><span>true</span><span> ];</span></div></div><div><div><div>41</div></div><div><span>}</span></div></div><div><div><div>42</div></div><div>
</div></div><div><div><div>43</div></div><div><span>/** </span><span>@</span><span>type</span><span> </span><span>{RequestInit}</span><span> */</span></div></div><div><div><div>44</div></div><div><span>const</span><span> </span><span>PREFLIGHT_INIT</span><span> </span><span>=</span><span> {</span></div></div><div><div><div>45</div></div><div><span>  </span><span>// 预检请求配置</span></div></div><div><div><div>46</div></div><div><span>  </span><span>headers</span><span>:</span><span> </span><span>new</span><span> </span><span>Headers</span><span>({</span></div></div><div><div><div>47</div></div><div><span>    </span><span>'access-control-allow-origin'</span><span>:</span><span> </span><span>'*'</span><span>, </span><span>// 允许所有来源</span></div></div><div><div><div>48</div></div><div><span>    </span><span>'access-control-allow-methods'</span><span>:</span><span> </span><span>'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS'</span><span>, </span><span>// 允许的HTTP方法</span></div></div><div><div><div>49</div></div><div><span>    </span><span>'access-control-max-age'</span><span>:</span><span> </span><span>'1728000'</span><span>, </span><span>// 预检请求的缓存时间</span></div></div><div><div><div>50</div></div><div><span><span>  </span></span><span>}),</span></div></div><div><div><div>51</div></div><div><span>}</span></div></div><div><div><div>52</div></div><div>
</div></div><div><div><div>53</div></div><div><span>/**</span></div></div><div><div><div>54</div></div><div><span><span> </span></span><span>* 构造响应</span></div></div><div><div><div>55</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{any}</span><span> </span><span>body</span><span> 响应体</span></div></div><div><div><div>56</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{number}</span><span> </span><span>status</span><span> 响应状态码</span></div></div><div><div><div>57</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{Object&lt;string, string&gt;}</span><span> </span><span>headers</span><span> 响应头</span></div></div><div><div><div>58</div></div><div><span><span> </span></span><span>*/</span></div></div><div><div><div>59</div></div><div><span>function</span><span> </span><span>makeRes</span><span><span>(</span><span>body</span><span>, </span><span>status</span><span> </span></span><span>=</span><span> </span><span>200</span><span><span>, </span><span>headers</span><span> </span></span><span>=</span><span> {}) {</span></div></div><div><div><div>60</div></div><div><span><span>  </span></span><span>headers</span><span>[</span><span>'access-control-allow-origin'</span><span>] </span><span>=</span><span> </span><span>'*'</span><span> </span><span>// 允许所有来源</span></div></div><div><div><div>61</div></div><div><span>  </span><span>return</span><span> </span><span>new</span><span> </span><span>Response</span><span><span>(</span><span>body</span><span>, { </span><span>status</span><span>, </span><span>headers</span><span> }) </span></span><span>// 返回新构造的响应</span></div></div><div><div><div>62</div></div><div><span>}</span></div></div><div><div><div>63</div></div><div>
</div></div><div><div><div>64</div></div><div><span>/**</span></div></div><div><div><div>65</div></div><div><span><span> </span></span><span>* 构造新的URL对象</span></div></div><div><div><div>66</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{string}</span><span> </span><span>urlStr</span><span> URL字符串</span></div></div><div><div><div>67</div></div><div><span><span> </span></span><span>*/</span></div></div><div><div><div>68</div></div><div><span>function</span><span> </span><span>newUrl</span><span><span>(</span><span>urlStr</span><span>) {</span></span></div></div><div><div><div>69</div></div><div><span>  </span><span>try</span><span> {</span></div></div><div><div><div>70</div></div><div><span>    </span><span>return</span><span> </span><span>new</span><span> </span><span>URL</span><span><span>(</span><span>urlStr</span><span>) </span></span><span>// 尝试构造新的URL对象</span></div></div><div><div><div>71</div></div><div><span><span>  </span></span><span>} </span><span>catch</span><span><span> (</span><span>err</span><span>) {</span></span></div></div><div><div><div>72</div></div><div><span>    </span><span>return</span><span> </span><span>null</span><span> </span><span>// 构造失败返回null</span></div></div><div><div><div>73</div></div><div><span><span>  </span></span><span>}</span></div></div><div><div><div>74</div></div><div><span>}</span></div></div><div><div><div>75</div></div><div>
</div></div><div><div><div>76</div></div><div><span>function</span><span> </span><span>isUUID</span><span><span>(</span><span>uuid</span><span>) {</span></span></div></div><div><div><div>77</div></div><div><span>  </span><span>// 定义一个正则表达式来匹配 UUID 格式</span></div></div><div><div><div>78</div></div><div><span>  </span><span>const</span><span> </span><span>uuidRegex</span><span> </span><span>=</span><span> /</span><span>^</span><span>[0-9a-f]</span><span><span>{8}</span><span>-</span></span><span>[0-9a-f]</span><span><span>{4}</span><span>-</span></span><span>[4][0-9a-f]</span><span><span>{3}</span><span>-</span></span><span>[89ab][0-9a-f]</span><span><span>{3}</span><span>-</span></span><span>[0-9a-f]</span><span>{12}</span><span>$</span><span>/</span><span>i</span><span>;</span></div></div><div><div><div>79</div></div><div>
</div></div><div><div><div>80</div></div><div><span>  </span><span>// 使用正则表达式测试 UUID 字符串</span></div></div><div><div><div>81</div></div><div><span>  </span><span>return</span><span><span> </span><span>uuidRegex</span><span>.</span></span><span>test</span><span><span>(</span><span>uuid</span><span>);</span></span></div></div><div><div><div>82</div></div><div><span>}</span></div></div><div><div><div>83</div></div><div>
</div></div><div><div><div>84</div></div><div><span>async</span><span> </span><span>function</span><span> </span><span>nginx</span><span>() {</span></div></div><div><div><div>85</div></div><div><span>  </span><span>const</span><span> </span><span>text</span><span> </span><span>=</span><span> </span><span>`</span></div></div><div><div><div>86</div></div><div><span><span>  </span></span><span>&lt;!DOCTYPE html&gt;</span></div></div><div><div><div>87</div></div><div><span><span>  </span></span><span>&lt;html&gt;</span></div></div><div><div><div>88</div></div><div><span><span>  </span></span><span>&lt;head&gt;</span></div></div><div><div><div>89</div></div><div><span><span>  </span></span><span>&lt;title&gt;Welcome to nginx!&lt;/title&gt;</span></div></div><div><div><div>90</div></div><div><span><span>  </span></span><span>&lt;style&gt;</span></div></div><div><div><div>91</div></div><div><span><span>    </span></span><span>body {</span></div></div><div><div><div>92</div></div><div><span><span>      </span></span><span>width: 35em;</span></div></div><div><div><div>93</div></div><div><span><span>      </span></span><span>margin: 0 auto;</span></div></div><div><div><div>94</div></div><div><span><span>      </span></span><span>font-family: Tahoma, Verdana, Arial, sans-serif;</span></div></div><div><div><div>95</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>96</div></div><div><span><span>  </span></span><span>&lt;/style&gt;</span></div></div><div><div><div>97</div></div><div><span><span>  </span></span><span>&lt;/head&gt;</span></div></div><div><div><div>98</div></div><div><span><span>  </span></span><span>&lt;body&gt;</span></div></div><div><div><div>99</div></div><div><span><span>  </span></span><span>&lt;h1&gt;Welcome to nginx!&lt;/h1&gt;</span></div></div><div><div><div>100</div></div><div><span><span>  </span></span><span>&lt;p&gt;If you see this page, the nginx web server is successfully installed and</span></div></div><div><div><div>101</div></div><div><span><span>  </span></span><span>working. Further configuration is required.&lt;/p&gt;</span></div></div><div><div><div>102</div></div><div>
</div></div><div><div><div>103</div></div><div><span><span>  </span></span><span>&lt;p&gt;For online documentation and support please refer to</span></div></div><div><div><div>104</div></div><div><span><span>  </span></span><span>&lt;a href="http://nginx.org/"&gt;nginx.org&lt;/a&gt;.&lt;br/&gt;</span></div></div><div><div><div>105</div></div><div><span><span>  </span></span><span>Commercial support is available at</span></div></div><div><div><div>106</div></div><div><span><span>  </span></span><span>&lt;a href="http://nginx.com/"&gt;nginx.com&lt;/a&gt;.&lt;/p&gt;</span></div></div><div><div><div>107</div></div><div>
</div></div><div><div><div>108</div></div><div><span><span>  </span></span><span>&lt;p&gt;&lt;em&gt;Thank you for using nginx.&lt;/em&gt;&lt;/p&gt;</span></div></div><div><div><div>109</div></div><div><span><span>  </span></span><span>&lt;/body&gt;</span></div></div><div><div><div>110</div></div><div><span><span>  </span></span><span>&lt;/html&gt;</span></div></div><div><div><div>111</div></div><div><span><span>  </span></span><span>`</span></div></div><div><div><div>112</div></div><div><span>  </span><span>return</span><span><span> </span><span>text</span><span>;</span></span></div></div><div><div><div>113</div></div><div><span>}</span></div></div><div><div><div>114</div></div><div>
</div></div><div><div><div>115</div></div><div><span>async</span><span> </span><span>function</span><span> </span><span>searchInterface</span><span>() {</span></div></div><div><div><div>116</div></div><div><span>  </span><span>const</span><span> </span><span>text</span><span> </span><span>=</span><span> </span><span>`</span></div></div><div><div><div>117</div></div><div><span><span>  </span></span><span>&lt;!DOCTYPE html&gt;</span></div></div><div><div><div>118</div></div><div><span><span>  </span></span><span>&lt;html&gt;</span></div></div><div><div><div>119</div></div><div><span><span>  </span></span><span>&lt;head&gt;</span></div></div><div><div><div>120</div></div><div><span><span>    </span></span><span>&lt;title&gt;Docker Hub Search&lt;/title&gt;</span></div></div><div><div><div>121</div></div><div><span><span>    </span></span><span>&lt;style&gt;</span></div></div><div><div><div>122</div></div><div><span><span>    </span></span><span>body {</span></div></div><div><div><div>123</div></div><div><span><span>      </span></span><span>font-family: Arial, sans-serif;</span></div></div><div><div><div>124</div></div><div><span><span>      </span></span><span>display: flex;</span></div></div><div><div><div>125</div></div><div><span><span>      </span></span><span>flex-direction: column;</span></div></div><div><div><div>126</div></div><div><span><span>      </span></span><span>align-items: center;</span></div></div><div><div><div>127</div></div><div><span><span>      </span></span><span>justify-content: center;</span></div></div><div><div><div>128</div></div><div><span><span>      </span></span><span>height: 100vh;</span></div></div><div><div><div>129</div></div><div><span><span>      </span></span><span>margin: 0;</span></div></div><div><div><div>130</div></div><div><span><span>      </span></span><span>background: linear-gradient(to right, rgb(28, 143, 237), rgb(29, 99, 237));</span></div></div><div><div><div>131</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>132</div></div><div><span><span>    </span></span><span>.logo {</span></div></div><div><div><div>133</div></div><div><span><span>      </span></span><span>margin-bottom: 20px;</span></div></div><div><div><div>134</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>135</div></div><div><span><span>    </span></span><span>.search-container {</span></div></div><div><div><div>136</div></div><div><span><span>      </span></span><span>display: flex;</span></div></div><div><div><div>137</div></div><div><span><span>      </span></span><span>align-items: center;</span></div></div><div><div><div>138</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>139</div></div><div><span><span>    </span></span><span>#search-input {</span></div></div><div><div><div>140</div></div><div><span><span>      </span></span><span>padding: 10px;</span></div></div><div><div><div>141</div></div><div><span><span>      </span></span><span>font-size: 16px;</span></div></div><div><div><div>142</div></div><div><span><span>      </span></span><span>border: 1px solid #ddd;</span></div></div><div><div><div>143</div></div><div><span><span>      </span></span><span>border-radius: 4px;</span></div></div><div><div><div>144</div></div><div><span><span>      </span></span><span>width: 300px;</span></div></div><div><div><div>145</div></div><div><span><span>      </span></span><span>margin-right: 10px;</span></div></div><div><div><div>146</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>147</div></div><div><span><span>    </span></span><span>#search-button {</span></div></div><div><div><div>148</div></div><div><span><span>      </span></span><span>padding: 10px;</span></div></div><div><div><div>149</div></div><div><span><span>      </span></span><span>background-color: rgba(255, 255, 255, 0.2); /* 设置白色，透明度为10% */</span></div></div><div><div><div>150</div></div><div><span><span>      </span></span><span>border: none;</span></div></div><div><div><div>151</div></div><div><span><span>      </span></span><span>border-radius: 4px;</span></div></div><div><div><div>152</div></div><div><span><span>      </span></span><span>cursor: pointer;</span></div></div><div><div><div>153</div></div><div><span><span>      </span></span><span>width: 44px;</span></div></div><div><div><div>154</div></div><div><span><span>      </span></span><span>height: 44px;</span></div></div><div><div><div>155</div></div><div><span><span>      </span></span><span>display: flex;</span></div></div><div><div><div>156</div></div><div><span><span>      </span></span><span>align-items: center;</span></div></div><div><div><div>157</div></div><div><span><span>      </span></span><span>justify-content: center;</span></div></div><div><div><div>158</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>159</div></div><div><span><span>    </span></span><span>#search-button svg {</span></div></div><div><div><div>160</div></div><div><span><span>      </span></span><span>width: 24px;</span></div></div><div><div><div>161</div></div><div><span><span>      </span></span><span>height: 24px;</span></div></div><div><div><div>162</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>163</div></div><div><span><span>    </span></span><span>&lt;/style&gt;</span></div></div><div><div><div>164</div></div><div><span><span>  </span></span><span>&lt;/head&gt;</span></div></div><div><div><div>165</div></div><div><span><span>  </span></span><span>&lt;body&gt;</span></div></div><div><div><div>166</div></div><div><span><span>    </span></span><span>&lt;div class="logo"&gt;</span></div></div><div><div><div>167</div></div><div><span><span>    </span></span><span>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 18" fill="#ffffff" width="100" height="75"&gt;</span></div></div><div><div><div>168</div></div><div><span><span>      </span></span><span>&lt;path d="M23.763 6.886c-.065-.053-.673-.512-1.954-.512-.32 0-.659.03-1.01.087-.248-1.703-1.651-2.533-1.716-2.57l-.345-.2-.227.328a4.596 4.596 0 0 0-.611 1.433c-.23.972-.09 1.884.403 2.666-.596.331-1.546.418-1.744.42H.752a.753.753 0 0 0-.75.749c-.007 1.456.233 2.864.692 4.07.545 1.43 1.355 2.483 2.409 3.13 1.181.725 3.104 1.14 5.276 1.14 1.016 0 2.03-.092 2.93-.266 1.417-.273 2.705-.742 3.826-1.391a10.497 10.497 0 0 0 2.61-2.14c1.252-1.42 1.998-3.005 2.553-4.408.075.003.148.005.221.005 1.371 0 2.215-.55 2.68-1.01.505-.5.685-.998.704-1.053L24 7.076l-.237-.19Z"&gt;&lt;/path&gt;</span></div></div><div><div><div>169</div></div><div><span><span>      </span></span><span>&lt;path d="M2.216 8.075h2.119a.186.186 0 0 0 .185-.186V6a.186.186 0 0 0-.185-.186H2.216A.186.186 0 0 0 2.031 6v1.89c0 .103.083.186.185.186Zm2.92 0h2.118a.185.185 0 0 0 .185-.186V6a.185.185 0 0 0-.185-.186H5.136A.185.185 0 0 0 4.95 6v1.89c0 .103.083.186.186.186Zm2.964 0h2.118a.186.186 0 0 0 .185-.186V6a.186.186 0 0 0-.185-.186H8.1A.185.185 0 0 0 7.914 6v1.89c0 .103.083.186.186.186Zm2.928 0h2.119a.185.185 0 0 0 .185-.186V6a.185.185 0 0 0-.185-.186h-2.119a.186.186 0 0 0-.185.186v1.89c0 .103.083.186.185.186Zm-5.892-2.72h2.118a.185.185 0 0 0 .185-.186V3.28a.186.186 0 0 0-.185-.186H5.136a.186.186 0 0 0-.186.186v1.89c0 .103.083.186.186.186Zm2.964 0h2.118a.186.186 0 0 0 .185-.186V3.28a.186.186 0 0 0-.185-.186H8.1a.186.186 0 0 0-.186.186v1.89c0 .103.083.186.186.186Zm2.928 0h2.119a.185.185 0 0 0 .185-.186V3.28a.186.186 0 0 0-.185-.186h-2.119a.186.186 0 0 0-.185.186v1.89c0 .103.083.186.185.186Zm0-2.72h2.119a.186.186 0 0 0 .185-.186V.56a.185.185 0 0 0-.185-.186h-2.119a.186.186 0 0 0-.185.186v1.89c0 .103.083.186.185.186Zm2.955 5.44h2.118a.185.185 0 0 0 .186-.186V6a.185.185 0 0 0-.186-.186h-2.118a.185.185 0 0 0-.185.186v1.89c0 .103.083.186.185.186Z"&gt;&lt;/path&gt;</span></div></div><div><div><div>170</div></div><div><span><span>    </span></span><span>&lt;/svg&gt;</span></div></div><div><div><div>171</div></div><div><span><span>    </span></span><span>&lt;/div&gt;</span></div></div><div><div><div>172</div></div><div><span><span>    </span></span><span>&lt;div class="search-container"&gt;</span></div></div><div><div><div>173</div></div><div><span><span>    </span></span><span>&lt;input type="text" id="search-input" placeholder="Search Docker Hub"&gt;</span></div></div><div><div><div>174</div></div><div><span><span>    </span></span><span>&lt;button id="search-button"&gt;</span></div></div><div><div><div>175</div></div><div><span><span>      </span></span><span>&lt;svg focusable="false" aria-hidden="true" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"&gt;</span></div></div><div><div><div>176</div></div><div><span><span>      </span></span><span>&lt;path d="M21 21L16.65 16.65M19 11C19 15.4183 15.4183 19 11 19C6.58172 19 3 15.4183 3 11C3 6.58172 6.58172 3 11 3C15.4183 3 19 6.58172 19 11Z" stroke="white" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"&gt;&lt;/path&gt;</span></div></div><div><div><div>177</div></div><div><span><span>      </span></span><span>&lt;/svg&gt;</span></div></div><div><div><div>178</div></div><div><span><span>    </span></span><span>&lt;/button&gt;</span></div></div><div><div><div>179</div></div><div><span><span>    </span></span><span>&lt;/div&gt;</span></div></div><div><div><div>180</div></div><div><span><span>    </span></span><span>&lt;script&gt;</span></div></div><div><div><div>181</div></div><div><span><span>    </span></span><span>function performSearch() {</span></div></div><div><div><div>182</div></div><div><span><span>      </span></span><span>const query = document.getElementById('search-input').value;</span></div></div><div><div><div>183</div></div><div><span><span>      </span></span><span>if (query) {</span></div></div><div><div><div>184</div></div><div><span><span>      </span></span><span>window.location.href = '/search?q=' + encodeURIComponent(query);</span></div></div><div><div><div>185</div></div><div><span><span>      </span></span><span>}</span></div></div><div><div><div>186</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>187</div></div><div>
</div></div><div><div><div>188</div></div><div><span><span>    </span></span><span>document.getElementById('search-button').addEventListener('click', performSearch);</span></div></div><div><div><div>189</div></div><div><span><span>    </span></span><span>document.getElementById('search-input').addEventListener('keypress', function(event) {</span></div></div><div><div><div>190</div></div><div><span><span>      </span></span><span>if (event.key === 'Enter') {</span></div></div><div><div><div>191</div></div><div><span><span>      </span></span><span>performSearch();</span></div></div><div><div><div>192</div></div><div><span><span>      </span></span><span>}</span></div></div><div><div><div>193</div></div><div><span><span>    </span></span><span>});</span></div></div><div><div><div>194</div></div><div><span><span>    </span></span><span>&lt;/script&gt;</span></div></div><div><div><div>195</div></div><div><span><span>  </span></span><span>&lt;/body&gt;</span></div></div><div><div><div>196</div></div><div><span><span>  </span></span><span>&lt;/html&gt;</span></div></div><div><div><div>197</div></div><div><span><span>  </span></span><span>`</span><span>;</span></div></div><div><div><div>198</div></div><div><span>  </span><span>return</span><span><span> </span><span>text</span><span>;</span></span></div></div><div><div><div>199</div></div><div><span>}</span></div></div><div><div><div>200</div></div><div>
</div></div><div><div><div>201</div></div><div><span>export</span><span> </span><span>default</span><span> {</span></div></div><div><div><div>202</div></div><div><span>  </span><span>async</span><span> </span><span>fetch</span><span><span>(</span><span>request</span><span>, </span><span>env</span><span>, </span><span>ctx</span><span>) {</span></span></div></div><div><div><div>203</div></div><div><span>    </span><span>const</span><span> </span><span>getReqHeader</span><span> </span><span>=</span><span><span> (</span><span>key</span><span>) </span></span><span>=&gt;</span><span><span> </span><span>request</span><span>.</span></span><span>headers</span><span>.</span><span>get</span><span>(</span><span>key</span><span>); </span><span>// 获取请求头</span></div></div><div><div><div>204</div></div><div>
</div></div><div><div><div>205</div></div><div><span>    </span><span>let</span><span> </span><span>url</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>URL</span><span><span>(</span><span>request</span><span>.</span></span><span>url</span><span>); </span><span>// 解析请求URL</span></div></div><div><div><div>206</div></div><div><span>    </span><span>const</span><span> </span><span>userAgentHeader</span><span> </span><span>=</span><span><span> </span><span>request</span><span>.</span></span><span>headers</span><span>.</span><span>get</span><span>(</span><span>'User-Agent'</span><span>);</span></div></div><div><div><div>207</div></div><div><span>    </span><span>const</span><span> </span><span>userAgent</span><span> </span><span>=</span><span> </span><span>userAgentHeader</span><span> </span><span>?</span><span><span> </span><span>userAgentHeader</span><span>.</span></span><span>toLowerCase</span><span>() </span><span>:</span><span> </span><span>"null"</span><span>;</span></div></div><div><div><div>208</div></div><div><span>    </span><span>if</span><span><span> (</span><span>env</span><span>.</span></span><span>UA</span><span>) </span><span>屏蔽爬虫UA</span><span> </span><span>=</span><span><span> </span><span>屏蔽爬虫UA</span><span>.</span></span><span>concat</span><span>(</span><span>await</span><span> </span><span>ADD</span><span><span>(</span><span>env</span><span>.</span></span><span>UA</span><span>));</span></div></div><div><div><div>209</div></div><div><span>    </span><span>workers_url</span><span> </span><span>=</span><span> </span><span>`https://</span><span>${</span><span>url</span><span>.</span><span>hostname</span><span>}</span><span>`</span><span>;</span></div></div><div><div><div>210</div></div><div><span>    </span><span>const</span><span> </span><span>pathname</span><span> </span><span>=</span><span><span> </span><span>url</span><span>.</span></span><span>pathname</span><span>;</span></div></div><div><div><div>211</div></div><div>
</div></div><div><div><div>212</div></div><div><span>    </span><span>// 获取请求参数中的 ns</span></div></div><div><div><div>213</div></div><div><span>    </span><span>const</span><span> </span><span>ns</span><span> </span><span>=</span><span><span> </span><span>url</span><span>.</span></span><span>searchParams</span><span>.</span><span>get</span><span>(</span><span>'ns'</span><span>);</span></div></div><div><div><div>214</div></div><div><span>    </span><span>const</span><span> </span><span>hostname</span><span> </span><span>=</span><span><span> </span><span>url</span><span>.</span></span><span>searchParams</span><span>.</span><span>get</span><span>(</span><span>'hubhost'</span><span>) </span><span>||</span><span><span> </span><span>url</span><span>.</span></span><span>hostname</span><span>;</span></div></div><div><div><div>215</div></div><div><span>    </span><span>const</span><span> </span><span>hostTop</span><span> </span><span>=</span><span><span> </span><span>hostname</span><span>.</span></span><span>split</span><span>(</span><span>'.'</span><span>)[</span><span>0</span><span>]; </span><span>// 获取主机名的第一部分</span></div></div><div><div><div>216</div></div><div>
</div></div><div><div><div>217</div></div><div><span>    </span><span>let</span><span> </span><span>checkHost</span><span>; </span><span>// 在这里定义 checkHost 变量</span></div></div><div><div><div>218</div></div><div><span>    </span><span>// 如果存在 ns 参数，优先使用它来确定 hub_host</span></div></div><div><div><div>219</div></div><div><span>    </span><span>if</span><span> (</span><span>ns</span><span>) {</span></div></div><div><div><div>220</div></div><div><span>      </span><span>if</span><span> (</span><span>ns</span><span> </span><span>===</span><span> </span><span>'docker.io'</span><span>) {</span></div></div><div><div><div>221</div></div><div><span>        </span><span>hub_host</span><span> </span><span>=</span><span> </span><span>'registry-1.docker.io'</span><span>; </span><span>// 设置上游地址为 registry-1.docker.io</span></div></div><div><div><div>222</div></div><div><span><span>      </span></span><span>} </span><span>else</span><span> {</span></div></div><div><div><div>223</div></div><div><span>        </span><span>hub_host</span><span> </span><span>=</span><span> </span><span>ns</span><span>; </span><span>// 直接使用 ns 作为 hub_host</span></div></div><div><div><div>224</div></div><div><span><span>      </span></span><span>}</span></div></div><div><div><div>225</div></div><div><span><span>    </span></span><span>} </span><span>else</span><span> {</span></div></div><div><div><div>226</div></div><div><span>      </span><span>checkHost</span><span> </span><span>=</span><span> </span><span>routeByHosts</span><span>(</span><span>hostTop</span><span>);</span></div></div><div><div><div>227</div></div><div><span>      </span><span>hub_host</span><span> </span><span>=</span><span> </span><span>checkHost</span><span>[</span><span>0</span><span>]; </span><span>// 获取上游地址</span></div></div><div><div><div>228</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>229</div></div><div>
</div></div><div><div><div>230</div></div><div><span>    </span><span>const</span><span> </span><span>fakePage</span><span> </span><span>=</span><span> </span><span>checkHost</span><span> </span><span>?</span><span> </span><span>checkHost</span><span>[</span><span>1</span><span>] </span><span>:</span><span> </span><span>false</span><span>; </span><span>// 确保 fakePage 不为 undefined</span></div></div><div><div><div>231</div></div><div><span><span>    </span></span><span>console</span><span>.</span><span>log</span><span>(</span><span>`域名头部: </span><span>${</span><span>hostTop</span><span>}</span><span>\n</span><span>反代地址: </span><span>${</span><span>hub_host</span><span>}</span><span>\n</span><span>伪装首页: </span><span>${</span><span>fakePage</span><span>}</span><span>`</span><span>);</span></div></div><div><div><div>232</div></div><div><span>    </span><span>const</span><span> </span><span>isUuid</span><span> </span><span>=</span><span> </span><span>isUUID</span><span><span>(</span><span>pathname</span><span>.</span></span><span>split</span><span>(</span><span>'/'</span><span>)[</span><span>1</span><span>].</span><span>split</span><span>(</span><span>'/'</span><span>)[</span><span>0</span><span>]);</span></div></div><div><div><div>233</div></div><div>
</div></div><div><div><div>234</div></div><div><span>    </span><span>if</span><span><span> (</span><span>屏蔽爬虫UA</span><span>.</span></span><span>some</span><span><span>(</span><span>fxxk</span><span> </span></span><span>=&gt;</span><span><span> </span><span>userAgent</span><span>.</span></span><span>includes</span><span>(</span><span>fxxk</span><span>)) </span><span>&amp;&amp;</span><span><span> </span><span>屏蔽爬虫UA</span><span>.</span></span><span>length</span><span> </span><span>&gt;</span><span> </span><span>0</span><span>) {</span></div></div><div><div><div>235</div></div><div><span>      </span><span>// 首页改成一个nginx伪装页</span></div></div><div><div><div>236</div></div><div><span>      </span><span>return</span><span> </span><span>new</span><span> </span><span>Response</span><span>(</span><span>await</span><span> </span><span>nginx</span><span>(), {</span></div></div><div><div><div>237</div></div><div><span>        </span><span>headers</span><span>:</span><span> {</span></div></div><div><div><div>238</div></div><div><span>          </span><span>'Content-Type'</span><span>:</span><span> </span><span>'text/html; charset=UTF-8'</span><span>,</span></div></div><div><div><div>239</div></div><div><span><span>        </span></span><span>},</span></div></div><div><div><div>240</div></div><div><span><span>      </span></span><span>});</span></div></div><div><div><div>241</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>242</div></div><div>
</div></div><div><div><div>243</div></div><div><span>    </span><span>const</span><span> </span><span>conditions</span><span> </span><span>=</span><span> [</span></div></div><div><div><div>244</div></div><div><span>      </span><span>isUuid</span><span>,</span></div></div><div><div><div>245</div></div><div><span><span>      </span></span><span>pathname</span><span>.</span><span>includes</span><span>(</span><span>'/_'</span><span>),</span></div></div><div><div><div>246</div></div><div><span><span>      </span></span><span>pathname</span><span>.</span><span>includes</span><span>(</span><span>'/r/'</span><span>),</span></div></div><div><div><div>247</div></div><div><span><span>      </span></span><span>pathname</span><span>.</span><span>includes</span><span>(</span><span>'/v2/user'</span><span>),</span></div></div><div><div><div>248</div></div><div><span><span>      </span></span><span>pathname</span><span>.</span><span>includes</span><span>(</span><span>'/v2/orgs'</span><span>),</span></div></div><div><div><div>249</div></div><div><span><span>      </span></span><span>pathname</span><span>.</span><span>includes</span><span>(</span><span>'/v2/_catalog'</span><span>),</span></div></div><div><div><div>250</div></div><div><span><span>      </span></span><span>pathname</span><span>.</span><span>includes</span><span>(</span><span>'/v2/categories'</span><span>),</span></div></div><div><div><div>251</div></div><div><span><span>      </span></span><span>pathname</span><span>.</span><span>includes</span><span>(</span><span>'/v2/feature-flags'</span><span>),</span></div></div><div><div><div>252</div></div><div><span><span>      </span></span><span>pathname</span><span>.</span><span>includes</span><span>(</span><span>'search'</span><span>),</span></div></div><div><div><div>253</div></div><div><span><span>      </span></span><span>pathname</span><span>.</span><span>includes</span><span>(</span><span>'source'</span><span>),</span></div></div><div><div><div>254</div></div><div><span>      </span><span>pathname</span><span> </span><span>===</span><span> </span><span>'/'</span><span>,</span></div></div><div><div><div>255</div></div><div><span>      </span><span>pathname</span><span> </span><span>===</span><span> </span><span>'/favicon.ico'</span><span>,</span></div></div><div><div><div>256</div></div><div><span>      </span><span>pathname</span><span> </span><span>===</span><span> </span><span>'/auth/profile'</span><span>,</span></div></div><div><div><div>257</div></div><div><span><span>    </span></span><span>];</span></div></div><div><div><div>258</div></div><div>
</div></div><div><div><div>259</div></div><div><span>    </span><span>if</span><span><span> (</span><span>conditions</span><span>.</span></span><span>some</span><span><span>(</span><span>condition</span><span> </span></span><span>=&gt;</span><span> </span><span>condition</span><span>) </span><span>&amp;&amp;</span><span> (</span><span>fakePage</span><span> </span><span>===</span><span> </span><span>true</span><span> </span><span>||</span><span> </span><span>hostTop</span><span> </span><span>==</span><span> </span><span>'docker'</span><span>)) {</span></div></div><div><div><div>260</div></div><div><span>      </span><span>if</span><span><span> (</span><span>env</span><span>.</span></span><span>URL302</span><span>) {</span></div></div><div><div><div>261</div></div><div><span>        </span><span>return</span><span><span> </span><span>Response</span><span>.</span></span><span>redirect</span><span><span>(</span><span>env</span><span>.</span></span><span>URL302</span><span>, </span><span>302</span><span>);</span></div></div><div><div><div>262</div></div><div><span><span>      </span></span><span>} </span><span>else</span><span> </span><span>if</span><span><span> (</span><span>env</span><span>.</span></span><span>URL</span><span>) {</span></div></div><div><div><div>263</div></div><div><span>        </span><span>if</span><span><span> (</span><span>env</span><span>.</span></span><span>URL</span><span>.</span><span>toLowerCase</span><span>() </span><span>==</span><span> </span><span>'nginx'</span><span>) {</span></div></div><div><div><div>264</div></div><div><span>          </span><span>//首页改成一个nginx伪装页</span></div></div><div><div><div>265</div></div><div><span>          </span><span>return</span><span> </span><span>new</span><span> </span><span>Response</span><span>(</span><span>await</span><span> </span><span>nginx</span><span>(), {</span></div></div><div><div><div>266</div></div><div><span>            </span><span>headers</span><span>:</span><span> {</span></div></div><div><div><div>267</div></div><div><span>              </span><span>'Content-Type'</span><span>:</span><span> </span><span>'text/html; charset=UTF-8'</span><span>,</span></div></div><div><div><div>268</div></div><div><span><span>            </span></span><span>},</span></div></div><div><div><div>269</div></div><div><span><span>          </span></span><span>});</span></div></div><div><div><div>270</div></div><div><span><span>        </span></span><span>} </span><span>else</span><span> </span><span>return</span><span> </span><span>fetch</span><span>(</span><span>new</span><span> </span><span>Request</span><span><span>(</span><span>env</span><span>.</span></span><span>URL</span><span>, </span><span>request</span><span>));</span></div></div><div><div><div>271</div></div><div><span><span>      </span></span><span>} </span><span>else</span><span> </span><span>if</span><span><span> (</span><span>url</span><span>.</span></span><span>pathname</span><span> </span><span>==</span><span> </span><span>'/'</span><span>){</span></div></div><div><div><div>272</div></div><div><span>        </span><span>return</span><span> </span><span>new</span><span> </span><span>Response</span><span>(</span><span>await</span><span> </span><span>searchInterface</span><span>(), {</span></div></div><div><div><div>273</div></div><div><span>          </span><span>headers</span><span>:</span><span> {</span></div></div><div><div><div>274</div></div><div><span>            </span><span>'Content-Type'</span><span>:</span><span> </span><span>'text/html; charset=UTF-8'</span><span>,</span></div></div><div><div><div>275</div></div><div><span><span>          </span></span><span>},</span></div></div><div><div><div>276</div></div><div><span><span>        </span></span><span>});</span></div></div><div><div><div>277</div></div><div><span><span>      </span></span><span>}</span></div></div><div><div><div>278</div></div><div>
</div></div><div><div><div>279</div></div><div><span>      </span><span>const</span><span> </span><span>newUrl</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>URL</span><span>(</span><span>"https://registry.hub.docker.com"</span><span> </span><span>+</span><span> </span><span>pathname</span><span> </span><span>+</span><span><span> </span><span>url</span><span>.</span></span><span>search</span><span>);</span></div></div><div><div><div>280</div></div><div>
</div></div><div><div><div>281</div></div><div><span>      </span><span>// 复制原始请求的标头</span></div></div><div><div><div>282</div></div><div><span>      </span><span>const</span><span> </span><span>headers</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>Headers</span><span><span>(</span><span>request</span><span>.</span></span><span>headers</span><span>);</span></div></div><div><div><div>283</div></div><div>
</div></div><div><div><div>284</div></div><div><span>      </span><span>// 确保 Host 头部被替换为 hub.docker.com</span></div></div><div><div><div>285</div></div><div><span><span>      </span></span><span>headers</span><span>.</span><span>set</span><span>(</span><span>'Host'</span><span>, </span><span>'registry.hub.docker.com'</span><span>);</span></div></div><div><div><div>286</div></div><div>
</div></div><div><div><div>287</div></div><div><span>      </span><span>const</span><span> </span><span>newRequest</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>Request</span><span>(</span><span>newUrl</span><span>, {</span></div></div><div><div><div>288</div></div><div><span>          </span><span>method</span><span>:</span><span><span> </span><span>request</span><span>.</span></span><span>method</span><span>,</span></div></div><div><div><div>289</div></div><div><span>          </span><span>headers</span><span>:</span><span> </span><span>headers</span><span>,</span></div></div><div><div><div>290</div></div><div><span>          </span><span>body</span><span>:</span><span><span> </span><span>request</span><span>.</span></span><span>method</span><span> </span><span>!==</span><span> </span><span>'GET'</span><span> </span><span>&amp;&amp;</span><span><span> </span><span>request</span><span>.</span></span><span>method</span><span> </span><span>!==</span><span> </span><span>'HEAD'</span><span> </span><span>?</span><span> </span><span>await</span><span><span> </span><span>request</span><span>.</span></span><span>blob</span><span>() </span><span>:</span><span> </span><span>null</span><span>,</span></div></div><div><div><div>291</div></div><div><span>          </span><span>redirect</span><span>:</span><span> </span><span>'follow'</span></div></div><div><div><div>292</div></div><div><span><span>      </span></span><span>});</span></div></div><div><div><div>293</div></div><div>
</div></div><div><div><div>294</div></div><div><span>      </span><span>return</span><span> </span><span>fetch</span><span>(</span><span>newRequest</span><span>);</span></div></div><div><div><div>295</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>296</div></div><div>
</div></div><div><div><div>297</div></div><div><span>    </span><span>// 修改包含 %2F 和 %3A 的请求</span></div></div><div><div><div>298</div></div><div><span>    </span><span>if</span><span> (</span><span>!</span><span>/%2F/</span><span>.</span><span>test</span><span><span>(</span><span>url</span><span>.</span></span><span>search</span><span>) </span><span>&amp;&amp;</span><span> /%3A/</span><span>.</span><span>test</span><span><span>(</span><span>url</span><span>.</span></span><span>toString</span><span>())) {</span></div></div><div><div><div>299</div></div><div><span>      </span><span>let</span><span> </span><span>modifiedUrl</span><span> </span><span>=</span><span><span> </span><span>url</span><span>.</span></span><span>toString</span><span>().</span><span>replace</span><span>(</span><span>/%3A(?=</span><span>.</span><span><span>*?</span><span>&amp;)/</span></span><span>, </span><span>'%3Alibrary%2F'</span><span>);</span></div></div><div><div><div>300</div></div><div><span>      </span><span>url</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>URL</span><span>(</span><span>modifiedUrl</span><span>);</span></div></div><div><div><div>301</div></div><div><span><span>      </span></span><span>console</span><span>.</span><span>log</span><span>(</span><span>`handle_url: </span><span>${</span><span>url</span><span>}</span><span>`</span><span>);</span></div></div><div><div><div>302</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>303</div></div><div>
</div></div><div><div><div>304</div></div><div><span>    </span><span>// 处理token请求</span></div></div><div><div><div>305</div></div><div><span>    </span><span>if</span><span><span> (</span><span>url</span><span>.</span></span><span>pathname</span><span>.</span><span>includes</span><span>(</span><span>'/token'</span><span>)) {</span></div></div><div><div><div>306</div></div><div><span>      </span><span>let</span><span> </span><span>token_parameter</span><span> </span><span>=</span><span> {</span></div></div><div><div><div>307</div></div><div><span>        </span><span>headers</span><span>:</span><span> {</span></div></div><div><div><div>308</div></div><div><span>          </span><span>'Host'</span><span>:</span><span> </span><span>'auth.docker.io'</span><span>,</span></div></div><div><div><div>309</div></div><div><span>          </span><span>'User-Agent'</span><span>:</span><span> </span><span>getReqHeader</span><span>(</span><span>"User-Agent"</span><span>),</span></div></div><div><div><div>310</div></div><div><span>          </span><span>'Accept'</span><span>:</span><span> </span><span>getReqHeader</span><span>(</span><span>"Accept"</span><span>),</span></div></div><div><div><div>311</div></div><div><span>          </span><span>'Accept-Language'</span><span>:</span><span> </span><span>getReqHeader</span><span>(</span><span>"Accept-Language"</span><span>),</span></div></div><div><div><div>312</div></div><div><span>          </span><span>'Accept-Encoding'</span><span>:</span><span> </span><span>getReqHeader</span><span>(</span><span>"Accept-Encoding"</span><span>),</span></div></div><div><div><div>313</div></div><div><span>          </span><span>'Connection'</span><span>:</span><span> </span><span>'keep-alive'</span><span>,</span></div></div><div><div><div>314</div></div><div><span>          </span><span>'Cache-Control'</span><span>:</span><span> </span><span>'max-age=0'</span></div></div><div><div><div>315</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>316</div></div><div><span><span>      </span></span><span>};</span></div></div><div><div><div>317</div></div><div><span>      </span><span>let</span><span> </span><span>token_url</span><span> </span><span>=</span><span> </span><span>auth_url</span><span> </span><span>+</span><span><span> </span><span>url</span><span>.</span></span><span>pathname</span><span> </span><span>+</span><span><span> </span><span>url</span><span>.</span></span><span>search</span><span>;</span></div></div><div><div><div>318</div></div><div><span>      </span><span>return</span><span> </span><span>fetch</span><span>(</span><span>new</span><span> </span><span>Request</span><span>(</span><span>token_url</span><span>, </span><span>request</span><span>), </span><span>token_parameter</span><span>);</span></div></div><div><div><div>319</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>320</div></div><div>
</div></div><div><div><div>321</div></div><div><span>    </span><span>// 修改 /v2/ 请求路径</span></div></div><div><div><div>322</div></div><div><span>    </span><span>if</span><span> ( </span><span>hub_host</span><span> </span><span>==</span><span> </span><span>'registry-1.docker.io'</span><span> </span><span>&amp;&amp;</span><span> /</span><span>^</span><span><span>\/</span><span>v2</span><span>\/</span></span><span>[</span><span>^</span><span>/]</span><span><span>+</span><span>\/</span></span><span>[</span><span>^</span><span>/]</span><span><span>+</span><span>\/</span></span><span>[</span><span>^</span><span>/]</span><span>+</span><span>$</span><span>/</span><span>.</span><span>test</span><span><span>(</span><span>url</span><span>.</span></span><span>pathname</span><span>) </span><span>&amp;&amp;</span><span> </span><span>!</span><span>/</span><span>^</span><span><span>\/</span><span>v2</span><span>\/</span><span>library/</span></span><span>.</span><span>test</span><span><span>(</span><span>url</span><span>.</span></span><span>pathname</span><span>)) {</span></div></div><div><div><div>323</div></div><div><span>      </span><span>//url.pathname = url.pathname.replace(/\/v2\//, '/v2/library/');</span></div></div><div><div><div>324</div></div><div><span><span>      </span></span><span>url</span><span>.</span><span>pathname</span><span> </span><span>=</span><span> </span><span>'/v2/library/'</span><span> </span><span>+</span><span><span> </span><span>url</span><span>.</span></span><span>pathname</span><span>.</span><span>split</span><span>(</span><span>'/v2/'</span><span>)[</span><span>1</span><span>];</span></div></div><div><div><div>325</div></div><div><span><span>      </span></span><span>console</span><span>.</span><span>log</span><span>(</span><span>`modified_url: </span><span>${</span><span>url</span><span>.</span><span>pathname</span><span>}</span><span>`</span><span>);</span></div></div><div><div><div>326</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>327</div></div><div>
</div></div><div><div><div>328</div></div><div><span>    </span><span>// 更改请求的主机名</span></div></div><div><div><div>329</div></div><div><span><span>    </span></span><span>url</span><span>.</span><span>hostname</span><span> </span><span>=</span><span> </span><span>hub_host</span><span>;</span></div></div><div><div><div>330</div></div><div>
</div></div><div><div><div>331</div></div><div><span>    </span><span>// 构造请求参数</span></div></div><div><div><div>332</div></div><div><span>    </span><span>let</span><span> </span><span>parameter</span><span> </span><span>=</span><span> {</span></div></div><div><div><div>333</div></div><div><span>      </span><span>headers</span><span>:</span><span> {</span></div></div><div><div><div>334</div></div><div><span>        </span><span>'Host'</span><span>:</span><span> </span><span>hub_host</span><span>,</span></div></div><div><div><div>335</div></div><div><span>        </span><span>'User-Agent'</span><span>:</span><span> </span><span>getReqHeader</span><span>(</span><span>"User-Agent"</span><span>),</span></div></div><div><div><div>336</div></div><div><span>        </span><span>'Accept'</span><span>:</span><span> </span><span>getReqHeader</span><span>(</span><span>"Accept"</span><span>),</span></div></div><div><div><div>337</div></div><div><span>        </span><span>'Accept-Language'</span><span>:</span><span> </span><span>getReqHeader</span><span>(</span><span>"Accept-Language"</span><span>),</span></div></div><div><div><div>338</div></div><div><span>        </span><span>'Accept-Encoding'</span><span>:</span><span> </span><span>getReqHeader</span><span>(</span><span>"Accept-Encoding"</span><span>),</span></div></div><div><div><div>339</div></div><div><span>        </span><span>'Connection'</span><span>:</span><span> </span><span>'keep-alive'</span><span>,</span></div></div><div><div><div>340</div></div><div><span>        </span><span>'Cache-Control'</span><span>:</span><span> </span><span>'max-age=0'</span></div></div><div><div><div>341</div></div><div><span><span>      </span></span><span>},</span></div></div><div><div><div>342</div></div><div><span>      </span><span>cacheTtl</span><span>:</span><span> </span><span>3600</span><span> </span><span>// 缓存时间</span></div></div><div><div><div>343</div></div><div><span><span>    </span></span><span>};</span></div></div><div><div><div>344</div></div><div>
</div></div><div><div><div>345</div></div><div><span>    </span><span>// 添加Authorization头</span></div></div><div><div><div>346</div></div><div><span>    </span><span>if</span><span><span> (</span><span>request</span><span>.</span></span><span>headers</span><span>.</span><span>has</span><span>(</span><span>"Authorization"</span><span>)) {</span></div></div><div><div><div>347</div></div><div><span><span>      </span></span><span>parameter</span><span>.</span><span>headers</span><span>.</span><span>Authorization</span><span> </span><span>=</span><span> </span><span>getReqHeader</span><span>(</span><span>"Authorization"</span><span>);</span></div></div><div><div><div>348</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>349</div></div><div>
</div></div><div><div><div>350</div></div><div><span>    </span><span>// 发起请求并处理响应</span></div></div><div><div><div>351</div></div><div><span>    </span><span>let</span><span> </span><span>original_response</span><span> </span><span>=</span><span> </span><span>await</span><span> </span><span>fetch</span><span>(</span><span>new</span><span> </span><span>Request</span><span>(</span><span>url</span><span>, </span><span>request</span><span>), </span><span>parameter</span><span>);</span></div></div><div><div><div>352</div></div><div><span>    </span><span>let</span><span> </span><span>original_response_clone</span><span> </span><span>=</span><span><span> </span><span>original_response</span><span>.</span></span><span>clone</span><span>();</span></div></div><div><div><div>353</div></div><div><span>    </span><span>let</span><span> </span><span>original_text</span><span> </span><span>=</span><span><span> </span><span>original_response_clone</span><span>.</span></span><span>body</span><span>;</span></div></div><div><div><div>354</div></div><div><span>    </span><span>let</span><span> </span><span>response_headers</span><span> </span><span>=</span><span><span> </span><span>original_response</span><span>.</span></span><span>headers</span><span>;</span></div></div><div><div><div>355</div></div><div><span>    </span><span>let</span><span> </span><span>new_response_headers</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>Headers</span><span>(</span><span>response_headers</span><span>);</span></div></div><div><div><div>356</div></div><div><span>    </span><span>let</span><span> </span><span>status</span><span> </span><span>=</span><span><span> </span><span>original_response</span><span>.</span></span><span>status</span><span>;</span></div></div><div><div><div>357</div></div><div>
</div></div><div><div><div>358</div></div><div><span>    </span><span>// 修改 Www-Authenticate 头</span></div></div><div><div><div>359</div></div><div><span>    </span><span>if</span><span><span> (</span><span>new_response_headers</span><span>.</span></span><span>get</span><span>(</span><span>"Www-Authenticate"</span><span>)) {</span></div></div><div><div><div>360</div></div><div><span>      </span><span>let</span><span> </span><span>auth</span><span> </span><span>=</span><span><span> </span><span>new_response_headers</span><span>.</span></span><span>get</span><span>(</span><span>"Www-Authenticate"</span><span>);</span></div></div><div><div><div>361</div></div><div><span>      </span><span>let</span><span> </span><span>re</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>RegExp</span><span>(</span><span>auth_url</span><span>, </span><span>'g'</span><span>);</span></div></div><div><div><div>362</div></div><div><span><span>      </span></span><span>new_response_headers</span><span>.</span><span>set</span><span>(</span><span>"Www-Authenticate"</span><span><span>, </span><span>response_headers</span><span>.</span></span><span>get</span><span>(</span><span>"Www-Authenticate"</span><span>).</span><span>replace</span><span>(</span><span>re</span><span>, </span><span>workers_url</span><span>));</span></div></div><div><div><div>363</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>364</div></div><div>
</div></div><div><div><div>365</div></div><div><span>    </span><span>// 处理重定向</span></div></div><div><div><div>366</div></div><div><span>    </span><span>if</span><span><span> (</span><span>new_response_headers</span><span>.</span></span><span>get</span><span>(</span><span>"Location"</span><span>)) {</span></div></div><div><div><div>367</div></div><div><span>      </span><span>return</span><span> </span><span>httpHandler</span><span>(</span><span>request</span><span><span>, </span><span>new_response_headers</span><span>.</span></span><span>get</span><span>(</span><span>"Location"</span><span>));</span></div></div><div><div><div>368</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>369</div></div><div>
</div></div><div><div><div>370</div></div><div><span>    </span><span>// 返回修改后的响应</span></div></div><div><div><div>371</div></div><div><span>    </span><span>let</span><span> </span><span>response</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>Response</span><span>(</span><span>original_text</span><span>, {</span></div></div><div><div><div>372</div></div><div><span>      </span><span>status</span><span>,</span></div></div><div><div><div>373</div></div><div><span>      </span><span>headers</span><span>:</span><span> </span><span>new_response_headers</span></div></div><div><div><div>374</div></div><div><span><span>    </span></span><span>});</span></div></div><div><div><div>375</div></div><div><span>    </span><span>return</span><span> </span><span>response</span><span>;</span></div></div><div><div><div>376</div></div><div><span><span>  </span></span><span>}</span></div></div><div><div><div>377</div></div><div><span>};</span></div></div><div><div><div>378</div></div><div>
</div></div><div><div><div>379</div></div><div><span>/**</span></div></div><div><div><div>380</div></div><div><span><span> </span></span><span>* 处理HTTP请求</span></div></div><div><div><div>381</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{Request}</span><span> </span><span>req</span><span> 请求对象</span></div></div><div><div><div>382</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{string}</span><span> </span><span>pathname</span><span> 请求路径</span></div></div><div><div><div>383</div></div><div><span><span> </span></span><span>*/</span></div></div><div><div><div>384</div></div><div><span>function</span><span> </span><span>httpHandler</span><span><span>(</span><span>req</span><span>, </span><span>pathname</span><span>) {</span></span></div></div><div><div><div>385</div></div><div><span>  </span><span>const</span><span> </span><span>reqHdrRaw</span><span> </span><span>=</span><span><span> </span><span>req</span><span>.</span></span><span>headers</span><span>;</span></div></div><div><div><div>386</div></div><div>
</div></div><div><div><div>387</div></div><div><span>  </span><span>// 处理预检请求</span></div></div><div><div><div>388</div></div><div><span>  </span><span>if</span><span><span> (</span><span>req</span><span>.</span></span><span>method</span><span> </span><span>===</span><span> </span><span>'OPTIONS'</span><span> </span><span>&amp;&amp;</span></div></div><div><div><div>389</div></div><div><span><span>    </span></span><span>reqHdrRaw</span><span>.</span><span>has</span><span>(</span><span>'access-control-request-headers'</span><span>)</span></div></div><div><div><div>390</div></div><div><span><span>  </span></span><span>) {</span></div></div><div><div><div>391</div></div><div><span>    </span><span>return</span><span> </span><span>new</span><span> </span><span>Response</span><span>(</span><span>null</span><span>, </span><span>PREFLIGHT_INIT</span><span>);</span></div></div><div><div><div>392</div></div><div><span><span>  </span></span><span>}</span></div></div><div><div><div>393</div></div><div>
</div></div><div><div><div>394</div></div><div><span>  </span><span>let</span><span><span> </span><span>rawLen</span><span> </span></span><span>=</span><span> </span><span>''</span><span>;</span></div></div><div><div><div>395</div></div><div>
</div></div><div><div><div>396</div></div><div><span>  </span><span>const</span><span> </span><span>reqHdrNew</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>Headers</span><span><span>(</span><span>reqHdrRaw</span><span>);</span></span></div></div><div><div><div>397</div></div><div>
</div></div><div><div><div>398</div></div><div><span>  </span><span>const</span><span> </span><span>refer</span><span> </span><span>=</span><span><span> </span><span>reqHdrNew</span><span>.</span></span><span>get</span><span>(</span><span>'referer'</span><span>);</span></div></div><div><div><div>399</div></div><div>
</div></div><div><div><div>400</div></div><div><span>  </span><span>let</span><span><span> </span><span>urlStr</span><span> </span></span><span>=</span><span><span> </span><span>pathname</span><span>;</span></span></div></div><div><div><div>401</div></div><div>
</div></div><div><div><div>402</div></div><div><span>  </span><span>const</span><span> </span><span>urlObj</span><span> </span><span>=</span><span> </span><span>newUrl</span><span><span>(</span><span>urlStr</span><span>);</span></span></div></div><div><div><div>403</div></div><div>
</div></div><div><div><div>404</div></div><div><span>  </span><span>/** </span><span>@</span><span>type</span><span> </span><span>{RequestInit}</span><span> */</span></div></div><div><div><div>405</div></div><div><span>  </span><span>const</span><span> </span><span>reqInit</span><span> </span><span>=</span><span> {</span></div></div><div><div><div>406</div></div><div><span>    </span><span>method</span><span>:</span><span><span> </span><span>req</span><span>.</span></span><span>method</span><span>,</span></div></div><div><div><div>407</div></div><div><span>    </span><span>headers</span><span>:</span><span><span> </span><span>reqHdrNew</span><span>,</span></span></div></div><div><div><div>408</div></div><div><span>    </span><span>redirect</span><span>:</span><span> </span><span>'follow'</span><span>,</span></div></div><div><div><div>409</div></div><div><span>    </span><span>body</span><span>:</span><span><span> </span><span>req</span><span>.</span></span><span>body</span></div></div><div><div><div>410</div></div><div><span><span>  </span></span><span>};</span></div></div><div><div><div>411</div></div><div><span>  </span><span>return</span><span> </span><span>proxy</span><span><span>(</span><span>urlObj</span><span>, </span><span>reqInit</span><span>, </span><span>rawLen</span><span>);</span></span></div></div><div><div><div>412</div></div><div><span>}</span></div></div><div><div><div>413</div></div><div>
</div></div><div><div><div>414</div></div><div><span>/**</span></div></div><div><div><div>415</div></div><div><span><span> </span></span><span>* 代理请求</span></div></div><div><div><div>416</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{URL}</span><span> </span><span>urlObj</span><span> URL对象</span></div></div><div><div><div>417</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{RequestInit}</span><span> </span><span>reqInit</span><span> 请求初始化对象</span></div></div><div><div><div>418</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{string}</span><span> </span><span>rawLen</span><span> 原始长度</span></div></div><div><div><div>419</div></div><div><span><span> </span></span><span>*/</span></div></div><div><div><div>420</div></div><div><span>async</span><span> </span><span>function</span><span> </span><span>proxy</span><span><span>(</span><span>urlObj</span><span>, </span><span>reqInit</span><span>, </span><span>rawLen</span><span>) {</span></span></div></div><div><div><div>421</div></div><div><span>  </span><span>const</span><span> </span><span>res</span><span> </span><span>=</span><span> </span><span>await</span><span> </span><span>fetch</span><span><span>(</span><span>urlObj</span><span>.</span></span><span>href</span><span><span>, </span><span>reqInit</span><span>);</span></span></div></div><div><div><div>422</div></div><div><span>  </span><span>const</span><span> </span><span>resHdrOld</span><span> </span><span>=</span><span><span> </span><span>res</span><span>.</span></span><span>headers</span><span>;</span></div></div><div><div><div>423</div></div><div><span>  </span><span>const</span><span> </span><span>resHdrNew</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>Headers</span><span><span>(</span><span>resHdrOld</span><span>);</span></span></div></div><div><div><div>424</div></div><div>
</div></div><div><div><div>425</div></div><div><span>  </span><span>// 验证长度</span></div></div><div><div><div>426</div></div><div><span>  </span><span>if</span><span><span> (</span><span>rawLen</span><span>) {</span></span></div></div><div><div><div>427</div></div><div><span>    </span><span>const</span><span> </span><span>newLen</span><span> </span><span>=</span><span><span> </span><span>resHdrOld</span><span>.</span></span><span>get</span><span>(</span><span>'content-length'</span><span>) </span><span>||</span><span> </span><span>''</span><span>;</span></div></div><div><div><div>428</div></div><div><span>    </span><span>const</span><span> </span><span>badLen</span><span> </span><span>=</span><span><span> (</span><span>rawLen</span><span> </span></span><span>!==</span><span><span> </span><span>newLen</span><span>);</span></span></div></div><div><div><div>429</div></div><div>
</div></div><div><div><div>430</div></div><div><span>    </span><span>if</span><span><span> (</span><span>badLen</span><span>) {</span></span></div></div><div><div><div>431</div></div><div><span>      </span><span>return</span><span> </span><span>makeRes</span><span><span>(</span><span>res</span><span>.</span></span><span>body</span><span>, </span><span>400</span><span>, {</span></div></div><div><div><div>432</div></div><div><span>        </span><span>'--error'</span><span>:</span><span> </span><span>`bad len: </span><span>${</span><span>newLen</span><span>}</span><span>, except: </span><span>${</span><span>rawLen</span><span>}</span><span>`</span><span>,</span></div></div><div><div><div>433</div></div><div><span>        </span><span>'access-control-expose-headers'</span><span>:</span><span> </span><span>'--error'</span><span>,</span></div></div><div><div><div>434</div></div><div><span><span>      </span></span><span>});</span></div></div><div><div><div>435</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>436</div></div><div><span><span>  </span></span><span>}</span></div></div><div><div><div>437</div></div><div><span>  </span><span>const</span><span> </span><span>status</span><span> </span><span>=</span><span><span> </span><span>res</span><span>.</span></span><span>status</span><span>;</span></div></div><div><div><div>438</div></div><div><span><span>  </span></span><span>resHdrNew</span><span>.</span><span>set</span><span>(</span><span>'access-control-expose-headers'</span><span>, </span><span>'*'</span><span>);</span></div></div><div><div><div>439</div></div><div><span><span>  </span></span><span>resHdrNew</span><span>.</span><span>set</span><span>(</span><span>'access-control-allow-origin'</span><span>, </span><span>'*'</span><span>);</span></div></div><div><div><div>440</div></div><div><span><span>  </span></span><span>resHdrNew</span><span>.</span><span>set</span><span>(</span><span>'Cache-Control'</span><span>, </span><span>'max-age=1500'</span><span>);</span></div></div><div><div><div>441</div></div><div>
</div></div><div><div><div>442</div></div><div><span>  </span><span>// 删除不必要的头</span></div></div><div><div><div>443</div></div><div><span><span>  </span></span><span>resHdrNew</span><span>.</span><span>delete</span><span>(</span><span>'content-security-policy'</span><span>);</span></div></div><div><div><div>444</div></div><div><span><span>  </span></span><span>resHdrNew</span><span>.</span><span>delete</span><span>(</span><span>'content-security-policy-report-only'</span><span>);</span></div></div><div><div><div>445</div></div><div><span><span>  </span></span><span>resHdrNew</span><span>.</span><span>delete</span><span>(</span><span>'clear-site-data'</span><span>);</span></div></div><div><div><div>446</div></div><div>
</div></div><div><div><div>447</div></div><div><span>  </span><span>return</span><span> </span><span>new</span><span> </span><span>Response</span><span><span>(</span><span>res</span><span>.</span></span><span>body</span><span>, {</span></div></div><div><div><div>448</div></div><div><span><span>    </span></span><span>status</span><span>,</span></div></div><div><div><div>449</div></div><div><span>    </span><span>headers</span><span>:</span><span><span> </span><span>resHdrNew</span></span></div></div><div><div><div>450</div></div><div><span><span>  </span></span><span>});</span></div></div><div><div><div>451</div></div><div><span>}</span></div></div><div><div><div>452</div></div><div>
</div></div><div><div><div>453</div></div><div><span>async</span><span> </span><span>function</span><span> </span><span>ADD</span><span><span>(</span><span>envadd</span><span>) {</span></span></div></div><div><div><div>454</div></div><div><span>  </span><span>var</span><span><span> </span><span>addtext</span><span> </span></span><span>=</span><span><span> </span><span>envadd</span><span>.</span></span><span>replace</span><span>(</span><span>/</span><span><span>[   |"'</span><span>\r\n</span><span>]</span></span><span><span>+</span><span>/</span></span><span>g</span><span>, </span><span>','</span><span>).</span><span>replace</span><span>(</span><span><span>/,</span><span>+</span><span>/</span></span><span>g</span><span>, </span><span>','</span><span>);  </span><span>// 将空格、双引号、单引号和换行符替换为逗号</span></div></div><div><div><div>455</div></div><div><span>  </span><span>if</span><span><span> (</span><span>addtext</span><span>.</span></span><span>charAt</span><span>(</span><span>0</span><span>) </span><span>==</span><span> </span><span>','</span><span><span>) </span><span>addtext</span><span> </span></span><span>=</span><span><span> </span><span>addtext</span><span>.</span></span><span>slice</span><span>(</span><span>1</span><span>);</span></div></div><div><div><div>456</div></div><div><span>  </span><span>if</span><span><span> (</span><span>addtext</span><span>.</span></span><span>charAt</span><span><span>(</span><span>addtext</span><span>.</span></span><span>length</span><span> </span><span>-</span><span> </span><span>1</span><span>) </span><span>==</span><span> </span><span>','</span><span><span>) </span><span>addtext</span><span> </span></span><span>=</span><span><span> </span><span>addtext</span><span>.</span></span><span>slice</span><span>(</span><span>0</span><span><span>, </span><span>addtext</span><span>.</span></span><span>length</span><span> </span><span>-</span><span> </span><span>1</span><span>);</span></div></div><div><div><div>457</div></div><div><span>  </span><span>const</span><span> </span><span>add</span><span> </span><span>=</span><span><span> </span><span>addtext</span><span>.</span></span><span>split</span><span>(</span><span>','</span><span>);</span></div></div><div><div><div>458</div></div><div><span>  </span><span>return</span><span><span> </span><span>add</span><span>;</span></span></div></div><div><div><div>459</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>有条件的可以绑定自己的域名，将cloudflare托管域名指向Workers</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250223121331504.png" alt="image-20250223121331504" /><figcaption>image-20250223121331504</figcaption></figure><p></p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/875/</id>
      <title type="text">我的NAS进化史：从矿渣改造到白群晖的四年折腾记录</title>
      <published>2025-02-04T00:32:52.000Z</published>
      <updated>2026-03-08T04:51:18.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/875/"/>
      <summary type="text">1️⃣ 初代矿渣改造：蜗牛星际的奇幻漂流 硬件配置（2021年） 核心部件：蜗牛星际C款机箱（二手￥280）+ G3220（TDP 53W）+ H81主板 升级插曲：后期更换E3-1230 v3（￥180）提升转码性能 存储方案：4盘位机械</summary>
      <content type="html"><![CDATA[<section><h2>1️⃣ 初代矿渣改造：蜗牛星际的奇幻漂流<a href="#1️⃣-初代矿渣改造蜗牛星际的奇幻漂流"><span>#</span></a></h2><section><h3>硬件配置（2021年）<a href="#硬件配置2021年"><span>#</span></a></h3><ul>
<li><strong>核心部件</strong>：蜗牛星际C款机箱（二手￥280）+ G3220（TDP 53W）+ H81主板</li>
<li><strong>升级插曲</strong>：后期更换E3-1230 v3（￥180）提升转码性能</li>
<li><strong>存储方案</strong>：4盘位机械硬盘笼+128G MSATA系统盘</li>
</ul><img src="http://imgbed.leihub.cn/img/2ceab2116ed2be0fc6a6cb83ac2d200.jpg" alt="蜗牛星际矿渣改造实拍图" /><img src="http://imgbed.leihub.cn/img/d389e5d4d913738768580cb5227eea3.jpg" alt="二手垃圾佬" /><p><em>矿渣改造前后对比，完美诠释”垃圾佬”精神</em></p></section><section><h3>软件踩坑实录<a href="#软件踩坑实录"><span>#</span></a></h3><ul>
<li>
<p><strong>虚拟化方案</strong>：ESXi 6.7 + 黑群晖DSM6.2 + Ubuntu Server</p>
</li>
<li>
<p><strong>安全事件</strong>：公网IP暴露导致的黑群晖入侵事件（日志分析显示22端口爆破攻击）</p>
</li>
<li>
<p><strong>经验教训</strong>：① 必须配置防火墙规则 ② 禁用默认admin账户 ③ 启用二次验证</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/c5c21c17aa0534f427f5fb21ed33049.jpg" alt="c5c21c17aa0534f427f5fb21ed33049" /><figcaption>c5c21c17aa0534f427f5fb21ed33049</figcaption></figure><p></p>
</li>
</ul><hr /></section></section>
<section><h2>2️⃣ 职场新人的性能升级：从至强E3到十二代酷睿<a href="#2️⃣-职场新人的性能升级从至强e3到十二代酷睿"><span>#</span></a></h2><section><h3>硬件迭代（2022）<a href="#硬件迭代2022"><span>#</span></a></h3>

<table><thead><tr><th>部件</th><th>升级前</th><th>升级后</th><th>成本</th></tr></thead><tbody><tr><td>CPU</td><td>E3-1230 v3</td><td>i5-12400（6C12T）</td><td>￥1450</td></tr><tr><td>主板</td><td>H81</td><td>精粤B450i</td><td>￥399</td></tr><tr><td>内存</td><td>DDR3 8G</td><td>DDR4 32G</td><td>￥580</td></tr></tbody></table></section><section><h3>虚拟化平台迁移史<a href="#虚拟化平台迁移史"><span>#</span></a></h3><ol>
<li><strong>ESXI 7.0</strong>：网卡驱动兼容问题（Realtek RTL8111H）</li>
<li><strong>PVE测试</strong>：LXC容器性能优势但学习成本高</li>
<li><strong>最终方案</strong>：Unraid 6.9（docker生态+硬件直通优势）</li>
</ol><p>💡 游戏服务器实测数据：</p><ul>
<li>森林（The Forest）：10人联机占用30% CPU</li>
<li>Minecraft：Paper服务端+8G内存分配</li>
</ul><hr /></section></section>
<section><h2>3️⃣ 时间成本的觉醒：拥抱白群晖DS220+<a href="#3️⃣-时间成本的觉醒拥抱白群晖ds220"><span>#</span></a></h2><section><h3>设备配置（2023）<a href="#设备配置2023"><span>#</span></a></h3><ul>
<li><strong>核心部件</strong>：DS220+（双盘位）+ 16G内存（非官方扩容）+ 2*4T西数</li>
<li><strong>功耗对比</strong>：整机待机15W vs 旧平台45W</li>
</ul><p><em>极简主义的胜利：安静省电的日常办公伴侣</em></p></section><section><h3>白群晖真香体验<a href="#白群晖真香体验"><span>#</span></a></h3><p>✅ Active Backup：整机备份神器
✅ Synology Drive：媲美坚果云的同步体验
✅ Video Station：硬解转码一条龙
❌ Docker性能瓶颈：Jellyfin转码卡顿
❌ 虚拟机鸡肋：仅支持vCPU分配</p><hr /></section></section>
<section><h2>4️⃣ 副业探索：当NAS遇上GTX1650的游戏之旅<a href="#4️⃣-副业探索当nas遇上gtx1650的游戏之旅"><span>#</span></a></h2><section><h3>硬件加装方案<a href="#硬件加装方案"><span>#</span></a></h3><p>因为最近也一直在玩部落，想用nas开模拟器赚点电费，在咸鱼上入了一个二手GTX1650 LP半高刀片卡，看能不能躲开模拟器，玩玩部落冲突，用unraid开虚拟机win10用于开模拟器。</p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/870/</id>
      <title type="text">Unraid 设置中文界面方法</title>
      <published>2025-01-28T05:14:55.000Z</published>
      <updated>2025-11-14T15:17:37.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/870/"/>
      <summary type="text">🚀 核心价值 实现中文可视化操作，解决英文界面理解障碍，适配==‌本地化插件管理‌==和==‌硬件监控‌==需求。 -- 🔍 操作方案对比 方案 永久生效 操作复杂度 适用场景 ------------ ---------- -------</summary>
      <content type="html"><![CDATA[<section><h2>🚀 核心价值<a href="#-核心价值"><span>#</span></a></h2><p>实现中文可视化操作，解决英文界面理解障碍，适配==‌<strong>本地化插件管理</strong>‌==和==‌<strong>硬件监控</strong>‌==需求。</p><hr /><section><h3>🔍 操作方案对比<a href="#-操作方案对比"><span>#</span></a></h3>

<table><thead><tr><th>方案</th><th>永久生效</th><th>操作复杂度</th><th>适用场景</th></tr></thead><tbody><tr><td>URL安装法</td><td>✅</td><td>⭐️⭐️</td><td>长期使用/系统升级兼容</td></tr><tr><td>ZIP上传法</td><td>❌</td><td>⭐️⭐️⭐️⭐️</td><td>临时调试/快速验证</td></tr></tbody></table><hr /></section></section>
<section><h2>📥 永久生效方案（URL安装法）<a href="#-永久生效方案url安装法"><span>#</span></a></h2><section><h3>1️⃣ 获取官方语言包<a href="#1️⃣-获取官方语言包"><span>#</span></a></h3><p>进入控制台：
<code>Tools → Language → 输入URL</code></p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 官方镜像加速地址（2025年验证有效）</span></div></div><div><div><div>2</div></div><div><span>https://mirrors.unraid.pro/language-packs/lang-zh_CN.xml</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section><section><h3>2️⃣ 应用中文界面<a href="#2️⃣-应用中文界面"><span>#</span></a></h3><p>[安装成功] —&gt; {刷新页面}—&gt;[Settings → Display Settings]—&gt;[选择”简体中文”]—&gt; [点击Apply} → 【Done]</p></section><section><h3>3️⃣ 验证生效<a href="#3️⃣-验证生效"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>bashCopy Code# 通过SSH检查语言配置</span></div></div><div><div><div>2</div></div><div><span>cat /boot/config/plugins/dynamix/lang/zh_CN.json | grep "TITLE"</span></div></div><div><div><div>3</div></div><div><span># 预期输出</span></div></div><div><div><div>4</div></div><div><span>"TITLE": "控制面板"</span></div></div></code></pre><div><div></div><div></div></div></figure></div><hr /></section></section>
<section><h2>⚡ 临时调试方案（ZIP上传法）<a href="#-临时调试方案zip上传法"><span>#</span></a></h2><section><h3>1️⃣ 进入开发者模式<a href="#1️⃣-进入开发者模式"><span>#</span></a></h3><p>浏览器访问（需替换实际IP）：
<code>http://[你的Unraid IP]/Tools/Language</code>
点击右侧切换按钮：<code>user → develop</code></p></section><section><h3>2️⃣ 上传语言包<a href="#2️⃣-上传语言包"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>操作路径:</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>1. Select language → 中文</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>2. Select language file → 上传ZIP包</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>3. 强制刷新页面: Ctrl+F5</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>3️⃣ 快速切换技巧<a href="#3️⃣-快速切换技巧"><span>#</span></a></h3><p>通过右上角语言切换图标：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>[EN] ↔️ [CN] 实时切换</span></div></div></code></pre><div><div></div><div></div></div></figure></div><hr /></section></section>
<section><h2>🛡️ 稳定性保障建议<a href="#️-稳定性保障建议"><span>#</span></a></h2><ol>
<li>
<p>‌<strong>备份语言配置</strong>‌</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>cp -r /boot/config/plugins/dynamix/lang/ /mnt/user/backup/</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p>‌<strong>版本兼容检查</strong>‌</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>grep "version" /boot/config/plugins/dynamix/lang/zh_CN.json</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p>‌<strong>异常恢复流程</strong>‌</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>[界面乱码] --&gt; {SSH连接}--&gt; H[rm -rf /boot/config/plugins/dynamix/lang/*]--&gt; [重启WebGUI]</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/859/</id>
      <title type="text">开源多端同步笔记软件-Joplin</title>
      <published>2024-12-27T16:09:35.000Z</published>
      <updated>2025-11-14T15:15:10.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/859/"/>
      <summary type="text">在之前，我一直使用Typora进行笔记和文档的编写。然而，Typora没有手机端应用。后来尝试了群晖自带的笔记软件Synology Note，但这个软件功能较为简陋，甚至不支持Markdown格式。因此，我开始寻找一款既能支持多端同步又支持</summary>
      <content type="html"><![CDATA[<p>在之前，我一直使用Typora进行笔记和文档的编写。然而，Typora没有手机端应用。后来尝试了群晖自带的笔记软件Synology Note，但这个软件功能较为简陋，甚至不支持Markdown格式。因此，我开始寻找一款既能支持多端同步又支持多种格式的免费笔记软件。</p>
<p>许多人推荐了诸如印象笔记、为知笔记、Obsidian、Notion等软件，但这些终究不是免费的。我希望找到一个能够“白嫖”并且能在自己的服务器上搭建同步服务的解决方案。最终，Joplin完美符合了我的需求。</p>
<p>本文将详细介绍如何在NAS中搭建Joplin服务端环境，并在手机端和PC端实现同步。</p>
<section><h3>一、安装Joplin Server<a href="#一安装joplin-server"><span>#</span></a></h3><p>我是选择在自己的nas-群晖中搭建Joplin服务端。</p><section><h4>docker安装Joplin服务端<a href="#docker安装joplin服务端"><span>#</span></a></h4><ol>
<li><strong>进入Container Manager</strong>，选择新增项目。</li>
<li>创建一个新的<code>docker-compose.yml</code>文件，填入以下内容：</li>
</ol><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>version: </span><span>'3'</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>services:</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>joplin-db:</span></div></div><div><div><div>5</div></div><div><span><span>        </span></span><span>image: postgres:15-alpine</span></div></div><div><div><div>6</div></div><div><span><span>        </span></span><span>container_name: joplin-db</span></div></div><div><div><div>7</div></div><div><span><span>        </span></span><span>restart: unless-stopped</span></div></div><div><div><div>8</div></div><div><span><span>        </span></span><span>volumes:</span></div></div><div><div><div>9</div></div><div><span><span>            </span></span><span>- ./data:/var/lib/postgresql/data</span></div></div><div><div><div>10</div></div><div><span><span>        </span></span><span>expose:</span></div></div><div><div><div>11</div></div><div><span><span>            </span></span><span>- </span><span>"5432"</span></div></div><div><div><div>12</div></div><div><span><span>        </span></span><span>environment:</span></div></div><div><div><div>13</div></div><div><span><span>            </span></span><span>- POSTGRES_PASSWORD=</span><span>"123456789"</span><span> # 按需改</span></div></div><div><div><div>14</div></div><div><span><span>            </span></span><span>- POSTGRES_USER=joplin</span></div></div><div><div><div>15</div></div><div><span><span>            </span></span><span>- POSTGRES_DB=joplin</span></div></div><div><div><div>16</div></div><div><span><span>        </span></span><span>networks:</span></div></div><div><div><div>17</div></div><div><span><span>            </span></span><span>- default</span></div></div><div><div><div>18</div></div><div>
</div></div><div><div><div>19</div></div><div><span><span>    </span></span><span>joplin-app:</span></div></div><div><div><div>20</div></div><div><span><span>        </span></span><span>image: joplin/server:latest</span></div></div><div><div><div>21</div></div><div><span><span>        </span></span><span>container_name: joplin-app</span></div></div><div><div><div>22</div></div><div><span><span>        </span></span><span>restart: unless-stopped</span></div></div><div><div><div>23</div></div><div><span><span>        </span></span><span>expose:</span></div></div><div><div><div>24</div></div><div><span><span>            </span></span><span>- </span><span>"22300"</span></div></div><div><div><div>25</div></div><div><span><span>        </span></span><span>environment:</span></div></div><div><div><div>26</div></div><div><span><span>            </span></span><span>- APP_PORT=22300</span></div></div><div><div><div>27</div></div><div><span><span>            </span></span><span>- APP_BASE_URL=https://test.com # 换为自己的域名</span></div></div><div><div><div>28</div></div><div><span><span>            </span></span><span>- DB_CLIENT=pg</span></div></div><div><div><div>29</div></div><div><span><span>            </span></span><span>- POSTGRES_PASSWORD=</span><span>"123456789"</span><span> # 与上一致</span></div></div><div><div><div>30</div></div><div><span><span>            </span></span><span>- POSTGRES_DATABASE=joplin</span></div></div><div><div><div>31</div></div><div><span><span>            </span></span><span>- POSTGRES_USER=joplin</span></div></div><div><div><div>32</div></div><div><span><span>            </span></span><span>- POSTGRES_PORT=5432</span></div></div><div><div><div>33</div></div><div><span><span>            </span></span><span>- POSTGRES_HOST=joplin-db</span></div></div><div><div><div>34</div></div><div><span><span>            </span></span><span>- TZ=Asia/Shanghai # 中国大陆用户推荐用亚洲/上海时区</span></div></div><div><div><div>35</div></div><div><span><span>        </span></span><span>depends_on:</span></div></div><div><div><div>36</div></div><div><span><span>            </span></span><span>- joplin-db</span></div></div><div><div><div>37</div></div><div><span><span>        </span></span><span>networks:</span></div></div><div><div><div>38</div></div><div><span><span>            </span></span><span>- default</span></div></div><div><div><div>39</div></div><div><span><span>        </span></span><span>ports:</span></div></div><div><div><div>40</div></div><div><span><span>            </span></span><span>- </span><span>"22300:22300"</span></div></div><div><div><div>41</div></div><div>
</div></div><div><div><div>42</div></div><div><span>networks:</span></div></div><div><div><div>43</div></div><div><span><span>  </span></span><span>default:</span></div></div><div><div><div>44</div></div><div><span><span>    </span></span><span>name: joplin</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><ol>
<li><strong>保存并构建项目</strong>，项目会新建一个<code>joplin-app</code>和 <code>joplin-db</code>容器，<code>joplin-app</code>容器运行服务，数据储存在 <code>joplin-db</code>容器中。</li>
</ol></section><section><h4>配置nginx<a href="#配置nginx"><span>#</span></a></h4><p>接下来，通过Nginx对容器的22300端口进行反向代理。注意我们在容器中设置了域名访问，所以通过localhost+端口是无法访问的，必须通过域名才能进行访问。</p><blockquote><p>我选择将Joplin服务端搭建在NAS中，然后通过frp将容器22300端口转发到云服务的22300端口，最后通过Nginx，将域名反向代理至云服务22300端口，实现域名访问本地22300端口的Joplin服务。</p></blockquote><p>nginx代理设置如下：</p><img src="http://imgbed.leihub.cn/img/image-20241227232225730.png" alt="image-20241227232225730" /><p>最后，我们访问<code>https://test.com</code>即可进入Joplin服务端网页，进行配置。初始帐户和密码为：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span> </span></span><span>帐户：admin@localhost</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>密码：admin</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>我们可以在后台Admin-Email中修改一个真实可用的邮箱：</p><img src="http://imgbed.leihub.cn/img/image-20241227232626292.png" alt="image-20241227232626292" /></section></section>
<section><h3>二、使用Joplin客户端<a href="#二使用joplin客户端"><span>#</span></a></h3><section><h4>windows<a href="#windows"><span>#</span></a></h4><p>在Windows环境中，访问<a href="https://joplinapp.org/download/" target="_blank">Downloading Joplin… | Joplin</a>即可下载客户端程序，比较简单，这里就不赘述。Joplin页面如下：</p><img src="http://imgbed.leihub.cn/img/image-20241227232840544.png" alt="image-20241227232840544" /><p>安装好后，按<code>Ctrl</code>+<code>,</code>即可进入设置页面，添加以下刚刚搭建的Joplin服务端账户。</p><img src="http://imgbed.leihub.cn/img/image-20241227233152310.png" alt="image-20241227233152310" /></section><section><h4>移动端<a href="#移动端"><span>#</span></a></h4><p>移动端在Google Play中下载或者通过<a href="https://objects.joplinusercontent.com/v2.11.31/joplin-v2.11.31.apk?source=JoplinWebsite&amp;type=New" target="_blank">链接</a>下载，简单填写同步信息即可进行多端同步。</p><img src="http://imgbed.leihub.cn/img/f3a11c08407c5113d451ddea2047e79.jpg" alt="f3a11c08407c5113d451ddea2047e79" /></section><section><h4>插件<a href="#插件"><span>#</span></a></h4><p>Joplin支持许多插件，可以在官方的插件商店<a href="https://joplinapp.org/plugins/" target="_blank">Joplin Plugins</a>进行搜索下载，</p><img src="http://imgbed.leihub.cn/img/image-20241227234618568.png" alt="image-20241227234618568" /><p>下载<code>.jpl</code>文件后，通过文件安装插件。</p><img src="http://imgbed.leihub.cn/img/image-20241227234716352.png" alt="image-20241227234716352" /><ol>
<li>这里罗列几个别人推荐的插件：
<ol>
<li><strong>Note Tabs</strong>：多标签页插件 <a href="https://github.com/benji300/joplin-note-tabs" target="_blank">Note Tabs</a></li>
<li><strong>Favorites</strong>：收藏夹插件 <a href="https://github.com/benji300/joplin-favorites" target="_blank">Favorites</a></li>
<li><strong>DDDot</strong>：超赞功能集合插件 <a href="https://github.com/benlau/joplin-plugin-dddot" target="_blank">DDDot</a></li>
<li><strong>Calendar</strong>：日历插件 <a href="https://github.com/rsandz/joplin-calendar" target="_blank">Calendar</a></li>
</ol>
</li>
</ol></section><section><h4>调用typora<a href="#调用typora"><span>#</span></a></h4><p>如果更喜欢使用Typora进行写作，可以调用Typora，写完后保存文件，就会保存到Joplin中，这样使用非常方便。</p><img src="http://imgbed.leihub.cn/img/image-20241227235255153.png" alt="image-20241227235255153" /><p>设置好后，按<code>Ctrl</code>+<code>E</code>就可以调用Typora编辑器，写完后按<code>Ctrl</code>+<code>E</code>就可以取消调用。</p></section></section>
<section><h3>三、最后<a href="#三最后"><span>#</span></a></h3><p>目前我也还在慢慢接触Joplin这款笔记软件，目前感觉还不错。毕竟这款跨平台的宝藏软件，越深度使用越能不断发现它的“惊艳”之处。</p></section>
<section><h3>参考<a href="#参考"><span>#</span></a></h3><p><a href="https://cloud.tencent.com/developer/news/1108756" target="_blank">Joplin插件推荐1：让做笔记无限丝滑的四款插件 - 腾讯云开发者社区-腾讯云</a></p><p><a href="https://blognas.hwb0307.com/other/5456" target="_blank">Docker系列 用Joplin系统地组织和记录笔记 - Bensz</a></p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/878/</id>
      <title type="text">自建密码堡垒：手把手教你搭建企业级Vaultwarden密码管理器</title>
      <published>2024-11-10T15:15:08.000Z</published>
      <updated>2025-08-26T12:11:14.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/878/"/>
      <summary type="text">自建密码堡垒：手把手教你搭建企业级Vaultwarden密码管理器 1️⃣ 为什么选择Vaultwarden？安全与便利的黄金平衡 对比主流密码方案 特性 Chrome密码本 1Password Vaultwarden :---------</summary>
      <content type="html"><![CDATA[<p>自建密码堡垒：手把手教你搭建企业级Vaultwarden密码管理器</p>
<section><h2>1️⃣ 为什么选择Vaultwarden？安全与便利的黄金平衡<a href="#1️⃣-为什么选择vaultwarden安全与便利的黄金平衡"><span>#</span></a></h2><section><h3>对比主流密码方案<a href="#对比主流密码方案"><span>#</span></a></h3>

<table><thead><tr><th>特性</th><th>Chrome密码本</th><th>1Password</th><th>Vaultwarden</th></tr></thead><tbody><tr><td>端到端加密</td><td>❌</td><td>✅</td><td>✅</td></tr><tr><td>自托管能力</td><td>❌</td><td>❌</td><td>✅</td></tr><tr><td>多设备同步</td><td>基础版✅</td><td>全平台✅</td><td>全平台✅</td></tr><tr><td>年度成本</td><td>免费</td><td>$36起</td><td>硬件成本</td></tr></tbody></table><p>💡 <strong>核心优势</strong>：Rust语言构建的性能优势，内存占用仅为官方客户端的1/3</p></section></section>
<section><h2>2️⃣ 环境准备：双平台部署指南<a href="#2️⃣-环境准备双平台部署指南"><span>#</span></a></h2><section><h3>最低硬件要求<a href="#最低硬件要求"><span>#</span></a></h3><ul>
<li><strong>x86平台</strong>：双核CPU / 2GB内存 / 10GB存储</li>
<li><strong>网络要求</strong>：开放80/443端口（需备案）</li>
</ul></section><section><h3>系统环境推荐<a href="#系统环境推荐"><span>#</span></a></h3><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># Ubuntu Server</span></div></div><div><div><div>2</div></div><div><span>推荐版本：22.04</span><span> </span><span>LTS</span></div></div><div><div><div>3</div></div><div><span>必备组件：Docker</span><span> </span><span>20.10+、docker-compose</span><span> </span><span>2.17+</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span># 群晖NAS</span></div></div><div><div><div>6</div></div><div><span>兼容型号：DS220+/DS920+（DSM7.0+）</span></div></div><div><div><div>7</div></div><div><span>第三方源：矿神spk（https://spk.imnks.com/）</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><ul>
<li>
<h2>3️⃣ 实战部署：Docker全流程详解<a href="#3️⃣-实战部署docker全流程详解"><span>#</span></a></h2>
<h3>Ubuntu部署模板<a href="#ubuntu部署模板"><span>#</span></a></h3>
<div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>version: </span><span>"2"</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>services:</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>app:</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>image: vaultwarden/server:latest</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>environment:</span></div></div><div><div><div>7</div></div><div><span><span>      </span></span><span>- SERVER_ADMIN_EMAIL=&lt;emali@qq.com&gt; # 按需修改</span></div></div><div><div><div>8</div></div><div><span><span>      </span></span><span>- SIGNUPS_ALLOWED=false</span></div></div><div><div><div>9</div></div><div><span><span>      </span></span><span>- INVITATIONS_ALLOWED=true</span></div></div><div><div><div>10</div></div><div><span><span>      </span></span><span>- WEBSOCKET_ENABLED=true</span></div></div><div><div><div>11</div></div><div><span><span>      </span></span><span>- ADMIN_TOKEN=&lt;token&gt; # 按需修改</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>volumes:</span></div></div><div><div><div>13</div></div><div><span><span>      </span></span><span>- ./app:/data/</span></div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>ports:</span></div></div><div><div><div>15</div></div><div><span><span>      </span></span><span>- 11111:80 # 按需修改</span></div></div><div><div><div>16</div></div><div><span><span>    </span></span><span>restart: unless-stopped</span></div></div><div><div><div>17</div></div><div><span><span>    </span></span><span>networks:</span></div></div><div><div><div>18</div></div><div><span><span>      </span></span><span>- default</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span>networks:</span></div></div><div><div><div>21</div></div><div><span><span>  </span></span><span>default:</span></div></div><div><div><div>22</div></div><div><span><span>    </span></span><span>name: bitwarden</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div>
<h3>关键部署命令<a href="#关键部署命令"><span>#</span></a></h3>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 创建专用网络</span></div></div><div><div><div>2</div></div><div><span>docker</span><span> </span><span>network</span><span> </span><span>create</span><span> </span><span>vault_net</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 启动服务（后台模式）</span></div></div><div><div><div>5</div></div><div><span>docker-compose</span><span> </span><span>up</span><span> </span><span>-d</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span># 查看实时日志</span></div></div><div><div><div>8</div></div><div><span>docker</span><span> </span><span>logs</span><span> </span><span>-f</span><span> </span><span>vaultwarden</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
</li>
</ul></section></section>
<section><h2>4️⃣ 安全加固：HTTPS与反向代理配置<a href="#4️⃣-安全加固https与反向代理配置"><span>#</span></a></h2><p>⚠️ <strong>安全警告</strong>：未启用HTTPS时，浏览器将阻止密码同步功能</p><section><h3>Nginx反向代理配置<a href="#nginx反向代理配置"><span>#</span></a></h3><p>首先使用FRP将内网的端口暴露到公网服务器的指定端口，然后用nginx进行反向代理。在文章<a href="/archives/623/">云服务器+FRP+Nginx，无需添加端口，直接使用域名访问家里的任何设备 - 阿雷的小窝</a>中我介绍了几种方向代理的方法，我使用的宝塔面板进行反向代理，将内网的11111端口代理到指定的域名，强制SSL和接受https。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250225001645583.png" alt="image-20250225001645583" /><figcaption>image-20250225001645583</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250225001714359.png" alt="image-20250225001714359" /><figcaption>image-20250225001714359</figcaption></figure><p></p></section></section>
<section><h2>5️⃣ 全平台同步：客户端配置终极指南<a href="#5️⃣-全平台同步客户端配置终极指南"><span>#</span></a></h2><p>通过上述设置，就可以通过指定域名<code>https://&lt;bitwarden.exampledomain.com&gt;</code>，访问vaultwarden，第一需要设置SMTP Email Settings，设置为自己的邮箱，给自己发送邀请邮件，这样就可以创建账户了。创建账户后进入服务端页面。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250225002254140.png" alt="image-20250225002254140" /><figcaption>image-20250225002254140</figcaption></figure><p></p><section><h3>客户端下载<a href="#客户端下载"><span>#</span></a></h3><p>使用时一般用<strong>Edge浏览器插件</strong>或者<strong>手机 APP</strong>的方式使用，在插件中输入网址登录账户后，浏览器用过的所有的密码都可以保存在密码库中。</p><p>🔐 <strong>主密码设置技巧</strong>：采用「虚构句子+特殊字符」模式（例：PurpleTiger$Climbs2023!）</p><hr /></section></section>
<section><h2>6️⃣ 迁移革命：从浏览器到专业密码库<a href="#6️⃣-迁移革命从浏览器到专业密码库"><span>#</span></a></h2><section><h3>Edge密码导出/导入流程<a href="#edge密码导出导入流程"><span>#</span></a></h3><p>在使用vaultwarden之前，我一直用edge浏览器来管理自己的密码库，目前部署了个人密码库，就可以将edge密码库迁移到vaultwarden里来了。</p><ol>
<li>
<p>访问 <code>edge://wallet/passwords</code></p>
</li>
<li>
<p>点击「导出密码」生成CSV文件</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250225002912608.png" alt="image-20250225002912608" /><figcaption>image-20250225002912608</figcaption></figure><p></p>
</li>
<li>
<p>在Vaultwarden控制台选择「工具」→「导入数据」</p>
</li>
<li>
<p>选择「Chrome (csv)」格式完成迁移</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250225003042226.png" alt="image-20250225003042226" /><figcaption>image-20250225003042226</figcaption></figure><p></p>
</li>
</ol></section></section>
<section><h2>7️⃣ 客户端使用<a href="#7️⃣-客户端使用"><span>#</span></a></h2><p>我目前只需要记住一个主密码，其他的密码我都通过Vaultwarden的密码生成器生成新的强密码，这样再也不怕泄露了。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20250225003207777.png" alt="image-20250225003207777" /><figcaption>image-20250225003207777</figcaption></figure><p></p><ul>
<li><strong>延伸阅读</strong>：
<a href="https://github.com/dani-garcia/vaultwarden" target="_blank">🔗 Vaultwarden官方文档</a>
<a href="https://certbot.eff.org/" target="_blank">🔗 Let’s Encrypt证书申请指南</a></li>
</ul></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/856/</id>
      <title type="text">足迹：桂林三日游</title>
      <published>2024-10-07T04:23:03.000Z</published>
      <updated>2025-11-14T15:18:18.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/856/"/>
      <summary type="text">国庆节期间，本想着回家，但由于中秋节刚回了一趟，便决定出去放松一下。正好同事也有出游的计划，我便跟随他们一起开启了桂林三日游。然而，这趟旅程并没有带来太多惊喜，反而在期望与现实的落差中，留下了几分遗憾。 第一天：商业化的面具下，失落的桂林夜</summary>
      <content type="html"><![CDATA[<p>国庆节期间，本想着回家，但由于中秋节刚回了一趟，便决定出去放松一下。正好同事也有出游的计划，我便跟随他们一起开启了桂林三日游。然而，这趟旅程并没有带来太多惊喜，反而在期望与现实的落差中，留下了几分遗憾。</p>
<section><h3><strong>第一天：商业化的面具下，失落的桂林夜晚</strong><a href="#第一天商业化的面具下失落的桂林夜晚"><span>#</span></a></h3><p>下午5点，我们抵达桂林北站，入住宾馆后就直接前往东西巷打卡。</p><img src="http://imgbed.leihub.cn/img/IMG_20241003_183359.jpg" alt="IMG_20241003_183359" /><p>说实话，这里并没有想象中的地方特色，反倒是全国各地的商业街如出一辙——人山人海、千篇一律。最终，只好随便吃了一碗桂林米粉和糖水草草了事，算是解决了晚餐。</p><img src="http://imgbed.leihub.cn/img/IMG_20241003_195818.jpg" alt="IMG_20241003_195818" /><p>接着我们匆匆路过了象鼻山和日月双塔，远远地看了一眼。可是，挤满了游客，完全没办法近距离欣赏。这样走走停停地到晚上11点，带着疲惫回到宾馆，结束了失望的第一天。</p></section>
<section><h3><strong>第二天：漓江的美景，和令人失望的竹筏漂流</strong><a href="#第二天漓江的美景和令人失望的竹筏漂流"><span>#</span></a></h3><p>早上6点半起床，急急忙忙赶往景区，9点才到，排了两小时的队才搞到游船票。还好，坐上了兴坪漓江游船，20元人民币的取景地，真是值得一看。桂林山水的独特魅力，与湖南的景致大不相同，一座座奇特的山峦和清澈的江水相映成趣，令人心旷神怡。</p><img src="http://imgbed.leihub.cn/img/IMG_20241004_125131.jpg" alt="IMG_20241004_125131" /><p>中午我们尝了桂林特色的啤酒鱼，味道平平无奇。下午继续我们的行程，去了遇龙河坐竹筏。本以为会像抖音上火爆的双人竹筏漂流，但现实却是8人竹筏，而且还只是在一个小池塘里打转转！每人45元，真的太令人失望了，毫无体验感。</p><img src="http://imgbed.leihub.cn/img/IMG_20241004_174527.jpg" alt="IMG_20241004_174527" /><p>晚上去了号称世界最美的溶洞——银子岩，尽管传说一游银子岩，一世不缺钱，但我只觉得这不过是个普通溶洞，没什么特别的。倒是夜晚的气温骤降，幸亏带了外套，不然真扛不住这寒意。</p><img src="http://imgbed.leihub.cn/img/IMG_20241004_185036.jpg" alt="IMG_20241004_185036" /></section>
<section><h3><strong>第三天：商业化的少数民族村寨和令人啼笑皆非的“世外桃源”</strong><a href="#第三天商业化的少数民族村寨和令人啼笑皆非的世外桃源"><span>#</span></a></h3><p>这一天的行程简直是糟糕透顶。我们去参观所谓的少数民族村寨，结果不过是个新建的商场，根本没有什么传统文化，倒是满满的商业气息。里面到处卖银饰，还号称48元一克，真不知道这银子里是不是掺了金子。</p><img src="http://imgbed.leihub.cn/img/IMG_20241005_090053.jpg" alt="IMG_20241005_090053" /><p>最后的“世外桃源”景点，号称国家4A级景区，却让我大跌眼镜。乘船绕了一圈，景区很快结束，紧接着就是带着我们去商场狠狠宰客。幸好我兜里没多少钱，不然真得被狠狠宰一顿。</p><img src="http://imgbed.leihub.cn/img/IMG_20241005_113346.jpg" alt="IMG_20241005_113346" /><p>本想着多留一天，结果看着旅游团的套路，还是连夜赶火车回了株洲，旅程草草结束。</p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/834/</id>
      <title type="text">足迹：2024高温假自驾游</title>
      <published>2024-08-05T03:59:12.000Z</published>
      <updated>2025-11-14T15:18:26.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/834/"/>
      <summary type="text">高温假自驾游 神农谷、井冈山、武功山、株洲方特 趁着高温假，和家人自驾出去走了一圈，虽然一路上有些累，但也有不少有趣的经历，随手记录一下。 ⛰ 神农谷 - “摇晃之旅”的小失望 第一站是炎陵的神农谷，虽然是“天然氧吧”，但整体没太多亮点。 </summary>
      <content type="html"><![CDATA[<section><h3>高温假自驾游 | 神农谷、井冈山、武功山、株洲方特<a href="#高温假自驾游--神农谷井冈山武功山株洲方特"><span>#</span></a></h3><p>趁着高温假，和家人自驾出去走了一圈，虽然一路上有些累，但也有不少有趣的经历，随手记录一下。</p><section><h4>⛰ 神农谷 - “摇晃之旅”的小失望<a href="#-神农谷---摇晃之旅的小失望"><span>#</span></a></h4><p>第一站是<strong>炎陵的神农谷</strong>，虽然是“天然氧吧”，但整体没太多亮点。</p><img src="http://imgbed.leihub.cn/img/IMG_20240803_142336.jpg" alt="IMG_20240803_142336" /><p>山腰上的瀑布还算不错，清凉的水雾让人感觉很舒服，但自驾车不能进山，我们只能乘坐景区大巴，那段山路真的摇晃得快让我晕车了😅。神农谷的总体感觉是：一般般，打个卡就好。</p><img src="http://imgbed.leihub.cn/img/IMG_20240803_154410.jpg" alt="IMG_20240803_154410" /></section><section><h4>🔴 井冈山 - 一次性打卡的红色之旅<a href="#-井冈山---一次性打卡的红色之旅"><span>#</span></a></h4><p>从神农谷出来后，我们去到了<strong>井冈山</strong>。井冈山可是革命圣地，满满的红色记忆。去了<strong>井冈山风景名胜区</strong>和<strong>井冈山革命博物馆</strong>，这些景点对了解中国近代革命史还是很有意义的，算是“红色旅游”的代表地。</p><img src="http://imgbed.leihub.cn/img/IMG_20240803_180914.jpg" alt="IMG_20240803_180914" /><p>但说实话，如果你不是特别喜欢历史，井冈山不太适合纯旅游。景色比较单调，游玩项目少，几乎就是一场打卡之旅。最让人头疼的是，这里的物价实在太高了！酒店贵，吃的也不好，菜品又贵又不好吃。除非你对革命文化特别感兴趣，不然我真的不推荐来这里专门玩一趟。</p><img src="http://imgbed.leihub.cn/img/IMG_20240804_095825.jpg" alt="IMG_20240804_095825" /></section><section><h4>🏞 武功山 - 风景很美，但爬山真的好累！<a href="#-武功山---风景很美但爬山真的好累"><span>#</span></a></h4><p>接着去了<strong>江西的武功山</strong>，爬山的过程真的是既辛苦又值得！虽然山不算高，但坡度很陡，爬了将近三个小时，累到怀疑人生😂。</p><img src="http://imgbed.leihub.cn/img/6e245530bde2fb884e90afbc170db05.jpg" alt="6e245530bde2fb884e90afbc170db05" /><p>不过，山顶的风景绝对不辜负你的努力。</p><img src="http://imgbed.leihub.cn/img/IMG_20240805_105502.jpg" alt="IMG_20240805_105502" /><p>爬山过程中还有个小插曲——快到山顶时，突然遇到了冰雹！山下是三十多度的艳阳天，谁知道山顶刮起大风、下起冰雹！在山顶避了一个小时，才终于等到天放晴，平安下山。尽管天气多变，但风景无敌美，武功山值得一爬。</p><img src="http://imgbed.leihub.cn/img/IMG_20240805_131447.jpg" alt="IMG_20240805_131447" /></section><section><h4>🎢 株洲方特 - 又累又刺激<a href="#-株洲方特---又累又刺激"><span>#</span></a></h4><p>最后一站是<strong>株洲的方特</strong>，游客不多，不用排队，玩得很爽！体验了传说中的“大摆锤”，刺激到腿软，再也不敢玩更惊险的项目了😂。不过要吐槽一下门票价格，当天买票贵得离谱💸，以后一定要提前买，省钱省心。</p></section><section><h4>总结<a href="#总结"><span>#</span></a></h4><p>这趟高温假自驾游，虽然有些地方稍微让人失望，比如井冈山和神农谷，但也有不少精彩瞬间，比如武功山的壮丽风景和方特的刺激体验。下一次出行要提前做好攻略，这样既省钱又省力，期待下次的旅行冒险！</p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/819/</id>
      <title type="text">搭建起我的第一口小草缸</title>
      <published>2024-07-18T14:17:05.000Z</published>
      <updated>2025-11-14T15:18:36.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/819/"/>
      <summary type="text">无意间在B站刷到了草缸的视频，第一眼就惊艳到了，被草缸里郁郁葱葱吸引到了眼球，立即入坑，毫不含糊。直接在B站上搜索教程，看完教程马上就下单了。 主要部件： 鱼缸： 金晶五线玻璃鱼缸超白方形缸玻璃定制小型家溪流缸生态造景缸水草-淘宝网 tao</summary>
      <content type="html"><![CDATA[<p>无意间在B站刷到了草缸的视频，第一眼就惊艳到了，被草缸里郁郁葱葱吸引到了眼球，立即入坑，毫不含糊。直接在B站上搜索教程，看完教程马上就下单了。</p>
<section><h1>主要部件：<a href="#主要部件"><span>#</span></a></h1><ol>
<li>
<p>鱼缸：</p>
<p><a href="https://item.taobao.com/item.htm?spm=a1z09.2.0.0.28312e8dwOEQyM&amp;id=610978175192&amp;_u=i2d24k53ae3f" target="_blank">金晶五线玻璃鱼缸超白方形缸玻璃定制小型家溪流缸生态造景缸水草-淘宝网 (taobao.com)</a></p>
<p>我买的是30x30x40的超白缸，虽说缸体越大水质越稳定，但是新手刚玩，还是买点小的试试水。</p>
</li>
<li>
<p>水草灯：<a href="https://item.taobao.com/item.htm?spm=a1z09.2.0.0.28312e8dwOEQyM&amp;id=619327993630&amp;_u=i2d24k53d6e1" target="_blank">魔点全新B三代水草灯 B2纯RGB版LED草缸造景灯水族鱼缸照明显色灯-淘宝网 (taobao.com)</a></p>
<p>水草灯使用的魔点B三代，可以通过蓝牙连接手机app魔点智能盒，对灯光进行控制。我设置的光照时间是一天6个小时。</p>
<img src="http://imgbed.leihub.cn/img/d32fa3eb9748dd6959bb7773afe4fef.jpg" alt="d32fa3eb9748dd6959bb7773afe4fef" />
</li>
<li>
<p>二氧化碳发生器：<a href="https://item.taobao.com/item.htm?spm=a1z09.2.0.0.28312e8dwOEQyM&amp;id=600157279841&amp;_u=i2d24k539f0b" target="_blank">鱼缸二氧化碳发生器diy自制CO2发生器套装水草缸钢瓶套装细化器-淘宝网 (taobao.com)</a></p>
<p>二氧化碳我本来想买罐装打气的那种，没气了直接去加气站加。结果下单时买错了，买成二氧化碳发生器了。。。</p>
<p>二氧化碳我调节的是两秒一泡，可以使用三个月。三个月后需要补充柠檬酸和小苏打，这确实比直接打气的要麻烦一点，不过便宜点也行。</p>
<p>我的发生器大小为4L，一次性加400g柠檬酸 和400g小苏打，600mL水。</p>
</li>
<li>
<p>过滤：<a href="https://item.taobao.com/item.htm?id=524764786950&amp;ft=t&amp;skuId=3123147001314" target="_blank">森森小型鱼缸前置过滤桶无动力HW603602水族箱外置过滤器静音净化-淘宝网 (taobao.com)</a></p>
<p>过滤使用的森森的602B，就一个特点，便宜。性价比较高。</p>
</li>
<li>
<p>水草泥：<a href="https://item.taobao.com/item.htm?spm=a1z09.2.0.0.67002e8dLFDfSQ&amp;id=672939212685&amp;_u=i2d24k53ea06" target="_blank">牧鱼水草泥鱼缸专用种植土底砂水族肥料生态造景草缸钾肥水藻泥沙-淘宝网 (taobao.com)</a></p>
<p>水草泥我买了6L，放我这个30缸戳戳有余了。</p>
</li>
<li>
<p>火山石：<a href="https://item.taobao.com/item.htm?spm=a1z09.2.0.0.67002e8dLFDfSQ&amp;id=636441186077&amp;_u=i2d24k530ba2" target="_blank">火山石底砂鱼缸过滤材料黑色细颗粒网袋包鱼池水族箱内置净水石头-淘宝网 (taobao.com)</a></p>
</li>
<li>
<p>水草：</p>
<p>绿宫廷和血宫廷各100株：<a href="https://item.taobao.com/item.htm?spm=a1z09.2.0.0.67002e8dLFDfSQ&amp;id=668355202480&amp;_u=i2d24k539560" target="_blank">丹麦血红宫廷绿宫廷趴地血宫廷粉宫廷水下叶鱼缸植物套餐草缸造景-淘宝网 (taobao.com)</a></p>
<p>迷你牛毛：<a href="https://item.taobao.com/item.htm?spm=a1z09.2.0.0.67002e8dLFDfSQ&amp;id=681133151416&amp;_u=i2d24k53c1e8" target="_blank">鱼缸水草莫斯无菌杯前景迷你牛毛日本矮珍珠椒草挖耳小水榕血心兰-淘宝网 (taobao.com)</a></p>
<p>水草布置我是按B站教程来的，布置如图所示。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240718220237466.png" alt="image-20240718220237466" /><figcaption>image-20240718220237466</figcaption></figure><p></p>
</li>
<li>
<p>小工具</p>
<p>刮藻刀：<a href="https://detail.tmall.com/item.htm?id=533667591587&amp;spm=a1z09.2.0.0.67002e8dLFDfSQ&amp;_u=i2d24k53c9ba" target="_blank">水草鱼缸刮藻刀不伤玻璃不锈钢除藻刷子清理清洁清洗神器工具刀片-tmall.com天猫</a></p>
<p>换水器：<a href="https://item.taobao.com/item.htm?spm=a1z09.2.0.0.67002e8dLFDfSQ&amp;id=679688389782&amp;_u=i2d24k53f72d" target="_blank">鱼缸换水器神器虹吸抽水软管洗沙手动清理吸鱼粪便大缸清洁工具-淘宝网 (taobao.com)</a></p>
<p>镊子和水草剪刀：<a href="https://item.taobao.com/item.htm?spm=a1z09.2.0.0.67002e8dLFDfSQ&amp;id=588463535029&amp;_u=i2d24k537803" target="_blank">不锈钢水草剪刀加长草缸波浪剪鱼缸造景夹修剪工具套装夹子镊子鱼-淘宝网 (taobao.com)</a></p>
</li>
</ol></section>
<section><h1>布置图<a href="#布置图"><span>#</span></a></h1><p></p><figure><img src="http://imgbed.leihub.cn/img/07504f9152237f546e3d152174df5e9.png" alt="07504f9152237f546e3d152174df5e9" /><figcaption>07504f9152237f546e3d152174df5e9</figcaption></figure><p></p></section>
<section><h1>开缸记录<a href="#开缸记录"><span>#</span></a></h1><p>2024/07/13（第一天）：</p><p>水草刚刚种下去，因为是第一次种，没太掌握好技巧，水草种的参差不齐。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/39647606e3b0399a35c3b458cbed8cb.jpg" alt="39647606e3b0399a35c3b458cbed8cb" /><figcaption>39647606e3b0399a35c3b458cbed8cb</figcaption></figure><p></p><p>2024/07/18：</p><p>水草逐渐长起来了，绿宫廷长得比较快，已经都没过二氧化碳细化器了，血宫廷就长得稍微慢一点，而迷你牛马感觉一点也没动。快一周了，也要准备买点黑壳虾了，防止涨水藻，</p><p></p><figure><img src="http://imgbed.leihub.cn/img/a4b1b95910c90a96eaf093946ba1c98.jpg" alt="a4b1b95910c90a96eaf093946ba1c98" /><figcaption>a4b1b95910c90a96eaf093946ba1c98</figcaption></figure><p></p></section>
<section><h1>参考<a href="#参考"><span>#</span></a></h1><p><a href="https://www.bilibili.com/video/BV1jL4y157wv/?spm_id_from=333.337.search-card.all.click&amp;vd_source=cb5ce25be8ee6f5af6871a77c17b2b21" target="_blank">保姆级教程 | 如何搭建起人生的第一口小草缸_哔哩哔哩_bilibili</a></p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/813/</id>
      <title type="text">基于steamcmd+zerotier搭建森林、未转变者、幻兽帕鲁等游戏服务器</title>
      <published>2024-06-24T12:48:50.000Z</published>
      <updated>2025-11-14T15:18:46.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/813/"/>
      <summary type="text">引言 之前我写了一篇文章内网访问：使用Zerotier进行打洞 - 阿雷的小窝 leihub.cn ，通过zerotier实现虚拟局域网组网，可以在外网访问内网服务。zerotier还有个玩法，那就是让处于不同地区的人进行局域网游戏，比如我</summary>
      <content type="html"><![CDATA[<section><h2>引言<a href="#引言"><span>#</span></a></h2><p>之前我写了一篇文章<a href="/archives/692/">内网访问：使用Zerotier进行打洞 - 阿雷的小窝 (leihub.cn)</a>，通过zerotier实现虚拟局域网组网，可以在外网访问内网服务。zerotier还有个玩法，那就是让处于不同地区的人进行局域网游戏，比如我的世界、泰拉瑞亚、幻兽帕鲁和森林等联机游戏。</p></section>
<section><h2>准备工作<a href="#准备工作"><span>#</span></a></h2><ul>
<li>系统要求：确保你的Win10系统具备至少8GB的内存和稳定的网络连接。</li>
</ul></section>
<section><h2>安装SteamCMD并下载The Forest服务器<a href="#安装steamcmd并下载the-forest服务器"><span>#</span></a></h2><ul>
<li>
<p>下载适用于 Windows 系统的 SteamCMD：<a href="https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip" target="_blank">https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip</a></p>
</li>
<li>
<p>下载文件后解压压缩包双击运行<code>steamcmd.exe</code>，就会自动更新运行<code>steamcmd</code>。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240624193924457.png" alt="image-20240624193924457" /><figcaption>image-20240624193924457</figcaption></figure><p></p>
</li>
<li>
<p>设置游戏安装目录(可选)，不设置的话默认将游戏安装在<code>\steamCMD\steamapps\common</code>目录。</p>
<p>在命令行中输入以下命令，指定游戏安装目录，</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>force_install_dir C:\Users\Administrator\Desktop\Forest</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p>匿名登录steam(国内服务器搭建可能存在登录不了的情况，重新打开steamcmd有几率成功)</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>login</span><span> </span><span>anonymous</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
</li>
<li>
<p>下载The Forest游戏</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>app_update 556450 validate</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240624194519575.png" alt="image-20240624194519575" /><figcaption>image-20240624194519575</figcaption></figure><p></p>
</li>
<li>
<p>执行完成后，在<code>\steamCMD\steamapps\common</code>多了一个<code>TheForestDedicatedServer</code>文件夹，<code>TheForestDedicatedServer.exe</code>这个就是我们需要的森林服务端文件，双击打开即可运行。然后关闭，去配置一下服务端文件。</p>
</li>
</ul></section>
<section><h2>配置The Forest服务器<a href="#配置the-forest服务器"><span>#</span></a></h2><ul>
<li>
<p>森林服务器的配置文件存在另外一个路径中。</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>C:\Users\Administrator\AppData\LocalLow\SKS\TheForestDedicatedServer\ds\server.cfg</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p>修改配置文件：根据需求调整服务器的配置，如设置服务器名称、密码、难度等。</p>
<div><div><div><figure><figcaption><span></span><span>Terminal window</span><span>展开</span><span>收起</span></figcaption><pre><code><div><div><div>1</div></div><div><span>//</span><span> </span><span>专用服务器设置。</span></div></div><div><div><div>2</div></div><div><span>//</span><span> </span><span>服务器IP地址</span><span> </span><span>-</span><span> </span><span>注意：如果有路由器，此地址为内部地址，需要配置端口转发</span></div></div><div><div><div>3</div></div><div><span>serverIP</span><span>  </span><span>172.28.64.43</span><span> </span><span>#这个是服务器的zerotier内网地址</span></div></div><div><div><div>4</div></div><div><span>//</span><span> </span><span>Steam</span><span> </span><span>通信端口</span><span> </span><span>-</span><span> </span><span>注意：如果有路由器，你需要打开这个端口。</span></div></div><div><div><div>5</div></div><div><span>serverSteamPort</span><span> </span><span>8766</span></div></div><div><div><div>6</div></div><div><span>//</span><span> </span><span>游戏通信端口</span><span> </span><span>-</span><span> </span><span>注意：如果有路由器，你需要打开这个端口。</span></div></div><div><div><div>7</div></div><div><span>serverGamePort</span><span> </span><span>27015</span></div></div><div><div><div>8</div></div><div><span>//</span><span> </span><span>查询通信端口</span><span> </span><span>-</span><span> </span><span>注意：如果有路由器，你需要打开这个端口。</span></div></div><div><div><div>9</div></div><div><span>serverQueryPort</span><span> </span><span>27016</span></div></div><div><div><div>10</div></div><div><span>//</span><span> </span><span>服务器显示名称</span></div></div><div><div><div>11</div></div><div><span>serverName</span><span> </span><span>aleileilei</span></div></div><div><div><div>12</div></div><div><span>//</span><span> </span><span>玩家最大数量</span></div></div><div><div><div>13</div></div><div><span>serverPlayers</span><span> </span><span>4</span></div></div><div><div><div>14</div></div><div><span>//</span><span> </span><span>启用</span><span> </span><span>VAC</span><span> (Valve </span><span>反作弊系统</span><span>)。必须设置为关闭或开启</span></div></div><div><div><div>15</div></div><div><span>enableVAC</span><span> </span><span>off</span></div></div><div><div><div>16</div></div><div><span>//</span><span> </span><span>服务器密码。空白表示无密码</span></div></div><div><div><div>17</div></div><div><span>serverPassword</span><span> </span><span>12345678</span></div></div><div><div><div>18</div></div><div><span>//</span><span> </span><span>服务器管理密码。空白表示无密码</span></div></div><div><div><div>19</div></div><div><span>serverPasswordAdmin</span><span> </span><span>12345678</span></div></div><div><div><div>20</div></div><div><span>//</span><span> </span><span>你的</span><span> </span><span>Steam</span><span> </span><span>账户名。空白表示匿名</span></div></div><div><div><div>21</div></div><div><span>serverSteamAccount</span></div></div><div><div><div>22</div></div><div><span>//</span><span> </span><span>服务器自动保存间隔时间（分钟）-</span><span> </span><span>最短时间为15分钟，默认时间为30分钟</span></div></div><div><div><div>23</div></div><div><span>serverAutoSaveInterval</span><span> </span><span>30</span></div></div><div><div><div>24</div></div><div><span>//</span><span> </span><span>游戏难度模式。必须设置为</span><span> </span><span>Peaceful、Normal</span><span> </span><span>或</span><span> </span><span>Hard</span></div></div><div><div><div>25</div></div><div><span>difficulty</span><span> </span><span>Normal</span></div></div><div><div><div>26</div></div><div><span>//</span><span> </span><span>新建或继续游戏。必须设置为</span><span> </span><span>New</span><span> </span><span>或</span><span> </span><span>Continue</span></div></div><div><div><div>27</div></div><div><span>initType</span><span> </span><span>Continue</span></div></div><div><div><div>28</div></div><div><span>//</span><span> </span><span>保存游戏的槽位。必须设置为</span><span> </span><span>1、2、3、4</span><span> </span><span>或</span><span> </span><span>5</span></div></div><div><div><div>29</div></div><div><span>slot</span><span> </span><span>1</span></div></div><div><div><div>30</div></div><div><span>//</span><span> </span><span>显示事件日志。必须设置为关闭或开启</span></div></div><div><div><div>31</div></div><div><span>showLogs</span><span> </span><span>on</span></div></div><div><div><div>32</div></div><div><span>//</span><span> </span><span>服务器管理员联系邮箱</span></div></div><div><div><div>33</div></div><div><span>serverContact</span><span> </span><span>email@gmail.com</span></div></div><div><div><div>34</div></div><div><span>//</span><span> </span><span>无敌人模式</span></div></div><div><div><div>35</div></div><div><span>veganMode</span><span> </span><span>off</span></div></div><div><div><div>36</div></div><div><span>//</span><span> </span><span>白天无敌人模式</span></div></div><div><div><div>37</div></div><div><span>vegetarianMode</span><span> </span><span>off</span></div></div><div><div><div>38</div></div><div><span>//</span><span> </span><span>加载保存时重置所有建筑孔洞</span></div></div><div><div><div>39</div></div><div><span>resetHolesMode</span><span> </span><span>off</span></div></div><div><div><div>40</div></div><div><span>//</span><span> </span><span>睡觉时重新生长10%被砍伐的树木</span></div></div><div><div><div>41</div></div><div><span>treeRegrowMode</span><span> </span><span>off</span></div></div><div><div><div>42</div></div><div><span>//</span><span> </span><span>允许破坏建筑</span></div></div><div><div><div>43</div></div><div><span>allowBuildingDestruction</span><span> </span><span>off</span></div></div><div><div><div>44</div></div><div><span>//</span><span> </span><span>允许在创意模式中出现敌人</span></div></div><div><div><div>45</div></div><div><span>allowEnemiesCreativeMode</span><span> </span><span>off</span></div></div><div><div><div>46</div></div><div><span>//</span><span> </span><span>允许客户端使用内置调试控制台</span></div></div><div><div><div>47</div></div><div><span>allowCheats</span><span> </span><span>on</span></div></div><div><div><div>48</div></div><div><span>//</span><span> </span><span>使用完整的武器伤害值攻击其他玩家</span></div></div><div><div><div>49</div></div><div><span>realisticPlayerDamage</span><span> </span><span>off</span></div></div><div><div><div>50</div></div><div><span>//</span><span> </span><span>允许定义自定义保存槽文件夹，留空则使用默认位置</span></div></div><div><div><div>51</div></div><div><span>saveFolderPath</span></div></div><div><div><div>52</div></div><div><span>//</span><span> </span><span>无客户端连接时的目标FPS</span></div></div><div><div><div>53</div></div><div><span>targetFpsIdle</span><span> </span><span>5</span></div></div><div><div><div>54</div></div><div><span>//</span><span> </span><span>至少有一个客户端连接时的目标FPS</span></div></div><div><div><div>55</div></div><div><span>targetFpsActive</span><span> </span><span>60</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div>
</li>
<li>
<p>完成服务器配置后，即可运行服务端了，这个时候会打开两个窗口（注意不要关了），当命令行中输出<code>Dedicated Server Running</code>时就代表服务器已经运行成功了。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240624200044829.png" alt="image-20240624200044829" /><figcaption>image-20240624200044829</figcaption></figure><p></p>
</li>
<li>
<p>不过此时游戏服务器是运行在内网的，没有外网ip的情况下，其他人是无法加入游戏的。接下来需要通过搭建虚拟局域网，让玩家加入虚拟局域网，得以进入游戏服务器。</p>
</li>
</ul></section>
<section><h2>使用ZeroTier进行远程联机<a href="#使用zerotier进行远程联机"><span>#</span></a></h2><ul>
<li>
<p>ZeroTier作为一款简单易用的VPN解决方案，可以帮助玩家建立安全的虚拟局域网。使用zerotier进行联机，只要能够打洞成功，整体的延迟还是比较低的，没有出现卡顿的情况。</p>
</li>
<li>
<p>安装ZeroTier：在服务器和客户端设备上下载并安装ZeroTier软件，并加入相同的网络。</p>
</li>
<li>
<p>创建和加入网络：在ZeroTier界面创建新的网络，设置网络ID和密码，并分享给其他玩家。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240624195601203.png" alt="image-20240624195601203" /><figcaption>image-20240624195601203</figcaption></figure><p></p>
</li>
<li>
<p>其他玩家加入网络就进入了局域网，通过在游戏中搜索服务器的内网ip地址，或者查看局域网游戏，就可以看到游戏服务器了，选择加入服务器即可进行游戏。</p>
</li>
<li>
<p>我遇到了一个bug，在游戏中局域网无法搜索到房间，我的解决方法是在<code>steam页面-查看-游戏服务器</code>，就可以看到局域网下的服务器，选择连接即可。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240624200246706.png" alt="image-20240624200246706" /><figcaption>image-20240624200246706</figcaption></figure><p></p>
</li>
<li>
<p>输入密码，点击加入服务器，就会自动打开游戏进入联机房间。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240624200600979.png" alt="image-20240624200600979" /><figcaption>image-20240624200600979</figcaption></figure><p></p>
</li>
</ul></section>
<section><h2>幻兽帕鲁<a href="#幻兽帕鲁"><span>#</span></a></h2><p>使用steamcmd安装幻兽帕鲁。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>app_update 2394010 validate</span></div></div></code></pre><div><div></div><div></div></div></figure></div><blockquote><p>默认配置文件位于steamcmd/steamapps/common/PalServer/Pal/Saved/Config/WindowsServer/PalWorldSettings.ini</p></blockquote><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>[</span><span>/Script/Pal.PalGameWorldSettings</span><span>]</span></div></div><div><div><div>2</div></div><div><span>OptionSettings=(</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>Difficulty=None, </span><span>// 游戏难度</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>DayTimeSpeedRate=</span><span>1</span><span>, </span><span>// 白天时间速度比率</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>NightTimeSpeedRate=</span><span>1</span><span>, </span><span>// 夜晚时间速度比率</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>ExpRate=</span><span>1</span><span>, </span><span>// 经验值获取速率</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>PalCaptureRate=</span><span>1</span><span>, </span><span>// 精灵捕捉速率</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>PalSpawnNumRate=</span><span>1</span><span>, </span><span>// 精灵生成数量速率</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>PalDamageRateAttack=</span><span>1</span><span>, </span><span>// 精灵攻击力伤害速率</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>PalDamageRateDefense=</span><span>1</span><span>, </span><span>// 精灵防御力伤害速率</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>PlayerDamageRateAttack=</span><span>1</span><span>, </span><span>// 玩家攻击力伤害速率</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>PlayerDamageRateDefense=</span><span>1</span><span>, </span><span>// 玩家防御力伤害速率</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>PlayerStomachDecreaceRate=</span><span>1</span><span>, </span><span>// 玩家饥饿度消耗速率</span></div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>PlayerStaminaDecreaceRate=</span><span>1</span><span>, </span><span>// 玩家耐力消耗速率</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>PlayerAutoHPRegeneRate=</span><span>1</span><span>, </span><span>// 玩家自动恢复生命值速率</span></div></div><div><div><div>16</div></div><div><span><span>    </span></span><span>PlayerAutoHpRegeneRateInSleep=</span><span>1</span><span>, </span><span>// 玩家在睡眠时自动恢复生命值速率</span></div></div><div><div><div>17</div></div><div><span><span>    </span></span><span>PalStomachDecreaceRate=</span><span>1</span><span>, </span><span>// 精灵饥饿度消耗速率</span></div></div><div><div><div>18</div></div><div><span><span>    </span></span><span>PalStaminaDecreaceRate=</span><span>1</span><span>, </span><span>// 精灵耐力消耗速率</span></div></div><div><div><div>19</div></div><div><span><span>    </span></span><span>PalAutoHPRegeneRate=</span><span>1</span><span>, </span><span>// 精灵自动恢复生命值速率</span></div></div><div><div><div>20</div></div><div><span><span>    </span></span><span>PalAutoHpRegeneRateInSleep=</span><span>1</span><span>, </span><span>// 精灵在睡眠时自动恢复生命值速率</span></div></div><div><div><div>21</div></div><div><span><span>    </span></span><span>BuildObjectDamageRate=</span><span>1</span><span>, </span><span>// 建筑对象损坏速率</span></div></div><div><div><div>22</div></div><div><span><span>    </span></span><span>BuildObjectDeteriorationDamageRate=</span><span>1</span><span>, </span><span>// 建筑对象老化损坏速率</span></div></div><div><div><div>23</div></div><div><span><span>    </span></span><span>CollectibleObjectHpRate=</span><span>1</span><span>, </span><span>// 可收集物品的生命值速率</span></div></div><div><div><div>24</div></div><div><span><span>    </span></span><span>CollectionObjectRespawnSpeedRate=</span><span>1</span><span>, </span><span>// 可收集物品的重生速度速率</span></div></div><div><div><div>25</div></div><div><span><span>    </span></span><span>EnemyDropItemRate=</span><span>1</span><span>, </span><span>// 敌人掉落物品速率</span></div></div><div><div><div>26</div></div><div><span><span>    </span></span><span>DeathPenalty=None, </span><span>// 死亡惩罚</span></div></div><div><div><div>27</div></div><div><span><span>    </span></span><span>bEnablePlayerToPlayerDamage=False, </span><span>// 是否允许玩家之间互相伤害</span></div></div><div><div><div>28</div></div><div><span><span>    </span></span><span>bEnableFriendlyFire=False, </span><span>// 是否允许友方伤害</span></div></div><div><div><div>29</div></div><div><span><span>    </span></span><span>bEnableInvaderEnemy=True, </span><span>// 是否启用入侵者敌人</span></div></div><div><div><div>30</div></div><div><span><span>    </span></span><span>bActiveUNKO=False, </span><span>// 是否激活UNKO功能</span></div></div><div><div><div>31</div></div><div><span><span>    </span></span><span>bEnableAimAssistPad=True, </span><span>// 是否启用手柄瞄准辅助</span></div></div><div><div><div>32</div></div><div><span><span>    </span></span><span>bEnableAimAssistKeyboard=False, </span><span>// 是否启用键盘瞄准辅助</span></div></div><div><div><div>33</div></div><div><span><span>    </span></span><span>DropItemMaxNum=</span><span>3000</span><span>, </span><span>// 最大掉落物品数量</span></div></div><div><div><div>34</div></div><div><span><span>    </span></span><span>DropItemMaxNum_UNKO=</span><span>100</span><span>, </span><span>// UNKO模式下的最大掉落物品数量</span></div></div><div><div><div>35</div></div><div><span><span>    </span></span><span>BaseCampMaxNum=</span><span>128</span><span>, </span><span>// 最大基地数量</span></div></div><div><div><div>36</div></div><div><span><span>    </span></span><span>BaseCampWorkerMaxNum=</span><span>15</span><span>, </span><span>// 每个基地最多工人数量</span></div></div><div><div><div>37</div></div><div><span><span>    </span></span><span>DropItemAliveMaxHours=</span><span>1</span><span>, </span><span>// 掉落物品存活的最长时间（小时）</span></div></div><div><div><div>38</div></div><div><span><span>    </span></span><span>bAutoResetGuildNoOnlinePlayers=False, </span><span>// 是否自动重置无在线成员的公会</span></div></div><div><div><div>39</div></div><div><span><span>    </span></span><span>AutoResetGuildTimeNoOnlinePlayers=</span><span>72</span><span>, </span><span>// 自动重置无在线成员的公会的时间（小时）</span></div></div><div><div><div>40</div></div><div><span><span>    </span></span><span>GuildPlayerMaxNum=</span><span>20</span><span>, </span><span>// 公会最大成员数量</span></div></div><div><div><div>41</div></div><div><span><span>    </span></span><span>PalEggDefaultHatchingTime=</span><span>0</span><span>, </span><span>// 精灵蛋孵化默认时间</span></div></div><div><div><div>42</div></div><div><span><span>    </span></span><span>WorkSpeedRate=</span><span>1</span><span>, </span><span>// 工作速度比率</span></div></div><div><div><div>43</div></div><div><span><span>    </span></span><span>bIsMultiplay=False, </span><span>// 是否为多人模式</span></div></div><div><div><div>44</div></div><div><span><span>    </span></span><span>bIsPvP=False, </span><span>// 是否为PvP模式</span></div></div><div><div><div>45</div></div><div><span><span>    </span></span><span>bCanPickupOtherGuildDeathPenaltyDrop=False, </span><span>// 是否可以拾取其他公会死亡惩罚掉落的物品</span></div></div><div><div><div>46</div></div><div><span><span>    </span></span><span>bEnableNonLoginPenalty=True, </span><span>// 是否启用非登录惩罚</span></div></div><div><div><div>47</div></div><div><span><span>    </span></span><span>bEnableFastTravel=True, </span><span>// 是否启用快速旅行功能</span></div></div><div><div><div>48</div></div><div><span><span>    </span></span><span>bIsStartLocationRandom=True, </span><span>// 是否随机选择出生点</span></div></div><div><div><div>49</div></div><div><span><span>    </span></span><span>bExistPlayerAfterLogout=False, </span><span>// 玩家登出后是否仍然存在</span></div></div><div><div><div>50</div></div><div><span><span>    </span></span><span>bEnableDefenseOtherGuildPlayer=False, </span><span>// 是否启用防御其他公会玩家的功能</span></div></div><div><div><div>51</div></div><div><span><span>    </span></span><span>CoopPlayerMaxNum=</span><span>4</span><span>, </span><span>// 合作模式最大玩家数量</span></div></div><div><div><div>52</div></div><div><span><span>    </span></span><span>ServerPlayerMaxNum=</span><span>32</span><span>, </span><span>// 服务器最大玩家数量</span></div></div><div><div><div>53</div></div><div><span><span>    </span></span><span>ServerName=</span><span>"Default Palworld Server"</span><span>, </span><span>// 服务器名称</span></div></div><div><div><div>54</div></div><div><span><span>    </span></span><span>ServerDescription=</span><span>""</span><span>, </span><span>// 服务器描述</span></div></div><div><div><div>55</div></div><div><span><span>    </span></span><span>AdminPassword=</span><span>""</span><span>, </span><span>// 管理员密码</span></div></div><div><div><div>56</div></div><div><span><span>    </span></span><span>ServerPassword=</span><span>""</span><span>, </span><span>// 服务器密码</span></div></div><div><div><div>57</div></div><div><span><span>    </span></span><span>PublicPort=</span><span>8211</span><span>, </span><span>// 公共端口号</span></div></div><div><div><div>58</div></div><div><span><span>    </span></span><span>PublicIP=</span><span>""</span><span>, </span><span>// 公共IP地址</span></div></div><div><div><div>59</div></div><div><span><span>    </span></span><span>RCONEnabled=False, </span><span>// 是否启用远程控制台</span></div></div><div><div><div>60</div></div><div><span><span>    </span></span><span>RCONPort=</span><span>25575</span><span>, </span><span>// 远程控制台端口号</span></div></div><div><div><div>61</div></div><div><span><span>    </span></span><span>Region=</span><span>""</span><span>, </span><span>// 服务器所在地区</span></div></div><div><div><div>62</div></div><div><span><span>    </span></span><span>bUseAuth=True, </span><span>// 是否使用身份验证</span></div></div><div><div><div>63</div></div><div><span><span>    </span></span><span>BanListURL=</span><span>"https://api.palworldgame.com/api/banlist.txt"</span><span> </span><span>// 封禁列表URL</span></div></div><div><div><div>64</div></div><div><span>)</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section>
<section><h2>泰拉瑞亚<a href="#泰拉瑞亚"><span>#</span></a></h2><p>使用steamcmd安装游戏。</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>app_update </span><span>105600</span><span> validate</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section>
<section><h2>未转变者<a href="#未转变者"><span>#</span></a></h2><p>安装游戏</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>app_update 1110390 validate</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>下载完成之后在<code>SteamCMD\steamapps\common\U3DS\</code>找到服务端启动Unturned.exe双击启动，运行一遍之后输入shutdown关闭服务器，启动一次服务器是为了让服务端生成地图和相应的配置文件配置。</p><p>相应文件在路径<code>steamCMD\steamapps\common\U3DS\Servers\Default\Server</code>中，里面有一个<code>commands.dat</code>文件，打开编辑文件，按实际需求填入以下指令</p>

<table><thead><tr><th>配置代码</th><th>功能</th><th>备注</th></tr></thead><tbody><tr><td>Name</td><td>服务器名称</td><td></td></tr><tr><td>Map</td><td>地图类型</td><td>默认PEI</td></tr><tr><td>Password</td><td>服务器密码</td><td>公开不填</td></tr><tr><td>Welcome</td><td>服务器欢迎语</td><td></td></tr><tr><td>Maxplayer</td><td>服务器人数</td><td>根据服务器配置填</td></tr><tr><td>Mode</td><td>服务器难度</td><td>可填Eazy,Normal,Hard</td></tr><tr><td>Perspective</td><td>服务器视角限制</td><td>可填First,Third,Both,Vehicle</td></tr><tr><td>PVE</td><td>开启PVE模式</td><td>留空为PVP</td></tr><tr><td>Cheats</td><td>服务器作弊模式</td><td>开True关False</td></tr><tr><td>Port</td><td>服务器端口</td><td>默认27015,更改需要开放端口</td></tr></tbody></table><p>完成之后不要着急开服，新版本加入了Steam秘钥，不添加Steam秘钥开服是可以开的，但是玩家进入不了游戏。</p><p>进入网站<a href="https://steamcommunity.com/dev/managegameservers" target="_blank">steamcommunity.com</a>，Steam 游戏服务器账户管理 点击打开，访问不了的话就需要使用魔法了，创建一个如图所示的登陆令牌。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240624203035476.png" alt="image-20240624203035476" /><figcaption>image-20240624203035476</figcaption></figure><p></p><p>申请完之后复制秘钥，找到<code>\steamCMD\steamapps\common\U3DS\Servers\Default</code>文件夹下的Config.json文件，编辑该文件，找到 Login_Token 填入复制好的秘钥。
</p><figure><img src="http://imgbed.leihub.cn/img/image-20240624203623820.png" alt="image-20240624203623820" /><figcaption>image-20240624203623820</figcaption></figure><p></p><p>配置完成之后双击U3DS文件夹下的Unturned.exe文件即可开服。</p></section>
<section><h2>结语<a href="#结语"><span>#</span></a></h2><p>大部分steam游戏服务器的开设都大同小异，基本上都可以通过上述方法进行开服，然后使用zerotier进行异地组网联机，希望你能进请享受联机带来的乐趣。</p></section>
<section><h2>参考<a href="#参考"><span>#</span></a></h2><ul>
<li><a href="https://developer.valvesoftware.com/wiki/SteamCMD:zh-cn" target="_blank">Steam 控制台客户端 - Valve Developer Community (valvesoftware.com)</a></li>
<li><a href="https://www.bilibili.com/read/cv25140869/" target="_blank">【森林】The Forest服务器搭建教程(适用于Windows) - 哔哩哔哩 (bilibili.com)</a></li>
<li><a href="https://blog.csdn.net/weixin_45749354/article/details/128651538" target="_blank">Unturned未转变者 Windows SteamCMD 2023最新开服教程-全网最全_steamcmd开服教程-CSDN博客</a></li>
</ul></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/802/</id>
      <title type="text">Hexo + Serverless免费部署属于自己的个人博客</title>
      <published>2024-06-23T06:38:50.000Z</published>
      <updated>2024-06-23T06:39:15.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/802/"/>
      <summary type="text">引言 之前许多其他的博客都讲到了将Hexo博客部署到github pages，vercel等网站进行托管，这些托管网站大都在境外，访问速度堪忧。本文将详细指导你如何利用腾讯云的Serverless服务和Hexo框架，在国内轻松部署自己的博客</summary>
      <content type="html"><![CDATA[<section><h3>引言<a href="#引言"><span>#</span></a></h3><p>之前许多其他的博客都讲到了将Hexo博客部署到github pages，vercel等网站进行托管，这些托管网站大都在境外，访问速度堪忧。本文将详细指导你如何利用腾讯云的Serverless服务和Hexo框架，在国内轻松部署自己的博客。</p></section>
<section><h3>一、准备阶段<a href="#一准备阶段"><span>#</span></a></h3><ol>
<li>
<p>安装Node.js环境</p>
<p>官网下载地址：<a href="http://nodejs.cn/download/%EF%BC%8C%E6%A0%B9%E6%8D%AE%E8%87%AA%E5%B7%B1%E7%94%B5%E8%84%91%E9%80%89%E6%8B%A932%E4%BD%8D%E8%BF%98%E6%98%AF64%E4%BD%8D%E9%80%89%E6%8B%A9%E8%BF%9B%E8%A1%8C%E5%AE%89%E8%A3%85%E3%80%82%E7%89%88%E6%9C%AC%E9%9C%80%E8%A6%81" target="_blank">http://nodejs.cn/download/，根据自己电脑选择32位还是64位选择进行安装。版本需要</a> &gt; 12，因为Serverless Cloud Framework只支持12以后的版本。</p>
</li>
<li>
<p>安装Hexo</p>
<p>进入安装hexo的文件夹，按住shift+右键，进入powershell命令行，执行以下命令使用nodejs安装hexo。</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>npm</span><span> </span><span>install</span><span> </span><span>hexo-cli</span><span> </span><span>-g</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
</li>
<li>
<p>安装最新版本的 Serverless Cloud Framework</p>
<p>在命令行中运行如下命令：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>npm</span><span> </span><span>i</span><span> </span><span>-g</span><span> </span><span>serverless-cloud-framework</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
<p>如果之前您已经安装过 Serverless Cloud Framework，可以通过以下命令升级到最新版。</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>npm</span><span> </span><span>update</span><span> </span><span>-g</span><span> </span><span>serverless-cloud-framework</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
<p>安装完毕后，通过运行<code>scf -v</code>命令，查看 Serverless Cloud Framework 的版本信息：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>scf</span><span> </span><span>-v</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
</li>
<li>
<p>开通腾讯云COS和CDN</p>
</li>
</ol></section>
<section><h3>二、Hexo博客初始化与配置<a href="#二hexo博客初始化与配置"><span>#</span></a></h3><ol>
<li>
<p>创建一个新的Hexo博客</p>
<p>执行下列命令，Hexo 将会在指定文件夹中新建所需要的文件。</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>hexo</span><span> </span><span>init</span><span> </span><span>hexo</span><span>   </span><span># 生成 Hexo 目录</span></div></div><div><div><div>2</div></div><div><span>$</span><span> </span><span>cd</span><span> </span><span>hexo</span><span>  </span><span># 进入Hexo目录</span></div></div><div><div><div>3</div></div><div><span>$</span><span> </span><span>npm</span><span> </span><span>install</span><span>  </span><span>#安装相关依赖</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
<p>新建完成后，指定文件夹的目录如下：</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>.</span></div></div><div><div><div>2</div></div><div><span>├── _config.yml</span></div></div><div><div><div>3</div></div><div><span>├── package.json</span></div></div><div><div><div>4</div></div><div><span>├── scaffolds</span></div></div><div><div><div>5</div></div><div><span>├── source</span></div></div><div><div><div>6</div></div><div><span>|   ├── _drafts</span></div></div><div><div><div>7</div></div><div><span>|   └── _posts</span></div></div><div><div><div>8</div></div><div><span>└── themes</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
</li>
<li>
<p>安装完成后，可以通过<code>hexo g</code>命令生成静态页面：</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>hexo</span><span> </span><span>g</span><span>   </span><span># generate</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
<p>如果希望在本地查看效果，也可以运行下列命令，通过浏览器访问 <code>localhost:4000</code> 查看页面效果。</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>hexo</span><span> </span><span>s</span><span>   </span><span># server</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
</li>
</ol><p>​		如果可以看到博客页面就说明已配置成功，接下来可以将博客文件部署到腾讯云Serverless了。</p></section>
<section><h3>三、部署到腾讯云<a href="#三部署到腾讯云"><span>#</span></a></h3><ol>
<li>
<p>准备工作</p>
<ul>
<li>已拥有自定义域名（例如 <a href="http://www.example.com%EF%BC%89%EF%BC%8C%E5%B9%B6%E7%A1%AE%E4%BF%9D%E8%BE%93%E5%85%A5%E7%9A%84%E5%9F%9F%E5%90%8D%E5%B7%B2%E5%A4%87%E6%A1%88%E3%80%82" target="_blank">www.example.com），并确保输入的域名已备案。</a></li>
<li>如果需要 HTTPS 访问，可以申请证书并且 <a href="https://console.cloud.tencent.com/ssl" target="_blank">获得证书 ID</a> （例如：certificateId : axE1bo3），个人站点可以直接申请 <a href="https://cloud.tencent.com/document/product/400/8422" target="_blank">域名型（DV）免费 SSL 证书</a>。</li>
<li>账号实名并已经 <a href="https://console.cloud.tencent.com/cdn" target="_blank">开通 CDN 服务</a>。</li>
</ul>
</li>
<li>
<p>配置部署文件</p>
<p>在<code>hexo</code>目录下，创建<code>serverless.yml</code>文件。</p>
<div><div><div><figure><figcaption><span>serverless.yml</span><span>展开</span><span>收起</span></figcaption><pre><code><div><div><div>1</div></div><div><span>component</span><span>: </span><span>website</span></div></div><div><div><div>2</div></div><div><span>name</span><span>: </span><span>myWebsite</span></div></div><div><div><div>3</div></div><div><span>app</span><span>: </span><span>websiteApp</span></div></div><div><div><div>4</div></div><div><span>stage</span><span>: </span><span>dev</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span>inputs</span><span>:</span></div></div><div><div><div>7</div></div><div><span>   </span><span>src</span><span>:</span></div></div><div><div><div>8</div></div><div><span>     </span><span>src</span><span>: </span><span>./public</span></div></div><div><div><div>9</div></div><div><span>     </span><span>index</span><span>: </span><span>index.html</span></div></div><div><div><div>10</div></div><div><span>     </span><span>error</span><span>: </span><span>index.html</span></div></div><div><div><div>11</div></div><div><span>   </span><span>region</span><span>: </span><span>ap-shanghai</span><span>  </span><span>#cos存储桶的地域</span></div></div><div><div><div>12</div></div><div><span>   </span><span>bucketName</span><span>: </span><span>my-hexo-bucket</span><span>  </span><span>#新建存储桶的名字</span></div></div><div><div><div>13</div></div><div><span>   </span><span>protocol</span><span>: </span><span>https</span></div></div><div><div><div>14</div></div><div><span>   </span><span># 新增的 CDN 自定义域名配置</span></div></div><div><div><div>15</div></div><div><span>   </span><span>hosts</span><span>:</span></div></div><div><div><div>16</div></div><div><span><span>     </span></span><span>- </span><span>host</span><span>: </span><span>www.example.com</span><span> </span><span># 希望配置的自定义域名</span></div></div><div><div><div>17</div></div><div><span>       </span><span>https</span><span>:</span></div></div><div><div><div>18</div></div><div><span>         </span><span>switch</span><span>: </span><span>on</span></div></div><div><div><div>19</div></div><div><span>         </span><span>http2</span><span>: </span><span>off</span></div></div><div><div><div>20</div></div><div><span>         </span><span>certInfo</span><span>:</span></div></div><div><div><div>21</div></div><div><span>           </span><span>certId</span><span>: </span><span>'axE1bo3'</span></div></div><div><div><div>22</div></div><div><span>           </span><span># certificate: 'xxx'</span></div></div><div><div><div>23</div></div><div><span>           </span><span># privateKey: 'xxx'</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div>
</li>
<li>
<p>部署服务</p>
<p>再次通过以下命令进行部署，并可以添加 <code>--debug</code> 参数查看部署过程中的信息。</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>scf</span><span> </span><span>deploy</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
<p>如您的账号未等率腾讯云，您可以直接通过<strong>微信</strong>扫描命令行中的二维码进行授权登录和注册。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240622225322206.png" alt="image-20240622225322206" /><figcaption>image-20240622225322206</figcaption></figure><p></p>
<p>部署完成后，在命令行的输出中可以查看到一个以 <code>.cdn.dnsv1.com</code> 为后缀的 CNAME 域名。在 DNS 服务商（推荐腾讯云）处设置好对应的 CNAME 并生效后，即可访问自定义 HTTPS 域名。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240622225530167.png" alt="image-20240622225530167" /><figcaption>image-20240622225530167</figcaption></figure><p></p>
<p>访问自定义的cdn域名，即可查看您的 Serverless Hexo 站点。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240622225853973.png" alt="image-20240622225853973" /><figcaption>image-20240622225853973</figcaption></figure><p></p>
</li>
<li>
<p>删除项目</p>
<p>在 serverless.yml 文件所在的目录下，通过以下命令移除部署的静态网站 Website 服务。移除该应用时，只删除云函数相关的配置、代码。关联的其他云资源（如 COS、CLS 等），平台均不会关联删除，需要自行前往对应产品控制台删除，避免不必要的计费。</p>
</li>
</ol></section>
<section><h3>总结<a href="#总结"><span>#</span></a></h3><p>通过腾讯云的Serverless服务和Hexo的强大功能，你可以快速部署并维护一个高性能、低成本的个人博客。希望本指南能帮助你顺利完成部署，享受写作和分享的乐趣。</p></section>
<section><h3>参考<a href="#参考"><span>#</span></a></h3><ol>
<li><a href="https://cloud.tencent.com/document/product/1154/42990" target="_blank">Serverless 应用中心 安装 Serverless Cloud Framework-快速入门-文档中心-腾讯云 (tencent.com)</a></li>
<li><a href="https://cloud.tencent.com/document/product/1154/41321" target="_blank">Serverless 应用中心 自定义域名及 HTTPS 访问配置-进阶指南-文档中心-腾讯云 (tencent.com)</a></li>
<li><a href="https://cloud.tencent.com/document/product/1154/40217" target="_blank">Serverless 应用中心 部署 Hexo 博客-实践教程-文档中心-腾讯云 (tencent.com)</a></li>
<li><a href="https://hexo.io/zh-cn/" target="_blank">Hexo</a></li>
<li><a href="https://butterfly.js.org/posts/21cfbf15/" target="_blank">Butterfly 安裝文檔(一) 快速開始 | Butterfly</a></li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/798/</id>
      <title type="text">typora+picgo+cos+cdn搭建个人写作环境</title>
      <published>2024-06-22T09:07:02.000Z</published>
      <updated>2024-06-22T09:12:49.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/798/"/>
      <summary type="text">概述 在众多搭建个人笔记系统的工具中，我选择了Typora、腾讯云COS、腾讯云CDN和Picgo的组合，通过这些工具协同工作，能够提供一个简洁、高效的编辑环境，还能确保内容的快速同步和访问，以及图片和资料的高效管理。 一、环境准备和要求 </summary>
      <content type="html"><![CDATA[<section><h3>概述<a href="#概述"><span>#</span></a></h3><p>在众多搭建个人笔记系统的工具中，我选择了Typora、腾讯云COS、腾讯云CDN和Picgo的组合，通过这些工具协同工作，能够提供一个简洁、高效的编辑环境，还能确保内容的快速同步和访问，以及图片和资料的高效管理。</p></section>
<section><h3>一、环境准备和要求<a href="#一环境准备和要求"><span>#</span></a></h3><ul>
<li>Typora是一款简洁、高效的Markdown编辑器，它提供了无缝的写作体验，让用户能够专注于内容创作而不必分心于格式设置。</li>
<li>腾讯云COS提供了安全、稳定的云存储服务，保证了数据的安全性和可靠性。</li>
<li>腾讯云CDN则能够加速全球访问速度，确保您的笔记内容可以快速被访问和加载，套上CDN也可以防止你的COS存储被打爆，收到天价账单。</li>
<li>Picgo作为一个图片管理工具，支持自动上传图片到COS，并配合CDN进行加速，极大地简化了图片资源的管理和使用流程。</li>
</ul></section>
<section><h3>二、配置腾讯云COS<a href="#二配置腾讯云cos"><span>#</span></a></h3><section><h4>（1）腾讯云COS<a href="#1腾讯云cos"><span>#</span></a></h4><p>腾讯云对象存储COS作为搭建个人博客系统的关键组成部分，可以提供稳定和安全的云端存储服务，而且通过其全球分布式的数据中心，确保高效的数据访问速度。</p></section><section><h4>（2）创建存储桶并配置权限<a href="#2创建存储桶并配置权限"><span>#</span></a></h4><ul>
<li>
<p><strong>创建存储桶</strong>: 在COS控制台的“存储桶列表”页面，点击“创建存储桶”按钮。输入您的存储桶名称，该名称在腾讯云中必须是唯一的。</p>
</li>
<li>
<p><strong>选择访问权限</strong>: 在创建存储桶的过程中，您需要设置存储桶的访问权限。为了保证图片可以正常读取，选择“公有读私有写”。这样，您可以在私有环境下上传和修改图片，同时允许公众读取图片，保证博客中图片的正常显示。</p>
</li>
<li>
<p><strong>选择地域</strong>: 根据您自己的位置选择一个合适的地域。这有助于提高访问速度和数据处理效率。例如，如果您在中国，可以选择“北京”、“上海”或“广州”等地域。</p>
<img src="https://imgbed.leihub.cn/img/image-20240622153120976.png" alt="image-20240622153120976" />
</li>
<li>
<p>在存储桶中创建文件夹，进入文件夹中，可以在界面右侧查看存储桶的基本信息</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20240622153822675.png" alt="image-20240622153822675" /><figcaption>image-20240622153822675</figcaption></figure><p></p>
</li>
</ul></section><section><h4>（3）设置COS的API密钥及访问权限<a href="#3设置cos的api密钥及访问权限"><span>#</span></a></h4><blockquote><p>腾讯云目前关闭了查询SecretKey的功能，仅支持在创建时查看和保存。 ，创建密钥后请及时前往控制台查询并保存好SecretKey。</p></blockquote><ol>
<li>
<p><strong>生成API密钥</strong>: 在<a href="https://console.cloud.tencent.com/cam/capi" target="_blank">访问密钥 - 控制台 (tencent.com)</a>中，您可以创建API密钥，该密钥包含访问键和密钥。确保妥善保管这些信息，因为它们是访问您COS资源的凭证。</p>
</li>
<li>
<p><strong>配置访问权限</strong>: 在创建API密钥时，您需要为其设置访问权限。权限设置可以非常细致，包括对特定存储桶或操作的读写权限。</p>
</li>
<li>
<p><strong>安全建议</strong>: 为保持最高安全性，建议仅授予API密钥必要的权限，以完成所需的操作。定期更换密钥也是一个好的安全实践。</p>
</li>
<li>
<p><strong>使用API密钥</strong>: 一旦设置完成，您可以在Typora和其他工具中使用这些API密钥来访问和管理COS中的资源。</p>
<p></p><figure><img src="https://imgbed.leihub.cn/img/image-20240622154310515.png" alt="image-20240622154310515" /><figcaption>image-20240622154310515</figcaption></figure><p></p>
</li>
</ol></section></section>
<section><h3>三、配置腾讯云CDN<a href="#三配置腾讯云cdn"><span>#</span></a></h3><section><h4>（1）腾讯云CDN<a href="#1腾讯云cdn"><span>#</span></a></h4><ul>
<li>通过将内容缓存到离用户最近的服务器节点，CDN能够显著减少内容传输的距离和时间，从而提高用户的访问速度。</li>
<li>通过将请求分发到多个CDN节点，减少了直接对源服务器的请求数量，从而降低了源服务器的负载</li>
<li>腾讯云CDN提供了DDoS防护和SSL/TLS加密等安全功能，进一步提高了网站的安全性，可以通过流量和带宽限制，防止COS被恶意攻击，产生高额费用。</li>
</ul></section><section><h4>（2）创建腾讯云CDN加速域名并关联COS存储桶<a href="#2创建腾讯云cdn加速域名并关联cos存储桶"><span>#</span></a></h4><p>在存储桶列表单击需要配置的存储桶操作栏的<strong>配置管理</strong>，进入配置管理页面，选择<strong>域名管理</strong>。绑定已备案的<strong>自定义域名</strong>，并开启 CDN 加速。</p><p></p><figure><img src="https://imgbed.leihub.cn/img/image-20240622155218894.png" alt="image-20240622155218894" /><figcaption>image-20240622155218894</figcaption></figure><p></p><p>添加域名的配置如下：</p><p><strong>域名</strong>：输入待绑定的自定义域名（例如<code>cdn.leihub.cn</code>）。请确保输入的域名已备案，并已在 DNS 服务商处设置好对应的 CNAME。</p><p><strong>回源鉴权</strong>：对于私有读存储桶，请手动开启回源鉴权以保护源站。 配置完成后，单击<strong>保存</strong>，即可完成对域名的添加。</p><img src="https://imgbed.leihub.cn/img/image-20240622155551550.png" alt="image-20240622155551550" /></section><section><h4>（3）配置CDN的缓存规则和访问控制<a href="#3配置cdn的缓存规则和访问控制"><span>#</span></a></h4><p>在cdn域名管理中，可以对cdn的缓存规则进行配置，推荐开启HTTPS，可以在腾讯云申请ssl证书，也可以自行通过<code>lets encrypt</code>自行申请证书并上传。</p><p></p><figure><img src="https://imgbed.leihub.cn/img/image-20240622155838890.png" alt="image-20240622155838890" /><figcaption>image-20240622155838890</figcaption></figure><p></p><p>在高级配置中，可以对CDN用量封顶进行配置，瞬时访问量超过限值就会报404，禁止访问COS，防止恶意攻击</p><img src="https://imgbed.leihub.cn/img/image-20240622160042190.png" alt="image-20240622160042190" /></section></section>
<section><h3>四、安装和配置Picgo<a href="#四安装和配置picgo"><span>#</span></a></h3><section><h4>（1）Picgo安装<a href="#1picgo安装"><span>#</span></a></h4><p>Picgo是一款开源的图床工具，主要用于将本地图片上传至云存储服务，并生成相应的URL链接。它支持多种云存储服务，如腾讯云COS、阿里云OSS等。</p><p>首先进入<a href="https://github.com/Molunerfinn/PicGo/releases" target="_blank">PicGo项目地址</a>下载相应的版本。</p><img src="https://imgbed.leihub.cn/img/image-20240622160938059.png" alt="image-20240622160938059" /><p>windows直接现在exe文件进行安装即可。</p></section><section><h4>（2）配置Picgo参数，<a href="#2配置picgo参数"><span>#</span></a></h4><p>打开软件，点击【腾讯云COS】，填入我们上面创建的信息：</p><ul>
<li>API密钥 <code>SecretId</code>和<code>SecretKey</code>，即腾讯云密钥设置中获取的；</li>
<li>APPID：即账号ID，即腾讯云密钥设置中获取的；</li>
<li>Bucket：即创建的存储同名字；</li>
<li>COS版本：选v5；</li>
<li>设定存储路径：在存储通中创建的文件夹，我的文件夹为<code>/img</code>；</li>
<li>存储区域：就是你创建的存储桶所在的区域，可以在存储桶基本信息中看到；</li>
<li>自定义域名：填写上一步cdn设置的加速域名。</li>
</ul><p></p><figure><img src="https://imgbed.leihub.cn/img/image-20240622161241434.png" alt="image-20240622161241434" /><figcaption>image-20240622161241434</figcaption></figure><p></p><p>记得设为默认图床，否则上传不会默认走腾讯云COS，通过拖拽图片到图片上传区即可上传</p></section></section>
<section><h3>五、在Typora配置picgo<a href="#五在typora配置picgo"><span>#</span></a></h3><p>点击【文件】→【偏好设置】→【图像】，配置成如下即可在typora插入图片的时候自动上传。</p><p></p><figure><img src="https://imgbed.leihub.cn/img/image-20240622165046271.png" alt="image-20240622165046271" /><figcaption>image-20240622165046271</figcaption></figure><p></p><p>我为了排版更喜欢，先不上传图片，调整好之后，再手动右键点击再上传。</p></section>
<section><h3>结语<a href="#结语"><span>#</span></a></h3><p>在本文中，我们详细介绍了如何使用Typora、腾讯云COS、腾讯云CDN和Picgo来搭建一个高效的个人笔记系统。通过配置腾讯云COS和CDN，我们确保了图片资源的快速加载和全球访问，同时利用Picgo工具简化了图片的上传和管理过程，使用这些工具和服务，可以极大地提高内容管理的效率。</p><p>希望这篇文章能够帮助您成功搭建自己的个人笔记系统，享受创作和分享的乐趣。</p></section>
<section><h3>参考<a href="#参考"><span>#</span></a></h3><ol>
<li><a href="https://zhuanlan.zhihu.com/p/340760172" target="_blank">PicGo+Typora搭建个人笔记系统 - 知乎 (zhihu.com)</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/440800482" target="_blank">腾讯云COS+PicGo+typora半个小时搞定个人博客图床 - 知乎 (zhihu.com)</a></li>
<li><a href="https://cloud.tencent.com/document/product/228/38194" target="_blank">内容分发网络 CDN 通过 COS 控制台实现 CDN 加速 COS-实践教程-文档中心-腾讯云 (tencent.com)</a></li>
<li><a href="https://cloud.tencent.com/document/product/436/13312" target="_blank">对象存储 存储桶概述-开发者指南-文档中心-腾讯云 (tencent.com)</a></li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/784/</id>
      <title type="text">足迹：端午长沙行</title>
      <published>2024-06-10T17:28:53.000Z</published>
      <updated>2025-11-14T15:19:10.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/784/"/>
      <summary type="text">端午节假期，本打算和朋友们一起去爬衡山，可惜天公不作美，连续几天的雨让我们不得不改变计划。既然爬山不行，那就去长沙逛逛吧！虽然我在株洲离长沙不远，但还真没怎么好好玩过。这次被推上了“导游”的位置，只好临时抱佛脚，研究起长沙的旅游攻略来。 第</summary>
      <content type="html"><![CDATA[<p>端午节假期，本打算和朋友们一起去爬衡山，可惜天公不作美，连续几天的雨让我们不得不改变计划。既然爬山不行，那就去长沙逛逛吧！虽然我在株洲离长沙不远，但还真没怎么好好玩过。这次被推上了“导游”的位置，只好临时抱佛脚，研究起长沙的旅游攻略来。</p>
<p>第一天的计划是满满的：逛五一广场、太平老街、长沙IFS、黄兴路步行街、南门口、杜甫江阁，最后沿着江边欣赏美景。结果，第一站就出了点小插曲——想去的<strong>秦娭毑皮蛋肉丸店</strong>竟然已经不接客了！好在旁边的<strong>钵一钵</strong>还能填填肚子，尽管那牛蛙里的生姜味道有点过于“冲”，让人有点受不了。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/30d69c866e24803c0523c6606a3fb85.jpg" alt="30d69c866e24803c0523c6606a3fb85" /><figcaption>30d69c866e24803c0523c6606a3fb85</figcaption></figure><p></p>
<p>下午的行程更是人山人海，几乎看不到什么风景，只记得到处都是人头攒动。这让我想起了在武汉读书的日子，虽然武汉也是个大城市，但相比之下，长沙的人潮似乎更加汹涌。人实在是太多了，风景没看到什么，脑海里只记得了人头，密密麻麻全是人。在武汉读了七年书，武汉也算是千万人口的大城市了，相比于长沙人流的密集程度，简直是小巫见大巫。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/e0115a62ce4a5b485e6e6c188e7f232.jpg" alt="e0115a62ce4a5b485e6e6c188e7f232" /><figcaption>e0115a62ce4a5b485e6e6c188e7f232</figcaption></figure><p></p>
<p>晚上尝试去笨萝卜浏阳菜馆用餐，没想到排队的人太多，根本挤不进去。无奈之下，只能在<strong>许大优的炸鸡铺</strong>随便吃点，结果不仅服务态度差，还吃坏了肚子，真是倒霉透顶。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/9c5dcb72d5c176bbf51cabbdf54ead2.jpg" alt="9c5dcb72d5c176bbf51cabbdf54ead2" /><figcaption>9c5dcb72d5c176bbf51cabbdf54ead2</figcaption></figure><p></p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/a45ae7acb786863fa568e082100874e.jpg" alt="a45ae7acb786863fa568e082100874e" /><figcaption>a45ae7acb786863fa568e082100874e</figcaption></figure><p></p>
<p>第一天就给了我一个教训，节假日千万不要来长沙，简直太挤了，同事也调侃我，这个时间点在长沙的肯定都是外地人，因为本地人不会选择这些热门地点游玩。也看得出来，长沙的市政规划不太好，所有的商业街都集中在五一这块，每逢节假日就会及其拥堵。而武汉的市政规划就要好太多了，商业街分布在三镇，玩起来有多个中心，相对不会这么挤，但是走在景点路上的时间就会相应增加。</p>
<p>第二天，我们决定去橘子洲和岳麓山。在橘子洲坐小火车游览，到橘子洲头和毛爷爷的雕像合影，整体轻松又愉快。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/8734b2bad7e6669b88a689fc3ac1829.jpg" alt="8734b2bad7e6669b88a689fc3ac1829" /><figcaption>8734b2bad7e6669b88a689fc3ac1829</figcaption></figure><p></p>
<p>午餐时再次尝试笨萝卜浏阳菜馆，依旧是人满为患，只好改去<strong>费大厨</strong>，那里的服务真是让人惊喜，感觉受到了贵宾级的待遇。与第一天的许大优简直是云泥之别，感觉是借鉴了海底捞的服务形式，整体进行下来让人非常舒适，这里点个赞。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/32751323e33c2dbb91263a02087e88a.jpg" alt="32751323e33c2dbb91263a02087e88a" /><figcaption>32751323e33c2dbb91263a02087e88a</figcaption></figure><p></p>
<p>下午登岳麓山，虽然累得够呛，但下山后发现岳麓书院已经关门，也算是一点小遗憾。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/50be1b7d13b6793417f1e8b26a0369d.jpg" alt="50be1b7d13b6793417f1e8b26a0369d" /><figcaption>50be1b7d13b6793417f1e8b26a0369d</figcaption></figure><p></p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/77c142a1211a49b95aaf82688268379.jpg" alt="77c142a1211a49b95aaf82688268379" /><figcaption>77c142a1211a49b95aaf82688268379</figcaption></figure><p></p>
<p>晚上，我们在岳麓山脚下的大学城闲逛，湖南大学、湖南师大和中南大学都在岳麓山脚，这边的美食街都非常繁华，感受到了与自己学校截然不同的繁华气息。</p>
<p>晚餐去吃了小红书上推荐了<strong>14栋家菜馆</strong>，但是去的时间点已经比较晚了（晚上7.30），他的招牌神仙鸡和砂锅猪脚都没菜了。这家店的菜，总体感觉还行，他的牛肚也喜欢放很多生姜，难道长沙这边都喜欢生姜吗？牛蛙个体都比较小，整体菜量也很少，四个人点了五个菜也没吃饱，最后只能去大学城的美食街吃了一顿夜宵。</p><figure><img src="http://imgbed.leihub.cn/img/d8e4370c5095061deb82e9cd4632226.jpg" alt="d8e4370c5095061deb82e9cd4632226" /><figcaption>d8e4370c5095061deb82e9cd4632226</figcaption></figure><p></p>
<p>第三天原本计划去<strong>湖南省博物馆</strong>，可惜节假日人太多，预约全满，加上外面下着大雨，只能在宾馆里度过半天。下午，同学们纷纷回武汉，我就去找了在长沙的老友打台球。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/5975518d47d1711b59c1e7dafe18c2a.jpg" alt="5975518d47d1711b59c1e7dafe18c2a" /><figcaption>5975518d47d1711b59c1e7dafe18c2a</figcaption></figure><p></p>
<p>晚餐，我们在河西的<strong>龙师傅卤炒</strong>解决，这家店的分量真的很足，两个人根本吃不完，最后只能打包带走。不过油盐味较重，吃完后口渴得厉害，看来我还是不太适合这种重口味的食物。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/700d05ac3edaaad652841ede1bef3a9.jpg" alt="700d05ac3edaaad652841ede1bef3a9" /><figcaption>700d05ac3edaaad652841ede1bef3a9</figcaption></figure><p></p>
<p>总的来说，这次长沙之行虽然有些小波折，但也体验了不少当地的风土人情。下次，或许可以选个人少一些的时候，慢慢品味这座城市的魅力。</p>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/717/</id>
      <title type="text">个人数据备份方案</title>
      <published>2024-06-02T15:35:10.000Z</published>
      <updated>2025-11-14T15:19:19.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/717/"/>
      <summary type="text">个人数据备份方案 在数字时代，数据的安全问题越来越受到重视。下面是基于我的个人经验，结合网络资源和实际知识，为您展示的一份综合性数据备份方案。 1. 硬件配置概览 群晖DS224+：配备两块4TB机械硬盘，增强的16GB内存（建议至少4GB</summary>
      <content type="html"><![CDATA[<section><h1>个人数据备份方案<a href="#个人数据备份方案"><span>#</span></a></h1><p>在数字时代，数据的安全问题越来越受到重视。下面是基于我的个人经验，结合网络资源和实际知识，为您展示的一份综合性数据备份方案。</p><section><h2>1. 硬件配置概览<a href="#1-硬件配置概览"><span>#</span></a></h2><ul>
<li>
<p><strong>群晖DS224+</strong>：配备两块4TB机械硬盘，增强的16GB内存（建议至少4GB，我这16G多少有点浪费了，基本占用就没超过1/4），提供了充足的存储空间和较快的处理速度，确保备份过程的高效性。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/ceQLu1fs4r7M.jpg" alt="群晖DS224+" /><figcaption>群晖DS224+</figcaption></figure><p></p>
</li>
<li>
<p><strong>腾讯云服务器</strong>：托管重要应用，如博客、导航页、聊天机器人、内网穿透服务等。</p>
</li>
<li>
<p><strong>白群晖NAS</strong>：负责家庭数据（照片、笔记、文件等）的存储与备份。</p>
</li>
<li>
<p><strong>unraid NAS</strong>：运行高性能游戏服务器(Minecraft、泰拉瑞亚、森林等)和本地服务，提升云服务性能。</p>
</li>
</ul></section><section><h2>2. 网络连接<a href="#2-网络连接"><span>#</span></a></h2><p>通过zerotier组建的安全内网不仅实现了各个设备间的互相访问，还便于远程管理和数据同步。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/u=2439012344,2775542224&amp;fm=253&amp;fmt=auto&amp;app=138&amp;f=PNG.webp" alt="u=2439012344,2775542224&amp;fm=253&amp;fmt=auto&amp;app=138&amp;f=PNG" /><figcaption>u=2439012344,2775542224&amp;fm=253&amp;fmt=auto&amp;app=138&amp;f=PNG</figcaption></figure><p></p></section><section><h2>3. 数据备份策略<a href="#3-数据备份策略"><span>#</span></a></h2><p></p><figure><img src="http://imgbed.leihub.cn/img/%E5%A4%87%E4%BB%BD%E6%B5%81%E7%A8%8B%E5%9B%BE3.png" alt="备份流程图 (1)" /><figcaption>备份流程图 (1)</figcaption></figure><p></p><section><h3>3.1 云服务器资料备份<a href="#31-云服务器资料备份"><span>#</span></a></h3><ul>
<li><strong>博客备份</strong>：使用WPvivid Backup插件，每月定时将WordPress博客的数据和文件备份至本地及白裙晖。</li>
<li><strong>网站备份</strong>：利用宝塔计划任务，每月自动备份网站目录与数据库至腾讯云COS和白裙晖。</li>
</ul></section><section><h3>3.2 群晖系统备份<a href="#32-群晖系统备份"><span>#</span></a></h3><ul>
<li>
<p><strong>Hyper Backup</strong>：执行本地增量备份整个系统，保留多版本历史，以便于随时回滚。</p>
</li>
<li>
<p><strong>Cloud Sync</strong>：将Hyper Backup生成的备份数据同步至百度云盘，实现异地容灾。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240602232113725.png" alt="image-20240602232113725" /><figcaption>image-20240602232113725</figcaption></figure><p></p>
</li>
</ul></section></section><section><h2>4. 数据同步与共享<a href="#4-数据同步与共享"><span>#</span></a></h2><ul>
<li><strong>Synology Drive</strong>：实现跨平台和设备的数据同步，确保随时随地访问最新文件。</li>
<li><strong>Note Station</strong>：整理笔记和文档，方便个人知识管理。</li>
<li><strong>Synology Photos</strong>：备份和同步手机照片，释放手机空间。</li>
</ul></section><section><h2>5. 安全性与冗余性措施<a href="#5-安全性与冗余性措施"><span>#</span></a></h2><ul>
<li><strong>异地备份</strong>：计划未来购买四盘位群晖，实现两地热备份，提高数据的抗灾能力。</li>
<li><strong>加密存储</strong>：启用群晖的加密功能，保护敏感数据免遭未授权访问。</li>
<li><strong>定期检查</strong>：定期验证备份数据的完整性，确保备份可以随时可用。</li>
</ul></section><section><h2>6. 备份任务明细表<a href="#6-备份任务明细表"><span>#</span></a></h2>

<table><thead><tr><th>备份任务类型</th><th>频率</th><th>存储位置</th><th>备注</th></tr></thead><tbody><tr><td>博客备份</td><td>每月</td><td>本地、白裙晖</td><td>使用WPvivid Backup插件</td></tr><tr><td>网站备份</td><td>每月</td><td>腾讯云COS、白裙晖</td><td>使用宝塔计划任务</td></tr><tr><td>系统备份</td><td>每周</td><td>本地</td><td>使用Hyper Backup</td></tr><tr><td>系统备份同步</td><td>实时</td><td>百度云盘</td><td>使用Cloud Sync同步备份数据</td></tr></tbody></table></section><section><h2>7. 结论<a href="#7-结论"><span>#</span></a></h2><p>一个周密的数据备份方案应当综合考虑数据的本地保护、异地容灾以及同步需求。通过上述策略的实施，可以有效地保障个人数据的安全性和可靠性。需要强调的是，数据备份是一个动态持续的过程，它要求我们不断地进行检查和更新以应对新的挑战。</p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/715/</id>
      <title type="text">聊天机器人（二）：chatgpt-on-wechat与星火大模型API搭建微信聊天机器人</title>
      <published>2024-06-02T12:30:03.000Z</published>
      <updated>2025-11-14T15:19:26.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/715/"/>
      <summary type="text">搭建个人聊天机器人：结合chatgpt-on-wechat与星火大模型API 在追求技术创新的时代，人工智能已经成为我们生活中不可或缺的一部分。之前，我们尝试通过QQ平台利用GtToken搭建了聊天机器人，尽管功能丰富，但GtToken易过</summary>
      <content type="html"><![CDATA[<section><h1>搭建个人聊天机器人：结合chatgpt-on-wechat与星火大模型API<a href="#搭建个人聊天机器人结合chatgpt-on-wechat与星火大模型api"><span>#</span></a></h1><p>在追求技术创新的时代，人工智能已经成为我们生活中不可或缺的一部分。之前，我们尝试通过QQ平台利用GtToken搭建了聊天机器人，尽管功能丰富，但GtToken易过期的问题仍然是一个困扰。如今，我探索到了一个新的项目——<code>zhayujie/chatgpt-on-wechat</code>，它不仅能通过微信公众号接入强大的星火大模型API，还允许我们免费试用，稳定性也更胜一筹。</p><section><h2>1. 准备工作<a href="#1-准备工作"><span>#</span></a></h2><section><h3>1.1 环境配置<a href="#11-环境配置"><span>#</span></a></h3><ul>
<li><strong>服务器选择</strong>：选择一个性能稳定的云服务器，如阿里云或腾讯云等。</li>
<li><strong>系统安装</strong>：安装Linux操作系统，推荐使用Ubuntu或CentOS。</li>
<li><strong>软件依赖</strong>：确保服务器上安装了Docker和Docker Compose。</li>
</ul></section><section><h3>1.2 项目地址<a href="#12-项目地址"><span>#</span></a></h3><p><strong>chatgpt-on-wechat项目：</strong><a href="https://github.com/zhayujie/chatgpt-on-wechat" target="_blank">zhayujie/chatgpt-on-wechat: 基于大模型搭建的聊天机器人，同时支持 微信公众号、企业微信应用、飞书、钉钉 等接入，可选择GPT3.5/GPT-4o/GPT4.0/ Claude/文心一言/讯飞星火/通义千问/ Gemini/GLM-4/Claude/Kimi/LinkAI，能处理文本、语音和图片，访问操作系统和互联网，支持基于自有知识库进行定制企业智能客服。 (github.com)</a></p><p><strong>星火大模型：</strong><a href="https://www.xfyun.cn/" target="_blank">讯飞开放平台-以语音交互为核心的人工智能开放平台 (xfyun.cn)</a></p><p>**企业微信：**<a href="https://mp.weixin.qq.com/" target="_blank">https://mp.weixin.qq.com/</a></p></section><section><h3>1.3获取必要的API密钥<a href="#13获取必要的api密钥"><span>#</span></a></h3><section><h4><strong>星火大模型API</strong>：申请并获取星火大模型的API接入权限。<a href="#星火大模型api申请并获取星火大模型的api接入权限"><span>#</span></a></h4><p>项目默认使用 OpenAI接口 进行对话，项目默认支持OpenAI接口，然而由于其费用和代理配置上的不便，我们转向使用星火大模型API。项目同时也支持文心、讯飞、GPT-3、GPT-4 等模型，所以这里选择使用星火大模型的API。</p><p>（1）首次使用的用户会看到免费试用的选项。由于我已经使用过API，所以显示的是在线调试界面。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240602192812444.png" alt="image-20240602192812444" /><figcaption>image-20240602192812444</figcaption></figure><p></p><p>完成个人认证后，你可以免费领取200万Tokens，足够长期使用。接下来需要创建一个应用并将套餐分配给该应用以便使用。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240602193158868.png" alt="image-20240602193158868" /><figcaption>image-20240602193158868</figcaption></figure><p></p><p>完成应用信息填写后，点击提交可创建应用，然后返回平台首页。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240602193306168.png" alt="image-20240602193306168" /><figcaption>image-20240602193306168</figcaption></figure><p></p><p>点击创建的应用查看APPID、APISecret和APIKey，这些信息将用于配置API。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240602193549063.png" alt="image-20240602193549063" /><figcaption>image-20240602193549063</figcaption></figure><p></p></section><section><h4><strong>微信公众号</strong>：注册并认证微信公众号<a href="#微信公众号注册并认证微信公众号"><span>#</span></a></h4><p>需要前往 <a href="https://mp.weixin.qq.com/" target="_blank">微信公众平台</a> 注册一个公众号，项目支持的公众号类型有两种，可根据你的需求进行选择：</p>

<table><thead><tr><th>类型</th><th>要求</th><th>特点</th></tr></thead><tbody><tr><td><strong>个人号</strong></td><td>个人可申请</td><td>在收到消息时会回复用户一条消息，回复生成后需要用户主动发消息获取</td></tr><tr><td><strong>企业号</strong></td><td>企业可申请，同时需要通过微信认证开通客服接口</td><td>回复生成后可主动推送给用户</td></tr></tbody></table><p>根据个人或企业的需求，我们可以选择合适的公众号类型进行注册。对于个人来说，订阅号是个不错的选择，尽管其交互能力有限；若是企业，则可以选择服务号并通过认证来获得更丰富的功能。</p></section></section></section><section><h2>2. 部署zhayujie/chatgpt-on-wechat<a href="#2-部署zhayujiechatgpt-on-wechat"><span>#</span></a></h2><section><h3>2.1 chatgpt-on-wechat项目<a href="#21-chatgpt-on-wechat项目"><span>#</span></a></h3><p>项目作者提供了四种安装方式：</p>

<table><thead><tr><th>运行方式</th><th>需要的资源</th><th>优势</th><th>劣势</th></tr></thead><tbody><tr><td><strong>Docker部署</strong></td><td>服务器 + docker环境</td><td>不用关心python环境和依赖</td><td>插件配置稍麻烦</td></tr><tr><td><strong>本地运行</strong></td><td>个人机器 + 本地代理 + python环境</td><td>方便本地代码调试</td><td>不适合长时间稳定运行</td></tr><tr><td><strong>服务器部署</strong></td><td>服务器 + python环境</td><td>方便配置和源码修改、稳定运行</td><td>需要简单的linux基础</td></tr><tr><td><strong>Railway部署</strong></td><td>一个超过半年的github账号</td><td>一键部署</td><td>免费额度有限，插件等高级功能使用不便</td></tr></tbody></table><p>我这里选择使用服务器 + docker进行部署，配置相对简单方便。</p></section><section><h3>2.2 配置Docker Compose文件<a href="#22-配置docker-compose文件"><span>#</span></a></h3><p>采用Docker部署的方式，我们编辑<code>docker-compose.yml</code>文件，填入必要的API密钥和微信公众号信息。通过简单的几个命令，即可轻松启动容器并完成配置。编辑<code>docker-compose.yml</code>文件，修改或添加所需的配置，如 <code>OPEN_AI_API_KEY</code> 和 <code>GROUP_NAME_WHITE_LIST</code> 等必填配置，其他配置参考 <a href="https://docs.link-ai.tech/cow/quick-start/config" target="_blank">配置说明</a>。这里我设置了微信公众号信息和星火大模型API密钥。</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>version: </span><span>'2.0'</span></div></div><div><div><div>2</div></div><div><span>services:</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>chatgpt-on-wechat:</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>image: zhayujie/chatgpt-on-wechat</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>container_name: chatgpt-on-wechat</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>security_opt:</span></div></div><div><div><div>7</div></div><div><span><span>      </span></span><span>- seccomp:unconfined</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>environment:</span></div></div><div><div><div>9</div></div><div><span><span>      </span></span><span>OPEN_AI_API_KEY: </span><span>'YOUR API KEY'</span></div></div><div><div><div>10</div></div><div><span><span>      </span></span><span>MODEL: </span><span>'xunfei'</span></div></div><div><div><div>11</div></div><div><span><span>      </span></span><span>XUNFEI_APP_ID: </span><span>'xxxx'</span><span>#前面获取的APPID，APISecret和APIKey</span></div></div><div><div><div>12</div></div><div><span><span>      </span></span><span>XUNFEI_API_KEY: </span><span>'xxxxx'</span></div></div><div><div><div>13</div></div><div><span><span>      </span></span><span>XUNFEI_API_SECRET: </span><span>'xxxxxx'</span></div></div><div><div><div>14</div></div><div><span><span>      </span></span><span>PROXY: </span><span>''</span></div></div><div><div><div>15</div></div><div><span><span>      </span></span><span>SINGLE_CHAT_PREFIX: </span><span>'[""]'</span></div></div><div><div><div>16</div></div><div><span><span>      </span></span><span>SINGLE_CHAT_REPLY_PREFIX: </span><span>" "</span></div></div><div><div><div>17</div></div><div><span><span>      </span></span><span>GROUP_CHAT_PREFIX: </span><span>'["@bot"]'</span></div></div><div><div><div>18</div></div><div><span><span>      </span></span><span>GROUP_NAME_WHITE_LIST: </span><span>'["ChatGPT测试群", "ChatGPT测试群2"]'</span></div></div><div><div><div>19</div></div><div><span><span>      </span></span><span>IMAGE_CREATE_PREFIX: </span><span>'["画", "看", "找"]'</span></div></div><div><div><div>20</div></div><div><span><span>      </span></span><span>CONVERSATION_MAX_TOKENS: 1000</span></div></div><div><div><div>21</div></div><div><span><span>      </span></span><span>SPEECH_RECOGNITION: </span><span>'False'</span></div></div><div><div><div>22</div></div><div><span><span>      </span></span><span>CHARACTER_DESC: </span><span>'你是基于大语言模型的AI智能助手，旨在回答并解决人们的任何问题，并且可以使用多种语言与人交流。'</span></div></div><div><div><div>23</div></div><div><span><span>      </span></span><span>EXPIRES_IN_SECONDS: 3600</span></div></div><div><div><div>24</div></div><div><span><span>      </span></span><span>USE_GLOBAL_PLUGIN_CONFIG: </span><span>'True'</span></div></div><div><div><div>25</div></div><div><span><span>      </span></span><span>USE_LINKAI: </span><span>'False'</span></div></div><div><div><div>26</div></div><div><span><span>      </span></span><span>LINKAI_API_KEY: </span><span>''</span></div></div><div><div><div>27</div></div><div><span><span>      </span></span><span>LINKAI_APP_CODE: </span><span>''</span></div></div><div><div><div>28</div></div><div><span>     </span><span># wechatmp的配置</span></div></div><div><div><div>29</div></div><div><span><span>      </span></span><span>channel_type: </span><span>"wechatmp"</span><span> #选择使用微信公众号</span></div></div><div><div><div>30</div></div><div><span><span>      </span></span><span>wechatmp_token: </span><span>'xxxxx'</span><span> # 微信公众平台的Token</span></div></div><div><div><div>31</div></div><div><span><span>      </span></span><span>wechatmp_port: 443  # 微信公众平台的端口需要端口转发到80或443</span></div></div><div><div><div>32</div></div><div><span><span>      </span></span><span>wechatmp_app_id: </span><span>'xxxxxx'</span><span>  # 微信公众平台的appID</span></div></div><div><div><div>33</div></div><div><span><span>      </span></span><span>wechatmp_app_secret: </span><span>'xxxxxxx'</span><span>  # 微信公众平台的appsecret</span></div></div><div><div><div>34</div></div><div><span><span>      </span></span><span>wechatmp_aes_key: </span><span>'xxxxxxx'</span><span>  # 微信公众平台的EncodingAESKey，加密模式需要</span></div></div><div><div><div>35</div></div><div><span><span>    </span></span><span>ports:</span></div></div><div><div><div>36</div></div><div><span><span>      </span></span><span>- </span><span>"18443:443"</span></div></div><div><div><div>37</div></div><div><span><span>    </span></span><span>volumes:</span></div></div><div><div><div>38</div></div><div><span><span>      </span></span><span>- ./config.json:/app/plugins/config.json</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>我这里选择将容器的443端口映射到服务器18443端口，后续使用nginx将域名反代到服务器的18443，实现外网通过域名访问容器443端口。同时，将配置文件config.json映射到本地，方便后续对配置进行更改，我这里也给出我的配置文件作为参考：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>{</span></div></div><div><div><div>2</div></div><div><span>  </span><span>"channel_type"</span><span>: </span><span>"wechatmp"</span><span>,</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span>  </span><span>"wechatmp_token"</span><span>: </span><span>xxxxx</span><span>" # 微信公众平台的Token</span></div></div><div><div><div>5</div></div><div><span><span>  </span></span><span>"</span><span>wechatmp_port</span><span>": 443  # 微信公众平台的端口需要端口转发到80或443</span></div></div><div><div><div>6</div></div><div><span><span>  </span></span><span>"</span><span>wechatmp_app_id</span><span>": "</span><span>xxxxxx</span><span>"  # 微信公众平台的appID</span></div></div><div><div><div>7</div></div><div><span><span>  </span></span><span>"</span><span>wechatmp_app_secret</span><span>": "</span><span>xxxxxx</span><span>"  # 微信公众平台的appsecret</span></div></div><div><div><div>8</div></div><div><span><span>  </span></span><span>"</span><span>wechatmp_aes_key</span><span>": "</span><span>xxxxxxxx</span><span>"  # 微信公众平台的EncodingAESKey，加密模式需要</span></div></div><div><div><div>9</div></div><div><span><span>  </span></span><span>"</span><span>model</span><span>": "</span><span>xunfei</span><span>",</span></div></div><div><div><div>10</div></div><div><span><span>  </span></span><span>"</span><span>xunfei_app_id</span><span>":"</span><span>xxxxxxxx</span><span>",</span></div></div><div><div><div>11</div></div><div><span><span>  </span></span><span>"</span><span>xunfei_api_key</span><span>":"</span><span>xxxxxxx</span><span>",</span></div></div><div><div><div>12</div></div><div><span><span>  </span></span><span>"</span><span>xunfei_api_secret</span><span>":"</span><span>xxxxxxx</span><span>",</span></div></div><div><div><div>13</div></div><div><span><span>  </span></span><span>"</span><span>open_ai_api_key</span><span>": "</span><span>YOUR</span><span> </span><span>API</span><span> </span><span>KEY</span><span>",</span></div></div><div><div><div>14</div></div><div><span><span>  </span></span><span>"</span><span>claude_api_key</span><span>": "</span><span>YOUR</span><span> </span><span>API</span><span> </span><span>KEY</span><span>",</span></div></div><div><div><div>15</div></div><div><span><span>  </span></span><span>"</span><span>text_to_image</span><span>": "</span><span>dall-e</span><span>-2</span><span>",</span></div></div><div><div><div>16</div></div><div><span><span>  </span></span><span>"</span><span>voice_to_text</span><span>": "</span><span>openai</span><span>",</span></div></div><div><div><div>17</div></div><div><span><span>  </span></span><span>"</span><span>text_to_voice</span><span>": "</span><span>openai</span><span>",</span></div></div><div><div><div>18</div></div><div><span><span>  </span></span><span>"</span><span>proxy</span><span>": "",</span></div></div><div><div><div>19</div></div><div><span><span>  </span></span><span>"</span><span>hot_reload</span><span>": false,</span></div></div><div><div><div>20</div></div><div><span><span>  </span></span><span>"</span><span>single_chat_prefix</span><span>": [</span></div></div><div><div><div>21</div></div><div><span><span>    </span></span><span>""</span></div></div><div><div><div>22</div></div><div><span><span>  </span></span><span>],</span></div></div><div><div><div>23</div></div><div><span><span>  </span></span><span>"</span><span>single_chat_reply_prefix</span><span>": "",</span></div></div><div><div><div>24</div></div><div><span><span>  </span></span><span>"</span><span>group_chat_prefix</span><span>": [</span></div></div><div><div><div>25</div></div><div><span><span>    </span></span><span>"</span><span>@bot</span><span>"</span></div></div><div><div><div>26</div></div><div><span><span>  </span></span><span>],</span></div></div><div><div><div>27</div></div><div><span><span>  </span></span><span>"</span><span>group_name_white_list</span><span>": [</span></div></div><div><div><div>28</div></div><div><span><span>    </span></span><span>"</span><span>ChatGPT测试群</span><span>",</span></div></div><div><div><div>29</div></div><div><span><span>    </span></span><span>"</span><span>ChatGPT测试群</span><span>2</span><span>"</span></div></div><div><div><div>30</div></div><div><span><span>  </span></span><span>],</span></div></div><div><div><div>31</div></div><div><span><span>  </span></span><span>"</span><span>image_create_prefix</span><span>": [</span></div></div><div><div><div>32</div></div><div><span><span>    </span></span><span>"</span><span>画</span><span>"</span></div></div><div><div><div>33</div></div><div><span><span>  </span></span><span>],</span></div></div><div><div><div>34</div></div><div><span><span>  </span></span><span>"</span><span>speech_recognition</span><span>": true,</span></div></div><div><div><div>35</div></div><div><span><span>  </span></span><span>"</span><span>group_speech_recognition</span><span>": false,</span></div></div><div><div><div>36</div></div><div><span><span>  </span></span><span>"</span><span>voice_reply_voice</span><span>": false,</span></div></div><div><div><div>37</div></div><div><span><span>  </span></span><span>"</span><span>conversation_max_tokens</span><span>": 2500,</span></div></div><div><div><div>38</div></div><div><span><span>  </span></span><span>"</span><span>expires_in_seconds</span><span>": 3600,</span></div></div><div><div><div>39</div></div><div><span><span>  </span></span><span>"</span><span>character_desc</span><span>": "</span><span>你是基于大语言模型的AI智能助手，旨在回答并解决人们的任何问题，并且可以使用多种语言与人交流。</span><span>",</span></div></div><div><div><div>40</div></div><div><span><span>  </span></span><span>"</span><span>temperature</span><span>": 0.7,</span></div></div><div><div><div>41</div></div><div><span><span>  </span></span><span>"</span><span>subscribe_msg</span><span>": "</span><span>感谢您的关注！\n这里是AI智能助手，可以自由对话。\n支持语音对话。\n支持图片输入。\n支持图片输出，画字开头的消息将按要求创作图片。\n支持tool、角色扮演和文字冒险等丰富的插件。\n输入</span><span>{</span><span>trigger_prefix</span><span>}</span><span>#help</span><span> </span><span>查看详细指令。</span><span>",</span></div></div><div><div><div>42</div></div><div><span><span>  </span></span><span>"</span><span>use_linkai</span><span>": false,</span></div></div><div><div><div>43</div></div><div><span><span>  </span></span><span>"</span><span>linkai_api_key</span><span>": "",</span></div></div><div><div><div>44</div></div><div><span><span>  </span></span><span>"</span><span>linkai_app_code</span><span>": ""</span></div></div><div><div><div>45</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h3>2.3 启动容器<a href="#23-启动容器"><span>#</span></a></h3><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>docker-compose</span><span> </span><span>up</span><span> </span><span>-d</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>为了让外部网络能够访问我们的聊天机器人，我采用了Nginx反向代理，并将一个域名指向了服务器的18443端口，这样用户便可通过HTTPS协议安全地与机器人交互。因为后续接入微信公众号平台的URL必须是HTTP/HTTPS协议，所以无法使用除80/443以外的端口。我这里选择使用nginx进行反代，首先将一个域名例如wechat.test.com解析到云服务器，然后使用nginx将wechat.test.com转发到服务器的18443端口，同时配置SSL证书，实现https协议访问云服务器的18443端口。我这里直接使用宝塔面板进行配置。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240602195558538.png" alt="image-20240602195558538" /><figcaption>image-20240602195558538</figcaption></figure><p></p></section><section><h3>2.4 接入微信公众号平台<a href="#24-接入微信公众号平台"><span>#</span></a></h3><p>docker compose.yml中的配置需要和 <a href="https://mp.weixin.qq.com/advanced/advanced?action=dev&amp;t=advanced/dev" target="_blank">微信公众号后台</a> 中的保持一致，进入页面后，在左侧菜单选择 “设置与开发 - 基本配置 - 服务器配置”，按下图进行配置:</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240602195813765.png" alt="image-20240602195813765" /><figcaption>image-20240602195813765</figcaption></figure><p></p><p><strong>配置的流程如下：</strong></p><ol>
<li>
<p>在公众平台启用开发者密码 (对应配置 <code>wechatmp_app_secret</code>)，并将服务器ip填入白名单中；</p>
</li>
<li>
<p>按上图填写 <code>config.json</code> 中与公众号相关的配置，要与公众号后台的配置一致；</p>
</li>
<li>
<p>在启动程序后会监听443端口；</p>
</li>
<li>
<p>在公众号后台启用服务器配置并提交，如果保存成功则表示已经成功配置。注意 <strong>“服务器地址(URL)”</strong> 这一项需要配置为 <code>http或https://{HOST}/wx</code> 的格式，其中 {HOST} 可以是服务器的ip或域名。</p>
</li>
<li>
<p>在完成配置后，可以到docker的后台日志查看是否成功接入，当日志中显示如下内容，则表示聊天机器人已成功接入公众号。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240602200221433.png" alt="image-20240602200221433" /><figcaption>image-20240602200221433</figcaption></figure><p></p>
</li>
</ol></section></section><section><h2>3. 使用和测试<a href="#3-使用和测试"><span>#</span></a></h2><p>可以看到，由于受订阅号限制，回复内容较短的情况下 (15s内)，可以立即完成回复，但耗时较长的回复则会先回复一句 “正在思考中”，后续需要用户输入任意文字主动获取答案，而服务号则可以通过客服接口解决这一问题。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240602200508352.png" alt="image-20240602200508352" /><figcaption>image-20240602200508352</figcaption></figure><p></p><section><h3>其他问题<a href="#其他问题"><span>#</span></a></h3><ol>
<li>语音识别：可利用微信自带的语音识别功能，提供语音输入能力。需要在公众号管理页面的 “设置与开发 -&gt; 接口权限” 页面开启 “接收语音识别结果”</li>
<li>语音回复：利用项目中的语音生成能力，项目作者推荐使用 azure 语音接口</li>
</ol></section></section><section><h2>5. 结语<a href="#5-结语"><span>#</span></a></h2><p>通过上述步骤，你不仅能够成功搭建一个基于<code>zhayujie/chatgpt-on-wechat</code>的微信聊天机器人，还能通过实际操作加深对Docker、微信公众平台和AI API的理解。希望本指南能帮助你顺利搭建起属于自己的聊天机器人。</p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/711/</id>
      <title type="text">铝合金焊接知识（一）</title>
      <published>2024-05-29T09:00:24.000Z</published>
      <updated>2025-11-14T15:19:36.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/711/"/>
      <summary type="text">一、介绍 铝合金焊接应符合ISO标准，包括检验方法、焊缝质量、焊丝选用等方面。这确保了焊接质量和结构完整性，提高了焊接接头的性能和可靠性。 二、铝合金焊接坡口 焊接坡口形式的选择应当符合ISO 9692-3:2016《焊接和相关工艺 - 接</summary>
      <content type="html"><![CDATA[<section><h1>一、介绍<a href="#一介绍"><span>#</span></a></h1><p>铝合金焊接应符合ISO标准，包括检验方法、焊缝质量、焊丝选用等方面。这确保了焊接质量和结构完整性，提高了焊接接头的性能和可靠性。</p></section>
<section><h1>二、铝合金焊接坡口<a href="#二铝合金焊接坡口"><span>#</span></a></h1><p>焊接坡口形式的选择应当符合ISO 9692-3&lt;2016&gt;《焊接和相关工艺 - 接头准备的建议 - 第3部分：铝及其合金的金属惰性气体焊接和钨极惰性气体焊接》的要求，确保所选用的坡口形式适用于具体的焊接场景和要求</p><p>ISO 9692-3&lt;2016标准规定了铝及其合金的金属惰性气体焊接&gt;（MIG）和钨极惰性气体焊接（TIG）中焊缝的技术参数。其中，包括了焊接坡口形式、坡口角度、间隙和钝边等方面的要求。</p><ol>
<li><strong>焊接坡口形式：</strong> 标准规定了不同类型的焊接坡口形式，如V型、X型、Y型、K型等，根据具体的焊接场景和要求选择合适的坡口形式。</li>
<li><strong>坡口角度：</strong> 对于每种焊接坡口形式，标准还规定了相应的坡口角度范围，确保焊接坡口的几何形状符合要求。</li>
<li><strong>间隙：</strong> 标准对焊接坡口中的间隙要求也进行了规定，包括了不同类型焊接坡口的间隙范围，以及在特定情况下的间隙允许范围。</li>
<li><strong>钝边：</strong> 在焊接坡口的设计中，还需要考虑到钝边的要求，即焊接坡口边缘的钝化处理，以确保焊接过程中的稳定性和焊缝质量。</li>
</ol><p>这些技术参数的规定，有助于指导焊接工程师和操作人员在铝合金焊接过程中选择合适的焊接坡口形式，并根据标准要求进行设计和施工，以确保焊接质量和接头性能达到要求。</p><section><h2>1、单面对接接口坡口<a href="#1单面对接接口坡口"><span>#</span></a></h2><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529160303883.png" alt="image-20240529160303883" /><figcaption>image-20240529160303883</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529160740499.png" alt="image-20240529160740499" /><figcaption>image-20240529160740499</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529160755084.png" alt="image-20240529160755084" /><figcaption>image-20240529160755084</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529160809231.png" alt="image-20240529160809231" /><figcaption>image-20240529160809231</figcaption></figure><p></p></section><section><h2>2、双面对接接口坡口<a href="#2双面对接接口坡口"><span>#</span></a></h2><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529160823167.png" alt="image-20240529160823167" /><figcaption>image-20240529160823167</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529160833248.png" alt="image-20240529160833248" /><figcaption>image-20240529160833248</figcaption></figure><p></p></section><section><h2>3、T型接口坡口<a href="#3t型接口坡口"><span>#</span></a></h2><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529160841899.png" alt="image-20240529160841899" /><figcaption>image-20240529160841899</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529160853782.png" alt="image-20240529160853782" /><figcaption>image-20240529160853782</figcaption></figure><p></p></section></section>
<section><h1>三、焊缝的检验<a href="#三焊缝的检验"><span>#</span></a></h1><p>对于检验方法，应当参照ISO 17635&lt;2016&gt;《焊接 - 非破坏试验 - 焊接的完全通用标准》中的规定，采用合适的非破坏检测方法来评估焊接接头的质量。</p><section><h2>1、检验方法<a href="#1检验方法"><span>#</span></a></h2><ol>
<li><strong>视觉检验（VT）：</strong> 使用裸眼或辅助视觉工具对焊接接头进行外观检查，以发现表面缺陷和几何形状问题。</li>
<li><strong>渗透检验（PT）：</strong> 使用可渗透性液体（如荧光或可见光检测剂）对焊缝表面进行涂覆，然后观察是否有渗透液流出来检测缺陷。</li>
<li><strong>磁粉检验（MT）：</strong> 使用磁粉颗粒涂覆在焊缝表面，然后施加磁场，观察是否有磁粉集聚来检测表面和近表面的缺陷。</li>
<li><strong>超声波检验（UT）：</strong> 使用超声波通过焊接接头，然后接收回波信号，通过分析回波信号来检测内部缺陷。</li>
<li><strong>射线检验（RT）：</strong> 使用X射线或γ射线穿透焊接接头，然后通过检测透射区域的密度变化来检测内部缺陷。</li>
<li>**涡流检验（ET）:**电磁检测利用涡流的产生和变化来检测焊接接头中的缺陷。通过在工件表面感应交变磁场，当电流通过线圈时，产生的涡流会受到焊缝内部缺陷的影响而发生变化，通过检测这种变化来确定缺陷位置和性质。</li>
</ol></section><section><h2>2、焊缝检验方法的选择<a href="#2焊缝检验方法的选择"><span>#</span></a></h2><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529163310104.png" alt="image-20240529163310104" /><figcaption>image-20240529163310104</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529163321522.png" alt="image-20240529163321522" /><figcaption>image-20240529163321522</figcaption></figure><p></p><p>推荐最小屈服强度大于 280MPa 的铁素体焊缝、奥氏体焊缝、铝焊缝、镍基和铜合金焊缝、钛焊缝除目视检测之外，根据表2选用一种或多种方法进行检测。为确定实际熔透程度和其他缺欠的尺寸，可协商使用表2和表3之外的检测方法及其技术。当使用表3给出的检测方法，对部分透焊缝和角焊缝进行检测时，未焊透可能无法令人满意的检出。如果未协商确认特定的检测方法，焊缝质量应由焊接工艺控制来保证。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529163711046.png" alt="image-20240529163711046" /><figcaption>image-20240529163711046</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529165350587.png" alt="image-20240529165350587" /><figcaption>image-20240529165350587</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529165404219.png" alt="image-20240529165404219" /><figcaption>image-20240529165404219</figcaption></figure><p></p></section></section>
<section><h1>四、焊缝质量等级<a href="#四焊缝质量等级"><span>#</span></a></h1><p>焊缝质量等级方面，应当根据ISO 10042&lt;2018&gt;《焊接 - 对焊接的金属材料的熔合焊的质量要求》的规定进行评估，以确定焊缝质量等级，并采取相应的措施确保焊接质量达到要求。</p><section><h2>1、表面缺欠<a href="#1表面缺欠"><span>#</span></a></h2><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529161916019.png" alt="image-20240529161916019" /><figcaption>image-20240529161916019</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529161928550.png" alt="image-20240529161928550" /><figcaption>image-20240529161928550</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529161938056.png" alt="image-20240529161938056" /><figcaption>image-20240529161938056</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529161949157.png" alt="image-20240529161949157" /><figcaption>image-20240529161949157</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529162015257.png" alt="image-20240529162015257" /><figcaption>image-20240529162015257</figcaption></figure><p></p></section><section><h2>2、内部缺欠<a href="#2内部缺欠"><span>#</span></a></h2><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529162023226.png" alt="image-20240529162023226" /><figcaption>image-20240529162023226</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529162038951.png" alt="image-20240529162038951" /><figcaption>image-20240529162038951</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529162046521.png" alt="image-20240529162046521" /><figcaption>image-20240529162046521</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529162053615.png" alt="image-20240529162053615" /><figcaption>image-20240529162053615</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529162104606.png" alt="image-20240529162104606" /><figcaption>image-20240529162104606</figcaption></figure><p></p></section><section><h2>3、接头的几何缺欠<a href="#3接头的几何缺欠"><span>#</span></a></h2><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529162112592.png" alt="image-20240529162112592" /><figcaption>image-20240529162112592</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240529162120981.png" alt="image-20240529162120981" /><figcaption>image-20240529162120981</figcaption></figure><p></p></section></section>
<section><h1>五、焊丝的选择<a href="#五焊丝的选择"><span>#</span></a></h1><p>焊接中焊丝选择需要考虑以下因素：</p><ol>
<li><strong>化学成分匹配：</strong> 焊接中使用的填充材料（焊丝）的化学成分应与母材相匹配，以确保焊缝和母材具有相似的化学成分，从而提高焊接接头的性能和可靠性。</li>
<li><strong>机械性能匹配：</strong> 焊丝的机械性能（如抗拉强度、屈服强度、延伸率等）应与母材和焊接接头的要求相匹配，以确保焊接接头具有所需的强度和可靠性。</li>
<li><strong>焊接性能：</strong> 焊丝的选择会影响焊接过程中的熔池流动性、焊缝形貌、气孔率等焊接性能，因此需要选择合适的焊丝以确保焊接质量。</li>
</ol><p>ISO 18273&lt;2017标准则针对铝及其合金的填充金属&gt;（焊丝）提出了相应的要求，包括化学成分和机械性能等方面的规定。</p></section>
<section><h1>六、焊接工艺<a href="#六焊接工艺"><span>#</span></a></h1><p>在焊接铝合金时，常用的焊接方法包括：</p><ol>
<li><strong>氩弧焊（TIG）141：</strong> 使用惰性气体（通常是氩气）保护焊接区域，通过钨极产生的电弧来熔化填充材料和工件。TIG焊常用于对焊、角焊和搭接焊等铝合金焊接。</li>
<li><strong>金属惰性气体弧焊（MIG）131：</strong> 使用惰性气体（通常是氩气）或混合气体（如氦-氩混合气体）保护焊接区域，通过电弧熔化铝合金焊丝和工件。MIG焊适用于大量生产和高速焊接。</li>
</ol></section>
<section><h1>七、焊接误差<a href="#七焊接误差"><span>#</span></a></h1><p>国际标准 ISO 13920 定义了关于焊接的一般尺寸公差和形状尺寸的标准。具体而言，ISO 13920 包括了以下几个方面的内容：</p><ol>
<li>**焊接尺寸公差：**长度、高度、根部宽度等方面的公差要求。这些公差规定了焊缝的几何尺寸与理论尺寸之间的允许偏差。</li>
<li>**焊接形状尺寸：**凹槽形状、根部形状、顶部形状等方面的尺寸要求。这些要求有助于确保焊接接头的形状满足设计要求。</li>
<li>**焊接缺陷公差：**焊缝内部和外部的缺陷类型、大小、数量等方面的要求。这些规定有助于评估焊接接头的质量。</li>
</ol><p>ISO 13920 标准的制定旨在提供一种统一的标准，用于确定焊接接头的尺寸公差和形状尺寸，从而确保焊接接头的质量和可靠性。这些标准适用于各种类型的焊接，包括手工焊接、自动焊接和机器焊接等。</p></section>
<section><h1>八、WPS验证<a href="#八wps验证"><span>#</span></a></h1><p>WPS（Welding Procedure Specification）验证是指对焊接工艺规程的验证过程。在焊接过程中，WPS是一份详细的文件，描述了所采用的焊接工艺的所有关键参数，包括焊接方法、材料、电流/电压、焊接速度、预热温度、焊接序列等信息。WPS的目的是确保焊接过程中的一致性和可重复性，以获得符合要求的焊接接头。</p><p>进行WPS验证的目的主要有以下几点：</p><ol>
<li><strong>质量控制：</strong> 确保焊接过程符合设计要求和相关标准，从而获得高质量的焊接接头。</li>
<li><strong>安全性：</strong> 通过验证焊接工艺规程，确保焊接过程中的安全操作和可靠性。</li>
<li><strong>法规遵从：</strong> 符合法规和标准的要求，避免可能的责任和法律问题。</li>
<li><strong>过程优化：</strong> 通过验证和评估，了解焊接工艺的可行性和优化空间，提高生产效率和质量水平。</li>
</ol><p>相关的标准包括：</p><ul>
<li>ISO 15614-1：焊接工艺规程的规范和验收标准，适用于金属材料的焊接。</li>
<li>AWS D1.1：美国焊接学会发布的焊接工艺规程标准，适用于结构钢的焊接。</li>
<li>ASME IX：美国机械工程师协会发布的焊接和焊接工艺规程的标准，适用于压力容器等设备的焊接。</li>
</ul><p>这些标准提供了关于焊接工艺规程的验证方法和要求，帮助焊接行业确保焊接过程的质量和安全性。</p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/709/</id>
      <title type="text">新能源油冷电机（二）：特斯拉和比亚迪</title>
      <published>2024-05-28T15:47:32.000Z</published>
      <updated>2025-11-14T15:19:52.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/709/"/>
      <summary type="text">2024年05月28日 初步摘抄了特斯拉原线电机和扁线电机的结构 介绍 在之前的博客文章中，我们为大家深入探讨了新能源油冷电机的概念、优势及其在电动汽车领域的应用。作为一种高效、稳定的动力解决方案，油冷电机凭借其出色的散热性能和较长的使用寿</summary>
      <content type="html"><![CDATA[<ul>
<li>2024年05月28日  初步摘抄了特斯拉原线电机和扁线电机的结构</li>
</ul>
<section><h1>介绍<a href="#介绍"><span>#</span></a></h1><p>在之前的博客文章中，我们为大家深入探讨了新能源油冷电机的概念、优势及其在电动汽车领域的应用。作为一种高效、稳定的动力解决方案，油冷电机凭借其出色的散热性能和较长的使用寿命，受到了业界的广泛关注。今天，我们将进一步细化这一话题，聚焦在特斯拉和比亚迪两大电动汽车制造商的油冷电机结构上，带大家领略这两家科技巨擘在电机技术领域的创新与突破。</p></section>
<section><h1>Tesla 圆线电机<a href="#tesla-圆线电机"><span>#</span></a></h1><p></p><figure><img src="http://imgbed.leihub.cn/img/clip_image002.png" alt="图片" /><figcaption>图片</figcaption></figure><p></p><p>定子</p><p>Tesla 永磁同步电机定子铁芯表面开有162个方形油道，与机壳过盈形成油路，这是该冷却系统最大的一个特色。</p><p>定子两端安装塑料油环（圆周均布16油孔）进行绕组两端喷油冷却。在这套冷却系统中，塑料零件的使用远远的超过以往设计。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/clip_image004.png" alt="图示  描述已自动生成" /><figcaption>图示  描述已自动生成</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/clip_image006.png" alt="图片" /><figcaption>图片</figcaption></figure><p></p><p>转子</p><p>Tesla 永磁同步电机转轴采用空心轴(焊接)工艺，内部开有油孔。通过转子甩油实现定子绕组内圈冷却。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/clip_image008.png" alt="图片包含 游戏机, 桌子, 灯光  描述已自动生成" /><figcaption>图片包含 游戏机, 桌子, 灯光  描述已自动生成</figcaption></figure><p></p><p>特斯拉的转子甩油技术通过轴孔将润滑油甩向定子绕组内侧，实现对电机的冷却。然而，这种甩油方式是直角甩出，且油孔距离定子绕组有一定的距离，因此油路并不一定能够高效地将油甩到绕组上。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/clip_image010.png" alt="图示, 工程绘图  描述已自动生成" /><figcaption>图示, 工程绘图  描述已自动生成</figcaption></figure><p></p><p><strong>优势</strong></p><p>1 油路设计简洁，降低了机壳制造成本。</p><p>2 油直接流入铁芯内部，冷却效果均匀且高效。</p><p><strong>劣势</strong></p><p>1 油环与定子铁芯的装配且存在密封风险，会导致油路不稳定。</p><p>2 轭部需要额外的油孔空间，可能导致径向空间增大。</p><p>3 油环成本较油管低，但是成本还是相对较高。</p></section>
<section><h1>Tesla扁线电机<a href="#tesla扁线电机"><span>#</span></a></h1><p>新的电机转轴更加“苗条”，同时油孔的位置及数量更加针对性，甩油效果更好。笔者实地接触过之前方案的电机轴，着实笨重，且制造难度极大（大直径+中空+焊接）。此次的改变，终于变得“正常”了，且重量减少0.5kg</p><p></p><figure><img src="http://imgbed.leihub.cn/img/clip_image012.png" alt="图片包含 室内, 飞机, 空气, 军事  描述已自动生成" /><figcaption>图片包含 室内, 飞机, 空气, 军事  描述已自动生成</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/clip_image014.png" alt="img" /><figcaption>img</figcaption></figure><p></p></section>
<section><h1>比亚迪<a href="#比亚迪"><span>#</span></a></h1><p>BYD的油冷技术采用了独特的平衡环甩油方案。在BYD的油冷技术中，转子轴上的ATF油经过平衡环油道，以一个倾斜的角度喷向绕组。这种喷油方式不仅路径更短，而且喷油角度更加合理，使得润滑油能够更直接、更均匀地覆盖在绕组上。这样一来，绕组的散热效果得到了显著提升，电机的运行效率和寿命也得到了有效保障。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/clip_image018.jpg" alt="img" /><figcaption>img</figcaption></figure><p></p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/707/</id>
      <title type="text">新能源电机油冷方案（一）</title>
      <published>2024-05-27T06:17:39.000Z</published>
      <updated>2025-11-14T15:19:45.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/707/"/>
      <summary type="text">介绍 电机的油冷技术对于转子和定子来说，有多种技术路线可以选择，每种路线都有其独特的特点和适用场景。以下是对目前的主要油冷技术路线： （1）浸油冷却转子是一种直接冷却方式，通过将转子浸入冷却油中，使冷却油与转子直接接触，达到散热的效果。这种</summary>
      <content type="html"><![CDATA[<section><h1>介绍<a href="#介绍"><span>#</span></a></h1><p>电机的油冷技术对于转子和定子来说，有多种技术路线可以选择，每种路线都有其独特的特点和适用场景。以下是对目前的主要油冷技术路线：</p><p>（1）浸油冷却转子是一种直接冷却方式，通过将转子浸入冷却油中，使冷却油与转子直接接触，达到散热的效果。这种方式冷却效果较好，能够有效地降低转子的温度。上汽的CN110323895A方案就是用冷却油淹没部分转子，同时利用转子搅动冷却油，将其甩到定子端部达到冷却定子的目的。此方案油温需要维持在较高的温度，以降低油的粘稠度，否则会有较大的电机转子的搅油损耗[14]。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527104741774.png" alt="图 浸油冷却转子" /><figcaption>图 浸油冷却转子</figcaption></figure><p></p><p>（2）油冷轴是通过在转轴上设置油路，使冷却油能够流经转轴内部，从而实现对转轴的冷却。这种方式能够直接对转轴进行冷却，散热效果较为显著。适用场景：适用于转轴温度较高且需要精确控制温度的场合，如高速电机等。</p><p>Tesla采用空心轴套的方式，在转轴内部布置油路，同时对转子和轴承进行冷却，空心轴套的难点在于空心轴和进油管之间需要刚性连接[8-9]。在冷却轴的同时，还可以在压板上开甩油孔，利用离心力将转轴中的冷却油通过压板甩向定子端部内测，达到冷却定子的目的[10-12,15-16,18]。这种方案因为油路布置原因，前后压板中的油压会有差异，导致对定子前后端部的冷却效果不均匀。</p><p>也有方案使用引油板将冷却油引导至转子套筒内侧，进而通过压板将冷却油甩向定子端部[19]。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527104831852.png" alt="图 转子甩油冷却定子端部" /><figcaption>图 转子甩油冷却定子端部</figcaption></figure><p></p><p>​    （3）对于定子油冷却，常见的是绕组喷淋冷却，一种是通过设计不同的定子冲片或错位叠片工艺，在定子铁心冲叠压出冷却油道和端部喷油口，对定子铁心直接进行冷却，同时利用喷油孔对定子端部进行喷淋冷却[1-7]。这种方案同时冷却铁心和端部，冷却效果较好，但是需要设计多种冲片规格，且冲片拓扑结构较为复杂，开模成本和工艺难度较高。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527104913325.png" alt="图 定子铁心爆炸图" /><figcaption>图 定子铁心爆炸图</figcaption></figure><p></p><p>​    （4）大部分方案采用的是多种技术路线并行，在电机内部布置多条冷却油道，同时冷却定子铁心，转子和定子端部，确实在提升冷却效率上具有一定的优势，但同时也带来了一些问题，特别是关于油阻和冷却效果的不均匀性。</p><p>电机内部布置多条冷却油道意味着冷却油需要在更复杂的路径中流动。这增加了冷却系统的复杂性和制造成本，同时也可能导致油阻的升高。高油阻不仅会增加冷却系统的能耗，还可能影响冷却油的流动速度和流量，进而影响冷却效果。</p><p>其次，由于电机内部的结构和散热需求存在差异，不同部件的冷却效果也可能有所不同。例如，定子铁心、转子和定子端部的材料和结构差异可能导致它们对冷却油的需求和散热能力不同，这可能导致某些部件的冷却效果不理想。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527104923149.png" alt="图 多路油道" /><figcaption>图 多路油道</figcaption></figure><p></p></section>
<section><h1><strong>1</strong>、Tesla-US11125315B（定子铁心喷油）<a href="#1tesla-us11125315b定子铁心喷油"><span>#</span></a></h1><p>该技术方案最大的特点就是在定子铁芯表面开有162个方形油道，与机壳过盈形成油路。并在定子两端各设置有喷油环，对绕组端部进行喷淋冷却。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105015121.png" alt="image-20240527105015121" /><figcaption>image-20240527105015121</figcaption></figure><p></p><p>冷却油从壳体310的进油孔303进入定子铁芯116的环状凹槽200，油流从定子表面的方形油道202、203沿轴向流入铁芯前后端部，再通过前后喷油环120、121的喷油孔315、317喷淋在绕组端部</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105001754.png" alt="密封放大图" /><figcaption>密封放大图</figcaption></figure><p></p><p>如图显示出了喷油环和密封件的装配关系，密封圈500通过凸起506装配在喷油环的凹槽504中，并与壳体挤压形成密封腔体。密封圈502装配在喷油环凹槽508中，使冷却油从方形油道出来后可以全部通过喷油环喷射在绕组端部，避免油泄露到气隙中。</p></section>
<section><h1>2、Lucid-US10128701B2、US20210351641A1（定子铁心喷油）<a href="#2lucid-us10128701b2us20210351641a1定子铁心喷油"><span>#</span></a></h1><p>冷却油1101从铁芯1103的中间段进入铁芯内部，再沿着冷却通道1105和冷却通道1109轴向流两端。最后1109排出的冷却剂1101穿过由叠片1205形成的冷却通道1207，和叠片1203形成的1211喷淋在定子端部1107。该定子铁芯通过四种不同结构的铁芯冲片，按照一定规律叠压，最终形成了内部的轴向喷油油道。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105030340.png" alt="image-20240527105030340" /><figcaption>image-20240527105030340</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105034142.png" alt="图 Luicd冷却系统" /><figcaption>图 Luicd冷却系统</figcaption></figure><p></p></section>
<section><h1>3、博格华纳（天津）-CN113612322B、CN114337106B（定子喷油）<a href="#3博格华纳天津-cn113612322bcn114337106b定子喷油"><span>#</span></a></h1><p>如图冷却液从进油口7进入定子中间段，并沿着定子铁芯2的外表面冷却通道5流通，实现对定子铁芯2表面降温，再通过第二类冲片旋转叠压构成的喷油部件3，形成阶梯型喷油通道4，使冷却液可以倾斜喷射在绕组端部。并在重力作用下，冷却液流经下半部分定子绕组6和绕组内表面，对定子绕组进行降温。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105056183.png" alt="图 博格华纳冷却系统" /><figcaption>图 博格华纳冷却系统</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105105401.png" alt="端部喷油口" /><figcaption>端部喷油口</figcaption></figure><p></p></section>
<section><h1>4、华为-CN115333265A（定子压板喷油）<a href="#4华为-cn115333265a定子压板喷油"><span>#</span></a></h1><p>冷却油从壳体1中间段的进油口11进入，与其他中间进油方案不同，该壳体具有环形通道12，中间端铁芯外径与其他段相同。进液口11将冷却液引入定子铁心21表面，定子铁芯1表面上有多个凹槽结构用于形成轴向冷却流道a。定子铁芯21沿轴向方向的两端的端面13和端面214冲片具有导流槽，形成径向的冷却通道b。第一端板23和第二端板24分别位于定子铁芯21轴向方向的两端，在端板23、24上分别具有喷油孔232和241，将冷却液体喷淋在绕组上。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105125906.png" alt="image-20240527105125906" /><figcaption>image-20240527105125906</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105130571.png" alt="image-20240527105130571" /><figcaption>image-20240527105130571</figcaption></figure><p></p></section>
<section><h1>5、华为-CN116865465A（定子压板孔喷油）<a href="#5华为-cn116865465a定子压板孔喷油"><span>#</span></a></h1><p>华为在原先专利CN115333265A上做出了改进，该冷却系统不仅在定子轭部有斜喷的第一冷冷却口11，在槽底上方还有第二冷却口孔12。多个第一冷却孔分别与多个第二冷却孔相邻排列，每个径向流道贯穿定子硅钢片并连通一个第一冷却孔和一个第二冷却孔。油路走向如下：</p><p>冷却油从壳体进油口501进入，通过壳体环形通道502，将冷却油引入第一类定子铁芯T1表面，并沿着T1表面上有多个的轴向冷却液流道D1分别流向前后两端，其中流向前端冷却油经过第二类定子铁芯T2、第三类定子铁芯（端板）T31和T32从第一冷却口11倾斜喷在绕组上方。流向后端的冷却油经过第二类定子铁芯T2的导油槽形成的径向流道15，经过第二冷却口12回流到铁芯T1的轴向冷却流道D2，并通过第二类定子铁芯T2、第三类定子铁芯（端板）T31和T32从槽底上方的第二冷却口12直喷在绕组上。第二类定子铁芯T2、第三类定子铁芯（端板）T31和T32通过前后通过旋转错位装配可以在绕组前后端均形成相互串联的冷却通道11、12。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105144554.png" alt="装配截面图" /><figcaption>装配截面图</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105154107.png" alt="流道示意图" /><figcaption>流道示意图</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105204654.png" alt="铁心爆炸视图" /><figcaption>铁心爆炸视图</figcaption></figure><p></p></section>
<section><h1>6、小米-CN116014928A（定子油环喷油）<a href="#6小米-cn116014928a定子油环喷油"><span>#</span></a></h1><p>专利采用冷却油环方案，所述冷却第一冷却油环21、第二冷却22设于所述定子铁芯1的前后端部，且与定子铁芯1同轴布置。冷却油环上设有多个进油通道23和多个出油通道24，进油通道23和出油通道24均与定子铁芯轴向的喷油孔形成的冷却通道12连通。</p><p>冷却油从壳体进油孔201进入，通过第一油环21的第一进油通道231通入至冷却通道12内，然后冷却油液沿冷却通道12的长度方向移动并由冷却通道12的另一端流出，流出的冷却油液可以进入至第二油环22的第二进油通道232。由于第二进油通道232与其相邻的第二出油通道242连通，从而可以将冷却油液通过第二出油通道242排出至第二油环22，最后再通过另一冷却通道12将冷却油液回流至第一出油通道241。同时冷却油环上设置有油喷孔，冷却油通过喷油孔喷淋在绕组端部</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105218436.png" alt="图 铁芯装配图" /><figcaption>图 铁芯装配图</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105225102.png" alt="图 油环放大图" /><figcaption>图 油环放大图</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105231303.png" alt="图 冷却系统截面" /><figcaption>图 冷却系统截面</figcaption></figure><p></p></section>
<section><h1>7、小米-CN116613907A（（定子油环喷油））<a href="#7小米-cn116613907a定子油环喷油"><span>#</span></a></h1><p>为了使前后两端和圆周方向绕组冷却更加均匀，得到更好的散热效果，小米在该专利中进行了改进设计。冷却介质由壳体4的第一进油口41进入定子后，沿定子铁芯21流向两侧，经过两侧的油环1后喷淋到定子绕组22的整个外周，以分别实现对定子铁芯21和定子绕组22的冷却。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105259152.png" alt="image-20240527105259152" /><figcaption>image-20240527105259152</figcaption></figure><p></p><p>小米的技术方案定子铁芯包含两种叠片，通过将多个叠片叠压和旋转设计，能够形成不同冷却介质流动路径，以提高对定子铁芯的冷却效果。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105305419.png" alt="image-20240527105305419" /><figcaption>image-20240527105305419</figcaption></figure><p></p></section>
<section><h1>8、Tesla-空心轴套（专利号：US7579725）（空心转子间接冷却）<a href="#8tesla-空心轴套专利号us7579725空心转子间接冷却"><span>#</span></a></h1><p>驱动轴103是一根较粗的驱动轴，在105端封闭，在107端打开。空心冷却剂进油管109通过多个辐条支架111，刚性地连接到轴103上。在运行过程中，冷却剂通过从113端进入进油管109，直到流到闭合端105的内表面，冷却剂将重新沿115方向重新流回，从而冷却传动轴和所驱动的转子。其中闭合端105的内表面设计成凸出式结构701，可以有效的减小管路的压头损失。在此方案中需要两个密封圈117和113，防止冷却液泄露。空心轴套的难点在于空心轴103和进油管109同时旋转需要他们之间刚性连接。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105312232.png" alt="image-20240527105312232" /><figcaption>image-20240527105312232</figcaption></figure><p></p></section>
<section><h1>9、Tesla-空心轴套+机壳冷却（专利号：US6191511）<a href="#9tesla-空心轴套机壳冷却专利号us6191511"><span>#</span></a></h1><p>在Tesla2007的基础上，特斯拉在2009年做了改进。用机械离心泵代替了外置油泵，也不需要外置的散热器，并且在机壳上做了冷却流道来使定子部分充分冷却。冷却液通过定子和转子之间循环保证了良好的温度循环，也减少了温差引起的热膨胀量不同造成轴承的磨损。</p><p>电机的空心轴11通过轴承6和7固定在在定子法兰4和法兰5上，轴上的中心孔12延伸长度覆盖到整个电枢10和前后轴承6、7，这样不仅可以冷却到转子温度还能有效的冷却轴承的发热。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105319583.png" alt="image-20240527105319583" /><figcaption>image-20240527105319583</figcaption></figure><p></p><p>10、宇通客车-机壳冷却+端部灌封（专利号：CN201720950781）</p><p>冷却油从电机壳体的进油口（3）进入通过壳体油路（21），流入电机的前端盖油路（6）。其中油路（6）和轴承室（8）连通，冷却油对定子和轴承室进行冷却后，最后从后端盖（5）流回壳体（1）的出油口（4）。整个回路中，壳体油路（21）与端盖油路（6）之间的对接处设有密封圈（15），防止冷却油的外泄。如图二，电机前后端盖的端面上设有用于将定子（14）的热量传递至前后端盖（5）的导热绝缘材料——灌封胶或导热硅胶（16）。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105330594.png" alt="image-20240527105330594" /><figcaption>image-20240527105330594</figcaption></figure><p></p><p>10、长城汽车-转子支架+甩油冷却（专利号：CN201620387763）</p><p>电机冷却方式（主要通过端盖（11）进油，通过转子支架（2）的转动，将油甩至转子和定子进行散热。</p><p>前端盖（11），其内表面设有凸台（13），冷却油从凸台外圈的进油口流入道其内部的油道（6），并从出油口（12）流入到转子支架（2）上。</p><p>电机的转子支架（2），冷却油从端盖侧流入进油槽口（28），并在槽口旁设置有安装环形密封圈的密封槽（29），冷却油通过油道（24），在转子支架的旋转作用下，冷却油受离心力的作用经内圈油孔（25），径向甩出到外油孔（26），进入外圈油道（27）并与转子（3）和定子（4）进行冷却，其中外油孔（26）、外圈油道（27）朝向各自接近的转子油道（7）倾斜，实现导向作用，将外圈油道（27）的冷却油在离心力的作用下进入平衡端板（5）上的油道（7）（如图四），在对转子（3）冷却的同时会同时冷却定子（4）的绕线端部，提升冷却效率，还能使转子受力均匀。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105344255.png" alt="image-20240527105344255" /><figcaption>image-20240527105344255</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105348384.png" alt="image-20240527105348384" /><figcaption>image-20240527105348384</figcaption></figure><p></p></section>
<section><h1>10、北京牟特科技-平衡板+甩油冷却（专利号CN208078826U）<a href="#10北京牟特科技-平衡板甩油冷却专利号cn208078826u"><span>#</span></a></h1><p>后端盖（200）纵向方向上开有后端盖油路（201），且设有后轴承座（202），其中后轴承座（202）内设置有与后端盖管路（201）相连的轴承座管路（203），油路（201）中有部分油通过油路（203）流至电机的主轴（400），通过主轴的油路，一部分从前轴承位置处的出孔（403）流出对前轴承进行冷却，一部分端板冷却出孔（401）、（402）将油送至端板（700）内部，再从端板（700）末端甩处对定子绕阻进行冷却。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105355684.png" alt="图 冷却系统" /><figcaption>图 冷却系统</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105406074.png" alt="图 甩油端板" /><figcaption>图 甩油端板</figcaption></figure><p></p></section>
<section><h1>11、通用-喷油环+甩油冷却(专利号）<a href="#11通用-喷油环甩油冷却专利号"><span>#</span></a></h1><p>冷却油从机壳右上端A侧进入，经过喷油环（100）。其中一部分油经过喷油环（100）流入绕阻端部，另一部分顺着机壳冷却通道A流入后端盖C通道。其中C通道的油，一部分通过后端盖的弧面设计，使油甩在绕阻端部的内表面；一部沿着E方向通过平衡端板弧形槽，把油带入下侧，实现对下侧绕阻的甩油；还有一部分油经过D和F通道，把油送入轴承室，对轴承进行冷却，以降低轴承温度减少转动损失。最终油都落入储油腔，经H通道流出，此设计的亮点在于，通过端板、端盖、喷油环的设计让电机各部件都可以冷却到，尤其是对绕阻端部内外表面都有喷油的冷却效果，大大增加了冷却的均匀性。保持电机各部件温度的一致性。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105419251.png" alt="image-20240527105419251" /><figcaption>image-20240527105419251</figcaption></figure><p></p></section>
<section><h1>12、北京牟特科技-外置油路喷油+甩油冷却（专利号CN201810168100）<a href="#12北京牟特科技-外置油路喷油甩油冷却专利号cn201810168100"><span>#</span></a></h1><p>电机工作时，进油管（4）输入冷却油，一部分冷却油流入机壳内部的管路（11），其中管路（11）在绕阻端部上侧开有径向方向的出油孔，实现绕阻端部的喷油，最终落入电机底部的储油腔（14）。另一部分冷却油通过外置油管5流入电机主轴（8）内，在主轴（8）的高速旋转的离心作用下从主轴（8）的出油孔甩出，用来冷却电机腔体内的其他零部件。转子支架（9）上设置有沿圆周方向的多个散热孔，使其于转子铁芯连通，给转子铁芯散热。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105424809.png" alt="图 冷却系统" /><figcaption>图 冷却系统</figcaption></figure><p></p></section>
<section><h1>13、上汽—CN207382136U（油管喷油冷却）<a href="#13上汽cn207382136u油管喷油冷却"><span>#</span></a></h1><p>电机由定子总成（1）、油管（2）、筒状钢套（3）构成，其中定子总成（1）与筒状钢套（3）过盈配合，油管（2）装配在筒状钢套（3）外侧。</p><p>系统油路：冷却油通过进油口（6）进入油管（2），一部分冷却油由油管（4）上喷嘴（7）透过对应的冷却槽（8）喷射在定子端部绕组（9），实现对两端端部绕组（9）的冷却；另一部分冷却油由直线油管（5）上的喷嘴（7）喷射至筒状钢套（3）的表面，实现对筒状钢套（3）的冷却，进而冷却定子总成（1）。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105435636.png" alt="image-20240527105435636" /><figcaption>image-20240527105435636</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105445694.png" alt="image-20240527105445694" /><figcaption>image-20240527105445694</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105450982.png" alt="image-20240527105450982" /><figcaption>image-20240527105450982</figcaption></figure><p></p></section>
<section><h1>14、上汽—CN110323895A（机壳水冷+搅动储油冷却）<a href="#14上汽cn110323895a机壳水冷搅动储油冷却"><span>#</span></a></h1><p>电机壳体(2)在底部设有储存变速箱油的储油区(14)，储油区（14）与变速箱（16）相连通，其油位超过驱动电机的最低气隙，并淹没部分电机转子（11）。电机工作时，通过转子（11）搅动储油区（14）的变速箱油，并且通过转子（11）旋转甩油冷却定子的上半部分。</p><p>油区（14）底部与电机定子（10）之间有一定间距，如图示电机壳体底部向下扩展成矩形形状，以便有足够空间来形成储油。储油区（14）底部设有水冷腔，水冷腔由“S”形水道（7）和进出水口（15）构成，带走变速箱油传递给电机壳体（2）的热量。</p><p>电机转子（11）设有平衡盘（17），在平衡盘（17）上分别设有8个甩油结构，甩油结构由甩油槽（18）、甩油孔（19）构成，其中甩油槽呈矩形位于平衡盘内壁，甩油孔为圆形孔位于平衡盘外壁且尺寸小于油槽（18）尺寸，且每一个油槽（18）对应一个甩油孔（19）。甩油结构可将油带到电机腔内高位，实现电机端部绕组的冷却，冷却油跌落时可对电机轴承进行润滑。</p><p>该系统需要将油温维持在较高的温度，以降低油的粘稠度，否则会有较大的变速箱齿轮和电机转子的搅油损耗。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105504415.png" alt="image-20240527105504415" /><figcaption>image-20240527105504415</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105508223.png" alt="image-20240527105508223" /><figcaption>image-20240527105508223</figcaption></figure><p></p></section>
<section><h1>15、长春一汽—CN209329892U（喷油冷却定子+空心转子）<a href="#15长春一汽cn209329892u喷油冷却定子空心转子"><span>#</span></a></h1><p>通过端盖使冷却油分别进入第一机壳油路和第二轴油路，第一机壳油路冷却定子和逆变器组件并同时通过喷洒孔设计冷却电机绕组端部，第二轴油路冷却转子和轴承。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105513848.png" alt="image-20240527105513848" /><figcaption>image-20240527105513848</figcaption></figure><p></p></section>
<section><h1>16、比亚迪—CN206149098U（喷油+甩油）<a href="#16比亚迪cn206149098u喷油甩油"><span>#</span></a></h1><p>如图6.1、图6.2此系统油路：冷却油从进油口（101）流入壳体（10），壳体油路（14）分为两路，一路通过壳体喷油口（14a）喷洒在绕组端部；另一路流入端盖油道（12b）并流向转子油路（21a），通过端板油路（23a）和端板喷油口（24a）向定子甩油，回落至空腔（13）的油通过出油口（102）与外部回油管路连通。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105520842.png" alt="image-20240527105520842" /><figcaption>image-20240527105520842</figcaption></figure><p></p></section>
<section><h1>17、大洋—CN203554162U（机壳水冷+负压转子甩油）<a href="#17大洋cn203554162u机壳水冷负压转子甩油"><span>#</span></a></h1><p>在机壳（4）的空腔（41）里装有部分冷却油，当转轴（1）转动时带动叶轮（7）旋转，并产生负压，将机壳（4）空腔（41）底部的冷却油前后通过第二进油孔（52）、第一油道（53）、第一进油孔（510）吸入到后轴承室（512）。后轴承室（512）里的冷却油从转轴（1）端部流入转子内部的第二油道（11）由于转轴（1）高速离心力的作用，冷却油会通过转轴上的出油孔（12）沿周向冷却定子组件、转子组件以及前轴承。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105527984.png" alt="image-20240527105527984" /><figcaption>image-20240527105527984</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105536839.png" alt="image-20240527105536839" /><figcaption>image-20240527105536839</figcaption></figure><p></p></section>
<section><h1>18、精进—CN103296824A（机壳油冷+甩油+喷油）<a href="#18精进cn103296824a机壳油冷甩油喷油"><span>#</span></a></h1><p>该油冷系统通过壳体（1）中的进油口（10），分别流向由壳体和定子配合构成的第一油道（15）冷却定子、壳体和油封环配合构成第二油道（12）、壳体和后端盖油封环构成的第三油道（17）冷却定子端部，以及通向转子内腔的导游管利用离心力甩油冷却端部。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105541434.png" alt="图 冷却系统结构" /><figcaption>图 冷却系统结构</figcaption></figure><p></p></section>
<section><h1>19、恒大—CN109194035A（机壳油冷+喷油+导油环甩油）<a href="#19恒大cn109194035a机壳油冷喷油导油环甩油"><span>#</span></a></h1><p>电机冷却系统油路：冷却油由机壳顶部进油口（31）经过机壳环形油道（33）到达前后导油环（2）（5）处，通过导油环的喷油口将冷却油均匀喷射在定子绕组上端部，绕组上端部的冷却油受重力影响跌落至引油板（12）（72），经引油板将冷却油引如转子支架（64）的内腔，由于电机转子（6）旋转离心力的作用，油液沿着转子支架（64）的带斜度内腔向外侧流动，到达平衡板（62）时，被平衡板（62）高出转子支架（64）的部分挡住，随后油液进入平衡板（62）的集油槽内，在离心力的作用下，油液从甩油孔甩出对定子绕组端部内侧进行冷却。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20240527105552040.png" alt="image-20240527105552040" /><figcaption>image-20240527105552040</figcaption></figure><p></p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/692/</id>
      <title type="text">内网访问：使用Zerotier进行打洞</title>
      <published>2023-12-21T15:47:06.000Z</published>
      <updated>2024-06-06T03:25:36.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/692/"/>
      <summary type="text">家里没有公网ipv4，只有ipv6，而许多公共场所的网络都是没有开启ipv6，无法直接访问内网服务。 之前一直使用FRP做内网穿透，将内网服务暴露到外网上，但是简单的tcp转发访问速度依靠公网服务器的带宽，我的腾讯云是8M的小水管，有点不太</summary>
      <content type="html"><![CDATA[<p>家里没有公网ipv4，只有ipv6，而许多公共场所的网络都是没有开启ipv6，无法直接访问内网服务。</p>
<p>之前一直使用FRP做内网穿透，将内网服务暴露到外网上，但是简单的tcp转发访问速度依靠公网服务器的带宽，我的腾讯云是8M的小水管，有点不太够用，同时每一个服务都要重新设置一遍FRP比较麻烦。尝试过使用FRP的P2P模式，但是打洞一直没成功，可能操作上有问题，也有可能是本地的NAT过于复杂，就放弃了。</p>
<p>于是，我转向了许多人都推荐过的内网穿透神器—<strong>Zerotier</strong>。ZeroTier 是一款网络层面的穿透工具，可以轻松搭建自己的虚拟网络，将不同局域网的电脑分配到同一网段下，并提供相应的虚拟网络 IP 地址，使得各个设备间可以通过虚拟地址来访问彼此。在 ZeroTier 网络体系中，根服务器被称为<strong>星球（planet）</strong>，每一台联网设备被称为<strong>叶子（leaf）</strong>，两台星球之间是通过星球节点握手建立隧道连接的。</p>
<p>ZeroTier 作为一家总部位于加州的美国公司，并没有在中国设有根服务器，因此在两台设备连接时受制于星球节点的连接质量，可能会产生高延迟。如果需要降低握手时的网络延迟、提高联网稳定性和安全性，可以按照官方指引来搭建<strong>月亮（moon）节点</strong>，让设备相互连接时通过自己搭建的月亮节点来握手建立隧道。</p>
<section><h3>开始<a href="#开始"><span>#</span></a></h3><p>Zerotier支持各种设备，包括windows，linux，安卓，docker等，可以使不同操作系统的用户轻松的建立网络，并进行互相访问和分享资源。</p><p>首先在<a href="https://www.zerotier.com/" target="_blank">官网</a>进行注册，创建一个自己的虚拟网络。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20231221231145923.png" alt="image-20231221231145923" /><figcaption>image-20231221231145923</figcaption></figure><p></p></section>
<section><h3>创建网络<a href="#创建网络"><span>#</span></a></h3><p>点击Create A Network，直接创建网络，只需一次点击，网络就创建好了。</p><p>记住这个 Network ID，加入虚拟局域网需要用到。</p></section>
<section><h3>Linux<a href="#linux"><span>#</span></a></h3><p>根据官网给的说明，直接运行脚本即可。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>curl -s https://install.zerotier.com | sudo bash</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>如果你安装了 GPG 密钥验证，用下面这条命令</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>curl -s 'https://raw.githubusercontent.com/zerotier/ZeroTierOne/master/doc/contact%40zerotier.com.gpg' | gpg --import &amp;&amp; \</span></div></div><div><div><div>2</div></div><div><span>if z=$(curl -s 'https://install.zerotier.com/' | gpg); then echo "$z" | sudo bash; fi</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>脚本会自动将 Zerotier 的源添加到 apt/yum 里并安装。</p><p>安装好后，运行命令即可。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>sudo zerotier-cli join 你的网络ID</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section>
<section><h3>群晖<a href="#群晖"><span>#</span></a></h3><p>群晖建议使用第三方套件来进行安装，我这里推荐矿神源。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20231221233112205.png" alt="image-20231221233112205" /><figcaption>image-20231221233112205</figcaption></figure><p></p><section><h4>DSM7.0特殊操作：ssh或者任务计划root执行以下代码，必须要操作的！！！安装后只需要执行一次<a href="#dsm70特殊操作ssh或者任务计划root执行以下代码必须要操作的安装后只需要执行一次"><span>#</span></a></h4><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>sudo sed -i 's/package/root/g' /var/packages/zerotier/conf/privilege</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>完成上述命令后，直接启动套件。</p><p>然后在ssh界面使用命令加入虚拟局域网。</p></section><section><h4>xxxxxx是zerotier的Network ID，填你自己的！！！<a href="#xxxxxx是zerotier的network-id填你自己的"><span>#</span></a></h4><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>sudo -i</span></div></div><div><div><div>2</div></div><div><span>cd /var/packages/zerotier/target/bin</span></div></div><div><div><div>3</div></div><div><span>./zerotier-one -q join xxxxxx</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20231221234522403.png" alt="image-20231221234522403" /><figcaption>image-20231221234522403</figcaption></figure><p></p></section></section>
<section><h3>Windows<a href="#windows"><span>#</span></a></h3><p>windows安装最简单了，直接官网下载安装包自行安装即可。</p><p>安装好后，点击Join Zerotier Network，输入加入的Network ID即可。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20231221233438482.png" alt="image-20231221233438482" /><figcaption>image-20231221233438482</figcaption></figure><p></p></section>
<section><h3>授权<a href="#授权"><span>#</span></a></h3><p>每一次添加了客户端后，在控制面板上会显示新设备加入，zerotier不会自动授权，需要手动勾选，对这个设备授权。</p><p>可以自动分配 IP也可以手动进行调整，显示 zerotier 客户端的版本号和物理地址。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20231221233701476.png" alt="image-20231221233701476" /><figcaption>image-20231221233701476</figcaption></figure><p></p><p>免费版最多一个网络可以有25个设备，对于设备不多的人应该是够用了。</p><p>完成授权后，只要输入对应的虚拟 IP，就可以访问对应的设备了。这些设备相当于都处于同一个局域网下了。你会发现，速度相当快了。</p></section>
<section><h3>高级自定义 Moon<a href="#高级自定义-moon"><span>#</span></a></h3><p>为了提高虚拟局域网的速度和可靠性，特别是在网络链接的延迟和不稳定的情况下，ZeroTier允许用户建立自己的moon卫星中转服务器。这种服务器作为Moon，可以搭建一个国内的“卫星”作为中转服务器，作为根节点速度慢，不稳定的一种补充保障。这样，即使根节点的速度慢或不稳定，也可以利用Moon服务器来保证网络的稳定性和流畅性。</p><p>在ZeroTier中，任何节点都可以被用作Moon。通常情况下，我们会选择公网IP的节点，例如云服务器。</p><p>官方文档可以在以下链接中找到：<a href="https://docs.zerotier.com/zerotier/moons" target="_blank">https://docs.zerotier.com/zerotier/moons</a></p><p>首先，我们需要准备一台云服务器并连接好网络。然后，进入配置文件夹，在Linux上通常是<code>/var/lib/zerotier-one</code>。接下来，执行以下命令：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>zerotier-idtool</span><span> </span><span>initmoon</span><span> </span><span>identity.public</span><span> &gt;&gt;</span><span>moon.json</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>打开生成的文件，它应该类似于以下内容：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>{</span></div></div><div><div><div>2</div></div><div><span>  </span><span>"id"</span><span>: </span><span>"deadbeef00"</span><span>,</span></div></div><div><div><div>3</div></div><div><span>  </span><span>"objtype"</span><span>: </span><span>"world"</span><span>,</span></div></div><div><div><div>4</div></div><div><span>  </span><span>"roots"</span><span>: [</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>{</span></div></div><div><div><div>6</div></div><div><span>      </span><span>"identity"</span><span>: </span><span>"deadbeef00:0:34031483094..."</span><span>,</span></div></div><div><div><div>7</div></div><div><span>      </span><span>"stableEndpoints"</span><span>: []</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>9</div></div><div><span><span>  </span></span><span>],</span></div></div><div><div><div>10</div></div><div><span>  </span><span>"signingKey"</span><span>: </span><span>"b324d84cec708d1b51d5ac03e75afba501a12e2124705ec34a614bf8f9b2c800f44d9824ad3ab2e3da1ac52ecb39ac052ce3f54e58d8944b52632eb6d671d0e0"</span><span>,</span></div></div><div><div><div>11</div></div><div><span>  </span><span>"signingKey_SECRET"</span><span>: </span><span>"ffc5dd0b2baf1c9b220d1c9cb39633f9e2151cf350a6d0e67c913f8952bafaf3671d2226388e1406e7670dc645851bf7d3643da701fd4599fedb9914c3918db3"</span><span>,</span></div></div><div><div><div>12</div></div><div><span>  </span><span>"updatesMustBeSignedBy"</span><span>: </span><span>"b324d84cec708d1b51d5ac03e75afba501a12e2124705ec34a614bf8f9b2c800f44d9824ad3ab2e3da1ac52ecb39ac052ce3f54e58d8944b52632eb6d671d0e0"</span><span>,</span></div></div><div><div><div>13</div></div><div><span>  </span><span>"worldType"</span><span>: </span><span>"moon"</span></div></div><div><div><div>14</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>在<code>roots/stableEndpoints</code>数组中填入本机的虚拟IP和端口号，通常端口是9993。如果你的服务器支持IPv6，也可以填入IPv6地址。</p><p>确保服务器打开了9993端口！</p><p>然后执行以下命令：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>zerotier-idtool</span><span> </span><span>genmoon</span><span> </span><span>moon.json</span></div></div><div><div><div>2</div></div><div><span>mkdir</span><span> </span><span>moons.d</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>这将生成一个以<code>000xxxx.moon</code>命名的文件，将其放入<code>moons.d</code>文件夹中。这个<code>000xxx</code>就是该Moon的ID。</p><p>在与其连接的客户端上，执行以下命令：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>zerotier-cli</span><span> </span><span>orbit</span><span> </span><span>000xxx</span><span> </span><span>000xxx</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>其中，第一个参数是World ID，第二个参数是Moon ID。无需过多考虑细节，两个参数相同即可。</p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/836/</id>
      <title type="text">足迹：2023年北京出差</title>
      <published>2023-11-25T05:34:55.000Z</published>
      <updated>2025-11-14T15:20:10.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/836/"/>
      <summary type="text">北京出差 一周足迹记录 这次被公司外派到北京出差，本来以为只是两三天的小差事，没想到一待就是一周。幸好利用下班时间和周末，正好能好好逛逛这座历史与现代交融的城市。 🌉第一站：卢沟桥 - 历史的沉思 我的住处就在丰台区，离卢沟桥很近，所以第一</summary>
      <content type="html"><![CDATA[<section><h3>北京出差 | 一周足迹记录<a href="#北京出差--一周足迹记录"><span>#</span></a></h3><p>这次被公司外派到<strong>北京</strong>出差，本来以为只是两三天的小差事，没想到一待就是一周。幸好利用下班时间和周末，正好能好好逛逛这座历史与现代交融的城市。</p><img src="http://imgbed.leihub.cn/img/IMG_20231119_145447.jpg" alt="IMG_20231119_145447" /><section><h4>🌉第一站：卢沟桥 - 历史的沉思<a href="#第一站卢沟桥---历史的沉思"><span>#</span></a></h4><p>我的住处就在丰台区，离<strong>卢沟桥</strong>很近，所以第一时间就跑去看了。卢沟桥不只是北京一座普通的桥，它承载着太多历史。桥上那些历经风雨的石狮子和桥上的弹孔，无声地诉说着当年那段悲壮的历史，仿佛让人回到了1937年的那个夜晚。桥旁还有<strong>宛平城</strong>和<strong>中国人民抗日战争纪念碑</strong>，肃穆之中更添一份沉重，参观完后心情久久不能平静。</p><img src="http://imgbed.leihub.cn/img/IMG_20231122_160253.jpg" alt="IMG_20231122_160253" /></section><section><h4>🎨周末：打卡北京经典景点<a href="#周末打卡北京经典景点"><span>#</span></a></h4><p>到了周末，当然得抓紧时间去逛一逛北京最经典的几个打卡地。</p><p>第一站是<strong>天安门广场</strong>，这里总是让人感受到一种磅礴的气势。不过当天风特别大，站在广场上几乎要被风吹跑了😅，北方的干冷果然和南方湿冷完全不同，哪怕裹着大棉袄也觉得冷到骨子里。</p><img src="http://imgbed.leihub.cn/img/IMG_20231123_132057.jpg" alt="IMG_20231123_132057" /><p><strong>紫禁城</strong>也是必不可少的一站，这里不仅是明清两代的皇宫，更是中国历史的象征。紫禁城真的非常大，走了一圈下来，脚都有点走软了😂。不过因为天气原因，很多场馆都没开放，还是有点小遗憾，期待下次再来。</p><img src="http://imgbed.leihub.cn/img/IMG_20231123_140337.jpg" alt="IMG_20231123_140337" /><p><strong>下一站是国家博物馆</strong>，这里的藏品真是让人眼花缭乱。<strong>四羊方尊</strong>、<strong>后母戊鼎</strong>等国宝让我惊叹中国古代工艺的精湛与文化的悠久。馆内文物种类繁多，每一件都值得细细品味，真的是一场视觉与文化的盛宴。</p><img src="http://imgbed.leihub.cn/img/IMG_20231123_121102.jpg" alt="IMG_20231123_121102" /></section><section><h4>🔫匆匆的军事博物馆<a href="#匆匆的军事博物馆"><span>#</span></a></h4><p><strong>军事博物馆</strong>也是我很想去的地方，但因为和同学约好了一起吃饭，时间有点紧凑。匆匆看了几件展品，还没来得及细细欣赏就得赶着走了。这里的展览非常震撼，尤其是看到那些真实的坦克、战机等军备，心中满满的敬畏感。不过短暂的参观让我觉得意犹未尽，留着下次有机会再深入探索吧。</p><img src="http://imgbed.leihub.cn/img/IMG_20231124_163658.jpg" alt="IMG_20231124_163658" /></section><section><h4>❄️ 雪中的北京告别<a href="#️-雪中的北京告别"><span>#</span></a></h4><p>最后，办完工作上的事情，准备离开北京时，正好赶上了<strong>北京的第一场雪</strong>。北方的初雪总是让人感到一丝浪漫与凛冽交织。漫天飞舞的雪花给这座城市增添了一抹静谧，也给我的这次出差画上了一个特别的句号。</p><img src="http://imgbed.leihub.cn/img/IMG_20231125_132302.jpg" alt="IMG_20231125_132302" /><p>在北京的一周，既有沉浸于历史的肃穆，也有在寒风中感受现代都市的活力。虽然出差有点忙碌，但这座城市的风景和文化深深打动了我。期待下一次再来探索这座充满故事的城市。</p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/846/</id>
      <title type="text">2023 国庆假期自驾游 | 郴州三大网红景点打卡</title>
      <published>2023-10-05T06:25:52.000Z</published>
      <updated>2025-11-14T15:20:23.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/846/"/>
      <summary type="text">2023 高温假自驾游 郴州三大网红景点打卡 刚入职不久，正好赶上高温假期，和家人一合计，决定来一场说走就走的自驾游！没有精心安排路线，嗦一碗家里美味的鱼粉直接开车出发，目的地暂定郴州。 郴州的旅游资源在湖南省内可谓丰富多彩，几天时间肯定是</summary>
      <content type="html"><![CDATA[<section><h3>2023 高温假自驾游 | 郴州三大网红景点打卡<a href="#2023-高温假自驾游--郴州三大网红景点打卡"><span>#</span></a></h3><p>刚入职不久，正好赶上高温假期，和家人一合计，决定来一场说走就走的自驾游！没有精心安排路线，嗦一碗家里美味的鱼粉直接开车出发，目的地暂定<strong>郴州</strong>。</p><img src="http://imgbed.leihub.cn/img/IMG_20231003_080319.jpg" alt="IMG_20231003_080319" /><p>郴州的旅游资源在湖南省内可谓丰富多彩，几天时间肯定是走不完的，于是我们挑了几个想打卡的网红景点，正式开启了这次自驾探险之旅。</p><section><h4>🌄 高椅岭 - 丹霞地貌的自然奇观<a href="#-高椅岭---丹霞地貌的自然奇观"><span>#</span></a></h4><p>第一站是<strong>高椅岭</strong>，一个还没完全开发的丹霞地貌“处女地”，这里山、水、泉、洞、崖、坦俱全，真的是美得让人惊叹。红岩配绿水，特别是那一个个水洼镶嵌在丹霞岩石间，如诗如画。</p><img src="http://imgbed.leihub.cn/img/IMG_20231003_134520.jpg" alt="IMG_20231003_134520" /><p>高椅岭有个著名的网红打卡点，就是那段陡峭的山崖，然而因为安全原因，这次没能爬上去，实在有些遗憾。不过，在山下环顾四周，山形奇特，像是一只巨大的蜥蜴趴伏在大地上，极具特色。</p><img src="http://imgbed.leihub.cn/img/mmexport1696512707667.jpg" alt="mmexport1696512707667" /><p>我们还体验了一把索道，从山顶滑下来，虽然不是特别惊险刺激，但也很有趣。</p><img src="http://imgbed.leihub.cn/img/IMG_20231003_134520.jpg" alt="IMG_20231003_134520" /></section><section><h4>🌬️ 仰天湖 - 自然与科技的完美结合<a href="#️-仰天湖---自然与科技的完美结合"><span>#</span></a></h4><p>第二站是<strong>仰天湖</strong>。这里不仅风景优美，山上还有大片的风电桩，站在山顶看着风车转动，仿佛现代科技与大自然相融。若不是当时没去风电，说不定这趟还是一次“内部出差”呢😂。</p><img src="http://imgbed.leihub.cn/img/IMG_20231004_104703.jpg" alt="IMG_20231004_104703" /><p>仰天湖的湖水倒映着蓝天，周围是连绵的群山，景色美不胜收。</p><img src="http://imgbed.leihub.cn/img/IMG_20231004_095940.jpg" alt="IMG_20231004_095940" /><img src="http://imgbed.leihub.cn/img/IMG_20231004_095940.jpg" alt="IMG_20231004_095940" /><p>不过这里的紫外线非常强，尤其是在山顶，稍不注意就容易被晒伤。没有做好防晒准备的我，成了反面教材，脖子和手臂全被晒得通红。所以提醒大家：去仰天湖一定要涂好防晒霜，做好遮阳措施！</p><img src="http://imgbed.leihub.cn/img/IMG_20231004_214713.jpg" alt="IMG_20231004_214713" /></section><section><h4>🌫️ 东江湖 - 错过的晨雾表演<a href="#️-东江湖---错过的晨雾表演"><span>#</span></a></h4><p>最后一站是<strong>东江湖</strong>。东江湖最出名的就是<strong>小东江晨雾</strong>，清晨时分，湖面上云雾缭绕，仿佛仙境。可惜我们没有早起，错过了这一奇景，实在有点遗憾。</p><img src="http://imgbed.leihub.cn/img/IMG_20231005_103140.jpg" alt="IMG_20231005_103140" /><p>虽然没看到晨雾表演，但在湖边散步，感受湖光山色，依然让人心旷神怡。我们还坐了游船，荡漾在清澈的湖面上，四周青山环绕，水天一色，非常宁静。</p><img src="http://imgbed.leihub.cn/img/IMG_20231005_111336.jpg" alt="IMG_20231005_111336" /><p>此外，还去探访了东江湖的地下溶洞<strong>兜率灵岩</strong>，洞内奇特的钟乳石景观让人流连忘返。</p><img src="http://imgbed.leihub.cn/img/IMG_20231005_112824.jpg" alt="IMG_20231005_112824" /><img src="http://imgbed.leihub.cn/img/IMG_20231005_103140.jpg" alt="IMG_20231005_103140" /><hr /><p>这一趟郴州自驾游，虽然有遗憾，但更多的是惊喜和收获。高椅岭的丹霞地貌、仰天湖的风电美景、东江湖的宁静悠远，都让人印象深刻。期待下一次的旅行冒险！</p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/683/</id>
      <title type="text">铣削加工机器人（四）：机器人铣削加工软件设计</title>
      <published>2023-09-02T08:49:39.000Z</published>
      <updated>2025-11-14T15:20:45.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/683/"/>
      <summary type="text">前言 本文介绍了所开发的KUKA机器人曲面铣削加工机器人系统软件，并结合前文介绍的机器人运动学建模、机器人刚度模型分析、加工轨迹分割和基于强化学习的轨迹分区域优化等内容，获取优化后的机器人冗余度和变位器转角参数，使用CoppeliaSim软</summary>
      <content type="html"><![CDATA[
# 前言
<p>本文介绍了所开发的KUKA机器人曲面铣削加工机器人系统软件，并结合前文介绍的机器人运动学建模、机器人刚度模型分析、加工轨迹分割和基于强化学习的轨迹分区域优化等内容，获取优化后的机器人冗余度和变位器转角参数，使用CoppeliaSim软件对优化后的轨迹进行仿真验证。</p>
<p>为了实现机器人铣削加工的自动化和数据监测的可视化，本节基于Python的Pyqt5开发机器人曲面铣削加工软件界面，通过多线程的方法处理机器人系统上传的数据、轨迹实时仿真、远程控制和上位机与机器人系统的数据交互通信。软件界面如图所示。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230902164233912.png" alt="image-20230902164233912" /><figcaption>image-20230902164233912</figcaption></figure><p></p>
<p>开发铣削加工机器人系统软件具有以下功能：</p>
<p>(1) 对机器人进行控制和监测，包括上位机与机器人以及整体加工系统通讯、加工轨迹以及振动实时监测等功能；</p>
<p>(2) 轨迹仿真功能，通过CoppeliaSim软件对预轨迹进行仿真，对加工轨迹进行验证；</p>
<p>(3) 加工轨迹处理功能，将UG软件生成的CLSF文件解析为机器人系统加工所需的末端和变位器轨迹，以及加工轨迹进行预分割和分区域优化；</p>
<p>(4) 加工结果测量功能，调用结构光相机测量加工表面点云，并进行配准，计算加工结果的加工误差。</p>
<section><h1>1 数据通信<a href="#1-数据通信"><span>#</span></a></h1><p>要实现通过上位机控制机器人进行加工，首先需要实现上位机和机器人系统之间的数据传输，再通过机器人系统程序读取数据，调用程序指令完成加工轨迹控制。UG生成的加工轨迹不能直接用于机器人加工，需要将五轴加工任务解析为机器人系统所需的末端轨迹和变位器轨迹，并转换为上位机和机器人系统通讯规定的数据格式发送给机器人并执行加工任务，流程如图所示。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230902164325741.png" alt="image-20230902164325741" /><figcaption>image-20230902164325741</figcaption></figure><p></p><p>KUKA机器人是通过Ethernet KRL模块(以下称Ethernet)实现上位机与机器人的数据通讯，Ethernet模块使用TCP/IP协议，以XML或二进制格式接收和发送数据。在机器人与上位机进行通讯前，需定义三个KRL同名文件，包括SRC和DAT、XML文件，SRC文件由实际运行的程序源代码构成，负责实现具体的机器人控制和外部通讯，DAT文件用于保存SRC文件中程序运行所需的变量以及通讯数据存储，XML文件定义了机器人与外部系统的通讯标准和数据格式。当在SRC程序中打开EKI(Ethernet KRL Interface)通讯接口，机器人系统会创建一个服务器，根据XML定义的配置不断监听外部连接，通讯原理如图所示。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230902164405227.png" alt="image-20230902164405227" /><figcaption>image-20230902164405227</figcaption></figure><p></p><p>在上位机上编写与机器人通讯的服务端，本文使用Python3.9进行编写，使用Socket模块与机器人系统进行通信，通过Socket创建一个客户端，根据EKI服务端监听的IP地址与端口号信息，向机器人系统发送连接请求，在服务端响应请求后，机器人系统与上位机的连接就建立起来，通信界面如图所示。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230902164421107.png" alt="image-20230902164421107" /><figcaption>image-20230902164421107</figcaption></figure><p></p></section>
<section><h1>2 加工程序解析<a href="#2-加工程序解析"><span>#</span></a></h1><p>本文使用UG软件生成机器人铣削加工的CLSF文件，CLSF文件存储了参考坐标系、加工轨迹和加工参数等，本文重点针对CLSF的加工轨迹指令进行提取解析。CLSF文件主要包括两种运动语句，分别是直线运动和圆弧语句，使用GOTO指令和CIRCLE指令来进行定位，其格式如下所示：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>GOTO/X,Y,Z,I,J,K</span></div></div><div><div><div>2</div></div><div><span>CIRCLE/X,Y,Z,I,J,K,R</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>其中，“X,Y,Z”表示刀轨位置，“I,J,K”表示刀轴矢量。</p><p>可以看出，CLSF文件定义的是五轴加工任务，即仅刀具末端的五个自由度，沿刀轴旋转的方向并未确定，与库卡的编程语言KRL并不通用，因此需要将其转换为KUKA机器人能够识别的轨迹数据。</p><p>由机器人铣削系统运动链分析可知，五轴加工任务转换到机器人加工时，机器人系统仍存在两个自由度，即绕刀轴旋转的自由度和工件变位器自由度。因此，在确定机器人冗余度和变位器转角后，即可将五轴加工任务<span><span>CLSCLS</span><span><span><span></span><span>C</span><span>L</span><span>S</span></span></span></span>转换为七自由度加工任务<span><span>(X,Y,Z,A,B,C,β)(X,Y,Z,A,B,C,β)</span><span><span><span></span><span>(</span><span>X</span><span>,</span><span></span><span>Y</span><span>,</span><span></span><span>Z</span><span>,</span><span></span><span>A</span><span>,</span><span></span><span>B</span><span>,</span><span></span><span>C</span><span>,</span><span></span><span>β</span><span>)</span></span></span></span>，确定机器人系统的加工轨迹。</p><p>在确定机器人的加工轨迹信息后，将刀轨转换为通讯所需的XML文件格式。按加工点位顺序将机器人末端加工姿态以及变位器转角写入XML文档，由于机器人控制柜数据存储器限制，每次传输的数据元素最大数量为512，需要对XML文件进行拆分处理，按加工顺序拆分为小文件再通过Socket传输给机器人系统，其格式如图所示。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230902164554036.png" alt="image-20230902164554036" /><figcaption>image-20230902164554036</figcaption></figure><p></p></section>
<section><h1>3 加工轨迹仿真<a href="#3-加工轨迹仿真"><span>#</span></a></h1><p>运动学仿真模块的操作界面如图所示，通过界面首页的仿真功能，与CoppeliaSim软件中的仿真环境建立连接，仿真图像通过CoppeliaSim软件的图像传输接口传输给界面，实时显示在界面中。在“关节角”这一栏中，可以在编辑框中输入机器人各关节的角度或拖动滑块改变编辑框数值，改变机器人形位。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230902164713118.png" alt="image-20230902164713118" /><figcaption>image-20230902164713118</figcaption></figure><p></p><p>可以通过仿真界面进行机器人加工轨迹仿真，有笛卡尔模式、关节模式和同步模式三种仿真模式。在进行实际的铣削加工前，可以将轨迹导入界面进行笛卡尔空间或者关节空间仿真，验证加工轨迹的正确性。当选择同步模式时，需要与机器人建立连接，仿真界面会实时接收机器人系统发送的机器人运动数据，仿真模型会根据实时数据进行在线仿真，在仿真环境中展示实际的加工轨迹。</p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/648/</id>
      <title type="text">铣削加工机器人（三）：机器人加工轨迹优化</title>
      <published>2023-09-02T08:23:18.000Z</published>
      <updated>2024-06-22T17:43:59.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/648/"/>
      <summary type="text">对于给定的加工任务，冗余自由度和变位器转角都会对机器人的加工位姿造成影响。因此，可以通过改变变位器的姿态和冗余自由度，进一步利用机器人的灵活性能，提高机器人的铣削加工性能。在上一篇文章中分别分析了冗余度和变位器转角与机器人刚度的关系，并提出</summary>
      <content type="html"><![CDATA[
对于给定的加工任务，冗余自由度和变位器转角都会对机器人的加工位姿造成影响。因此，可以通过改变变位器的姿态和冗余自由度，进一步利用机器人的灵活性能，提高机器人的铣削加工性能。在上一篇文章中分别分析了冗余度和变位器转角与机器人刚度的关系，并提出了基于刚度的曲面轨迹分割方法。
<p>本文在次基础上，得到分割后的加工轨迹，同时对冗余度和变位器进行优化，考虑机器人的运动学和碰撞约束，获取每个子区域的最优的冗余度和变位器参数，使整个加工区域的整体刚度指标最优。针对传统算法在进行优化时难以收敛的问题，使用强化学习算法DDPG建立模型优化环境，设计轨迹优化的马尔可夫决策过程，通过DDPG算法的不断学习，实现加工轨迹的最优化。</p>
<section><h1>1 、基于整体刚度指标的加工轨迹优化模型<a href="#1-基于整体刚度指标的加工轨迹优化模型"><span>#</span></a></h1><p>本节以提高机器人加工过程中的刚度指标<span><span>HH</span><span><span><span></span><span>H</span></span></span></span>为目标，建立一个同时考虑变位器和冗余度的轨迹优化模型。对于一个给定的五轴加工任务，机器人的加工姿态<span><span>(X,Y,Z,A,B,C)(X,Y,Z,A,B,C)</span><span><span><span></span><span>(</span><span>X</span><span>,</span><span></span><span>Y</span><span>,</span><span></span><span>Z</span><span>,</span><span></span><span>A</span><span>,</span><span></span><span>B</span><span>,</span><span></span><span>C</span><span>)</span></span></span></span>会随变位器旋转角度和机器人冗余度的变化而变化。由前文刚度模型的推导可知，机器人刚度随姿态变化而变化，在加工任务确定的情况下，机器人姿态由冗余自由度和工件设置决定，所以机器人刚度可以看作是关于冗余度和变位器转角的函数。</p><span><span><span>fst(α1,β1,...,αn,βn)=H(α1,β1,...,αn,βn)f_{st}(\alpha_1,\beta_1,...,\alpha_n,\beta_n)=H(\alpha_1,\beta_1,...,\alpha_n,\beta_n)</span><span><span><span></span><span><span>f</span><span><span><span><span><span><span></span><span><span><span>s</span><span>t</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span><span>α</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>β</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>...</span><span>,</span><span></span><span><span>α</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>β</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>)</span><span></span><span>=</span><span></span></span><span><span></span><span>H</span><span>(</span><span><span>α</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>β</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>...</span><span>,</span><span></span><span><span>α</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>β</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>)</span></span></span></span></span><p>根据前文的轨迹分割，假设将加工轨迹分割为<span><span>nn</span><span><span><span></span><span>n</span></span></span></span>个不同的子区域，每个区域对应一组最优冗余角和变位器旋转角，优化目标函数设为机器人在加工任务的整体刚度指标<span><span>HH</span><span><span><span></span><span>H</span></span></span></span>，并且其是冗余角和变位器旋转角的函数，如下所示：</p><span><span><span>μ(θ)=det(J(θ)J(θ)T)\mu(\theta)=\sqrt{det(J(\theta)J(\theta)^T)}</span><span><span><span></span><span>μ</span><span>(</span><span>θ</span><span>)</span><span></span><span>=</span><span></span></span><span><span></span><span><span><span><span><span><span></span><span><span>d</span><span>e</span><span>t</span><span>(</span><span>J</span><span>(</span><span>θ</span><span>)</span><span>J</span><span>(</span><span>θ</span><span><span>)</span><span><span><span><span><span><span></span><span><span>T</span></span></span></span></span></span></span></span><span>)</span></span></span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span><p>另外，机器人加工轨迹优化中还需要考虑许多约束条件，首先，机器人姿态应该避免处于奇异形位或者奇异形位附近。
其次，为了避免加工过程中达到机器人关节极限姿态，加工过程中机器人的各个关节角也应该受到限制，机器人的关节角要处于各个关节的转动范围内，同时也要考虑机器人关节速度不超过关节速度极限，即：</p><span><span><span>θmin≤θ≤θmax\theta{min}\leq \theta \leq \theta{max}</span><span><span><span></span><span>θ</span><span><span>min</span></span><span></span><span>≤</span><span></span></span><span><span></span><span>θ</span><span></span><span>≤</span><span></span></span><span><span></span><span>θ</span><span><span>ma</span><span>x</span></span></span></span></span></span><span><span><span>Δθ≤Δθmax\Delta \theta \leq \Delta \theta {max}</span><span><span><span></span><span>Δ</span><span>θ</span><span></span><span>≤</span><span></span></span><span><span></span><span>Δ</span><span>θ</span><span><span>ma</span><span>x</span></span></span></span></span></span><p>通过可操作度、关节和关节速度等约束，建立起基于分区域轨迹优化方法的变位器旋转角度和机器人冗余角的优化模型。
最后，在对机器人轨迹进行优化后，还需要进一步考虑碰撞问题。在加工平台中，有工件、变位器和夹具等辅助设备，机器人与加工系统发生碰撞不仅会对设备产生损伤，而且会危及研究人员的人身安全，在加工过程中，必须保证机器人不会存在碰撞的发生。因此，使用CoppeliaSim中的物理引擎进行碰撞检测，保证优化后的轨迹在加工过程无碰撞，如图所示。
</p><figure><img src="http://imgbed.leihub.cn/img/image-20230902160702345.png" alt="image-20230902160702345" /><figcaption>image-20230902160702345</figcaption></figure><p></p></section>
<section><h1>2 、基于强化学习的机器人轨迹优化方法<a href="#2-基于强化学习的机器人轨迹优化方法"><span>#</span></a></h1><p>上一节所展示的是一个多维优化问题，问题复杂度会随着区域划分数量的增长而增长。由前文的刚度分析可知，加工区域的整体刚度不是跟随变位器旋转角和机器人冗余角单调变化的。在求解这种高维问题时，使用启发式算法存在陷入局部最优的问题，本节提出使用深度确定性策略梯度算法 **(Deep Deterministic Policy Gradient, DDPG)**来对加工轨迹各个子区域的变位器转角和机器人冗余角参数进行优化。</p><section><h2>2.1 基于参数优化的马尔可夫决策过程设计<a href="#21-基于参数优化的马尔可夫决策过程设计"><span>#</span></a></h2><p>强化学习是一种基于马尔可夫决策过程的人工智能机器学习算法，在机器人研究领域得到广泛应用。本文对机器人曲面加工轨迹优化问题进行了建模，优化目标为最大化机器人加工过程中的整体刚度指标<span><span>HH</span><span><span><span></span><span>H</span></span></span></span>，将问题转换为马尔可夫决策过程，包括状态空间，动作空间和奖励函数的设计。</p><p>如图所示，智能体和环境分别是强化学习的主要元素，智能体根据当前状态<span><span>ss</span><span><span><span></span><span>s</span></span></span></span>来产生下一的动作<span><span>aa</span><span><span><span></span><span>a</span></span></span></span>，并产生当前的奖励<span><span>rr</span><span><span><span></span><span>r</span></span></span></span>。当智能体的动作导致了奖励为正值，智能体后续产生这个动作的概率就会上升，若奖励为负值，智能体产生这个动作的概率就会下降，通过迭代不断优化智能体，使智能体在环境中找到最优解。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230902160947087.png" alt="image-20230902160947087" /><figcaption>image-20230902160947087</figcaption></figure><p></p><p>**状态空间设计：**在机器人加工轨迹参数优化问题中，状态设置为优化模型中变量的信息，即由各个加工区域的冗余自由度<span><span>αiα_i</span><span><span><span></span><span><span>α</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>和变位器旋转角<span><span>βiβ_i</span><span><span><span></span><span><span>β</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>组成的集合 。</p><p>**动作空间设计：**在本文的优化模型中，动作空间根据优化变量的变化而设计，加工参数即各个区域的冗余自由度<em>αi</em>和变位器旋转角<em>βi</em>可以增大、减小或者不变。在DDPG中，参数的变化可以是连续的动作，选择各个参数的动作空间为各个加工参数的变化量  ，根据优化的经验，选择动作空间范围为[-1,1]。</p><p>**奖励函数构建：**奖励函数主要通过参数模型优化目标和优化适应度函数进行构建。奖励用于评价当前状态<span><span>sts_t</span><span><span><span></span><span><span>s</span><span><span><span><span><span><span></span><span><span>t</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>下选取动作<span><span>ata_t</span><span><span><span></span><span><span>a</span><span><span><span><span><span><span></span><span><span>t</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>对环境的好坏影响，奖励函数的设计会影响算法的寻优性能，通常根据寻优目标进行设计，本文的目标是最小化机器人加工的整体刚度指标<span><span>HH</span><span><span><span></span><span>H</span></span></span></span>，<span><span>DDPGDDPG</span><span><span><span></span><span>D</span><span>D</span><span>P</span><span>G</span></span></span></span>算法的目标是使累计奖励最大，因此奖励函数应与整体刚度指标<span><span>HH</span><span><span><span></span><span>H</span></span></span></span>呈负相关。</p></section><section><h2>2.2 DDPG算法原理<a href="#22-ddpg算法原理"><span>#</span></a></h2><p>DDPG是一种基于策略梯度的强化学习算法。与DQN基于值的强化学习训练方法不同，DDPG通过梯度来更新网络，使其向累计奖励增高的方向进行更新。DDPG算法可以处理连续空间问题，且在高维优化问题上适应性较强，而基于区域分割的机器人参数优化问题是一个高维且连续的问题，因此DDPG算法比较适合本文的参数优化问题。</p><p>DDPG算法基于Actor-Critic框架，通过训练以及环境的奖励机制不断更新网络，如图所示。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230902161409445.png" alt="image-20230902161409445" /><figcaption>image-20230902161409445</figcaption></figure><p></p><p>Actor和Critic分别各自含有两个神经网络，因此，DDPG有四个网络，即：Actor_online、Actor_target、Critic_online和Critic_target。其核心思想是用Actor网络输出一个确定的动作，然后使用Critic网络对动作进行评估，最后对Actor网络进行更新。</p><p>Actor网络根据状态输出一个确定的动作<span><span>aa</span><span><span><span></span><span>a</span></span></span></span>，Critic_online对动作进行评估，利用策略梯度的方法更新Actor_online：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230902161510816.png" alt="image-20230902161510816" /><figcaption>image-20230902161510816</figcaption></figure><p></p><p>Critic_target网络对动作<span><span>aa</span><span><span><span></span><span>a</span></span></span></span>进行评估，计算Critic网络的损失函数，利用反向传播更新Critic_online：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230902161545786.png" alt="image-20230902161545786" /><figcaption>image-20230902161545786</figcaption></figure><p></p><p>最后，在经过一定次数的训练后，更新Actor_target和Critic_target网络：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230902161559128.png" alt="image-20230902161559128" /><figcaption>image-20230902161559128</figcaption></figure><p></p></section><section><h2>3.3 基于DDPG的参数优化流程<a href="#33-基于ddpg的参数优化流程"><span>#</span></a></h2><p>基于DDPG算法，以最大化奖励<span><span>rtr_t</span><span><span><span></span><span><span>r</span><span><span><span><span><span><span></span><span><span>t</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>为目标，将优化的参数作为优化变量<span><span>sts_t</span><span><span><span></span><span><span>s</span><span><span><span><span><span><span></span><span><span>t</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>，通过智能体的不断迭代，得到使累计奖励最高的状态<span><span>sts_t</span><span><span><span></span><span><span>s</span><span><span><span><span><span><span></span><span><span>t</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>，即机器人整体刚度指标<span><span>HH</span><span><span><span></span><span>H</span></span></span></span>最优的加工参数。DDPG的算法步骤可以见表所示：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230902161631532.png" alt="image-20230902161631532" /><figcaption>image-20230902161631532</figcaption></figure><p></p></section></section>
<section><h1>3 优化结果与分析<a href="#3-优化结果与分析"><span>#</span></a></h1><p>首先，使用DDPG算法与其他常用的启发式优化算法对优化模型进行求解，并对求解效果进行比较，对算法的优化性能在多个方面进行评价，优化轨迹如图所示，为一个凹凸不平的自由曲面，本文使用第3章所示轨迹分割方法，将其分割为4个子区域。</p><p>​      </p><figure><img src="http://imgbed.leihub.cn/img/image-20230902161921674.png" alt="image-20230902161921674" /><figcaption>image-20230902161921674</figcaption></figure><p></p><p>使用Tensorflow框架进行DDPG的设计，在Intel Core i7-7600HQ CPU和GTX965M GPU的硬件配置上运行。关于DDPG算法的参数设置如表所示：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230902161946089.png" alt="image-20230902161946089" /><figcaption>image-20230902161946089</figcaption></figure><p></p><p>DDPG算法训练结束后，输出最优状态，为了对比DDPG算法与启发式算法之间的优化过程，用于验证DDPG算法进行参数优化的性能。给定一组加工任务，将DDPG算法与粒子群算法(PSO)和遗传算法(GA)等启发式算法进行对比。</p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/713/</id>
      <title type="text">聊天机器人（一）：Mirai+ChatGPT搭建QQ聊天机器人</title>
      <published>2023-09-01T11:22:08.000Z</published>
      <updated>2025-11-14T15:20:52.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/713/"/>
      <summary type="text">Mirai+ChatGPT实现机器人聊天 mirai：mamoe/mirai: 高效率 QQ 机器人支持库 github.com chatgpt-mirai-qq-bot:lss233/chatgpt-mirai-qq-bot: 🚀 一键部</summary>
      <content type="html"><![CDATA[<section><h1>Mirai+ChatGPT实现机器人聊天<a href="#miraichatgpt实现机器人聊天"><span>#</span></a></h1><p>mirai：<a href="https://github.com/mamoe/mirai" target="_blank">mamoe/mirai: 高效率 QQ 机器人支持库 (github.com)</a></p><p>chatgpt-mirai-qq-bot:<a href="https://github.com/lss233/chatgpt-mirai-qq-bot" target="_blank">lss233/chatgpt-mirai-qq-bot: 🚀 一键部署！真正的 AI 聊天机器人！支持ChatGPT、文心一言、讯飞星火、Bing、Bard、ChatGLM、POE，多账号，人设调教，虚拟女仆、图片渲染、语音发送 | 支持 QQ、Telegram、Discord、微信 等平台 (github.com)</a></p><p></p><figure><img src="http://imgbed.leihub.cn/img/1.jpg" alt="1" /><figcaption>1</figcaption></figure><p></p></section>
<section><h1>下载 docker-compose.yaml<a href="#下载-docker-composeyaml"><span>#</span></a></h1><p>新建一个文件夹，创建一个名为docker-compose.yml的文件，然后把以下内容写进去</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>version</span><span>: </span><span>'3.4'</span></div></div><div><div><div>2</div></div><div><span>services</span><span>:</span></div></div><div><div><div>3</div></div><div><span>  </span><span>mirai</span><span>:</span></div></div><div><div><div>4</div></div><div><span>    </span><span>image</span><span>: </span><span>lss233/mirai-http:latest</span></div></div><div><div><div>5</div></div><div><span>    </span><span>restart</span><span>: </span><span>always</span></div></div><div><div><div>6</div></div><div><span>    </span><span>environment</span><span>:</span></div></div><div><div><div>7</div></div><div><span>      </span><span>LANG</span><span>: </span><span>'C.UTF-8'</span></div></div><div><div><div>8</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>9</div></div><div><span><span>      </span></span><span>- </span><span>./mirai/bots:/app/bots</span></div></div><div><div><div>10</div></div><div><span><span>      </span></span><span>- </span><span>./mirai/config:/app/config</span></div></div><div><div><div>11</div></div><div><span><span>      </span></span><span>- </span><span>./mirai/data:/app/data</span></div></div><div><div><div>12</div></div><div><span>      </span><span># - ./mirai/config.json:/app/config.json # 如果你要修改 mcl 的设置，就解除这个注释</span></div></div><div><div><div>13</div></div><div><span>  </span><span>chatgpt</span><span>:</span></div></div><div><div><div>14</div></div><div><span>    </span><span>image</span><span>: </span><span>lss233/chatgpt-mirai-qq-bot:browser-version</span></div></div><div><div><div>15</div></div><div><span>    </span><span>restart</span><span>: </span><span>always</span></div></div><div><div><div>16</div></div><div><span>    </span><span>environment</span><span>:</span></div></div><div><div><div>17</div></div><div><span>      </span><span>LANG</span><span>: </span><span>'C.UTF-8'</span></div></div><div><div><div>18</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>19</div></div><div><span><span>      </span></span><span>- </span><span>./config.cfg:/app/config.cfg</span></div></div><div><div><div>20</div></div><div><span><span>      </span></span><span>- </span><span>./data:/app/data</span></div></div><div><div><div>21</div></div><div><span><span>      </span></span><span>- </span><span>./presets:/app/presets</span></div></div><div><div><div>22</div></div><div><span>      </span><span># - ./fonts:/app/fonts # 如果你想自定义字体，就解除注释</span></div></div><div><div><div>23</div></div><div><span>  </span><span>watchtower</span><span>: </span><span># [可选] 自动更新</span></div></div><div><div><div>24</div></div><div><span>    </span><span>image</span><span>: </span><span>containrrr/watchtower</span></div></div><div><div><div>25</div></div><div><span>    </span><span>volumes</span><span>: </span><span># 如果启动失败，请修改下面这条：</span></div></div><div><div><div>26</div></div><div><span><span>      </span></span><span>- </span><span>/var/run/docker.sock:/var/run/docker.sock</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section>
<section><h1>配置 Mirai<a href="#配置-mirai"><span>#</span></a></h1><p>因为 MCL 的交互似乎有点问题，所以接下来我们需要先启动 Mirai，登录好你的机器人QQ，配置自动登录。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>docker-compose run --rm mirai</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>当你看见终端出现</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>2022-12-10 04:30:19 I/MCL Addon: iTXTech MCL Version: 2.1.2-61c8bd8</span></div></div><div><div><div>2</div></div><div><span>2022-12-10 04:30:19 W/MCL Addon: iTXTech Soyuz 未安装，Soyuz MCL Handler 特性已禁用</span></div></div><div><div><div>3</div></div><div><span>2022-12-10 04:30:19 I/main: 3 plugin(s) enabled.</span></div></div><div><div><div>4</div></div><div><span>2022-12-10 04:30:19 I/main: Auto-login _________</span></div></div><div><div><div>5</div></div><div><span>2022-12-10 04:30:20 W/stderr: ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...</span></div></div><div><div><div>6</div></div><div><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>的时候，意味着 Mirai 启动完毕。 接下来执行命令登录机器人 QQ。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>login &lt;机器人QQ号&gt; &lt;机器人密码&gt; ANDROID_PAD</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>然后根据提示进行即可。</p><p>一般第一次登录的时候都需要验证码进行验证</p><p><strong>qq登录的验证工具</strong>：KasukuSakura/mirai-login-solver-sakura (github.com)](<a href="https://github.com/KasukuSakura/mirai-login-solver-sakura" target="_blank">https://github.com/KasukuSakura/mirai-login-solver-sakura</a>)</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230901164856624.png" alt="image-20230901164856624" /><figcaption>image-20230901164856624</figcaption></figure><p></p><p>下载<code>mirai-login-solver-sakura</code>手机版app，在命令行中复制需要进行验证的链接，粘贴至软件中，点击下一步进行验证，验证好后会返回一串字符串，将字符串粘贴指命令行中。完成滑块验证后，还需要进行手机验证，将收集验证码填入即可。这样就完成了qq登录。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/NTN@5L1P2B~E@DO0YPZMGZG.jpg" alt="NTN@5L1P2B~E@DO0YPZMGZG" /><figcaption>NTN@5L1P2B~E@DO0YPZMGZG</figcaption></figure><p></p><p>当机器人账号登录成功以后，执行以下命令进行信息保存</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>autologin add &lt;机器人QQ号&gt; &lt;机器人密码&gt;</span></div></div><div><div><div>2</div></div><div><span>autologin setConfig &lt;机器人QQ号&gt; protocol ANDROID_PAD</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section>
<section><h1>配置 mirai-http-api<a href="#配置-mirai-http-api"><span>#</span></a></h1><p>在你创建的文价夹中，会出现一个mirai文佳佳，编辑 <code>mirai/config/net.mamoe.mirai-api-http/setting.yml</code>，填入以下内容：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>adapters</span><span>:</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>- </span><span>reverse-ws</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span>enableVerify</span><span>: </span><span>true</span></div></div><div><div><div>5</div></div><div><span>verifyKey</span><span>: </span><span>1234567890</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>debug</span><span>: </span><span>false</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>singleMode</span><span>: </span><span>false</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>cacheSize</span><span>: </span><span>4096</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>adapterSettings</span><span>:</span></div></div><div><div><div>14</div></div><div><span>  </span><span>reverse-ws</span><span>:</span></div></div><div><div><div>15</div></div><div><span>    </span><span>## 远端 websocket server 地址配置</span></div></div><div><div><div>16</div></div><div><span>    </span><span>destinations</span><span>:</span></div></div><div><div><div>17</div></div><div><span><span>    </span></span><span>- </span><span>host</span><span>: </span><span>chatgpt</span></div></div><div><div><div>18</div></div><div><span>      </span><span>port</span><span>: </span><span>8554</span></div></div><div><div><div>19</div></div><div><span>      </span><span>path</span><span>: </span><span>/</span></div></div><div><div><div>20</div></div><div><span>      </span><span>protocol</span><span>: </span><span>ws</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section>
<section><h1>配置chatgpt-mirai-qq-bot<a href="#配置chatgpt-mirai-qq-bot"><span>#</span></a></h1><p>在文件夹中创建一个<code>config.cfg</code>文件，按照<a href="https://chatgpt-qq.lss233.com/" target="_blank">ChatGPT for Bot 使用文档 - ChatGPT for QQ 使用文档 (lss233.com)</a>中完整配置文件样例的说明进行填写</p><p>这里给出我的配置文件</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># 这里是 ChatGPT for QQ 的所有配置文件</span></div></div><div><div><div>2</div></div><div><span># 请注意：以 "#" 开头的文本均为注释</span></div></div><div><div><div>3</div></div><div><span># 不会被程序读取</span></div></div><div><div><div>4</div></div><div><span># 如果你想要使用某个设置，请确保前面没有 "#" 号</span></div></div><div><div><div>5</div></div><div><span>########################</span></div></div><div><div><div>6</div></div><div><span># 配置文件编写教程：</span></div></div><div><div><div>7</div></div><div><span># https://chatgpt-qq.lss233.com/</span></div></div><div><div><div>8</div></div><div><span>########################</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span>[</span><span>mirai</span><span>]</span></div></div><div><div><div>11</div></div><div><span>qq = xxxxxxxxx</span></div></div><div><div><div>12</div></div><div><span>manager_qq = xxxxxxxxx</span></div></div><div><div><div>13</div></div><div><span>api_key = "1234567890"</span></div></div><div><div><div>14</div></div><div><span>http_url = "http://mirai:8080"</span></div></div><div><div><div>15</div></div><div><span>ws_url = "http://mirai:8080"</span></div></div><div><div><div>16</div></div><div><span># 此处设置应该与 mirai api http 中的端口号一致</span></div></div><div><div><div>17</div></div><div><span>reverse_ws_port = 8554</span></div></div><div><div><div>18</div></div><div>
</div></div><div><div><div>19</div></div><div><span>[</span><span>xinghuo</span><span>]</span></div></div><div><div><div>20</div></div><div><span>[[</span><span>xinghuo.accounts</span><span>]]</span></div></div><div><div><div>21</div></div><div><span># 必填</span></div></div><div><div><div>22</div></div><div><span>ssoSessionId = "xxxx-xxxx-xxxx"</span></div></div><div><div><div>23</div></div><div><span># 保持固定即可，也可以自己抓包获取</span></div></div><div><div><div>24</div></div><div><span>GtToken = "R0VFAAYyNDAzOTU0YzM5Y2M0ZTRlNDY2MTE2MDA4ZGZlYjZjMGQzNGMyMGY0YjQ1NTA1NDg3OWQ0ZWJlOTk0NzQxNGI1MWUzM2IzZDUyZTEyMGM3MWYxNjlmNWY2YmYwMWMxNDI2YzIxOTlmZjMzYTI5YmY3YjQ1M2RjZGQwZWNjMDdiYjMzMmY4OTE2OTRhYTk1OWIyZWVlNzFjNmI5ZWFmY2MxNDFkNjk2MWYzYWQ3ZDAyYjZkM2U0YTllYWZlOTM0Njc4NmMyZmQ4NTRiYWViMTI2NjhlZmFhMWRiNmRmMDc5MzQxN2EyYzMzZDhiN2M4NzJjMzQ3YTYwNDFiMGZkZjkxN2Q2OTRlOWFiZWMwN2U0ZTg3Y2UwM2UxNDlmODBjMzA0MmE4NTAyNzhiNjU0MTU3ZjBlMmMzN2UxMTQ0MjA3ZWE0MDIzZTMyNDRiMjJmMjcwYjE5NGZiMWJhMmFlNGQ4YzkxMWNmZmQ0OGQzYzBlYmQxMTk1ZjE5MDJmMTVjNWUyMDI3ZmNmMDI0ODIxYWJiMWZhNzc3MTExOTBiZmZhMWRhYmRlYzVhYTkwMGRlMjU2YjFhNGQ4ZGYwYzQ0ZjI4MGJiNzcyNGIyOTlkYjU0ZGMyYjllY2U1NjNlYjQzZWE5MzhkMmQ3NTFjMTVkMGY0NDNkYjdhNzdlMmQ4NzM1NTQ3NDI0ZDBjNzRmMTA0NzY4NmI2M2UwZWRiMDM0ZjNhODc1NGZkYjgxMDBlNDA0MmZlZDYzZmFlYmYyNTExMTI5NTIyOTg0ZDMzN2UxYTBhN2NiZWZlZGMxOTVjOWQ2MGVhOTMyY2E5M2VhYmZkODI1YjBiMzU0ZDViYzUzMmM5YzI5NjA2ZWU3MmFmNGYwNGRkNTlhNDEzYzJiZmYyODllZjBkNWJlNWU5ZjZkZWVlMjk4MDUyMTU2OTQwNzE3ZDQ5M2NlM2E4YmIwN2YyZjE4MzgzZmEwNjQxNGZlYmFlNzdmN2QwNTZlYTQ3NDEwMmNlZjU1YmZhNjNjMDM2MmI5OTU2NjBkZjg4YzFjYzA2MmY0NjU2OTE0ZGIwMWE3ODQxNjA2YjdlZWE3ZDJjZTM4NjE5YTcwYjg0MmVkZTBmM2Y1MzI3ZGI2YmU5M2ZjYTNiMzg4OTJkOGQ3NWI4Y2M4YjQ3NjBkNDExZmQ3ZmFlNGIxY2YwMGE5ZDk2MmM2ZDYzMWE1YmRjNmYzMmU0Y2U5MDYwOGNiMDMzMTlkZGE2ZDlkMGU4OGUwMzUwMDkwZTQ5MGRhMmY5ODU1MGU4ZmQ1ODc3NmQ0Yjg5MDM1Y2FiNTg3MjMyMGMwOTJmOTUyODkwYmQ3YjIwYTMzODI5Y2MwY2VlZTE0MWY5N2FiN2IzYmJjNDg3MWM0M2E3ZTViYWNjZWZiZjg4MjM1ZDRiNWMzMjBjM2IxNGM2ZWE2NWVkZjc0OWI0ZDNlNzZjOWYyMTkwZDM0ZTVkYTZkNjM1NjFmZWNmMWYyODIxMTMyNjIyOGFjMWU0MTA2NjY1OWQ4Y2JlZTRmMjIwYzI2NjNmNzYxYzBhZGEyY2VkZjkyNDkzZWExNzFhN2NhZThiNTMxNDNmNzEzM2RhY2UyOWNmYjQ4ZTk5YzE2YjcyM2ZmZTJjZDk5MjU0NGM5OWNhOTFlMDRlMWNiNTQ5ZjU4MGQxY2I4YWU5MWU0MDlmZDZmYjhjNGYzYTRmODA2ZWFiZjRlMDI3OWJmOTM4NmQwN2I5MTBmYzlkYzNjMGM2ODIzYjg4OWFjNWZkZjBhYWNjYzNhYmU0MDRmMTg3Y2Q0MGNmMjcyNWFmY2VkYzAzYmVjZGY2MmMzNWRkNzQ5MGExYjQ1MDdlNTczNDI1OTliYTJhMjNmM2FmNDg1NGM3ODZkYzBiZWIzYTllMGEwYWUyMTllNmZhNzYyN2YyNTI5ZDc3YzQ3MGY1YzIxNzI1NzhhM2EwYzM3NzM0NTM4MTlhYjE3ODJiNmRmOGM1NTI2YjQzZjUzNTZlNDVhM2Q5MDc4N2IwZGNkZTdmYmYzM2ZkMWQ2NGY2NjdmOWYzNDIzZjJkMmU2NzgyMTY5ZWM3MTE1Y2E3MDdlYWRhOGJmNzI0OTJmMGM3Y2QxNjJjMDI4NmFjOThmNDhmOWEyYWQzZDAwYzg5YmViYzA3NTA4ZjYwYzE1OGVmYjk5ZjBkOGY4MzQ1ODI5Yzg4Yzc0YTA3OGQyZjU5NTFjNmQzNTc1N2QyNjI0NWVjNTk0Y2JkMzc2YmVhMGNiZmEzMWYwZTA5MGRhYzhlYzNlYjQ0ZGIxN2M4MWE5NWY4MTE4MDAwNDJkMjQ2MmMzMjk2ODU5Yjg3ZjRhZmI1MDYxM2MxY2FiYTZkZDI0ODdiZDQ3MmVmNzBjMzFkN2YwNjZmZTMxOThiYzFhOWFlZjIwZTQzY2FlNDBkMDkxZWEzMmNiYTBhNDM0YmQ2ZDU2NDQ3YTU4YTNjODZjYTk0NjQ3MGNiZjM4ZjM3ZjU2YTZkZmQ4MDY0OWEyZGU3MzllN2EyZWE3M2RlNDE5NDljNmI4ODU2YmE5ZTM4Njc2YmRhNzA1MWE5MjlmMWU1YTczZjEwYTg2ZjgwNDJjZDQxZTMwYjVjMTA1ODYzNzlhMGY3NmRlOWExODZiZmU2N2Y5NzZhOTY3MTg0ZjNkYmFhYWU0YjdmNmFlMjM5MTlkNDljNDNiODc4MzRjMjA0MzY4YThkOGEyYzRkNjc3MzhkMTU0NmFiNTVjMWE0YTQ0Y2M3MzE5OGM4Y2YzOTAxZGI0ZGY1MzFmNGY5NTI4MDE5MjZjN2I2MDg1YjQzODI0YmFiMTQ3NTIxZTYwNWQzYzhmZjljYjNmOTRlNzg3MDJiYzc1MzE4NTRhN2M3ZDE2OWQyMzcyYjUzMDBhNGQzNzhhYWNjOTk3ZDM1ZTZjODYwZGQwMWNlYTMwZjU1YTFlMjQxMTMxMTQwZjQwMWJmZGJkNWU3NzA4OWE5YzljNDIzY2E2ODk3OGE2ODMwYWEzYTlkZGJiZmMyYTE3NGZhOTc4NmI3ZTYyYmIzNTZlNjRiMzBiYzI4ZDMyYTVjMDMxYzgxZjZlOGEyMGMwNWFlNjJlYWM2ZWExNDY5OTFiZjk1Yzc4NzQzMjMwYTIyNzk1MWRlMzI4NjFjYjU5ZGQ3N2QxOWQ5MTMxNDgwYmY2ZTgyYTkwNzgwMTBlYjAzMzIzYjcxNGY0NzM5NDNmY2MwNTM3ODJmOTIwMGFkNzlmNzZiNjkxNDdmZGQwOTdhZTUwMTk1YjE4M2Q2YWM5NjVmN2NkNDNhMGI3MTEwOTNkZTM5NGM3OTYwNjNlNTBhMDAyNzNkOTE2MzQzODY2MzFkZThkMzViYTUxNmI4MTIyZWZjNzE5MTU0OTQ2NTIyYzc0YjhmNTY2OTMwZDM3YmIwZjJkM2Q4ODgyZGQwZTU0YTcyODM1NmYyZDk2ZWVlNzZiYmZlYjI1YTFjM2ZhNTg5OGY5OTM0YTc4NTBjYzRlNjY4NjE5YWMzOTg2MmE5NDhjMDVhMTc0MzE0MjIwOGFhMjk5OGY2ZmIwMmZlZWI2YTk0M2Q1NzcyN2JhZWU4ZmY5NGFmZjgzZGVjMTUyZmYxOWVkYmM1Y2RiZDkzYzBiNDc1OTEzMjFhYTY4MjI1MDA4ODhmYWJhMzAzNjdlZmRjYmJjNzhjYzE5MWI1MDViNTlmMjBhY2RiYTYzMzQyYzE1YTI2M2NiOGE1NDQ3NzQ4ODU3YWYxMzllMDJlMzY0ODlkNjRlNTRiMTc5YTgwOGRmMWU5YTk1ODY2YzE2YTYzM2EyZmUyYjA2MzM4OTI5YTc4MmRlMGFkZDgwZDZiYWU3Y2M1ZjljMWEzYzA5MGU4MTVlNjc2MGJjMzA0ZWU3ZmY1MDM5OGRiNDc0YTJkNWMzYWVhNTMxZjc0ZDU3NGNhZGNhZTIzZmZiZjcyY2FhNmU5YTNjNjFhYzNiMDJjNDdjYzQzZGJhYjA2NTgwNTkyZmE5YjMyNGMxMGJhMGRjNjgzZWIyYzRiNDg4NzFiMjk2YmIxNDBhMWUyZWRlOTE0NmY3MThkZTE4ZWU0M2QwZTk4NWY3NWQ1YWYyYjlkNjU5ODM5YzQwZWFiMzg2"</span></div></div><div><div><div>25</div></div><div><span># 可以不填，如果经常出现验证码可以填下试试</span></div></div><div><div><div>26</div></div><div><span>fd = ""</span></div></div><div><div><div>27</div></div><div>
</div></div><div><div><div>28</div></div><div><span>[</span><span>yiyan</span><span>]</span></div></div><div><div><div>29</div></div><div><span>[[</span><span>yiyan.accounts</span><span>]]</span></div></div><div><div><div>30</div></div><div><span>BDUSS='xxxxxxxxxx'</span></div></div><div><div><div>31</div></div><div><span>BAIDUID='xxxxxxxxxx'</span></div></div><div><div><div>32</div></div><div>
</div></div><div><div><div>33</div></div><div><span>[</span><span>presets</span><span>]</span></div></div><div><div><div>34</div></div><div><span># 切换预设的命令： 加载预设 猫娘</span></div></div><div><div><div>35</div></div><div><span>command = "加载预设 (\\w+)"</span></div></div><div><div><div>36</div></div><div>
</div></div><div><div><div>37</div></div><div><span>[</span><span>presets.keywords</span><span>]</span></div></div><div><div><div>38</div></div><div><span># 预设关键词 &lt;-&gt; 实际文件</span></div></div><div><div><div>39</div></div><div><span>"聊天"</span><span> </span><span>= "presets/issue402.txt"</span></div></div><div><div><div>40</div></div><div><span>"猫娘"</span><span> </span><span>= "presets/catgirl.txt"</span></div></div><div><div><div>41</div></div><div>
</div></div><div><div><div>42</div></div><div><span>[</span><span>response</span><span>]</span></div></div><div><div><div>43</div></div><div><span>default_ai = "xinghuo"</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>默认使用星火大模型进行对话。</p></section>
<section><h1>聊天机器人，启动！<a href="#聊天机器人启动"><span>#</span></a></h1><p>接下来就可以启动整个项目了。 你可以用</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>docker-compose</span><span> </span><span>up</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230901165612651.png" alt="image-20230901165612651" /><figcaption>image-20230901165612651</figcaption></figure><p></p><p>来启动。 如果没问题的话，可以 Ctrl + C 退出来，然后换成以下命令在后台启动。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>docker-compose up -d</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>如果你发现你的机器人不回你了，看看是 mirai 那边出问题了，还是 chatgpt 那边出问题了。通过这两个命令可也查看他们的运行输出</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>docker-compose logs mirai</span></div></div><div><div><div>2</div></div><div><span>docker-compose logs chatgpt</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section>
<section><h1>机器人运行<a href="#机器人运行"><span>#</span></a></h1><p>如图所示</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230901165912778.png" alt="image-20230901165912778" /><figcaption>image-20230901165912778</figcaption></figure><p></p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/644/</id>
      <title type="text">白嫖微软云（二）：虚拟机创建和服务搭建</title>
      <published>2023-08-29T16:14:26.000Z</published>
      <updated>2025-11-14T15:21:05.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/644/"/>
      <summary type="text">在上一篇文章白嫖微软云（一）：申请Azure学生订阅中介绍了如何申请Azure的学生订阅，学生订阅中包含了100美金和两台虚拟机（linux和windows）一年的使用时长。需要注意的是，需要选定要特定的配置，不然会产生额外的费用，不过一般</summary>
      <content type="html"><![CDATA[<p>在上一篇文章<a href="/archives/631/">白嫖微软云（一）：申请Azure学生订阅</a>中介绍了如何申请Azure的学生订阅，学生订阅中包含了100美金和两台虚拟机（linux和windows）一年的使用时长。需要注意的是，需要选定要特定的配置，不然会产生额外的费用，不过一般问题不大，毕竟还有100美金的额度。</p>
<p>在这篇文章中，介绍虚拟机的创建以及部分服务的部署。</p>
<section><h1>一、虚拟机创建<a href="#一虚拟机创建"><span>#</span></a></h1><section><h2>Linux虚拟机<a href="#linux虚拟机"><span>#</span></a></h2><section><h3>1、虚拟机配置<a href="#1虚拟机配置"><span>#</span></a></h3><p>在微软云首页，点击虚拟机。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230828223713189.png" alt="image-20230828223713189" /><figcaption>image-20230828223713189</figcaption></figure><p></p><p>进入虚拟机页面，选择创建Azure虚拟机，进行配置选择</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230828224653282.png" alt="image-20230828224653282" /><figcaption>image-20230828224653282</figcaption></figure><p></p><p>进入虚拟机的基本配置页面，订阅就选Azure for Students，资源组自己新建一个，名称可以随便起，区域最好选亚太或者美国西海岸，这样延迟会比较低。还有些服务只对美国本土开放，这样最好选美国西海岸，如果没有需求，最好就选日本的节点。</p><p>映像就是服务器的操作系统，目前主流的有Centos、Ubuntu以及Debian，鉴于Centos已经停止更新了，Debian可能对新手不太友好，个人推荐使用Ubuntu作为虚拟机的操作系统，这里选择Ubuntu Server 20.04。</p><p><strong>在大小这个选项中，记得选<code>B1s</code>这个套餐，只有这个套餐 才是对学生免费开放使用的。</strong></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230828232833508.png" alt="image-20230828232833508" /><figcaption>image-20230828232833508</figcaption></figure><p></p><p>在管理员账户类型上，如果追求安全可以使用<code>SSH公钥</code>，这样密码很难被破解。本文为了登录方便，这里选择密码作为身份验证类型，设置相应的用户名和密码。</p><p>在入口规则的配置中，选择<code>允许特定的端口</code>，勾选<code>22</code>、<code>443</code>和<code>80</code>端口。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230828232807802.png" alt="image-20230828232807802" /><figcaption>image-20230828232807802</figcaption></figure><p></p><p>在磁盘设置中，记得将OS磁盘大小<strong>重设为大小为64G（P6）免费账户可用</strong>，这个套餐对学生免费，其他保持默认即可。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230828233318563.png" alt="image-20230828233318563" /><figcaption>image-20230828233318563</figcaption></figure><p></p><p>在网络设置中，如果使用的是默认设置，使用的是固定ip，虚拟机开关机都不会影响ip地址，但是是收费的，价格还不低。这里建议使用动态ip，在公用ip一栏中，点击新建，右边弹出创建公共IP地址菜单，SKU记得选择基本，否则不能选择动态ip。</p><p>而且动态ip对于有科学上网需求的人还更好，可能技术不够精湛导致ip被封禁，这样只需要重新关机选择不保留ip地址，这样就有一个新的ip地址供你使用，像很多vps厂家更换ip地址还需要额外收费，微软还给咱们免费更换。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230828233637534.png" alt="image-20230828233637534" /><figcaption>image-20230828233637534</figcaption></figure><p></p><p>其他都保持默认即可，最后点击“查看+创建”，在保证设置正确后点击创建，此时就会开始部署虚拟机，只需等待几分钟后，虚拟机就创建完成，点击跳转资源进入虚拟机页面。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230828234330316.png" alt="image-20230828234330316" /><figcaption>image-20230828234330316</figcaption></figure><p></p></section><section><h3>2、SSH连接Linux虚拟机<a href="#2ssh连接linux虚拟机"><span>#</span></a></h3><p>在这一部分，我们使用Xshell客户端与虚拟机进行连接，在主机一栏中填写虚拟机的公共IP地址</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230828234445855.png" alt="image-20230828234445855" /><figcaption>image-20230828234445855</figcaption></figure><p></p><p>设置完主机后，点击连接，弹出一个SSH用户名和密码验证框栏，将虚拟机配置中设置的用户名和密码填入即可。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230828234555080.png" alt="image-20230828234555080" /><figcaption>image-20230828234555080</figcaption></figure><figure><img src="http://imgbed.leihub.cn/img/image-20230828234638405.png" alt="image-20230828234638405" /><figcaption>image-20230828234638405</figcaption></figure><p></p><p>如果端口已放行、用户名和密码都没有错误，就可以顺利进入命令行界面，现在就可以操作这台linux虚拟机了</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230828234940977.png" alt="image-20230828234940977" /><figcaption>image-20230828234940977</figcaption></figure><p></p></section></section><section><h2>Windows虚拟机<a href="#windows虚拟机"><span>#</span></a></h2><p>Windows虚拟机的创建和Linux基本一致，需要注意的是，硬盘只有64G，可能系统占用就把空间占完了，所以要选择小一点的映像进行安装，这里选择<code>[smalldisk] Windows Server 2012 R2 Datacenter - x64 Gen2</code>映像，这个映像可以流畅运行系统。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829000110971.png" alt="image-20230829000110971" /><figcaption>image-20230829000110971</figcaption></figure><p></p><p>点击查看所有映像，在Windows Server下拉栏中可以找到这个映像。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829000000025.png" alt="image-20230829000000025" /><figcaption>image-20230829000000025</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829000048964.png" alt="image-20230829000048964" /><figcaption>image-20230829000048964</figcaption></figure><p></p><p>创建完成后，转到对应的资源页面。选择左侧边栏中的连接，下载RDP文件。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/v2-c2689de5d2ffd6060273b97317f2333d_720w.webp" alt="img" /><figcaption>img</figcaption></figure><p></p><p>打开下载好的RDP文件进行连接。注意在输入密码时默认是以电脑上的Windows用户名进行连接的。如果你的电脑用户名和创建虚拟机配置的用户名不同，则需要点击“更多选项”-“使用其他用户”，输入用户名登录。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/v2-037a59f2084a1b15afeaa2140000650e_720w.webp" alt="img" /><figcaption>img</figcaption></figure><p></p><p>连接成功后就可以远程操控Windows虚拟机了。</p></section></section>
<section><h1>二、安装宝塔<a href="#二安装宝塔"><span>#</span></a></h1><p>如果你是新手，推荐使用宝塔进行服务器管理，宝塔集成了一套使用工具，并提供了一个WEB操作页面，对新手非常友好。如果是老手，可以不使用宝塔，宝塔最近还爆出窃取隐私的新闻，可以不使用的话尽量不使用吧。</p><p>使用SSH连接Linux服务器后，根据操作系统类型执行相应的命令进行安装</p><p><strong>Centos安装脚本</strong></p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>yum</span><span> </span><span>install</span><span> </span><span>-y</span><span> </span><span>wget</span><span> &amp;&amp; </span><span>wget</span><span> </span><span>-O</span><span> </span><span>install.sh</span><span> </span><span>https://download.bt.cn/install/install_6.0.sh</span><span> &amp;&amp; </span><span>sh</span><span> </span><span>install.sh</span><span> </span><span>ed8484bec</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p><strong>Ubuntu/Deepin安装脚本</strong></p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>wget</span><span> </span><span>-O</span><span> </span><span>install.sh</span><span> </span><span>https://download.bt.cn/install/install-ubuntu_6.0.sh</span><span> &amp;&amp; </span><span>sudo</span><span> </span><span>bash</span><span> </span><span>install.sh</span><span> </span><span>ed8484bec</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p><strong>Debian安装脚本</strong></p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>wget</span><span> </span><span>-O</span><span> </span><span>install.sh</span><span> </span><span>https://download.bt.cn/install/install-ubuntu_6.0.sh</span><span> &amp;&amp; </span><span>bash</span><span> </span><span>install.sh</span><span> </span><span>ed8484bec</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p><strong>万能安装脚本</strong></p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>if</span><span><span> [ </span><span>-f</span><span> /usr/bin/curl ];</span></span><span>then</span><span> curl -sSO https://download.bt.cn/install/install_panel.sh;</span><span>else</span><span> wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;</span><span>fi</span><span>;</span><span>bash</span><span> </span><span>install_panel.sh</span><span> </span><span>ed8484bec</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>安装好宝塔后，在ssh命令行页面，通过输入bt命令即可对宝塔进行配置，比如修改访问端口，登录用户民和密码。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829001203950.png" alt="image-20230829001203950" /><figcaption>image-20230829001203950</figcaption></figure><p></p><p>如果没有修改，通过ip地址：8888即可访问宝塔web页面，在web页面中可以进行可视化环境配置。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829001306317.png" alt="image-20230829001306317" /><figcaption>image-20230829001306317</figcaption></figure><p></p><p>进入面板主界面，会推荐安装套件。这里有LNMP和LAMP两个选项，二者不同的地方是Web服务器不同。前者使用Nginx服务器，后者使用Apache服务器。由于我们的服务器配置比较低，所以选择性能更好的Ngnix服务器，即左边的LNMP套件。（LNMP和LAMP中的L代表Linux，N代表Nginx，M代表Mysql，P代表PHP，A代表Apache）</p><p></p><figure><img src="http://imgbed.leihub.cn/img/v2-131e9f9a97002e7756b5ff4045ad0f4d_720w.webp" alt="img" /><figcaption>img</figcaption></figure><p></p><p>进入宝塔主界面如图所示，首页可对服务器资源进行检测，网站可以手动或者一键创建自己的网址，安全页面起到防火墙的作用，可对端口进行放行，<strong>今后放行端口时不但要在Azure网络安全组中添加规则，也要在这里添加</strong>。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829001531331.png" alt="image-20230829001531331" /><figcaption>image-20230829001531331</figcaption></figure><p></p><p>这样就完成了服务器的创建和基本配置的设定了，接下来可以根据需求自己进行服务部署，</p></section>
<section><h1>参考<a href="#参考"><span>#</span></a></h1><p>1、<a href="https://www.bt.cn/new/download.html" target="_blank">宝塔面板下载，免费全能的服务器运维软件 (bt.cn)</a></p><p>2、<a href="https://portal.azure.com/" target="_blank">虚拟机 - Microsoft Azure</a></p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/637/</id>
      <title type="text">ANSYS学习笔记（一）</title>
      <published>2023-08-28T13:18:05.000Z</published>
      <updated>2024-06-06T03:26:43.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/637/"/>
      <summary type="text">一、有限元基本理论 二、结构静力学分析 1.实体静力分析 2.子模型分析 3.大变形静力学分析 三、模态分析 1.模态分析理论基础 无阻尼分析 当解决无阻尼结构动力学中的特征值问题时，我们可以采用矩阵形式来描述。假设我们有一个线性多自由度系</summary>
      <content type="html"><![CDATA[<section><h1>一、有限元基本理论<a href="#一有限元基本理论"><span>#</span></a></h1></section>
<section><h1>二、结构静力学分析<a href="#二结构静力学分析"><span>#</span></a></h1><section><h2>1.实体静力分析<a href="#1实体静力分析"><span>#</span></a></h2></section><section><h2>2.子模型分析<a href="#2子模型分析"><span>#</span></a></h2></section><section><h2>3.大变形静力学分析<a href="#3大变形静力学分析"><span>#</span></a></h2></section></section>
<section><h1>三、模态分析<a href="#三模态分析"><span>#</span></a></h1><section><h2>1.模态分析理论基础<a href="#1模态分析理论基础"><span>#</span></a></h2><section><h3>无阻尼分析<a href="#无阻尼分析"><span>#</span></a></h3><p>当解决无阻尼结构动力学中的特征值问题时，我们可以采用矩阵形式来描述。假设我们有一个线性多自由度系统，其中质量矩阵为 <span><span>MM</span><span><span><span></span><span>M</span></span></span></span>，刚度矩阵为<span><span>KK</span><span><span><span></span><span>K</span></span></span></span>，位移向量为 <span><span>XX</span><span><span><span></span><span>X</span></span></span></span>，加速度向量为 <span><span>X¨\ddot{X}</span><span><span><span></span><span><span><span><span><span><span></span><span>X</span></span><span><span></span><span><span>¨</span></span></span></span></span></span></span></span></span></span>。</p><p><strong>步骤1：建立动力学方程</strong></p><p>动力学方程可以表示为：</p><span><span><span>MX¨+KX=0M \ddot{X} + K X = 0</span><span><span><span></span><span>M</span><span><span><span><span><span><span></span><span>X</span></span><span><span></span><span><span>¨</span></span></span></span></span></span></span><span></span><span>+</span><span></span></span><span><span></span><span>K</span><span>X</span><span></span><span>=</span><span></span></span><span><span></span><span>0</span></span></span></span></span><p><strong>步骤2：物体自由振动为简谐运动</strong></p><p>假设自由度 <span><span>ii</span><span><span><span></span><span>i</span></span></span></span> 的位移<span><span>xix_i</span><span><span><span></span><span><span>x</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span> 随时间 <span><span>tt</span><span><span><span></span><span>t</span></span></span></span>变化为正弦函数：</p><span><span><span>xi(t)=Aisin⁡(ωt+ϕi)x_i(t) = A_i \sin(\omega t + \phi_i)</span><span><span><span></span><span><span>x</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>t</span><span>)</span><span></span><span>=</span><span></span></span><span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>sin</span><span>(</span><span>ω</span><span>t</span><span></span><span>+</span><span></span></span><span><span></span><span><span>ϕ</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>)</span></span></span></span></span><p><strong>步骤3：引入特征值问题</strong></p><p>代入简谐振动假设到动力学方程，得到：</p><span><span><span>−Mω2Aisin⁡(ωt+ϕi)+KAisin⁡(ωt+ϕi)=0-M \omega^2 A_i \sin(\omega t + \phi_i) + K A_i \sin(\omega t + \phi_i) = 0</span><span><span><span></span><span>−</span><span>M</span><span><span>ω</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>sin</span><span>(</span><span>ω</span><span>t</span><span></span><span>+</span><span></span></span><span><span></span><span><span>ϕ</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>)</span><span></span><span>+</span><span></span></span><span><span></span><span>K</span><span><span>A</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>sin</span><span>(</span><span>ω</span><span>t</span><span></span><span>+</span><span></span></span><span><span></span><span><span>ϕ</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>)</span><span></span><span>=</span><span></span></span><span><span></span><span>0</span></span></span></span></span><p>化简后得到：</p><span><span><span>(K−ω2M)Aisin⁡(ωt+ϕi)=0(K - \omega^2 M) A_i \sin(\omega t + \phi_i) = 0</span><span><span><span></span><span>(</span><span>K</span><span></span><span>−</span><span></span></span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span><span>M</span><span>)</span><span><span>A</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>sin</span><span>(</span><span>ω</span><span>t</span><span></span><span>+</span><span></span></span><span><span></span><span><span>ϕ</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>)</span><span></span><span>=</span><span></span></span><span><span></span><span>0</span></span></span></span></span><p><strong>步骤4：解特征值问题</strong></p><p>我们要找到特征值 <span><span>ω2ω^2</span><span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span></span></span></span> 和对应的特征向量 <span><span>AiA_i</span><span><span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>，使得</p><span><span><span>(K−ω2M)Ai=0(K - \omega^2 M) A_i = 0</span><span><span><span></span><span>(</span><span>K</span><span></span><span>−</span><span></span></span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span><span>M</span><span>)</span><span><span>A</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>0</span></span></span></span></span><p>成立。这个特征值问题可以通过数值计算方法来求解，从而获得固有频率的平方  <span><span>ω2ω^2</span><span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span></span></span></span> 和对应的振幅<span><span>AiA_i</span><span><span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>。</p></section></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/633/</id>
      <title type="text">电机学（一）：导论</title>
      <published>2023-08-28T13:14:33.000Z</published>
      <updated>2025-11-14T15:21:17.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/633/"/>
      <summary type="text">1.电机的基本概念 电机是依据电磁感应定律和电磁力定律，由电路和磁路构成的能实现机电能量转换或信号传递与转换的装置。 2.电机的分类 电机从运动方式上分为变压器和旋转电机，而旋转电机又分为直流和交流，交流电机分为异步和同步电机。 从功能上分</summary>
      <content type="html"><![CDATA[<section><h2>1.电机的基本概念<a href="#1电机的基本概念"><span>#</span></a></h2><p><strong>电机</strong>是依据<strong>电磁感应定律</strong>和<strong>电磁力定律</strong>，由<strong>电路</strong>和<strong>磁路</strong>构成的能实现机电能量转换或信号传递与转换的装置。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282109807.png" alt="image-20230828193417481" /><figcaption>image-20230828193417481</figcaption></figure><p></p></section>
<section><h2>2.电机的分类<a href="#2电机的分类"><span>#</span></a></h2><p>电机从运动方式上分为变压器和旋转电机，而旋转电机又分为直流和交流，交流电机分为异步和同步电机。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282109231.png" alt="image-20230828193920910" /><figcaption>image-20230828193920910</figcaption></figure><p></p><p>从功能上分类可以将电机分为电动机、发电机、变压器和控制电机。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282109169.png" alt="image-20230828194111970" /><figcaption>image-20230828194111970</figcaption></figure><p></p></section>
<section><h2>3.电机的发展趋势<a href="#3电机的发展趋势"><span>#</span></a></h2><section><h3>1）新型特种电机<a href="#1新型特种电机"><span>#</span></a></h3><p>新型特种电机是与科技最新发展联系最紧密、最富想象力、最具活力、也最具挑战性的学科分支。</p></section><section><h3>2）基于计算机技术、电力电子技术、超导技术的发展<a href="#2基于计算机技术电力电子技术超导技术的发展"><span>#</span></a></h3><ul>
<li>设计制造最优化</li>
<li>运行控制最优化（自动化、数字化、最优化）</li>
<li>高温超导技术应用</li>
<li>集成化、机电一体化</li>
<li>小型化、微型化</li>
<li>与高新技术融为一体</li>
<li>形成新的理论方法体系</li>
</ul></section></section>
<section><h2>4.铁磁材料特性<a href="#4铁磁材料特性"><span>#</span></a></h2><section><h3>1）电机中使用的材料<a href="#1电机中使用的材料"><span>#</span></a></h3><p><strong>①</strong> <strong>导电材料</strong>：铜线。构成<strong>电路</strong></p><p><strong>②</strong> <strong>导磁材料</strong>：硅钢片。构成<strong>磁路</strong></p><p><strong>③</strong> <strong>结构材料</strong>：铸铁、铸钢和钢板。承受<strong>力</strong>。</p><p><strong>④</strong> <strong>绝缘材料</strong>：聚酯漆、环氧树脂、玻璃丝带等。用于导体之间和各类构件之间的绝缘处理。电机常用绝缘材料按性能划分为 A 、 E <strong>、</strong> B 、 F <strong>、</strong> H <strong>、</strong> C等 6 个等级。</p></section><section><h3>2）铁磁材料的磁导率<a href="#2铁磁材料的磁导率"><span>#</span></a></h3><p><strong>磁导率</strong>是一个衡量物质对磁场的响应能力的物理量。在电磁学中，磁导率通常用来描述材料在磁场中的行为，类似于电导率用来描述材料在电场中的行为。磁导率通常用希腊字母<span><span>μμ</span><span><span><span></span><span>μ</span></span></span></span>表示</p><span><span><span>μ=B/H\mu  = B/ H</span><span><span><span></span><span>μ</span><span></span><span>=</span><span></span></span><span><span></span><span>B</span><span>/</span><span>H</span></span></span></span></span><ul>
<li>铁磁材料的磁导率通常远远大于自由空间中的真空磁导率 <span><span>μ0μ_0</span><span><span><span></span><span><span>μ</span><span><span><span><span><span><span></span><span><span>0</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>，这表示铁磁材料对磁场的响应能力要更强。</li>
<li><span><span>μFeμ_{Fe}</span><span><span><span></span><span><span>μ</span><span><span><span><span><span><span></span><span><span><span>F</span><span>e</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>为非常数，随 <span><span>BB</span><span><span><span></span><span>B</span></span></span></span>的变化而变化。</li>
<li>存在<strong>磁饱和现象</strong>：当铁磁材料中的磁感应强度<span><span>BB</span><span><span><span></span><span>B</span></span></span></span>达到一定程度后，材料会进入磁饱和状态。在磁饱和状态下，随着外加磁场强度 <span><span>HH</span><span><span><span></span><span>H</span></span></span></span> 的增加，磁感应强度 <span><span>BB</span><span><span><span></span><span>B</span></span></span></span> 的增加会逐渐减缓，这是因为材料的磁性已经接近饱和状态，难以进一步增强磁感应强度。因此，铁磁材料的磁导率 <span><span>μFeμ_{Fe}</span><span><span><span></span><span><span>μ</span><span><span><span><span><span><span></span><span><span><span>F</span><span>e</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span> 随着外加磁场强度<span><span>HH</span><span><span><span></span><span>H</span></span></span></span> 的增加而减小，反映了这种磁饱和现象。</li>
</ul></section><section><h3>3）磁化曲线<a href="#3磁化曲线"><span>#</span></a></h3><p>当外部磁场 <span><span>HH</span><span><span><span></span><span>H</span></span></span></span> 作用在材料上时，磁感应强度 <span><span>BB</span><span><span><span></span><span>B</span></span></span></span> 会发生变化，它们之间的关系可以表示为磁化曲线，记作 <span><span>B=f(H)B=f(H)</span><span><span><span></span><span>B</span><span></span><span>=</span><span></span></span><span><span></span><span>f</span><span>(</span><span>H</span><span>)</span></span></span></span>。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282109260.png" alt="image-20230828201450222" /><figcaption>image-20230828201450222</figcaption></figure><p></p></section><section><h3>4）磁滞与磁滞损耗<a href="#4磁滞与磁滞损耗"><span>#</span></a></h3><p>铁磁材料中磁感应强度<span><span>BB</span><span><span><span></span><span>B</span></span></span></span>的变化滞后于外部磁场强度<span><span>HH</span><span><span><span></span><span>H</span></span></span></span>的变化的现象被称为<strong>磁滞</strong>。</p><p>如下图所示就是铁磁材料交变(循环)磁化过程中的<strong>磁滞回线</strong>。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282109130.png" alt="image-20230828201529425" /><figcaption>image-20230828201529425</figcaption></figure><p></p><ul>
<li><strong>剩磁</strong> <span><span>BrB_r</span><span><span><span></span><span><span>B</span><span><span><span><span><span><span></span><span><span>r</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></li>
<li><strong>矫顽力</strong> <span><span>HcH_c</span><span><span><span></span><span><span>H</span><span><span><span><span><span><span></span><span><span>c</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></li>
<li>软磁材料：磁滞回线很窄。硅钢片、铸铁、铸钢等。</li>
<li>硬磁材料：磁滞回线很宽，或叫永磁材料。常用的永磁材料有钐钴（ SmCo）、钕铁硼（ NdFeB ）等。</li>
</ul><section><h4>基本磁化曲线<a href="#基本磁化曲线"><span>#</span></a></h4><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282109070.png" alt="image-20230828202059997" /><figcaption>image-20230828202059997</figcaption></figure><p></p><p><strong>磁滞损耗</strong>：铁磁材料在交变磁场作用下的反复磁化过程中，磁畴会不停转动，相互之间会不断摩擦，因而就要消耗一定的能量，产生功率损耗。这种损耗称为磁滞损耗。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282109192.png" alt="image-20230828202239360" /><figcaption>image-20230828202239360</figcaption></figure><p></p><p>磁滞损耗（Hysteresis Loss）的大小与磁滞回线的面积、交变磁场频率 <span><span>ff</span><span><span><span></span><span>f</span></span></span></span> 和铁心体积 <span><span>VV</span><span><span><span></span><span>V</span></span></span></span> 成<strong>正比</strong>，这可以用如下表达式表示：</p><span><span><span>Ph∝A⋅f⋅VP_h \propto A \cdot f \cdot V</span><span><span><span></span><span><span>P</span><span><span><span><span><span><span></span><span><span>h</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>∝</span><span></span></span><span><span></span><span>A</span><span></span><span>⋅</span><span></span></span><span><span></span><span>f</span><span></span><span>⋅</span><span></span></span><span><span></span><span>V</span></span></span></span></span><p>由于硅钢片的磁滞回线面积很小，而且导磁性能好。 因此，大多数电机、变压器或普通电器的铁心都采用。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282109533.jpeg" alt="宝钢B35A250硅钢片 冷轧矽钢片电工钢 马达电机产品图片，宝钢B35A250硅钢片 冷轧矽钢片电工钢 马达电机产品相册 - 东莞市浙威工具 ..." /><figcaption>宝钢B35A250硅钢片 冷轧矽钢片电工钢 马达电机产品图片，宝钢B35A250硅钢片 冷轧矽钢片电工钢 马达电机产品相册 - 东莞市浙威工具 ...</figcaption></figure><p></p></section></section><section><h3>5）涡流与涡流损耗<a href="#5涡流与涡流损耗"><span>#</span></a></h3><p><strong>涡流</strong>是一种在铁磁材料中产生的感应电动势和电流的现象，在交变磁场中呈现涡旋状，因此被称为涡流。涡流在材料内部形成闭合回路，导致电流环流而产生损耗和能量耗散。</p><p>涡流损耗指的是涡流在其流通路径上的等效电阻中产生的 <span><span>I2RI^2R</span><span><span><span></span><span><span>I</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span><span>R</span></span></span></span>损耗，其中<span><span>II</span><span><span><span></span><span>I</span></span></span></span> 为涡流产生的电流，<span><span>RR</span><span><span><span></span><span>R</span></span></span></span> 为等效电阻。这种损耗会导致能量转化为热，造成材料发热。</p><p>涡流损耗<span><span>PwP_w</span><span><span><span></span><span><span>P</span><span><span><span><span><span><span></span><span><span>w</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span> 与磁场交变频率 <span><span>ff</span><span><span><span></span><span>f</span></span></span></span>、材料厚度 <span><span>dd</span><span><span><span></span><span>d</span></span></span></span>、最大磁感应强度 <span><span>BmB_m</span><span><span><span></span><span><span>B</span><span><span><span><span><span><span></span><span><span>m</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span> 和材料的电阻率 <span><span>ρρ</span><span><span><span></span><span>ρ</span></span></span></span>成<strong>正比</strong>，可以用以下公式表示：</p><span><span><span>Pw∝ρ⋅V⋅f⋅d2⋅Bm2P_w \propto \rho \cdot V \cdot f \cdot d^2 \cdot B_m^2</span><span><span><span></span><span><span>P</span><span><span><span><span><span><span></span><span><span>w</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>∝</span><span></span></span><span><span></span><span>ρ</span><span></span><span>⋅</span><span></span></span><span><span></span><span>V</span><span></span><span>⋅</span><span></span></span><span><span></span><span>f</span><span></span><span>⋅</span><span></span></span><span><span></span><span><span>d</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span><span></span><span>⋅</span><span></span></span><span><span></span><span><span>B</span><span><span><span><span><span><span></span><span><span>m</span></span></span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282110088.png" alt="image-20230828203116426" /><figcaption>image-20230828203116426</figcaption></figure><p></p><p>要减少涡流损耗，首先可以通过减小材料的厚度<span><span>dd</span><span><span><span></span><span>d</span></span></span></span> 来降低损耗，其次可以增加涡流回路中的电阻，例如通过在电工钢片中添加适量的硅制成硅钢片，以显著提高电阻率<span><span>ρρ</span><span><span><span></span><span>ρ</span></span></span></span>，从而减少涡流损耗。这对于设计和制造电机、变压器等设备非常重要，以提高设备的效率和性能。</p></section><section><h3>6）铁耗<a href="#6铁耗"><span>#</span></a></h3><p><strong>铁耗</strong>是指在铁磁材料中，由于<strong>交变磁场作用</strong>产生的<strong>磁滞损耗</strong>和涡流损耗的综合效应。</p></section></section>
<section><h2>5.电机中的基本电磁定律<a href="#5电机中的基本电磁定律"><span>#</span></a></h2><section><h3>1）常用的物理量<a href="#1常用的物理量"><span>#</span></a></h3><p>磁通密度<span><span>BB</span><span><span><span></span><span>B</span></span></span></span> 单位：特斯拉<span><span>TT</span><span><span><span></span><span>T</span></span></span></span></p><p>磁通<span><span>ΦΦ</span><span><span><span></span><span>Φ</span></span></span></span>  单位韦伯<span><span>WbWb</span><span><span><span></span><span>W</span><span>b</span></span></span></span></p><p>磁场强度<span><span>HH</span><span><span><span></span><span>H</span></span></span></span>  单位<span><span>A/mA/m</span><span><span><span></span><span>A</span><span>/</span><span>m</span></span></span></span></p></section><section><h3>2）全电流定律<a href="#2全电流定律"><span>#</span></a></h3><p>磁场强度沿任意的闭合路径的线积分等于闭合路径包围的导体电流的代数和。</p><p><strong>电流是产生磁场的源</strong></p><span><span><span>∮H⋅dl=I\oint \mathbf{H} \cdot d\mathbf{l} = I</span><span><span><span></span><span>∮</span><span></span><span>H</span><span></span><span>⋅</span><span></span></span><span><span></span><span>d</span><span>l</span><span></span><span>=</span><span></span></span><span><span></span><span>I</span></span></span></span></span><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282110166.png" alt="image-20230828203744339" /><figcaption>image-20230828203744339</figcaption></figure><p></p></section><section><h3>3）电磁感应定律<a href="#3电磁感应定律"><span>#</span></a></h3><p><strong>运动电动势</strong></p><p>当描述运动电动势时，它通常与一个导体在磁场中运动时产生的感应电动势相关。运动电动势的一般公式可以表示为：</p><span><span><span>ET=B⋅l⋅v\mathcal{E}_T = B \cdot l \cdot v</span><span><span><span></span><span><span>E</span><span><span><span><span><span><span></span><span><span>T</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>B</span><span></span><span>⋅</span><span></span></span><span><span></span><span>l</span><span></span><span>⋅</span><span></span></span><span><span></span><span>v</span></span></span></span></span><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282110360.png" alt="image-20230828204106020" /><figcaption>image-20230828204106020</figcaption></figure><p></p><p><strong>变压器电动势</strong></p><p>对于变压器电动势，这通常涉及到一个变压器的电磁感应。对于一个理想的变压器，其次级绕组的电动势可以表示为：</p><span><span><span>EV=−N⋅dΦdt\mathcal{E}_V = -N \cdot \frac{d\Phi}{dt}</span><span><span><span></span><span><span>E</span><span><span><span><span><span><span></span><span><span>V</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>−</span><span>N</span><span></span><span>⋅</span><span></span></span><span><span></span><span><span></span><span><span><span><span><span><span></span><span><span>d</span><span>t</span></span></span><span><span></span><span></span></span><span><span></span><span><span>d</span><span>Φ</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span></span></span></span></span><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282110301.png" alt="image-20230828204115739" /><figcaption>image-20230828204115739</figcaption></figure><p></p><p>当磁通按正弦规律变化时，感应电动势有效值为：</p><span><span><span>e=−NωΦmcos⁡(ωt)=Emsin⁡(ωt−90∘)e = -N \omega \Phi_m \cos(\omega t) = E_m \sin(\omega t - 90^\circ)</span><span><span><span></span><span>e</span><span></span><span>=</span><span></span></span><span><span></span><span>−</span><span>N</span><span>ω</span><span><span>Φ</span><span><span><span><span><span><span></span><span><span>m</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>cos</span><span>(</span><span>ω</span><span>t</span><span>)</span><span></span><span>=</span><span></span></span><span><span></span><span><span>E</span><span><span><span><span><span><span></span><span><span>m</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>sin</span><span>(</span><span>ω</span><span>t</span><span></span><span>−</span><span></span></span><span><span></span><span>9</span><span><span>0</span><span><span><span><span><span><span></span><span><span>∘</span></span></span></span></span></span></span></span><span>)</span></span></span></span></span><p>感应电动势与磁通变化规律一致，滞后90度。</p></section><section><h3>4）电磁力定律<a href="#4电磁力定律"><span>#</span></a></h3><p>将长度为<span><span>ll</span><span><span><span></span><span>l</span></span></span></span>的导体置于磁场<span><span>BB</span><span><span><span></span><span>B</span></span></span></span>中，通入电流<span><span>ii</span><span><span><span></span><span>i</span></span></span></span>，导体会受到力的作用，称为电磁力，其计算公式为：</p><span><span><span>f=B⋅l⋅if = B \cdot l \cdot i</span><span><span><span></span><span>f</span><span></span><span>=</span><span></span></span><span><span></span><span>B</span><span></span><span>⋅</span><span></span></span><span><span></span><span>l</span><span></span><span>⋅</span><span></span></span><span><span></span><span>i</span></span></span></span></span><p>式中，电磁力、磁场和载流导体的关系由<strong>左手定则</strong>确定。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282110247.png" alt="image-20230828204828979" /><figcaption>image-20230828204828979</figcaption></figure><p></p></section></section>
<section><h2>6.磁路基本定律及其计算方法<a href="#6磁路基本定律及其计算方法"><span>#</span></a></h2><p>磁路的基本概念类似于电路，其中磁通被类比为电流，而磁阻和磁导率与电路中的电阻和电导率类似。</p><section><h3><strong>1）磁阻欧姆定律</strong><a href="#1磁阻欧姆定律"><span>#</span></a></h3><p>根据磁路的欧姆定律，磁通（磁通量） <span><span>ΦΦ</span><span><span><span></span><span>Φ</span></span></span></span> 与磁势（磁动势） <span><span>FF</span><span><span><span></span><span>F</span></span></span></span>之间的关系可以表示为：</p><span><span><span>Φ=F⋅Rm\Phi = \mathcal{F} \cdot R_m</span><span><span><span></span><span>Φ</span><span></span><span>=</span><span></span></span><span><span></span><span>F</span><span></span><span>⋅</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>m</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span><p>铁磁材料的磁阻随饱和程度的提高而增加，磁导随饱和程度的提高而减小。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282110012.png" alt="image-20230828205314718" /><figcaption>image-20230828205314718</figcaption></figure><p></p></section><section><h3>2）<strong>磁路基尔霍夫第一定律</strong><a href="#2磁路基尔霍夫第一定律"><span>#</span></a></h3><p>描述了磁通在封闭磁路中的守恒原理，类似于电路中的基尔霍夫第一定律。根据这一定律，通过任何封闭面的总磁通量的代数和等于零，或者说进入封闭面的磁通量等于从该封闭面穿出的磁通量。数学表达如下:</p><span><span><span>ΣΦ=0\Sigma \Phi = 0</span><span><span><span></span><span>ΣΦ</span><span></span><span>=</span><span></span></span><span><span></span><span>0</span></span></span></span></span><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282110604.png" alt="image-20230828205519377" /><figcaption>image-20230828205519377</figcaption></figure><p></p></section><section><h3><strong>3）磁路基尔霍夫第二定律</strong><a href="#3磁路基尔霍夫第二定律"><span>#</span></a></h3><p>描述了在一个封闭磁路中，沿着任意闭合路径的磁势 <span><span>FF</span><span><span><span></span><span>F</span></span></span></span>与通过该路径的电流 <span><span>ii</span><span><span><span></span><span>i</span></span></span></span> 之间的关系。该定律可以根据麦克斯韦方程组的积分形式推导得出。</p><p>根据磁路基尔霍夫第二定律，对于任意封闭路径，有以下等式：</p><span><span><span>∑Ni⋅ii=∑Hi⋅li=∑Φ⋅Rm\sum N_i \cdot i_i = \sum H_i \cdot l_i = \sum \Phi \cdot R_m</span><span><span><span></span><span>∑</span><span></span><span><span>N</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>⋅</span><span></span></span><span><span></span><span><span>i</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>∑</span><span></span><span><span>H</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>⋅</span><span></span></span><span><span></span><span><span>l</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>∑</span><span></span><span>Φ</span><span></span><span>⋅</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>m</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282110567.png" alt="image-20230828205628650" /><figcaption>image-20230828205628650</figcaption></figure><p></p><p>以上等式强调了磁路中的电流、磁场强度、磁通和磁阻之间的关系，即在封闭路径中，磁势的代数和等于通过该路径的电流乘以其绕组匝数之和，同时也等于磁场强度与路径长度之积之和，还等于通过路径的磁通乘以路径的磁阻之和。</p></section><section><h3>4）磁路和电路的类比关系<a href="#4磁路和电路的类比关系"><span>#</span></a></h3>

<table><thead><tr><th>特性/方面</th><th>电路</th><th>磁路</th></tr></thead><tbody><tr><td>物理量</td><td>电流 (<span><span>II</span><span><span><span></span><span>I</span></span></span></span>)</td><td>磁通 (<span><span>ΦΦ</span><span><span><span></span><span>Φ</span></span></span></span>)</td></tr><tr><td>类比关系</td><td>电流传递能量，产生电场</td><td>磁通传递能量，产生磁场</td></tr><tr><td>单位</td><td>安培（<span><span>AA</span><span><span><span></span><span>A</span></span></span></span>）</td><td>韦伯（<span><span>WbWb</span><span><span><span></span><span>W</span><span>b</span></span></span></span>）</td></tr><tr><td>欧姆定律</td><td><span><span>V=I⋅RV = I \cdot R</span><span><span><span></span><span>V</span><span></span><span>=</span><span></span></span><span><span></span><span>I</span><span></span><span>⋅</span><span></span></span><span><span></span><span>R</span></span></span></span></td><td><span><span>F=Φ⋅Rm\mathcal{F} = \Phi \cdot R_m</span><span><span><span></span><span>F</span><span></span><span>=</span><span></span></span><span><span></span><span>Φ</span><span></span><span>⋅</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>m</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></td></tr><tr><td>等效电阻/磁阻</td><td>串/并联电阻：<span><span>Req=R1+R2R_{\text{eq}} = R_1 + R_2</span><span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span><span><span>eq</span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>+</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></td><td>串/并联磁阻：<span><span>Rm,eq=Rm1+Rm2R_{m,eq} = R_{m1} + R_{m2}</span><span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span><span>m</span><span>,</span><span>e</span><span>q</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span><span>m</span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>+</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span><span>m</span><span>2</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></td></tr><tr><td>电流流向</td><td>电流从高电势到低电势流动</td><td>磁通从高磁势到低磁势流动</td></tr><tr><td>欧姆定律推导</td><td><span><span>V=I⋅RV = I \cdot R</span><span><span><span></span><span>V</span><span></span><span>=</span><span></span></span><span><span></span><span>I</span><span></span><span>⋅</span><span></span></span><span><span></span><span>R</span></span></span></span></td><td><span><span>F=Φ⋅Rm\mathcal{F} = \Phi \cdot R_m</span><span><span><span></span><span>F</span><span></span><span>=</span><span></span></span><span><span></span><span>Φ</span><span></span><span>⋅</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>m</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></td></tr><tr><td>基尔霍夫定律</td><td><span><span>ΣI=0ΣI = 0</span><span><span><span></span><span>Σ</span><span>I</span><span></span><span>=</span><span></span></span><span><span></span><span>0</span></span></span></span>(节点定律)</td><td><span><span>ΣΦ=0ΣΦ = 0</span><span><span><span></span><span>ΣΦ</span><span></span><span>=</span><span></span></span><span><span></span><span>0</span></span></span></span> (磁路基尔霍夫第一定律)</td></tr><tr><td></td><td><span><span>ΣV=0ΣV = 0</span><span><span><span></span><span>Σ</span><span>V</span><span></span><span>=</span><span></span></span><span><span></span><span>0</span></span></span></span>(环路定律)</td><td><span><span>ΣN⋅i=ΣH⋅l=ΣΦ⋅RmΣN \cdot i = ΣH \cdot l = ΣΦ \cdot R_m</span><span><span><span></span><span>Σ</span><span>N</span><span></span><span>⋅</span><span></span></span><span><span></span><span>i</span><span></span><span>=</span><span></span></span><span><span></span><span>Σ</span><span>H</span><span></span><span>⋅</span><span></span></span><span><span></span><span>l</span><span></span><span>=</span><span></span></span><span><span></span><span>ΣΦ</span><span></span><span>⋅</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>m</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span> (磁路基尔霍夫第二定律)</td></tr></tbody></table></section></section>
<section><h2>7.磁路计算方法<a href="#7磁路计算方法"><span>#</span></a></h2><p>在磁路计算中，通常会遇到以下两类问题：</p><ol>
<li>第一类问题：已知磁通<span><span>ΦΦ</span><span><span><span></span><span>Φ</span></span></span></span>，求解磁动势 <span><span>FF</span><span><span><span></span><span>F</span></span></span></span>。</li>
<li>第二类问题：已知磁动势 <span><span>FF</span><span><span><span></span><span>F</span></span></span></span>，求解磁通 <span><span>ΦΦ</span><span><span><span></span><span>Φ</span></span></span></span>。</li>
</ol><p>在电机和变压器设计等领域的磁路计算中，常常涉及第一类问题。而对于第二类问题，一般需要使用迭代法进行求解，这种计算往往由计算机来完成。</p><p>磁路计算中的欧姆定律是描述磁路中磁通、磁动势和磁阻之间关系的类比法则，类似于电路中的欧姆定律。根据磁路欧姆定律，磁动势<span><span>FF</span><span><span><span></span><span>F</span></span></span></span> 与磁通<span><span>ΦΦ</span><span><span><span></span><span>Φ</span></span></span></span>之间的关系可以表示为：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282111153.png" alt="image-20230828210524556" /><figcaption>image-20230828210524556</figcaption></figure><p></p><section><h3>自感和互感<a href="#自感和互感"><span>#</span></a></h3><section><h4>自感<a href="#自感"><span>#</span></a></h4><span><span><span>L=N2⋅μ⋅AL = N^2 \cdot \mu \cdot A</span><span><span><span></span><span>L</span><span></span><span>=</span><span></span></span><span><span></span><span><span>N</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span><span></span><span>⋅</span><span></span></span><span><span></span><span>μ</span><span></span><span>⋅</span><span></span></span><span><span></span><span>A</span></span></span></span></span><ul>
<li>自感的大小与匝数的平方和磁路的磁导率成正比。</li>
<li>铁心线圈的自感要比空心线圈的大得多，这是因为铁心可以集中磁场并增加自感。</li>
<li>铁心线圈的电感不是常数，当磁路饱和程度增加时，自感会下降。磁路饱和会影响磁通量和磁动势之间的关系，从而影响自感的大小。</li>
</ul><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282111405.png" alt="image-20230828210646207" /><figcaption>image-20230828210646207</figcaption></figure><p></p></section><section><h4>互感<a href="#互感"><span>#</span></a></h4><p>互感描述了两个线圈之间的耦合效应，其中线圈之间的匝数乘积和互感磁通所经过的磁路的磁导率成正比。</p><span><span><span>M=k⋅N1⋅N2M = k \cdot \sqrt{N_1 \cdot N_2}</span><span><span><span></span><span>M</span><span></span><span>=</span><span></span></span><span><span></span><span>k</span><span></span><span>⋅</span><span></span></span><span><span></span><span><span><span><span><span><span></span><span><span><span>N</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>⋅</span><span></span><span><span>N</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span><p></p><figure><img src="http://imgbed.leihub.cn/img/202308282111427.png" alt="image-20230828210748836" /><figcaption>image-20230828210748836</figcaption></figure><p></p></section></section></section>
<section><h2>参考<a href="#参考"><span>#</span></a></h2><p>1、《电机学第四版》 华中科技大学出版社 辜承林</p><p>2、<a href="https://www.bilibili.com/video/BV1fp411Z7uJ" target="_blank">华中科技大学 电机学__bilibili</a></p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/631/</id>
      <title type="text">白嫖微软云（一）：申请Azure学生订阅</title>
      <published>2023-08-27T16:08:56.000Z</published>
      <updated>2025-11-14T15:21:25.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/631/"/>
      <summary type="text">一、微软云Azure Azure学生订阅是微软Azure云平台面向合格学生提供的一个优惠计划，旨在让学生能够免费使用Azure云服务，以支持他们的学习和项目开发。这个订阅为学生提供了一些免费的服务和一定额度的免费资金，使他们能够在云环境中尝</summary>
      <content type="html"><![CDATA[<section><h1>一、微软云Azure<a href="#一微软云azure"><span>#</span></a></h1><p>Azure学生订阅是微软Azure云平台面向合格学生提供的一个优惠计划，旨在让学生能够免费使用Azure云服务，以支持他们的学习和项目开发。这个订阅为学生提供了一些免费的服务和一定额度的免费资金，使他们能够在云环境中尝试各种技术和构建应用程序，无需太多负担。</p><section><h3>1.优惠内容<a href="#1优惠内容"><span>#</span></a></h3><p>Azure学生订阅通常包括以下内容：</p><ol>
<li><strong>免费服务：</strong> 订阅提供了一些常用的Azure服务，如<strong>虚拟机</strong>、数据库、存储等，供学生免费使用。这些服务可以帮助学生学习云计算和应用开发。</li>
<li><strong>免费额度：</strong> 订阅附带了一定额度的免费资金（通常是<strong>100美元</strong>），用于支付那些不在免费服务范围内的其他服务。这意味着学生可以使用这些资金来体验更多高级服务，但需要留意额度的使用情况。</li>
<li><strong>有效期和续订：</strong> 订阅的<strong>有效期通常为一年</strong>。如果在一年后学生仍然保持学生身份，他们可以申请续订订阅，继续享受免费服务和额度。</li>
</ol></section><section><h3>2.Azure用途<a href="#2azure用途"><span>#</span></a></h3><p>可以利用Azure学生订阅做的事情：</p><ol>
<li><strong>运行服务器和服务：</strong> 可以在Azure虚拟机上运行各种服务，如网站托管、数据库、应用程序等。这让您能够学习如何部署和管理应用程序以及服务器基础设施。</li>
<li><strong>创建个人网站：</strong> 您可以在虚拟机上搭建个人博客、网站或在线简历，展示您的项目和技能。</li>
<li><strong>利用AI和数据分析：</strong> Azure提供了丰富的人工智能和数据分析工具，您可以使用这些工具来开发和部署机器学习模型、进行数据可视化等。</li>
</ol></section><section><h3>3.申请流程<a href="#3申请流程"><span>#</span></a></h3><p>申请Azure教育优惠理论上需要有具有在读高校学生身份和拥有edu电子邮件地址，但在实际的申请流程中只会验证你的edu电子邮箱地址，申请失败时才会要你证明学生身份。</p><p>首先进入<a href="https://azure.microsoft.com/zh-cn/free/students/" target="_blank">面向学生的 Azure - 免费帐户额度 | Microsoft Azure</a>)的网页，点击“免费开始使用”。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827233710731.png" alt="image-20230827233710731" /><figcaption>image-20230827233710731</figcaption></figure><p></p><p>登录自己的账号，使用手机号码进行验证</p><p></p><figure><img src="http://imgbed.leihub.cn/img/v2-db2f30dccb6794f6df5eaecf607c1cac_720w.webp" alt="img" /><figcaption>img</figcaption></figure><p></p><p>接下来验证学生身份，验证方法选择“学校电子邮件地址”，在下面填写你的学校电子邮件地址。点击“验证学术地位”后，微软会向你的学校电子邮箱发送一封验证邮件。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/v2-8efe34ac10c52640b05cca4d57581319_720w.webp" alt="img" /><figcaption>img</figcaption></figure><p></p><p>打开学校的教育邮箱，点击邮件中的网址进行验证。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827234438664.png" alt="image-20230827234438664" /><figcaption>image-20230827234438664</figcaption></figure><p></p><p>然后填写你的个人资料。重要通知的电子邮件地址填写你常用的电子邮件地址，不要填写学校的电子邮件地址。地址部分填写学校的地址，如果不知道学校具体地址可以搜索或到学校官网首页的最底部查看。信息填写完成后，勾选同意协议，点击注册。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/v2-b7b6df932b5a60ac6a775d274da4e51a_720w.webp" alt="img" /><figcaption>img</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827234851301.png" alt="image-20230827234851301" /><figcaption>image-20230827234851301</figcaption></figure><p></p><p>之后会显示申请结果。如果按照提示操作后跳转到Azure门户，在教育页面可以看到自己的资源使用情况，比如可用额度，服务器过期时间等，那么恭喜你申请成功了。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827235043113.png" alt="image-20230827235043113" /><figcaption>image-20230827235043113</figcaption></figure><p></p><p>也有可能会申请失败，这个很玄学，我使用同样的申请方式，我申请成功了，我同学却申请失败，显示没有资格使用教育优惠。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/v2-21c5e0df3b7e06fba093e3d45ca2e6db_720w.webp" alt="img" /><figcaption>img</figcaption></figure><p></p><p>这种情况就要申请人工进行验证了，可能会需要学生证、学信网证明之类的材料，因为我没有申请过，这里就不赘述了。</p><blockquote><p>PS：理论上一次教育认证持续一年时间，我同学申请满一年后，微软发了一封验证邮件，通过教育邮件再次进行了验证，又续了一年。</p><p>那岂不是可以利用教育邮箱永久续费，我学校毕业了也没注销我们的教育邮箱。</p></blockquote><p>至此，Azure学生订阅的申请就完成了，接下来可以进行虚拟机创建，部署自己想要的服务了。</p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/627/</id>
      <title type="text">Stable Diffusion（一）：AI绘画AutoDL平台云端部署</title>
      <published>2023-08-27T06:57:03.000Z</published>
      <updated>2024-06-06T04:26:51.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/627/"/>
      <summary type="text">最近AI绘图很火，一直想入坑，但是苦于没有显卡，7月英伟达出了 RTX 4060TI 16G，当时看到大显存非常心动，但是4000左右的答辩价格实在是劝退。 现在是坐等4060TI降价了，本来下定决心下单了，突然看到消息说RX7600发售，</summary>
      <content type="html"><![CDATA[<p>最近AI绘图很火，一直想入坑，但是苦于没有显卡，7月英伟达出了 RTX 4060TI 16G，当时看到大显存非常心动，但是4000左右的答辩价格实在是劝退。</p>
<p>现在是坐等4060TI降价了，本来下定决心下单了，突然看到消息说RX7600发售，英伟达可能为了应对A卡的冲击，这几周会选择给4060TI降价，那就再等几周咯。</p>
<p>但是一直心痒痒想玩，就想到了租用GPU玩玩Stable diffusion试试水。</p>
<p><strong>GPU平台选择</strong></p>
<p>最开始想到的是谷歌的colab，考虑到谷歌云盘那点空间，还有colab非vip只能分到M40这种上古显卡，忙的时候还可能分不到显卡，只能免费连续使用8个小时，要获取最好的使用效果，最终还是要付费，而我又没有国外信用卡，就排除了colab。</p>
<p>看了国内腾讯云、阿里云等厂家，感觉有点小贵，最后找到了AutoDL，可以进行计量付费，不适用的时候可以关机，停止计费，正好我这种业余爱好者的需求。</p>
<p>这里就介绍下，如何在AutoDL平台租用GPU进行Stable Diffusion的部署。</p>
<section><h1>一、注册AutoDL<a href="#一注册autodl"><span>#</span></a></h1><p>1、注册AutoDL账号，如果还没有账号可以点击以下链接进行注册</p><p><a href="https://www.autodl.com/" target="_blank">https://www.autodl.com/</a></p><p>2、如果是学生还可以注册学生认证，免费激活一年炼丹会员，租用GPU打95折，能省一点是一点。</p><p>注册后进入首页，点击认证学生进入快速升级通道，通过教育邮箱即可进行认证。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20211229150313968.png" alt="image-20211229150313968" /><figcaption>image-20211229150313968</figcaption></figure><p></p></section>
<section><h1>二、使用Stable-diffusion镜像<a href="#二使用stable-diffusion镜像"><span>#</span></a></h1><p>这里推荐使用<strong>xiaolxl</strong>的stable-diffusion-webui镜像，可以直接在首页的算法社区找到。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827131910752.png" alt="image-20230827131910752" /><figcaption>image-20230827131910752</figcaption></figure><p></p><p>选择镜像版本，就可以一键自动化部署</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827131945297.png" alt="image-20230827131945297" /><figcaption>image-20230827131945297</figcaption></figure><p></p><p>点击AutoDL创建实例进入GPU选择界面，有多种GPU供大家租用。因为<strong>xiaolxl</strong>的stable-diffusion-webui镜像使用的A5000进行部署，为了防止部署时出现自己解决不来的问题，这里我也选择使用A5000。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827132051284.png" alt="image-20230827132051284" /><figcaption>image-20230827132051284</figcaption></figure><p></p><p>点击<strong>立即创建</strong>，就会自动根据选择的社区镜像进行部署，只需要等一切部署好就行。</p><p>在控制台界面的容器实例中，可以查看实例部署状况，一般部署1-2两分钟就完成了。</p></section>
<section><h1>三、绑定网盘<a href="#三绑定网盘"><span>#</span></a></h1><p>autoDL支持实例和百度网盘、阿里云盘进行数据传输，可以 备份相关实例数据、迁移数据，和别人共享数据集。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220325102905470.png" alt="image-20220325102905470" /><figcaption>image-20220325102905470</figcaption></figure><p></p><p>这里以百度网盘为例，登录百度网盘，在左边的工具界面中，选择效率助手，进入百度开放平台页面。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827132758734.png" alt="image-20230827132758734" /><figcaption>image-20230827132758734</figcaption></figure><p></p><p>如果没有进行过百度的开发者认证就会创建失败，加入百度开发者平台，完成认证后即可。</p><p>在控制台中，选择创建应用</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827133034686.png" alt="image-20230827133034686" /><figcaption>image-20230827133034686</figcaption></figure><p></p><p>应用类别和应用名称随便填填就行，也可以填AutoDL，避免不必要的麻烦</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827133058291.png" alt="image-20230827133058291" /><figcaption>image-20230827133058291</figcaption></figure><p></p><p>创建成功后，就可以看到创建应用的<code>AppKey</code>和 <code>Secretkey</code></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827132942326.png" alt="image-20230827132942326" /><figcaption>image-20230827132942326</figcaption></figure><p></p><p>在完成实例开机后，在快捷工具一栏中，可以找到AutoPannel入口，点击打开</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827133546384.png" alt="image-20230827133546384" /><figcaption>image-20230827133546384</figcaption></figure><p></p><p>这里选择百度网盘存储资料，现在阿里云盘也限速了，还不如百度。</p><p>在左边菜单栏中点击添加授权，选择百度网盘，将在百度开发平台中获取的的<code>AppKey</code>和 <code>Secretkey</code>填入。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827133759560.png" alt="image-20230827133759560" /><figcaption>image-20230827133759560</figcaption></figure><p></p><p>点击获取Access Token，弹出百度云盘网页，进行账号授权，获取授权后返回的Token，粘贴进来就完成了百度网盘的授权。</p></section>
<section><h1>四、镜像配置<a href="#四镜像配置"><span>#</span></a></h1><p>在实例界面的快捷工具中，点击<code>JupyterHub</code>进入配置界面</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827134445319.png" alt="image-20230827134445319" /><figcaption>image-20230827134445319</figcaption></figure><p></p><p>配置已经帮我们写好了，一步一步点击运行就可以自动进行配置</p><p>在<code>JupyterHub</code>页面点击代码块，选择进行运行</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827134739810.png" alt="image-20230827134739810" /><figcaption>image-20230827134739810</figcaption></figure><p></p><p>在执行上述步骤后，刷新浏览器，在jupyterhub笔记本页面重新选择内核。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827134926515.png" alt="image-20230827134926515" /><figcaption>image-20230827134926515</figcaption></figure><p></p><p>这样就可以愉快的使用镜像了。</p></section>
<section><h1>五、Stable diffusion配置<a href="#五stable-diffusion配置"><span>#</span></a></h1><p>在笔记本中，点击第二个代码块就打开了模型配置界面，可以进行模型下载、更新、WebUi启动以及模组安装。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827135255974.png" alt="image-20230827135255974" /><figcaption>image-20230827135255974</figcaption></figure><p></p><section><h4>1.插件安装<a href="#1插件安装"><span>#</span></a></h4><p>在工具栏中，点击拓展安装工具，填入需要安装的插件网址，点击安装即可进行拓展安装，信息栏弹出安装完成，即完成插件安装。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827135855613.png" alt="image-20230827135855613" /><figcaption>image-20230827135855613</figcaption></figure><p></p><p>这里提供几个拓展安装地址：</p><p>c站助手：<a href="https://ghproxy.com/https://github.com/butaixianran/Stable-Diffusion-Webui-Civitai-Helper.git" target="_blank">https://ghproxy.com/https://github.com/butaixianran/Stable-Diffusion-Webui-Civitai-Helper.git</a></p><p>3D OpenPose 编辑器插件：<a href="https://ghproxy.com/https://github.com/hnmr293/posex.git" target="_blank">https://ghproxy.com/https://github.com/hnmr293/posex.git</a></p><p>ControlNet 插件：<a href="https://gitcode.net/ranting8323/sd-webui-controlnet.git" target="_blank">https://gitcode.net/ranting8323/sd-webui-controlnet.git</a></p></section><section><h4>2.模型下载<a href="#2模型下载"><span>#</span></a></h4><p>在下载器中可以进行模型安装，点击内置模型下载，镜像中内置了许多主流模型，按需可以进行一键下载。</p><p>建议将数据移动到数据盘，系统盘不够下载模型。</p><p>移动到数据盘后，webui的文件就移动到了/autodl-tmp文件夹。</p><p>stable-diffusion-webui文件夹中，models存储着下载的模型文件，extensions存储着下载的插件文件。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827140405992.png" alt="image-20230827140405992" /><figcaption>image-20230827140405992</figcaption></figure><p></p></section><section><h4>3.本地模型上传<a href="#3本地模型上传"><span>#</span></a></h4><p>本地的模型文件可以上传至/autodl-tmp/models/Stable-diffusion/文件夹中。</p></section><section><h4>4.运行WebUi<a href="#4运行webui"><span>#</span></a></h4><p>在启动WebUi界面中，可以对需要开启的参数进行选择，点击运行WebUI</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827141446138.png" alt="image-20230827141446138" /><figcaption>image-20230827141446138</figcaption></figure><p></p><p>当输出以下信息后，webui就启动成功了，控制台实例的快捷工具中，点击自定义服务，即可访问WebUI的网页。</p><p>在新安装了模型和插件后，最好还是在笔记本中重新运行代码块重启下webui</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230827141730563.png" alt="image-20230827141730563" /><figcaption>image-20230827141730563</figcaption></figure><p></p></section></section>
<section><h1>总结<a href="#总结"><span>#</span></a></h1><p>1.当实例不使用时可以关机，如果使用的计量付费服务，就会停止扣费，下次使用的时候再开机。</p><p>2.但是需要注意的是，关机后，数据并不是永久存储的，以前是可以存储30天，现在是关机15天后释放，所以要记得做好实例和数据备份。</p><p>3.关机后，下次开机大概率会存在当前机房GPU不足的问题，这样是无法进行开机的。</p></section>
<section><h1>参考<a href="#参考"><span>#</span></a></h1><p>1.<a href="https://www.autodl.com/" target="_blank">AutoDL算力云</a></p><p>2.<a href="https://www.codewithgpu.com/i/AUTOMATIC1111/stable-diffusion-webui/NovelAI-Consolidation-Package-3.1" target="_blank">AUTOMATIC1111/stable-diffusion-webui/NovelAI-Consolidation-Package-3.1: (本地整合版)NovelAI+DreamBooth+DeepdanBooru+Xformers+官网效果+可视化启动界面整合包是NovelAI-Consolidation-Package的第三代版本 - CG (codewithgpu.com)</a></p><p>3.<a href="https://www.bilibili.com/video/BV12o4y1j7Ca/?spm_id_from=333.337.search-card.all.click&amp;vd_source=cb5ce25be8ee6f5af6871a77c17b2b21" target="_blank">超简单autodl云端部署stable diffusion及一些使用方法-bilibili</a></p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/623/</id>
      <title type="text">云服务器+FRP+Nginx，无需添加端口，直接使用域名访问家里的任何设备</title>
      <published>2023-08-06T10:04:24.000Z</published>
      <updated>2024-06-06T04:27:15.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/623/"/>
      <summary type="text">之前写过ipv6+ddns访问nas服务的文章，这种方法有许多不足 一是必须在支持ipv6的环境下访问，许多公共场所的wifi一般就不支持ipv6，无法访问网站，像腾讯轻量云服务器也不支持访问纯ipv6服务，好像要云服务器才支持。这样轻量云</summary>
      <content type="html"><![CDATA[<p>之前写过ipv6+ddns访问nas服务的文章，这种方法有许多不足
一是必须在支持ipv6的环境下访问，许多公共场所的wifi一般就不支持ipv6，无法访问网站，像腾讯轻量云服务器也不支持访问纯ipv6服务，好像要云服务器才支持。这样轻量云上搭建的alist就无法访问nas中的nextcloud服务。
二是家庭宽带都封禁了80 443等端口，虽然使用域名加ddns可以正常访问，但无法省略掉端口，这样看起来网站就不是特别正式。接下来介绍一种方法，可以实现无端口访问nas中的服务，在ipv4环境下也可以访问nas。通过云服务器实现流量中转，使用nginx进行反向代理，实现无端口访问内网服务，而且还可以申请SSL证书，支持https。</p>
<section><h1>FRP安装<a href="#frp安装"><span>#</span></a></h1><p>frp 是一个专注于内网穿透的高性能的反向代理应用，支持 TCP、UDP、HTTP、HTTPS 等多种协议，且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。</p><p>frp 主要由 <strong>客户端(frpc)</strong> 和 <strong>服务端(frps)</strong> 组成，服务端通常部署在具有公网 IP 的机器上，<strong>客户端</strong>通常部署在需要穿透的内网服务所在的机器上，内网服务由于没有公网 IP，不能被非局域网内的其他用户访问。用户通过访问服务端的 frps，由 frp 负责根据请求的端口或其他信息将请求路由到对应的内网机器，从而实现通信。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/architecture.png" alt="architecture.png" /><figcaption>architecture.png</figcaption></figure><p></p><section><h2>服务端<a href="#服务端"><span>#</span></a></h2><p><strong>下载</strong></p><p>网址：<a href="https://github.com/fatedier/frp" target="_blank">GitHub - fatedier/frp: A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.</a></p><p>在 Github 的 <a href="https://github.com/fatedier/frp/releases" target="_blank">Release</a> 页面中下载到最新版本的客户端和服务端二进制文件，所有文件被打包在一个压缩包中。其中的 frpc 拷贝到内网服务所在的机器上，将 frps 拷贝到具有公网 IP 的机器上，放置在任意目录。</p><p><strong>部署</strong></p><p>将运行文件拷贝到云服务中，编写配置文件<code>frps.ini</code></p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>[common]</span></div></div><div><div><div>2</div></div><div><span>#frp 监听端口，与客户端绑定端口</span></div></div><div><div><div>3</div></div><div><span>bind_port</span><span><span>=</span><span> </span></span><span>4000</span></div></div><div><div><div>4</div></div><div><span>kcp_bind_port</span><span> </span><span>=</span><span> </span><span>4000</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span>#dashboard用户名</span></div></div><div><div><div>7</div></div><div><span>dashboard_user</span><span><span>=</span><span> </span></span><span>user</span></div></div><div><div><div>8</div></div><div><span>#dashboard密码</span></div></div><div><div><div>9</div></div><div><span>dashboard_pwd</span><span><span>=</span><span> </span></span><span>passwd</span></div></div><div><div><div>10</div></div><div><span>#dashboard端口，启动成功后可通过浏览器访问如http://ip:1234</span></div></div><div><div><div>11</div></div><div><span>dashboard_port</span><span><span>=</span><span> </span></span><span>1234</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>#设置客户端token，对应客户端有页需要配置一定要记住，如果客户端不填写你连不上服务端</span></div></div><div><div><div>14</div></div><div><span>token</span><span> </span><span>=</span><span> </span><span>123456789</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>先通过 <code>./frps -c ./frps.ini</code> 启动服务端,如果需要在后台长期运行，建议结合其他工具使用，例如 <a href="https://gofrp.org/docs/setup/systemd/" target="_blank">systemd</a> 和 <code>supervisor</code>。</p><p>宝塔面板商店中可以安装进程守护管理器，如果将运行文件<code>frps</code>放在<code>/opt/frp</code>文件夹中，则启动命令改写为<code>/opt/frp/frps -c /opt/frp/frps.ini</code>，进程目录为<code>/opt/frp</code>。</p><p>完成设置后，进程会自动启动在后台运行，每次服务器重启都会自动运行，这样就完成了服务端的设置。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230806154055360.png" alt="image-20230806154055360" /><figcaption>image-20230806154055360</figcaption></figure><p></p></section><section><h2>客户端<a href="#客户端"><span>#</span></a></h2><p><strong>群晖安装</strong></p><p>群晖下安装FRP比较简单，可以使用矿神源，第三方套件安装。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230806170548201.png" alt="image-20230806170548201" /><figcaption>image-20230806170548201</figcaption></figure><p></p><p>1.打开群辉套件中心</p><p>2.在设置中新增套件来源</p><p>3.添加<a href="https://spk7.imnks.com/" target="_blank">矿神群晖SPK套件源</a>输入如图链接</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230806165826522.png" alt="image-20230806165826522" /><figcaption>image-20230806165826522</figcaption></figure><p></p><p>在套件中心的社群套件中搜索frpc，点击安装即可一键安装。打开frpc，在窗口中可对frpc.ini配置文件进行设置。设置的ip地址和端口要与frps配置设文件中一致。</p><p>在具体的内网穿透服务配置中，local_ip为要暴露到外网的本地服务部署的IP地址，local_port为本地服务监听的端口，remote_port为暴露到云服务器的端口。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230806170843759.png" alt="image-20230806170843759" /><figcaption>image-20230806170843759</figcaption></figure><p></p><p>点击保存，即完成了frpc的部署。</p><p>frp除了用直接二进制文件进行部署，还可以采用docker的方式来安装frp的服务端和客户端，用<a href="https://hub.docker.com/r/snowdreamtech/frpc" target="_blank">@snowdreamtech</a> 的docker镜像，这样后台运行，重启和配置会稍微简单一些。docker-compose.yml文件如下，将<code>frpc.ini</code>配置文件映射到了本地的<code>/opt/frp/docker/frpc.ini</code>文件。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>version: </span><span>'3'</span></div></div><div><div><div>2</div></div><div><span>services:</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>frpc:</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>image: snowdreamtech/frpc</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>network_mode: host</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>volumes:</span></div></div><div><div><div>7</div></div><div><span><span>      </span></span><span>- /opt/frp/docker/frpc.ini:/etc/frp/frpc.ini</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>container_name: frpc</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>restart: always</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>还是和往常一样，使用docker-compose进行部署。</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>docker-compose</span><span> </span><span>up</span><span> </span><span>-d</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>如果需要增加穿透服务，对<code>frpc.ini</code>配置文件进行修改，然后重启容器即可。</p><p>通过查看容器日志，可以了解穿透是否成功。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230806172501701.png" alt="image-20230806172501701" /><figcaption>image-20230806172501701</figcaption></figure><p></p><p>如frpc.ini配置文件所示，本地端口的5000服务被暴露到了云服务公网IP的5000端口，通过云服务器ip地址+5000端口，即可实现对本地服务的访问，但是这样通过ip地址加端口的访问让人感觉不是特别正式，可以进一步通过反向代理，消除掉端口。</p></section></section>
<section><h1>反向代理<a href="#反向代理"><span>#</span></a></h1><p>接下来进行反向代理，将指定的域名反代到内网服务暴露到公网的端口，这样就可以实现域名直接访问内网服务。</p><p>在进行反向代理前，要保证域名指向了部署frps的主机。首先需要申请一个域名，并将子域名指定到frps部署的云服务器ip地址。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230806172907766.png" alt="image-20230806172907766" /><figcaption>image-20230806172907766</figcaption></figure><p></p><p>反向代理有几种方法，一种是使用宝塔安装好的nginx环境进行反代。另一种是通过docker安装的nginxproxymanager进行反代。两者的操作都非常简单，而且都可以申请ssl证书。</p><p>在之前介绍了利用NPM进行反代，这里就介绍使用宝塔面板进行反向代理。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230806173147761.png" alt="image-20230806173147761" /><figcaption>image-20230806173147761</figcaption></figure><p></p><p>完成网站创建后，点击网站即可对站点信息进行配置，在左边菜单中选择反向代理，点击添加反向代理，在界面中，目标URL填写代理到的地址，在本文中，则为将本地服务暴露到制定公网端口地址，即在<a href="http://blog.leihub.cn">http://blog.leihub.cn</a> + fprc中设置的remote_port，点击提交即完成了域名反代到本地服务的设置。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230806173412923.png" alt="image-20230806173412923" /><figcaption>image-20230806173412923</figcaption></figure><p></p></section>
<section><h1>SSL证书申请<a href="#ssl证书申请"><span>#</span></a></h1><p>上一次介绍了如何使用NPM进行证书申请，宝塔面板也可以进行证书申请。</p><p>反向代理的域名只支持使用DNS验证进行SSL证书申请，我的域名在腾讯云上进行解析，选择DnsPod设置，在弹窗中填入腾讯云DnsPod的ID以及Token，选择需要申请证书的域名，点击申请即可。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230806175009099.png" alt="image-20230806175009099" /><figcaption>image-20230806175009099</figcaption></figure><p></p><p>完成设置后，申请的证书会自动进行部署，推荐打开强制HTTPS，这样更安全可靠。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230806175314670.png" alt="image-20230806175314670" /><figcaption>image-20230806175314670</figcaption></figure><p></p></section>
<section><h1>小结<a href="#小结"><span>#</span></a></h1><p>具体的原理就是，假设本地服务部署在<code>4025</code>端口，通过FRP将本地内网指定端口<code>4025</code>的服务暴露到云服务的指定端口<code>5025</code>上，通过<code>云服务ip地址+端口5025</code>即可实现对本地部署在4025服务的访问。</p><p>进一步，在云服务中通过反向代理，将域名<code>sample.leiting2020.top</code>反代到云服务的指定端口，将域名的流量都转发的云服务的端口5025，而本地端口4025的服务又通过FRP暴露在云服务器的端口5025上，这样通过域名就可以实现对本地4025端口服务的访问。</p><p>通过上述方法，就可以在无ipv6环境下，实现无端口访问nas的服务。但这种方法也收到云服务器性能的影响，比如服务器的带宽，流量总数，我的云服务器带宽8M，实在是小水管，卡起来真烦人。一个月1200g，做网站还够用，如果做下载的中转，可能流量就不够用了。</p><p>如果说上传一些文件到nas中，或者做下载服务，最好还是使用ipv6+ddns，网速不会受到服务器带宽的影响。</p></section>
<section><h1>参考<a href="#参考"><span>#</span></a></h1><p>FRP：<a href="https://github.com/fatedier/frp" target="_blank">GitHub - fatedier/frp: A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.</a></p><p>群晖矿神源：<a href="https://spk7.imnks.com/" target="_blank">https://spk7.imnks.com/</a></p><p>FRP的docker镜像：<a href="https://hub.docker.com/r/snowdreamtech/frpc" target="_blank">https://hub.docker.com/r/snowdreamtech/frpc</a></p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/585/</id>
      <title type="text">铣削加工机器人（二）：机器人刚度性能建模及轨迹分割</title>
      <published>2023-07-23T15:44:37.000Z</published>
      <updated>2024-06-22T17:42:43.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/585/"/>
      <summary type="text">机器人刚度建模 机器人在进行曲面加工时，铣削加工的铣削力数值较大且方向经常变化，机器人各个关节在抵御铣削力时容易发生形变，累积到末端产生变形误差，从而使机器人加工精度下降。因此，如何提高机器人的刚度性能是目前研究的重点。 1 机器人雅可比矩</summary>
      <content type="html"><![CDATA[
<h1>机器人刚度建模</h1>
<p>机器人在进行曲面加工时，铣削加工的铣削力数值较大且方向经常变化，机器人各个关节在抵御铣削力时容易发生形变，累积到末端产生变形误差，从而使机器人加工精度下降。因此，如何提高机器人的刚度性能是目前研究的重点。</p>
<h2>1 机器人雅可比矩阵</h2>
<p>除了关节角度和机器人末端执行器位置之间的关系外，还需要研究关节和末端执行器速度之间的关系。由机器人运动学公式，当给定一组关节角 时，可以确定机器人末端的位置与姿态。</p>
<div><div></div></div>
<p>其中，，将公式两边进行求导，可以得到：</p>
<div><div></div></div>
<p>式中，为雅可比矩阵。</p>
<p>一般情况下，雅可比矩阵通过矢量差乘积法、微分变换法得到。而使用指数积公式表示正运动学，可以更加明确、优雅的推导出雅可比矩阵。在机器人正运动学的指数积公式下，末端的速度的表达式为：</p>
<div><div></div></div>
<p>带入机器人正运动学公式，并使用伴随映射将上式写成向量形式，即： </p>
<div><div></div></div>
<div><div></div></div>
<p>   式中，对于任意，与相关联的伴随映射为:</p>
<div><div></div></div>
<p>由虚功原理，关节处的功率消耗为机器人运动的功率消耗和末端执行器的功率消耗之和，假设机器人处于静平衡状态，没有用于机器人运动的功率消耗，关节处功率消耗等于末端执行器的功率消耗，用公式表示为：</p>
<div><div></div></div>
<p>式中，为关节力矩的列向量形式，为关节角速度，<strong>F</strong>为末端所受外力，<strong>V</strong>为末端空间速度，利用公式可得：</p>
<div><div></div></div>
<p>上式表示的是关节力矩与末端所受外力之间的关系，若一个外力作用在末端器上以平衡各关节力矩，使用上式便可用于计算该力矩，以产生反作用力使机器人处于平衡状态。与雅可比矩阵一样，也具有相似的特性。由公式可知，当机器人处于奇异形位时，关节产生的驱动力矩不能在机器人末端产生得到相应的平衡力矩，也就是丧失了对末端力矩的控制，使机器人变得难以控制，在加工过程中应尽量避免。</p>
<h2>2 机器人刚度建模</h2>
<p>KUKA KR60-3机器人臂架的刚性远大于关节的刚性，因此我们将仅考虑关节柔性对末端的偏移造成的影响，同时将关节的刚度映射至机器人末端的刚度。将各个关节间的驱动装置的刚度用一个弹簧来近似，各关节的受外力矩<em><strong>τ</strong></em>和关节变形Δ<em><strong>θ</strong></em>的关系可以表示为：</p>
<div><div></div></div>
<p>式中，为关节刚度矩阵，其对角元素为6个关节的刚度值，</p>
<p>由前文机器人力雅可比矩阵可知外力与关节力矩的关系，带入上述公式为：</p>
<div><div></div></div>
<p>末端变形为：</p>
<div><div></div></div>
<p>根据胡克定律，机器人末端执行器在空间中受到外力发生变形，可以使用公式表示为：</p>
<div><div></div></div>
<p>式中，<em><strong>F</strong></em>为末端执行器所受的空间力-力矩向量，<em><strong>X</strong></em>为末端受外力产生的空间位移-转角向量。</p>
<p>将上述公式联合可得：</p>
<div><div></div></div>
<p>式中，<em><strong>J</strong></em>为雅可比矩阵。</p>
<p>当机器人处于奇异形位，雅可比矩阵不可逆，导致上述公式不成立，尽管知道末端受力也无法预测末端变形情况。因此，在加工过程中需要避免使机器人处于奇异形位。关节刚度矩阵为对角矩阵，由矩阵的运算性质可知，末端笛卡尔刚度矩阵<em><strong>K</strong></em>为对称矩阵，其形式如下：      </p>
<div><div></div></div>
<h2>3 刚度性能指标</h2>
<p>上述运算涉及雅可比矩阵的求逆，这会导致运算过程中出现误差，尤其是在靠近机器人奇异形位的情况，针对上述问题，定义柔度矩阵为：</p>
<div><div></div></div>
<p>由公式可以看出，机器人末端笛卡尔柔度矩阵的计算未涉及到雅可比矩阵的求逆运算。机器人末端变形和所受外力<em><strong>F</strong></em>的关系可以表示为，用矩阵形式表示为：               </p>
<div><div></div></div>
<p>式中，为平移柔度矩阵，为旋转柔度矩阵，和为耦合柔度矩阵。</p>
<p>在实际加工过程中，末端的扭转变形与平移变形相比可以忽略不计，为了简化问题，只考虑末端的平移变形，将的笛卡尔柔度矩阵简化为平移柔度矩阵。</p>
<p>刚度是影响机器人末端变形的重要因素，为了研究刚度对机器人铣削加工变形的影响，需要引入一个刚度性能指标对机器人的刚度进行评价，而柔度矩阵<em><strong>C</strong></em>是一个张量，无法直观地反映机器人的刚度性能，通常使用柔度椭球来描述机器人的刚度性能，末端平移变形为：</p>
<div><div></div></div>
<p>其中，为末端所受单位力。</p>
<p>设机器人末端受外力的平移变形为单位向量：</p>
<div><div></div></div>
<p>上述公式定义了一个三维笛卡尔柔度椭球，如图所示。半长轴长度为、、的平方根，其中、、为的特征值。椭球的各个半长轴代表了机器人在各个方向上的刚度性能，该半轴越短，代表在该方向上的受力变形就越小，刚度性能就越优。因此，柔度椭球的体积<em><strong>V</strong></em>与半长轴的乘积成正比，柔度椭球的体积也代表了当前位置的综合刚度性能，将的特征值。椭球的各个半长轴代表了机器人在各个方向上的刚度性能，该半轴越短，代表在该方向上的受力变形就越小，刚度性能就越的条件数作为刚度性能评价指标，即：</p>
<div><div></div></div>
<p><img src="http://imgbed.leihub.cn/img/202307232341783.png" alt="刚度椭球" /></p>
<p>以下为机器人刚度性能指标计算代码：</p>
<pre><code>#每个姿态下机器人受沿刀轴方向单位力的末端变形向量
def Stiffness(thetalist):
    Jb =  mr.JacobianBody(Blist, thetalist)
    try:
        A = np.dot(Jb, Jb.T)
        K_theta = np.diag([5.7e7, 6.2e6, 1.2e7, 2.1e6, 2.3e6, 2.3e6])  # 关节刚度矩阵,打单位是N/MM
        StiffnessMatrix = np.linalg.inv(Jb).T @ K_theta @ np.linalg.inv(Jb)  # 笛卡尔刚度矩阵
        transStiffnessMatrix = StiffnessMatrix[3:6, 0:3]  # 平移刚度矩阵
        ComplianceMatrix = Jb @ np.linalg.inv(K_theta) @ Jb.T  # 柔度矩阵
        transComplianceMatrix = ComplianceMatrix[3:6, 0:3]  # 平移柔度矩阵
        A = np.dot( transComplianceMatrix.T,  transComplianceMatrix)
        eigenvalue, featurevector = np.linalg.eig(A)
    except:
        print('该姿态处于奇异形位！')
    return eigenvalue
</code></pre>
<p>在实际铣削加工中，加工效果的评价往往是针对整个曲面或者某一个区域，而不是某一个加工点。机器人刚度评价指标是对某一个机器人姿态进行评价，一个位姿的刚度良好并不能代表整个区域的刚度符合要求，因而需要提出一个评价区域的整体刚度的指标，使区域整体符合加工需求。使用加工区域内所有轨迹点刚度指标的统计特征整体刚度指标<em>H</em>来描述区域加工效果，整体刚度指标<em>H</em>体现的是全局的加工效果，而不是针对某个点，可以使姿态优化更为全面，使整个区域满足优化目标。               </p>
<div><div></div></div>
<p>其中，为机器人加工第<em>i</em>个轨迹时的刚度评价指标，<em>r</em>为平均值和标准差的权重，可以根据加工需求进行调整。轨迹分割</p>
<p>对于给定加工曲面，其相邻的刀位点对应的理想最优姿态都比较相近，因为相邻的刀位点具有接近的位置和姿态，其对应的机器人加工姿态也是相似的。对于相对简单，变化平缓的曲面，可以使用相同的优化参数，而对于曲率大、法向变化频繁的曲面，可以对其进行分割，使用不同参数进行加工，提高加工性能的同时降低计算时间。</p>
<h1>基于谱聚类的区域分割方法</h1>
<p>首先使用UG软件生成加工轨迹，如图3-12所示。机器人的加工性能与铣削力和加工姿态相关，而铣削力和姿态又由加工轨迹决定。因此，相邻轨迹点的机器人姿态和所受铣削力是接近的，其所对应最优加工参数也应该是相近的。由此，可以使用聚类算法根据加工轨迹点对应的机器人刚度性能将曲面划分为不同的子区域，每个子区域内加工点使用同一组优化参数，提高轨迹优化的效率。</p>
<p><img src="http://imgbed.leihub.cn/img/202307232341639.png" alt="轨迹点" /></p>
<p>对于待分割的轨迹点，通过机器人运动学逆解，求解刀具轨迹点对应的机器人关节角，计算机器人当前姿态下刚度椭球的各长半轴长度、、，结合轨迹点的位置的刚度性能，定义一个轨迹点对应的六维向量为，并进行归一化处理。以加工轨迹点作为顶点，构造一个有权无向图，为边的集合，使用欧氏距离衡量两个顶点之间的相似度，借助高斯核函数计算两个顶点之间的权重：          </p>
<div><div></div></div>
<p>其中，表示两个顶点之间的距离函数，用于衡量两个相邻顶点之间的几何距离和刚度性能的相似度：</p>
<div><div></div></div>
<p>其中，是一个比例参数，如果太小了，可能会分离本应该属于同一子区域的点，如果太大了，可能会将不同子区域中的点错误的聚在一起。在本文中，根据以前的研究经验[65]，选择设置为刀具轨迹点相似度的平均值： </p>
<div><div></div></div>
<p>通过公式(3-21)构建一个的相似度矩阵<em><strong>W</strong></em>，<em>n</em>为轨迹点数量：</p>
<div><div></div></div>
<p>进一步地，使用谱聚类算法对所构建的相似度矩阵进行处理，选择将轨迹分割为5个子区域，得到最终的分类结果，轨迹聚类结果如图所示。</p>
<p><img src="http://imgbed.leihub.cn/img/%E5%87%B8%E5%B9%B3%E9%9D%A2%E6%95%A3%E7%82%B9.png" alt="凸平面散点" /></p>
<p>以下为基于刚度性能的加工轨迹分割：</p>
<pre><code>#导入需要的包
import numpy as np
from sklearn.cluster import KMeans,spectral_clustering
import matplotlib.pyplot as plt
from kine import  PoeIkine
from kine import  PoeFkine
from CLSHander import clsTrans
import math
<p>#距离计算
def dis(X1, X2):
x1 = X1.copy()
x2 = X2.copy()
geoDist =  np.linalg.norm(x1[0&lt;3&gt;] - x2[0&lt;3&gt;])
stiffnessDist  = np.linalg.norm(x1[3] - x2[3])  #总刚度
return geoDist,stiffnessDist</p>
<p>#相似度矩阵计算
def affinity_matrix(X):
disSum = np.zeros([len(X),len(X)])
geoMatrix = np.zeros([len(X),len(X)])
stiffMatrix = np.zeros([len(X),len(X)])
#获取平均值
for i in range(len(X) - 1):  # 长度为len(x) 但是从0开始
for j in range(i + 1, len(X)):  # 从1开始，到len(x) 是方阵 为啥下角标取值的初始值不同？？？
geoDist, stiffnessDist = dis(X[i], X[j])
geoMatrix[i,j] = geoMatrix[j,i] = geoDist
stiffMatrix[i,j] = stiffMatrix[j,i] = stiffnessDist
geoMatrix = geoMatrix / np.mean(geoMatrix)
angMatrix = stiffMatrix / np.mean(stiffMatrix)
disSum = geoMatrix + stiffMatrix
sigma = 0.7
#相似度矩阵
A = np.exp(-disSum  / (2 * sigma ** 2))
return A</p>
<p>#计算拉普拉斯矩阵
def unnormalized_laplacian(adj_matrix):
# 先求度矩阵
R = np.sum(adj_matrix, axis=1)
degreeMatrix = np.diag(R)
return degreeMatrix - adj_matrix</p>
</code><section><code><h1>对称归一化的laplacian矩阵<a href="#对称归一化的laplacian矩阵"><span>#</span></a></h1><p>def normalized_laplacian(adj_matrix):
R = np.sum(adj_matrix, axis=1)
R_sqrt = 1/np.sqrt(R)
D_sqrt = np.diag(R_sqrt)
I = np.eye(adj_matrix.shape[0])
return I - np.matmul(np.matmul(D_sqrt, adj_matrix), D_sqrt)</p><p>def get_eigen(L, num_clusters):#获取特征
eigenvalues, eigenvectors = np.linalg.eigh(L)#获取特征值  特征向量
best_eigenvalues = np.argsort(eigenvalues)[0]#argsort函数返回的是数组值从小到大的索引值
U = np.zeros((L.shape[0], num_clusters))
U = eigenvectors[:, best_eigenvalues]#将这些特征取出 构成新矩阵
return U</p><p>#K-Means聚类
def cluster(data, num_clusters):
data = np.array(data)
W = affinity_matrix(data)
L = normalized_laplacian(W)
eigenvectors = get_eigen(L, num_clusters)
clf = KMeans(n_clusters=num_clusters)
s = clf.fit(eigenvectors)  # 聚类
label = s.labels_
return label</p><p>def plotRes(data, clusterResult, clusterNum):
"""
结果可似化
: data:  样本集
: clusterResult: 聚类结果
: clusterNum: 聚类个数
:return:
"""
fig1 = plt.figure()
ax1 = fig1.add_subplot(projection=‘3d’)
ax1.axis(“off”)</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>fig2 = plt.figure()</span></div></div><div><div><div>2</div></div><div><span>ax2 = fig2.add_subplot(projection='3d')</span></div></div><div><div><div>3</div></div><div><span>ax2.plot(data[:,0], data[:,1], data[:,2], c="red", marker='.')</span></div></div><div><div><div>4</div></div><div><span>ax2.axis("off")</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span>n = len(data)</span></div></div><div><div><div>7</div></div><div><span>scatterColors = ['black', 'blue', 'red', 'yellow', 'green', 'purple', 'orange']</span></div></div><div><div><div>8</div></div><div><span>for i in range(clusterNum):</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>color = scatterColors[i % len(scatterColors)]</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>x1 = []</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>y1 = []</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>z1 = []</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>for j in range(n):</span></div></div><div><div><div>14</div></div><div><span><span>        </span></span><span>if clusterResult[j] == i:</span></div></div><div><div><div>15</div></div><div><span><span>            </span></span><span>x1.append(data[j, 0])</span></div></div><div><div><div>16</div></div><div><span><span>            </span></span><span>y1.append(data[j, 1])</span></div></div><div><div><div>17</div></div><div><span><span>            </span></span><span>z1.append(data[j, 2])</span></div></div><div><div><div>18</div></div><div><span><span>    </span></span><span>ax1.plot(x1, y1, z1, c=color, marker='.')</span></div></div><div><div><div>19</div></div><div><span><span>    </span></span><span>plt.subplots_adjust(top=1, bottom=0, left=0, right=1, hspace=0, wspace=0)</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>def normalization(pos): #数据归一化
data = np.copy(pos)
length = len(data[0])
for i in range(length):
#最值归一化
data[:, i] = (data[:, i] - np.min(data[:, i])) / ( np.max(data[:, i]) - np.min(data[:, i])  ) #
return data</p><p>#聚类主程序
def clusterMain(data,cluster_num):
pos = data.copy()
for i in range(len(pos)):#加上工件坐标系
pos[i] = pos[i]
vectorList = []#求解位置和变形向量
initial = np.array([3.50 / 180 * math.pi, -70.43 / 180 * math.pi, 125.62 / 180 * math.pi,
6.41 / 180 * math.pi, -55.40 / 180 * math.pi, -2.67 / 180 * math.pi])
for i in range(len(pos)):
position = np.array(pos[i][0&lt;3&gt;])
Tmatrix = PoeIkine.RpToMatrix(pos[i])  # 加工任务转换为矩阵
[theta,success] = PoeIkine.ikine(Tmatrix,initial)#逆运动学
translation_vector,_ = PoeFkine.StiffnessMatrix(theta)  #总刚度
vector = np.append(position,translation_vector)
vectorList.append(vector)
initial = theta
data = np.array(vectorList)
data = normalization(data)</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>label = cluster(data, cluster_num)#进行聚类</span></div></div><div><div><div>2</div></div><div><span>plotRes(np.array(vectorList), label, cluster_num)#绘图</span></div></div><div><div><div>3</div></div><div><span>return label</span></div></div></code></pre><div><div></div><div></div></div></figure></div></code><p><code>def main():
xpath = ’../data/clsdata/曲面轨迹精密.cls’ #cls文件路径
workpieceFrame = np.array([1545.32,-49.85,730.99,0,0,0])#工件坐标系
pos = clsTrans.cls_Main(xpath, workpieceFrame)#读取姿态列表
label = clusterMain(pos,4)
plt.show()
</code></p></section></pre><p></p><p> </p>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/538/</id>
      <title type="text">搭建网盘聚合应用Alist</title>
      <published>2023-07-11T09:20:43.000Z</published>
      <updated>2024-06-22T04:40:43.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/538/"/>
      <summary type="text">Alist Alist是一个简单而实用的应用程序，旨在帮助用户集中管理和浏览多个网络存储服务。通过使用Alist，你可以方便地整合各种网盘服务，如Google Drive、Dropbox、OneDrive等，并在一个统一的界面中进行文件管理</summary>
      <content type="html"><![CDATA[<section><h1>Alist<a href="#alist"><span>#</span></a></h1><p>Alist是一个简单而实用的应用程序，旨在帮助用户集中管理和浏览多个网络存储服务。通过使用Alist，你可以方便地整合各种网盘服务，如Google Drive、Dropbox、OneDrive等，并在一个统一的界面中进行文件管理和浏览。</p><p>Alist可以通过Docker进行安装，提供了一个直观易用的界面，使文件的整理和查找变得简单快捷。无论是上传、下载、重命名文件，还是创建文件夹、共享链接，你都可以在Alist中完成。</p><p>我在Alist中挂载了三个云盘，分别是百度云、阿里云和自己搭建的Nextcloud。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111711463.png" alt="image-20230711170919237" /><figcaption>image-20230711170919237</figcaption></figure><p></p></section>
<section><h1>安装<a href="#安装"><span>#</span></a></h1><p>使用docker-compose进行安装，创建一个文件夹用于存放alist容器映射的配置文件，在文件夹中创建docker-compose.yml，添加以下内容：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>version: </span><span>"2"</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>services:</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>app:</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>image: xhofe/alist-aria2:latest</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>container_name: alist</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>volumes:</span></div></div><div><div><div>8</div></div><div><span><span>      </span></span><span>- ./app:/opt/alist/data</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>ports:</span></div></div><div><div><div>10</div></div><div><span><span>      </span></span><span>- 5244:5244 # 按需修改</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>restart: unless-stopped</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>networks:</span></div></div><div><div><div>13</div></div><div><span><span>      </span></span><span>- default</span></div></div><div><div><div>14</div></div><div>
</div></div><div><div><div>15</div></div><div><span>networks:</span></div></div><div><div><div>16</div></div><div><span><span>  </span></span><span>default:</span></div></div><div><div><div>17</div></div><div><span><span>    </span></span><span>name: alist</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>在docker-compose.yml所在文件夹运行命令，创建容器</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>docker-compose</span><span> </span><span>up</span><span> </span><span>-d</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>在docker安装alist后，可以通过进入容器查看用户信息，也可以在宝塔中查看容器日志，日志中可以看到默认的用户名和密码</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>docker</span><span> </span><span>exec</span><span> </span><span>-it</span><span> </span><span>alist</span><span> </span><span>./alist</span><span> </span><span>admin</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111711053.png" alt="image-20230711105910477" /><figcaption>image-20230711105910477</figcaption></figure><p></p><p>使用默认的账号密码登录进界面后，可以自行进行修改</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111711294.png" alt="image-20230711110034456" /><figcaption>image-20230711110034456</figcaption></figure><p></p></section>
<section><h1>NPM反向代理设置<a href="#npm反向代理设置"><span>#</span></a></h1><p>通过ddns-go或者域名托管后台解析一个域名<code>example.com</code>。</p><p>NPM反代<code>http://172.17.0.1:5244</code>。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111711131.png" alt="image-20230711114704391" /><figcaption>image-20230711114704391</figcaption></figure><p></p></section>
<section><h1>配置<a href="#配置"><span>#</span></a></h1><p>登录反代的域名<code>example.com</code>进入Alist页面。</p><p>上面日志输出的<code>admin</code>和<code>XXXXXX</code>就是登陆Alist的初始密码。你可以从下面的<code>管理</code>进入后台，在后台中进行硬盘挂载。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111711497.png" alt="image-20230711114944011" /><figcaption>image-20230711114944011</figcaption></figure><p></p></section>
<section><h1>云盘挂载<a href="#云盘挂载"><span>#</span></a></h1><p>在左边存储菜单栏中可以添加云盘，支持阿里云、百度云、谷歌云和WebDav等方式挂载云盘</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111711180.png" alt="image-20230711110140165" /><figcaption>image-20230711110140165</figcaption></figure><p></p><p>云盘的挂载可以按官方教程来：<a href="https://alist.nn.ci/zh/guide/" target="_blank">Introduction | AList文档 (nn.ci)</a>，我这里提供简单的设置步骤。</p><section><h2>Nextcloud<a href="#nextcloud"><span>#</span></a></h2><p>Nextcloud需要通过WebDav的方式进行挂载。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111711311.png" alt="image-20230711110634145" /><figcaption>image-20230711110634145</figcaption></figure><p></p><p>在地址中填入Nextcloud的WebDav服务地址，用户名和密码就填Nextcloud的登录账号和密码</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111711763.png" alt="image-20230711110816518" /><figcaption>image-20230711110816518</figcaption></figure><p></p><p>进入nextcloud界面，点击文件设置，就可以看到WebDav地址</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111711308.png" alt="image-20230711110446114" /><figcaption>image-20230711110446114</figcaption></figure><p></p></section><section><h2>阿里云盘<a href="#阿里云盘"><span>#</span></a></h2><p>阿里云盘挂载驱动选择的是阿里云盘Open，主要是这个**刷新令牌(refresh token)**获取</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111712748.png" alt="image-20230711111711002" /><figcaption>image-20230711111711002</figcaption></figure><p></p><p>阿里云盘刷新令牌获取前往：<a href="https://alist.nn.ci/tool/aliyundrive/request" target="_blank">刷新令牌获取</a></p><p>进入上述网站，点击<strong>Scan QrCode(扫描二维码)</strong>，使用阿里云盘app扫描二维码进行授权，然后点击 <strong>I have scan</strong>(我已经扫描)</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111712823.png" alt="image-20230711112230521" /><figcaption>image-20230711112230521</figcaption></figure><p></p><p>弹出新页面，页面中<strong>refresh_token</strong>就是我们所需的刷新令牌</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111712581.png" alt="image-20230711112310692" /><figcaption>image-20230711112310692</figcaption></figure><p></p></section><section><h2>百度网盘<a href="#百度网盘"><span>#</span></a></h2><p>百度网盘和阿里云类似，也是通过接口进行授权，获取相应的刷新令牌进行登录。</p><p>由于百度网盘 API 的限制，下载大于 20M 左右的文件需要携带 <code>header："User-Agent":"[pan.baidu.comopen in new window](http://pan.baidu.com/)"</code>，所以下载大于 20M 的文件时，需要设置请求头。</p><p><a href="https://openapi.baidu.com/oauth/2.0/authorize?response_type=code&amp;client_id=iYCeC9g08h5vuP9UqvPHKKSVrKFXGa1v&amp;redirect_uri=https://alist.nn.ci/tool/baidu/callback&amp;scope=basic,netdisk&amp;qrcode=1" target="_blank">点击这里</a> 来获取刷新令牌。</p><p>将client_id，client_server分别填入客户端ID和客户端密钥中（一般都会自动填），将获取到的<strong>refresh_token</strong>填入刷新令牌即可。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111712147.png" alt="image-20230711112919923" /><figcaption>image-20230711112919923</figcaption></figure><p></p></section></section>
<section><h1>访客目录<a href="#访客目录"><span>#</span></a></h1><p>Alist有一个GUEST用户，可以为访客指定一个分享文件的文件夹。可以在<code>编辑</code>里改属性，包括目录和权限。修改基本路径很重要，否则<strong>访客可以直接查看你所有挂载的云盘（因为默认路径是<code>/</code>）</strong>！</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307111712618.png" alt="image-20230711165611285" /><figcaption>image-20230711165611285</figcaption></figure><p></p><hr /></section>
<section><h1>基于WebDav访问Alist<a href="#基于webdav访问alist"><span>#</span></a></h1><p>你可以在win10里基于WebDav挂载Alist作为硬盘。Alist的WebDav信息很简单，格式如下：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>URL: https://example.com/dav/</span></div></div><div><div><div>2</div></div><div><span>Username: admin</span></div></div><div><div><div>3</div></div><div><span>Password: XXXXXX</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section>
<section><h1>小结<a href="#小结"><span>#</span></a></h1><p>Alist是一个简单易用的应用程序，可以通过Docker进行安装。它的主要优点在于能够集成和管理各种网络存储服务，使其一应俱全。使用Alist，你可以方便地将各种杂乱的网盘服务整合在一起进行管理，简化了文件管理的繁琐过程。</p><p>然而，使用Alist也存在一些不足之处。其中之一是它引入了一个中转层，可能会增加网络连接的延迟。特别是当你将Alist部署在海外的VPS上时，延迟问题可能会更加明显。这可能会对文件访问速度产生一定的影响。</p><p>尽管存在这些缺点，根据我个人的使用经验，我认为Alist的性能还是相当不错的。特别是对于处理较小文件的情况，使用Alist来管理文件仍然非常方便。它提供了简洁直观的界面，使文件的整理和查找变得轻而易举。</p></section>
<section><h1>参考资料<a href="#参考资料"><span>#</span></a></h1><ol>
<li><a href="https://alist.nn.ci/zh/" target="_blank">Home | AList文档 (nn.ci)</a></li>
<li><a href="https://blognas.hwb0307.com/linux/docker/2906" target="_blank">Docker系列 搭建支持WebDav的网盘聚合平台Alist - Bensz (hwb0307.com)</a></li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/535/</id>
      <title type="text">DDNS+IPV6实现外网访问</title>
      <published>2023-07-10T16:42:50.000Z</published>
      <updated>2024-06-06T04:27:37.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/535/"/>
      <summary type="text">DDNS+IPV6实现外网访问 上网配置 之前一直是通过搭建在腾讯云上的FPR实现内网穿透，访问家里的设备，但这样也不是持久的办法。毕竟云服务器一年的费用让我非常肉痛，4核4g的云服务器我一次性购买了4年，花了四百多，然后一看续费，一年14</summary>
      <content type="html"><![CDATA[<section><h1>DDNS+IPV6实现外网访问<a href="#ddnsipv6实现外网访问"><span>#</span></a></h1><section><h2>上网配置<a href="#上网配置"><span>#</span></a></h2><p>之前一直是通过搭建在腾讯云上的FPR实现内网穿透，访问家里的设备，但这样也不是持久的办法。毕竟云服务器一年的费用让我非常肉痛，4核4g的云服务器我一次性购买了4年，花了四百多，然后一看续费，一年1400…，这坚定了我为NAS整一个IP地址的想法。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307110040839.png" alt="image-20230709234913108" /><figcaption>image-20230709234913108</figcaption></figure><p></p><p>我按照网上的教程和联通运营商battle了几次，客服一直一副糊弄的态度，说什么也不给IP地址。</p><p>刚开始一直以为家里没有ipv6地址，在cmd命令行里用<code>ipconfig</code>指令也获取不到IPV6地址。在一次偶然情况，越过路由器把网线插电脑上，直接用电脑进行拨号，发现获取到了IPV6地址，原来是路由器太老了，不支持IPV6协议。赶紧买了个支持IPV6协议的路由器，买的型号是京东的无线宝，一边当路由器，一边用闲置带宽挂积分，一天也能有个接近一块钱的收益。</p><img src="http://imgbed.leihub.cn/img/202307110040163.jpg" alt="79BC79CCB968B32597C2768698BC06C5" /><p>将支持IPV6的路由器连接在光猫上，光猫改桥接，由路由器进行拨号，打开路由器IPV6开关，上网方式选择自动获取IP地址，关闭IPV6的防火墙。保存配置之后，路由器下的设备就都获取到了IPV6地址了。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307110040775.png" alt="image-20230709235706639" /><figcaption>image-20230709235706639</figcaption></figure><p></p><p>获取到IPV6地址后可能还不能非常愉快的进行内网访问，因为运营商都会把敏感的端口例如443，80等端口封禁掉，这样在访问时要加上相应的端口号，使外网访问的地址看起来不是很正式，但也没有很好的办法了。</p><p>在支持IPV6的外网环境下，使用python代码扫描内网端口，发现 **[53, 80, 135, 139, 443, 445, 593, 1062, 1569, 3175, 3669, 4444, 5293, 5554, 5791, 7375, 7850, 8080, 9515, 9955, 9995]**等端口都被运营商封禁了，要把内网服务暴露到外网，只能使用这些之外的端口了。</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>import</span><span> socket</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>def</span><span> </span><span>scan_port</span><span>(</span><span>target_host</span><span>,</span><span><span> </span><span>target_ports</span></span><span>):</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>filtered_ports </span><span>=</span><span> []</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span>    </span><span>try</span><span>:</span></div></div><div><div><div>7</div></div><div><span>        </span><span># 解析域名获取 IPv6 地址</span></div></div><div><div><div>8</div></div><div><span><span>        </span></span><span>target_ip </span><span>=</span><span> socket.</span><span>getaddrinfo</span><span>(target_host, </span><span>None</span><span><span>, socket.</span><span>AF_INET6</span><span>)[</span></span><span>0</span><span>][</span><span>4</span><span>][</span><span>0</span><span>]</span></div></div><div><div><div>9</div></div><div><span>        </span><span>print</span><span>(</span><span>f</span><span>"正在扫描 </span><span>{</span><span>target_host</span><span>}</span><span>(</span><span>{</span><span>target_ip</span><span>}</span><span>) 的端口...</span><span>\n</span><span>"</span><span>)</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>        </span><span>for</span><span> port </span><span>in</span><span> target_ports:</span></div></div><div><div><div>12</div></div><div><span>            </span><span>try</span><span>:</span></div></div><div><div><div>13</div></div><div><span><span>                </span></span><span>sock </span><span>=</span><span> socket.</span><span>socket</span><span>(socket.</span><span>AF_INET6</span><span>, socket.</span><span>SOCK_STREAM</span><span>)</span></div></div><div><div><div>14</div></div><div><span><span>                </span></span><span>sock.</span><span>settimeout</span><span>(</span><span>1</span><span>)</span></div></div><div><div><div>15</div></div><div><span><span>                </span></span><span>result </span><span>=</span><span> sock.</span><span>connect_ex</span><span>((target_ip, port))</span></div></div><div><div><div>16</div></div><div>
</div></div><div><div><div>17</div></div><div><span>                </span><span>if</span><span><span> result </span><span>==</span><span> </span></span><span>11</span><span>:</span></div></div><div><div><div>18</div></div><div><span>                    </span><span>print</span><span>(</span><span>f</span><span>"端口 </span><span>{</span><span>port</span><span>}</span><span> 过滤"</span><span>)</span></div></div><div><div><div>19</div></div><div><span><span>                    </span></span><span>filtered_ports.</span><span>append</span><span>(port)</span></div></div><div><div><div>20</div></div><div>
</div></div><div><div><div>21</div></div><div><span><span>                </span></span><span>sock.</span><span>close</span><span>()</span></div></div><div><div><div>22</div></div><div>
</div></div><div><div><div>23</div></div><div><span>            </span><span>except</span><span> socket.error:</span></div></div><div><div><div>24</div></div><div><span>                </span><span>print</span><span>(</span><span>f</span><span>"无法连接到主机 </span><span>{</span><span>target_host</span><span>}</span><span>"</span><span>)</span></div></div><div><div><div>25</div></div><div><span>                </span><span>break</span></div></div><div><div><div>26</div></div><div>
</div></div><div><div><div>27</div></div><div><span>    </span><span>except</span><span> socket.gaierror:</span></div></div><div><div><div>28</div></div><div><span>        </span><span>print</span><span>(</span><span>f</span><span>"无法解析域名 </span><span>{</span><span>target_host</span><span>}</span><span>"</span><span>)</span></div></div><div><div><div>29</div></div><div>
</div></div><div><div><div>30</div></div><div><span>    </span><span>return</span><span> filtered_ports</span></div></div><div><div><div>31</div></div><div>
</div></div><div><div><div>32</div></div><div><span><span>target_host </span><span>=</span><span> </span></span><span>"example.com"</span></div></div><div><div><div>33</div></div><div><span><span>target_ports </span><span>=</span><span> </span></span><span>range</span><span>(</span><span>1</span><span>, </span><span>10001</span><span>)</span></div></div><div><div><div>34</div></div><div>
</div></div><div><div><div>35</div></div><div><span><span>filtered_ports </span><span>=</span><span> </span><span>scan_port</span><span>(target_host, target_ports)</span></span></div></div><div><div><div>36</div></div><div>
</div></div><div><div><div>37</div></div><div><span># 输出被过滤的端口</span></div></div><div><div><div>38</div></div><div><span>print</span><span>(</span><span>"被过滤的端口："</span><span>, filtered_ports)</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h2>DDNS<a href="#ddns"><span>#</span></a></h2><p>我们通过拨号从运营商那获取的IPV6地址并不是一成不变的，每当光猫重启或者隔一段时间，IPV6地址就会改变。因此通过固定的ip地址访问是不可行的，这就要用到<strong>动态域名解析DDNS</strong>，绑定域名实现内网设备访问了。</p><p>DDNS GO是一款动态域名解析神器，提供友好的WEB界面进行操作。</p><section><h3>docker安装DDNS-GO<a href="#docker安装ddns-go"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>mkdir -p ${path_docker}/ddns-go</span></div></div><div><div><div>2</div></div><div><span>docker run -d \</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>--restart=unless-stopped \</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>--name ddns-go-aliyun \</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>-e PUID=1000 \</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>-e PGID=100 \</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>-p &lt;yourIP&gt;:9876 \</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>-v ${path_docker}/ddns-go:/root \</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>jeessy/ddns-go \</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>-f 60</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>通过<code>ip:9876</code>访问DDNS GO页面</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307110040184.png" alt="image-20230710191653685" /><figcaption>image-20230710191653685</figcaption></figure><p></p></section><section><h3>DDNS GO配置<a href="#ddns-go配置"><span>#</span></a></h3><p>DDNS GO通过实时监测宿主机的ip地址和绑定域名解析的ip地址是否一致，一旦宿主机的ip地址发生改变，就通过DNS服务商提供的API对绑定域名的解析地址进行更新，保证解析到宿主机ip地址。</p><p>DDNS GO支持各家dns服务商，如阿里云、腾讯云以及cloudflare等。我使用的是腾讯云的DnsPod进行域名解析，首先需要进入<a href="https://console.dnspod.cn/account/token/token" target="_blank">DNSPod的控制台</a>，创建一个API密钥，<strong>通过这个密钥可以自动添加DNS解析</strong>。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307110040335.png" alt="image-20230710234843720" /><figcaption>image-20230710234843720</figcaption></figure><p></p><p>将获取的ID和token填入DDNS GO中，因为本地没有IPV4地址，所以选择不启用IPV4。在Domains中填入需要进行解析的域名，可以一次性填入多个域名，当打开公网访问时，需要设置用户名和密码，完成设置后，点击保存就会自动进行域名解析。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307110040077.png" alt="image-20230710235523200" /><figcaption>image-20230710235523200</figcaption></figure><p></p><p>从日志中可以看出，每隔一段时间，DDNS GO就会检查本机地址和解析地址是否一致，保证解析地址的正确性。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307110040317.png" alt="image-20230710235826694" /><figcaption>image-20230710235826694</figcaption></figure><p></p></section></section><section><h2>NgnixProxyManager<a href="#ngnixproxymanager"><span>#</span></a></h2><p>Nginx proxy manager（NPM）是集Nginx设置和ssl证书申请的docker神器。</p><p>官方网站：<a href="https://nginxproxymanager.com/" target="_blank">https://nginxproxymanager.com/</a></p><p>通过DNS或者DDNS，我们打通了了<strong>域名到公网IP连接</strong>，<strong>Ngnix</strong>的作用是什么呢，通过建立一个反向代理服务器，他的作用是监听本地的<strong>ip地址的端口（如443和80端口）</strong>，按设置拦截客户端的请求，并转发的宿主机相应的端口上，它可以决定将哪个域名的流量转发到哪一个服务器的端口，打通了<strong>公网IP到端口</strong>这个连接。</p><p>而<strong>NgnixProxyManager</strong>提供了一个Ngnix的可视化面板，可以有效地对反向代理服务器进行管理，并且还具有申请SSL证书的功能。</p><p>当然，通过宝塔面板也可以对Ngnix进行可视化操作，但是是将Nginx直接安装在宿主机上，对于非专业的用户，一旦安装的web应用过多，非常容易发生冲突，导致web无法被访问，而<strong>NgnixProxyManager</strong>将Nginx安装在docker容器中，利用了容器的隔离避免了误操作带来的软件版本冲突。</p><p>docker安装和直接部署两者各有各的好处，对于新手来说，安装在docker中更加省心，也易于迁移。</p><section><h3>docker-compose安装<a href="#docker-compose安装"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>version: </span><span>'3'</span></div></div><div><div><div>2</div></div><div><span>services:</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>app:</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>image: </span><span>'jc21/nginx-proxy-manager:2.9.18'</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>restart: unless-stopped</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>ports:</span></div></div><div><div><div>7</div></div><div><span><span>      </span></span><span>- </span><span>'7080:80'</span><span>#80被封禁所以修改</span></div></div><div><div><div>8</div></div><div><span><span>      </span></span><span>- </span><span>'7081:81'</span></div></div><div><div><div>9</div></div><div><span><span>      </span></span><span>- </span><span>'7443:443'</span><span>#443被封禁所以修改</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>volumes:</span></div></div><div><div><div>11</div></div><div><span><span>      </span></span><span>- ./data:/data</span></div></div><div><div><div>12</div></div><div><span><span>      </span></span><span>- ./letsencrypt:/etc/letsencrypt</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>因为80、443端口被运营商封禁，所以这里进行了映射，如果是在VPS中，可不用进行修改。这个81端口是NPM的默认后台端口，这个你可以改一个自己喜欢的。我建议不要用默认的81端口，这样可以使NPM更加隐蔽。</p></section><section><h3>服务管理<a href="#服务管理"><span>#</span></a></h3><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 上线服务</span></div></div><div><div><div>2</div></div><div><span>docker-compose</span><span> </span><span>up</span><span> </span><span>-d</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 下线服务</span></div></div><div><div><div>5</div></div><div><span>docker-compose</span><span> </span><span>down</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span># 更新服务（我还没用过。更新的话建议先对旧服务进行备份，以防新旧版本有兼容问题。）</span></div></div><div><div><div>8</div></div><div><span>docker-compose</span><span> </span><span>pull</span></div></div><div><div><div>9</div></div><div><span>docker-compose</span><span> </span><span>up</span><span> </span><span>-d</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>不要忘了用在防火墙里开放你选择的<code>NPM-后台端口</code>端口，开放端口后通过访问：<code>http://&lt;ip&gt;:&lt;NPM-后台端口&gt;</code>进行NPM管理。</p><p>NPM的默认账号如下，在登录后可以自行进行修改。</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>默认帐户：admin@example.com</span></div></div><div><div><div>2</div></div><div><span>默认密码：changeme</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>在访问后web服务后，在登陆时可能存在Bad Gateway的问题。</p><figure><img src="http://imgbed.leihub.cn/img/202307110040822.png" alt="image-20230710002554860" /><figcaption>image-20230710002554860</figcaption></figure><p></p><p>在查看docker日志后发现，运行卡在<code>Fetching https://www.cloudflare.com/ips-v4</code>这一步</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307110040500.png" alt="image-20230710003441145" /><figcaption>image-20230710003441145</figcaption></figure><p></p><p>上网一查<strong>cloudflare</strong>的ipv4和ipv6网段被宝塔面板屏蔽，访问ipv4和ipv6地址获取宝塔的网段，在宝塔中添加进白名单进行放行即可。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307110040272.png" alt="image-20230710003738967" /><figcaption>image-20230710003738967</figcaption></figure><p></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>Cloudflare 官方公布IP段：</span></div></div><div><div><div>2</div></div><div><span>https://www.cloudflare.com/ips-v4</span></div></div><div><div><div>3</div></div><div><span>https://www.cloudflare.com/ips-v6</span></div></div><div><div><div>4</div></div><div><span>IPv4</span></div></div><div><div><div>5</div></div><div><span>173.245.48.0/20</span></div></div><div><div><div>6</div></div><div><span>103.21.244.0/22</span></div></div><div><div><div>7</div></div><div><span>103.22.200.0/22</span></div></div><div><div><div>8</div></div><div><span>103.31.4.0/22</span></div></div><div><div><div>9</div></div><div><span>141.101.64.0/18</span></div></div><div><div><div>10</div></div><div><span>108.162.192.0/18</span></div></div><div><div><div>11</div></div><div><span>190.93.240.0/20</span></div></div><div><div><div>12</div></div><div><span>188.114.96.0/20</span></div></div><div><div><div>13</div></div><div><span>197.234.240.0/22</span></div></div><div><div><div>14</div></div><div><span>198.41.128.0/17</span></div></div><div><div><div>15</div></div><div><span>162.158.0.0/15</span></div></div><div><div><div>16</div></div><div><span>104.16.0.0/13</span></div></div><div><div><div>17</div></div><div><span>104.24.0.0/14</span></div></div><div><div><div>18</div></div><div><span>172.64.0.0/13</span></div></div><div><div><div>19</div></div><div><span>131.0.72.0/22</span></div></div><div><div><div>20</div></div><div>
</div></div><div><div><div>21</div></div><div><span>IPv6</span></div></div><div><div><div>22</div></div><div><span>2400:cb00::/32</span></div></div><div><div><div>23</div></div><div><span>2606:4700::/32</span></div></div><div><div><div>24</div></div><div><span>2803:f800::/32</span></div></div><div><div><div>25</div></div><div><span>2405:b500::/32</span></div></div><div><div><div>26</div></div><div><span>2405:8100::/32</span></div></div><div><div><div>27</div></div><div><span>2a06:98c0::/29</span></div></div><div><div><div>28</div></div><div><span>2c0f:f248::/32</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>放行后就可以顺利登录NPM面板，对于需要代理的域名为example.com，设置其转发到172.17.0.1的4025端口，如果Nginx监听的是80和443端口，这样example.com&lt;80&gt;/443的所有流量就会转发到172.17.0.1&lt;4025&gt;，在访问的时候就会自动隐去端口号，显得域名更加正式。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307110040583.png" alt="image-20230711002026859" /><figcaption>image-20230711002026859</figcaption></figure><p></p><p>在SSL菜单中，可以为域名添加SSL证书实现HTTPS访问，由于家庭宽带的80和443端口是被封锁的，所以用http challenge申请ssl证书的方式很容易失败。在Nginx proxmy manager中，<strong>对于NAS用户推荐使用DNS challge的方式来申请Let’s Encrypt证书</strong>。我选择的是DNSPod进行域名解析，id和key申请在上面DDNS GO中也进行说明，直接填入就行。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307110041859.png" alt="image-20230711002519537" /><figcaption>image-20230711002519537</figcaption></figure><p></p><p>我一般喜欢统一申请好二级域名证书（只为<code>leiting2020.top</code>申请1个证书），然后在建立新的反向代理记录后添加申请好的二级域名证书，要同时为两个域名申请<code>*.leiting2020.top</code>、<code>leiting2020.top</code>（<code>*</code>是一种常用的正则表达式，用来代表所有字符），这样才可以正常使用。</p><p>多数docker应用可以通过这样简单地设置即可以实现成功代理。</p><p>通过上述配置，这样就可以为IPV6地址的NAS解锁外网访问，需要注意的是，如果NAS只有IPV6地址，建立的网站就是纯IPV6网站，在纯IPV4网络环境中是无法进行访问的，通过<a href="https://www.test-ipv6.com/index.html.zh_CN" target="_blank">IPv6 测试 (test-ipv6.com)</a>测试当前网络环境是否支持IPV6。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307110041351.png" alt="image-20230711003544076" /><figcaption>image-20230711003544076</figcaption></figure><p></p><p>有一种方法也可以实现纯ipv4环境访问ipv6网页，那就是将域名挂载在cdn中，开启回源鉴权，这样可以实现ipv4访问，国内的dns厂商都不提供免费的ipv6 cdn，而且还将ipv4和ipv6分开进行计费。这样还不如白嫖cloudflare的免费cdn，将域名挂在cloudflare上，点亮小云朵就可以白嫖cloudflare的免费cdn。</p><p>不过cf的免费cdn主机都不在国内，使用起来可能还是降速，而且对于家用NAS来说，443和80端口被封锁，配置cdn变得比较麻烦，我最终还是放弃了。</p></section></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/531/</id>
      <title type="text">改善深度神经网络：超参数调试（一） 深度学习实践层面</title>
      <published>2023-07-09T11:14:27.000Z</published>
      <updated>2024-06-06T04:27:43.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/531/"/>
      <summary type="text">深度学习实践层面 1.1 训练集、验证集、测试集 深度学习是一个典型的迭代过程，需要进行多次循环往复，得到自己称心如意的神经网络。因此，循环过程的效率是决定项目推进速度的关键因素，而创建高质量的训练、验证和测试集有助于提高循环过程的效率。 </summary>
      <content type="html"><![CDATA[<section><h1>深度学习实践层面<a href="#深度学习实践层面"><span>#</span></a></h1><section><h2>1.1 训练集、验证集、测试集<a href="#11-训练集验证集测试集"><span>#</span></a></h2><p>深度学习是一个典型的迭代过程，需要进行多次循环往复，得到自己称心如意的神经网络。因此，循环过程的效率是决定项目推进速度的关键因素，而创建高质量的训练、验证和测试集有助于提高循环过程的效率。</p><p>通常，将训练数据分为三部分，一部分作为训练集，一部分作为简单交叉验证集，最后一部分作为测试集。接下来对模型进行训练，通过验证集选择最好的模型，经过充分验证，得到了最终模型，然后就可以在测试集上进行了评估，为了无偏估计算法的运行状况。</p><p>1、在小数据集时代，即数据在100，1000，10000这个量级，常见的做法是“三七分”，即70%的数据作为验证集，30%测试集。如果没有明确设置验证集，也可以按照60%训练集，20%验证集，20%测试集来进行划分，这是前几年机器学习领域公认的最好的数据划分方法。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091911535.png" alt="image-20230709172256728" /><figcaption>image-20230709172256728</figcaption></figure><p></p><p>2、在大数据时代，我们获取的数据在百万级别，验证集和测试集占的比例就会相应的减少。验证集的作用是检验不同的算法，验证哪个算法最有效，因此需要足够大才能对算法进行评估，而在大数据时代，数据集的1%就可能有上万组数据，足以验证不同的算法，因此，我们不可能拿出20%的数据来作为验证集。</p><p>因此，在数据足够多的情况，例如有100w组数据，其中1w组，即作为验证集，1w组作为测试集，98w组作为训练集，测试集和验证集各占1%，训练集占98%。在数据更大的情况中，训练集可以达到99.5%，验证和测试集各占0.25%，或者验证0.4%，测试集0.1%。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091911415.png" alt="image-20230709173016052" /><figcaption>image-20230709173016052</figcaption></figure><p></p><p>现代深度学习的另一个趋势是训练和测试集不匹配的情况下进行训练，训练的数据可能是在网上爬取的，而进行验证和测试的数据是网友上传的，这两种数据有所不同，来自于不同的分布。根据经验，为了更好的提高训练性能，要保证验证集和测试集来自于同一个分布。</p></section><section><h2>1.2 方差、偏差（Variance,Bias）<a href="#12-方差偏差variancebias"><span>#</span></a></h2><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091911899.png" alt="image-20230709173844698" /><figcaption>image-20230709173844698</figcaption></figure><p></p><p>假设这就是数据集，假设将这个数据集拟合为一条直线，这就是逻辑回归拟合，但它并不能很好的你和数据，存在<strong>高偏差（high bias）<strong>的现象，我们称之为</strong>欠拟合（underfitting）</strong>。</p><p>相反，我们设置一个非常复杂的分类器，比如深度神经网络，可能非常适合这个数据集，但是可能不是一个好的拟合方式，存在<strong>高方差（high variance）<strong>的现象，称之为</strong>过拟合（overfitting）</strong>。</p><p>在两者之间，可能存在一个复杂程度适中，对数据集拟合适度的分类器，我们称之为<strong>适度拟合（just right）</strong></p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091911023.png" alt="image-20230709173638109" /><figcaption>image-20230709173638109</figcaption></figure><p></p><p>两个特征的二维数据集中，我们可以绘制数据，将偏差和方差可视化。在多维空间数据中，绘制数据和可视化分割边界无法实现，但我们可以通过几个指标来研究偏差和方差。</p><p>理解偏差和方差的两个关键数据是<strong>训练集误差（Train set error）<strong>和</strong>验证集误差（Dev set error）</strong>。通过分析在训练集上训练算法产生的误差和验证集上验证算法 产生的误差来诊断算法是否存在高偏差和高方差</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091911004.png" alt="image-20230709175312935" /><figcaption>image-20230709175312935</figcaption></figure><p></p><ol>
<li>假定训练集误差是 1%，为了方便论证，假定验证集误差是 11%，可以看出训练集设置得非常好，而验证集设置相对较差，我们可能过度拟合了训练集，在某种程度上，验证集并没有充分利用交叉验证集的作用，像这种情况，我们称之为**“高方差”**。</li>
<li>假设训练集误差是 15%，验证集误差是 16%。算法并没有在训练集中得到很好训练，如果训练数据的拟合度不高，就是数据欠拟合，就可以说这种算法偏差比较高。 相反，它对于验证集产生的结果却是合理的，验证集中的错误率只比训练集的多了 1%，所 以这种算法<strong>偏差高</strong>，因为它甚至不能拟合训练集</li>
<li>训练集误差是 15%，偏差相当高，但是，验证集的评估结果更糟糕，错误率达到 30%，在这种情况下，我会认为这种算法偏差高，因为它在训练集上结果不理想， 而且方差也很高，这是<strong>方差偏差都很糟糕</strong>的情况</li>
<li>训练集误差是 0.5%，验证集误差是 1%，<strong>偏差和方差都很低</strong>。</li>
</ol></section><section><h2>1.3 机器学习基础<a href="#13-机器学习基础"><span>#</span></a></h2><p>初始模型训练完成后，试着评估训练集或训练数据的性能，如果偏差较高，甚至无法拟合训练集，那么你要做的就是选择一个新的网络，比如含有更多隐藏层或者隐藏单元的网络，或者花费更多时间来训练网络，或者尝试更先进的优化算法。</p><p>一旦偏差降低到可以接受的数值，检查一下方差有没有问题，为了评估方差，我们要查看验证集性能，我们能从一个性能理想的训练集推断出验证集的性能是否也理想，如果方差高，最好的解决办法就是<strong>采用更多数据</strong>，我们也可以尝试通过<strong>正则化</strong>来减少过拟合。</p><p>总之就是不断 重复尝试，直到找到一个低偏差，低方差的框架，这时你就成功了。</p></section><section><h2>1.4 L2正则化<a href="#14-l2正则化"><span>#</span></a></h2><p>深度学习可能存在过拟合问题——高方差，有两个解决方法，一个是正则化，另一个是准备更多的数据，这是非常可靠的方法，但你可能无法时时刻刻准备足够多的训练数据或者获取更多数据的成本很高，但正则化通常有助于避免过拟合或减少你的网络误差。</p><p>神经网络模型中通常使用<strong>L2正则化</strong>对<strong>损失函数</strong>进行修正，给损失函数加上正则项。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912694.png" alt="image-20230709180748111" /><figcaption>image-20230709180748111</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912807.png" alt="image-20230709181437852" /><figcaption>image-20230709181437852</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912180.png" alt="image-20230709181531720" /><figcaption>image-20230709181531720</figcaption></figure><p></p><p>其中<span><span>λ\lambda</span><span><span><span></span><span>λ</span></span></span></span>是正则化参数，正则项代表了利用权重计算的过程。L2正则损失部分是神经网络中每一层的权重矩阵<span><span>WW</span><span><span><span></span><span>W</span></span></span></span>的Frobenius范数的平方和。</p><p>对于正向传播而言，只需要考虑对损失函数进行正则化计算。对于反向传播还需要考虑梯度计算时多出来的正则项，必须针对新损失函数计算所有梯度。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912619.png" alt="image-20230709181258182" /><figcaption>image-20230709181258182</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912564.png" alt="image-20230709181711583" /><figcaption>image-20230709181711583</figcaption></figure><p></p><p>因此梯度下降方向变为：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912104.png" alt="image-20230709181828739" /><figcaption>image-20230709181828739</figcaption></figure><p></p><p>该正则项说明，不论<span><span>W[l]W^{[l]}</span><span><span><span></span><span><span>W</span><span><span><span><span><span><span></span><span><span><span>[</span><span>l</span><span>]</span></span></span></span></span></span></span></span></span></span></span></span>是什么，我们都试图让它变得更小，实际上，相当于我们给矩阵<span><span>WW</span><span><span><span></span><span>W</span></span></span></span>乘以<span><span>(1−aλ/m)(1-a\lambda/m)</span><span><span><span></span><span>(</span><span>1</span><span></span><span>−</span><span></span></span><span><span></span><span>aλ</span><span>/</span><span>m</span><span>)</span></span></span></span>倍的权重，矩阵<span><span>WW</span><span><span><span></span><span>W</span></span></span></span>减去<span><span>αλ/m\alpha\lambda/m</span><span><span><span></span><span>α</span><span>λ</span><span>/</span><span>m</span></span></span></span>倍的它，也就是用这个系数<span><span>(1−aλ/m)(1-a\lambda/m)</span><span><span><span></span><span>(</span><span>1</span><span></span><span>−</span><span></span></span><span><span></span><span>aλ</span><span>/</span><span>m</span><span>)</span></span></span></span>乘以矩阵<span><span>WW</span><span><span><span></span><span>W</span></span></span></span>，相对于一般的梯度下降，<span><span>WW</span><span><span><span></span><span>W</span></span></span></span>被更新为少了<span><span>aa</span><span><span><span></span><span>a</span></span></span></span>乘以 backprop 输出的最初梯度值，同时<span><span>WW</span><span><span><span></span><span>W</span></span></span></span>也乘以了这个系数，这个系数小于 1，因此$𝐿2正则化$也被称为**“权重衰减”**。</p><section><h3>为什么正则化有助于预防过拟合<a href="#为什么正则化有助于预防过拟合"><span>#</span></a></h3><p>直观上理解就是如果正则化<span><span>λ\lambda</span><span><span><span></span><span>λ</span></span></span></span>设置得足够大，权重矩阵<span><span>WW</span><span><span><span></span><span>W</span></span></span></span>被设置为接近于 0 的值，直观理解就是把多隐藏单元的权重设为 0，于是基本上消除了这些隐藏单元的许多影响。如果是 这种情况，这个被大大简化了的神经网络会变成一个很小的网络，小到如同一个逻辑回归单 元，可是深度却很大，它会使这个网络从过度拟合的状态向的高偏差状态转移。</p><p>但是<span><span>λ\lambda</span><span><span><span></span><span>λ</span></span></span></span>会存在一个中间值，于是会有一个接近“Just Right”的中间状态。</p></section></section><section><h2>1.5 Dropout正则化<a href="#15-dropout正则化"><span>#</span></a></h2><p>Dropout提供了正则化一大类模型的方法，计算方便但功能强大。简单来说Dropout可以理解为在概率意义上随机删除神经网络中的节点，以此简化神经网络模型来防止过拟合的一种正则化方法，下图说明了Dropout的处理过程。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912312.png" alt="在这里插入图片描述" /><figcaption>在这里插入图片描述</figcaption></figure><p></p><p>Dropout会在每次迭代中随机关闭一些神经元,其中涉及到正则化参数keep-prob,keep-prob是一个随机数，在正向传播时，我们给每一个神经元赋予一个概率，通过比较keep-prob与神经元的随机概率大小来给出决策。当该概率小于keep-prob时，我们关闭该神经元。做法是通过应用掩码来关闭正向传播过程中的某些神经元。对于反向传播，将用相同的掩码重新来关闭相同的神经元，进而进行导数的计算。</p><p>计算视觉中的输入量非常大，输入太多像素，以至于没有足够的数据，所以 dropout 在计算机视觉中应用得比较频繁，它在其它领域应用得比较少。</p></section><section><h2>1.6 其他正则化方法<a href="#16-其他正则化方法"><span>#</span></a></h2><p><strong>数据扩增</strong></p><p>假设我们的数据集是图片，那对图片进行旋转、裁剪等可以达到数据扩增的目的。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912298.png" alt="img" /><figcaption>img</figcaption></figure><p></p><p><strong>early stopping</strong></p><p>过拟合一定程度上是由于训练过度导致的，为了防止过拟合带了的高方差，把方差和损失函数作为训练结束的评判标准可以一定程度上减少过拟合。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912371.png" alt="image-20230709184153827" /><figcaption>image-20230709184153827</figcaption></figure><p></p></section><section><h2>1.7 归一化输入<a href="#17-归一化输入"><span>#</span></a></h2><p>训练神经网络，其中一个加速训练的方法就是归一化输入。</p><p>归一化需要两个步骤：</p><p>（1）零均值<span><span>μ\mu</span><span><span><span></span><span>μ</span></span></span></span></p><p>（2）归一化方差<span><span>σ2σ^2</span><span><span><span></span><span><span>σ</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span></span></span></span></p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912198.png" alt="image-20230709184604962" /><figcaption>image-20230709184604962</figcaption></figure><p></p><p>第一步是零均值化</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912509.png" alt="image-20230709184918199" /><figcaption>image-20230709184918199</figcaption></figure><p></p><p>它是一个向量，<span><span>xx</span><span><span><span></span><span>x</span></span></span></span>等于每个训练数据 <span><span>xx</span><span><span><span></span><span>x</span></span></span></span>减去<span><span>μ\mu</span><span><span><span></span><span>μ</span></span></span></span>，意思是移动训练集，直到它完成零均值化。</p><p>第二步是归一化方差，我们要做的是给𝜎 赋值</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912978.png" alt="image-20230709185021292" /><figcaption>image-20230709185021292</figcaption></figure><p></p><p>这是节点𝑦 的平方，<span><span>σ2\sigma^2</span><span><span><span></span><span><span>σ</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span></span></span></span>是一个向量，它的每个特征都有方差，注意，我们已经完成零值均化，<span><span>(x(i))2(x^{(i)} )^2</span><span><span><span></span><span>(</span><span><span>x</span><span><span><span><span><span><span></span><span><span><span>(</span><span>i</span><span>)</span></span></span></span></span></span></span></span></span><span><span>)</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span></span></span></span>元素<span><span>y2y^2</span><span><span><span></span><span><span>y</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span></span></span></span>就是方差，我们把所有数据除以向量<span><span>σ2\sigma^2</span><span><span><span></span><span><span>σ</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span></span></span></span>，最后变成上图形式。</p><p>实际上如果假设特征𝑥1范围在 0-1 之间，𝑥2的范围在-1 到 1 之间，𝑥3范围在 1-2 之间， 它们是相似范围，所以会表现得很好。 当它们在非常不同的取值范围内，如其中一个从 1 到 1000，另一个从 0 到 1，这对优化算法非常不利。但是仅将它们设置为均化零值，假设方差为 1，确保所有特征都在相似范围内，通常可以帮助学习算法运行得更快</p></section><section><h2>1.8 梯度消失和梯度爆炸<a href="#18-梯度消失和梯度爆炸"><span>#</span></a></h2><p>目前深度学习方法中，深度神经网络的发展造就了我们可以构建更深层的网络完成更复杂的任务，深层网络比如深度卷积网络，LSTM等等，而且最终结果表明，在处理复杂任务上，深度网络比浅层的网络具有更好的效果。但是，目前优化神经网络的方法都是基于反向传播的思想，即根据损失函数计算的误差通过梯度反向传播的方式，指导深度网络权值的更新优化。这样做是有一定原因的，首先，深层网络由许多非线性层堆叠而来，每一层非线性层都可以视为是一个非线性函数<span><span>F(x)F(x)</span><span><span><span></span><span>F</span><span>(</span><span>x</span><span>)</span></span></span></span> (非线性来自于非线性激活函数），因此整个深度网络可以视为是一个复合的非线性多元函数。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912025.png" alt="image-20230709185830791" /><figcaption>image-20230709185830791</figcaption></figure><p></p><p>图中是一个四层的全连接网络，假设每一层网络激活后的输出为<span><span>fi(x)f_i(x)</span><span><span><span></span><span><span>f</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>x</span><span>)</span></span></span></span> ,其中<span><span>ii</span><span><span><span></span><span>i</span></span></span></span>为第<span><span>ii</span><span><span><span></span><span>i</span></span></span></span>层,<span><span>xx</span><span><span><span></span><span>x</span></span></span></span>代表第<span><span>ii</span><span><span><span></span><span>i</span></span></span></span>层的输入，也就是第<span><span>i−1i-1</span><span><span><span></span><span>i</span><span></span><span>−</span><span></span></span><span><span></span><span>1</span></span></span></span>层的输出，<span><span>ff</span><span><span><span></span><span>f</span></span></span></span>是激活函数，那么，得出<span><span>fi+1=f(fi∗wi+1+bi+1)f_{i+1}= f(f_i * w_i+1+b_i +1)</span><span><span><span></span><span><span>f</span><span><span><span><span><span><span></span><span><span><span>i</span><span>+</span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>f</span><span>(</span><span><span>f</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>∗</span><span></span></span><span><span></span><span><span>w</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>+</span><span></span></span><span><span></span><span>1</span><span></span><span>+</span><span></span></span><span><span></span><span><span>b</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>+</span><span></span></span><span><span></span><span>1</span><span>)</span></span></span></span>，简单记为<span><span>fi+1=f(f∗wi+1)f_{i+1} = f(f* w_i+ 1)</span><span><span><span></span><span><span>f</span><span><span><span><span><span><span></span><span><span><span>i</span><span>+</span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>f</span><span>(</span><span>f</span><span></span><span>∗</span><span></span></span><span><span></span><span><span>w</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>+</span><span></span></span><span><span></span><span>1</span><span>)</span></span></span></span>。</p><p>BP算法基于梯度下降策略，以目标的负梯度方向对参数进行调整，参数的更新为<span><span>w=w−αdww=w-\alpha dw</span><span><span><span></span><span>w</span><span></span><span>=</span><span></span></span><span><span></span><span>w</span><span></span><span>−</span><span></span></span><span><span></span><span>α</span><span>d</span><span>w</span></span></span></span> ，如果要更新第二隐藏层的权值信息，根据链式求导法则，更新梯度信息：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307091912728.png" alt="image-20230709190653070" /><figcaption>image-20230709190653070</figcaption></figure><p></p><p>所以说，<span><span>∂f4∂f3\frac{ \partial f_4 }{ \partial f_3 }</span><span><span><span></span><span><span></span><span><span><span><span><span><span></span><span><span><span>∂</span><span><span>f</span><span><span><span><span><span><span></span><span><span>3</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span><span><span></span><span></span></span><span><span></span><span><span><span>∂</span><span><span>f</span><span><span><span><span><span><span></span><span><span>4</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span></span></span></span>就是对激活函数进行求导，如果此部分大于1，那么层数增多的时候，最终的求出的梯度更新将以指数形式增加，即发生<strong>梯度爆炸</strong>，如果此部分小于1，那么随着层数增多，求出的梯度更新信息将会以指数形式衰减，即发生了<strong>梯度消失</strong>。从而导致训练难度上升，尤其是梯度指数小于<span><span>LL</span><span><span><span></span><span>L</span></span></span></span>时，梯 度下降算法的步长会非常非常小，梯度下降算法将花费很长时间来学习。</p></section><section><h2>1.9 神经网络的权重初始化<a href="#19-神经网络的权重初始化"><span>#</span></a></h2></section><section><h2>1.10 梯度逼近<a href="#110-梯度逼近"><span>#</span></a></h2></section><section><h2>1.11 梯度检验<a href="#111-梯度检验"><span>#</span></a></h2></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/507/</id>
      <title type="text">机器学习与神经网络学习笔记</title>
      <published>2023-06-30T12:17:38.000Z</published>
      <updated>2024-06-06T04:27:51.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/507/"/>
      <summary type="text">机器学习与神经网络学习笔记 这几天在看吴恩达的深度学习视频，记不清已经是第几次捡起来了，之前每次都没看完，希望在正式上班之前把这部分看完吧 神经网络基础 神经网络是深度学习的基本组成部分。它由多个神经元和层级组成，每个神经元通过激活函数对输</summary>
      <content type="html"><![CDATA[<section><h1>机器学习与神经网络学习笔记<a href="#机器学习与神经网络学习笔记"><span>#</span></a></h1><p>这几天在看吴恩达的深度学习视频，记不清已经是第几次捡起来了，之前每次都没看完，希望在正式上班之前把这部分看完吧</p><section><h3>神经网络基础<a href="#神经网络基础"><span>#</span></a></h3><p>神经网络是深度学习的基本组成部分。它由多个神经元和层级组成，每个神经元通过激活函数对输入进行处理，并将输出传递给下一层。神经网络通过学习权重和偏置来逼近目标函数。</p><p>下图是一个简单的逻辑回归模型，首先需要输入特征，通过特征和计算出，接下来使用就可以计算出，然后可以计算 出 loss function 𝐿(𝑎, 𝑦)</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306301953647.png" alt="image-20230630195352602" /><figcaption>image-20230630195352602</figcaption></figure><p></p><p>神经网络看起来是如下这个样子。可以把许多 sigmoid 单元堆叠起来形成一个神经网络。它包含了之前讲的计算的 两个步骤：首先计算出值𝑧，然后通过𝜎(𝑧)计算值𝑎。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306301959456.png" alt="image-20230630195927387" /><figcaption>image-20230630195927387</figcaption></figure><p></p><p>在这个神经网络对应的 3 个节点，首先计算第一层网络中的各个节点相关的数𝑧 [1]，接着计算𝛼 [1]，在计算下一层网络同理； 我们会使用符号 [𝑚]表示第𝑚层网络中 节点相关的数，这些节点的集合被称为第𝑚层网络。</p><p>我们有输入特征𝑥1、𝑥2、𝑥3，它们被竖直地堆叠起来，这叫做神经网络的<strong>输入层</strong>。它包含了神经网络的输入；然后这里有另外一层我们称之为<strong>隐藏层</strong>（图中的四个结点），最后一层只由一个结点构成，而这个只 有一个结点的层被称为<strong>输出层</strong>，它负责产生预测值。解释隐藏层的含义：在一个神经网络中， 当你使用监督学习训练它的时候，训练集包含了输入𝑥也包含了目标输出𝑦，所以术语隐藏层 的含义是在训练集中，这些中间结点的准确值我们是不知道到的，也就是说你看不见它们在 训练集中应具有的值。你能看见输入的值，你也能看见输出的值，但是隐藏层中的东西，在训练集中你是无法看到的。所以这也解释了词语隐藏层，只是表示你无法在训练集中看到他 们。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306302001630.png" alt="image-20230630200137512" /><figcaption>image-20230630200137512</figcaption></figure><p></p><p>神经元模型是神经网络中的基本单元，它接收输入信号并通过激活函数进行非线性变换。</p><ul>
<li>输入：神经元接收来自上一层的输入信号。</li>
<li>权重：每个输入信号都与一个权重相关联，权重决定了输入对神经元的影响程度。</li>
<li>偏置：每个神经元还有一个偏置，它相当于一个常数项，可以调整神经元的输出。</li>
</ul><p>神经网络的训练通常涉及以下步骤：</p><ol>
<li><strong>数据准备</strong>：收集和准备用于训练神经网络的数据集。这包括对数据进行清洗、划分训练集和测试集，并进行必要的预处理步骤，例如标准化或归一化。</li>
<li><strong>定义网络结构</strong>：确定神经网络的结构，包括层数、每层的神经元数量以及激活函数的选择。这些决定将根据特定问题和数据集的需求进行调整。</li>
<li><strong>参数初始化</strong>：初始化神经网络的参数，例如权重和偏置项。常见的初始化方法包括零初始化、随机初始化和He初始化等。</li>
<li><strong>前向传播</strong>：执行前向传播算法，将输入数据通过神经网络进行推理，计算每一层的激活值（输出）。</li>
<li><strong>计算损失</strong>：使用定义的损失函数（例如交叉熵损失）计算预测结果与真实标签之间的差异，衡量模型的性能。</li>
<li><strong>反向传播</strong>：通过反向传播算法计算每一层的梯度，根据损失函数的梯度信息更新参数，以便减少损失。</li>
<li><strong>参数更新</strong>：根据反向传播计算得到的梯度信息，使用优化算法（如梯度下降）更新神经网络的参数。</li>
<li><strong>重复迭代</strong>：重复执行步骤4到步骤7，直到达到指定的训练迭代次数或满足停止条件。</li>
<li><strong>模型评估</strong>：使用测试集或交叉验证集对训练后的神经网络进行评估，计算准确率、精确率、召回率等指标，评估模型的性能。</li>
<li><strong>预测</strong>：使用训练好的神经网络对新的未见过的数据进行预测。</li>
</ol></section><section><h3>参数初始化<a href="#参数初始化"><span>#</span></a></h3><p>当你训练神经网络时，权重随机初始化是很重要的。对于逻辑回归，把权重初始化为 0 当然也是可以的。但是对于一个神经网络，如果你把权重或者参数都初始化为 0，那么梯度下降将不会起作用。因此，一般把初 始化为很小的随机数。然后没有这个对称的问题（叫做 symmetry breaking problem），所以可以把初始化为 0。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>def</span><span> </span><span>initialize_parameters_random</span><span>(</span><span>layers_dims</span><span>):</span></div></div><div><div><div>2</div></div><div><span><span>    </span></span><span>parameters </span><span>=</span><span> {}</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>L </span><span>=</span><span> </span><span>len</span><span><span>(layers_dims) </span><span>-</span><span> </span></span><span>1</span><span>  </span><span># 网络层数</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span>    </span><span>for</span><span> l </span><span>in</span><span> </span><span>range</span><span>(</span><span>1</span><span><span>, L </span><span>+</span><span> </span></span><span>1</span><span>):</span></div></div><div><div><div>6</div></div><div><span><span>        </span></span><span>parameters </span><span>=</span><span> np.random.</span><span>randn</span><span>(layers_dims, layers_dims) </span><span>*</span><span> </span><span>0.01</span></div></div><div><div><div>7</div></div><div><span><span>        </span></span><span>parameters </span><span>=</span><span> np.</span><span>zeros</span><span>((layers_dims, </span><span>1</span><span>))</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>    </span><span>return</span><span> parameters</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section><section><h3>前向传播<a href="#前向传播"><span>#</span></a></h3><p>神经网络的前向传播过程是从输入层到输出层的计算过程。对于每一层，输入经过权重和偏置的线性变换，然后通过激活函数进行非线性变换，得到输出。</p><section><h4>计算流程<a href="#计算流程"><span>#</span></a></h4><p>前向传播的计算流程为：</p><p>…</p><p>其中， 表示输入数据， 表示第 l 层的输出， 和  分别表示第 l 层的权重和偏置， 表示第 l 层的激活函数。</p></section><section><h4>激活函数<a href="#激活函数"><span>#</span></a></h4><p>激活函数引入了非线性特性，使神经网络能够学习复杂的非线性关系。常见的激活函数有sigmoid函数、ReLU函数和tanh函数。</p><p><strong>sigmoid函数</strong></p><p><strong>tanh激活函数</strong></p><p><strong>ReLU函数</strong></p><p>sigmoid 激活函数：除了输出层是一个二分类问题基本不会用它。</p><p>tanh 激活函数：tanh 是非常优秀的，几乎适合所有场合。</p><p>ReLu 激活函数：最常用的默认函数，如果不确定用哪个激活函数，就使用 ReLu 或者 Leaky ReLu。</p></section><section><h4>代码实现<a href="#代码实现"><span>#</span></a></h4><ul>
<li>在以下代码中，<code>forward_propagation</code>函数接受输入特征数据<code>X</code>和包含参数的字典<code>parameters</code>作为输入，执行n层神经网络的前向传播计算。</li>
<li>根据网络的层数L，依次从参数字典中提取权重矩阵和偏置向量，并根据前向传播的计算公式，计算每一层的加权输入Z和激活值A。</li>
<li>中间计算结果以元组形式保存在<code>caches</code>列表中，用于后续的后向传播计算。</li>
<li>最后，返回输出层的激活值AL和中间计算结果的缓存<code>caches</code>。这些结果可以用于损失计算和反向传播过程。</li>
</ul><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>def</span><span> </span><span>forward_propagation</span><span>(</span><span>X</span><span>,</span><span><span> </span><span>parameters</span></span><span>):</span></div></div><div><div><div>2</div></div><div><span>    </span><span>"""</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>前向传播计算</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>参数：</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>X - 输入特征数据，维度为（特征数量，样本数量）</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>parameters - 包含参数的字典，参数命名规则为"Wl"和"bl"，表示第l层的权重矩阵和偏置向量</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>返回：</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>AL - 输出层的激活值</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>caches - 包含每一层的中间计算结果的字典列表，用于后向传播</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>"""</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>L </span><span>=</span><span> </span><span>len</span><span><span>(parameters) </span><span>//</span><span> </span></span><span>2</span><span>  </span><span># 神经网络的层数</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>caches </span><span>=</span><span> []</span></div></div><div><div><div>16</div></div><div><span><span>    </span></span><span>A </span><span>=</span><span> X</span></div></div><div><div><div>17</div></div><div>
</div></div><div><div><div>18</div></div><div><span>    </span><span># 前L-1层的前向传播（使用ReLU激活函数）</span></div></div><div><div><div>19</div></div><div><span>    </span><span>for</span><span> l </span><span>in</span><span> </span><span>range</span><span>(</span><span>1</span><span>, L):</span></div></div><div><div><div>20</div></div><div><span><span>        </span></span><span>W </span><span>=</span><span> parameters[</span><span>'W'</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span>(l)]</span></div></div><div><div><div>21</div></div><div><span><span>        </span></span><span>b </span><span>=</span><span> parameters[</span><span>'b'</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span>(l)]</span></div></div><div><div><div>22</div></div><div><span><span>        </span></span><span>Z </span><span>=</span><span> np.</span><span>dot</span><span>(W, A) </span><span>+</span><span> b</span></div></div><div><div><div>23</div></div><div><span><span>        </span></span><span>A </span><span>=</span><span> </span><span>relu</span><span>(Z)</span></div></div><div><div><div>24</div></div><div><span><span>        </span></span><span>cache </span><span>=</span><span> (Z, A)</span></div></div><div><div><div>25</div></div><div><span><span>        </span></span><span>caches.</span><span>append</span><span>(cache)</span></div></div><div><div><div>26</div></div><div>
</div></div><div><div><div>27</div></div><div><span>    </span><span># 输出层的前向传播（使用Sigmoid激活函数）</span></div></div><div><div><div>28</div></div><div><span><span>    </span></span><span>WL</span><span> </span><span>=</span><span> parameters[</span><span>'W'</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span>(L)]</span></div></div><div><div><div>29</div></div><div><span><span>    </span></span><span>bL </span><span>=</span><span> parameters[</span><span>'b'</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span>(L)]</span></div></div><div><div><div>30</div></div><div><span><span>    </span></span><span>ZL</span><span> </span><span>=</span><span> np.</span><span>dot</span><span>(</span><span>WL</span><span>, A) </span><span>+</span><span> bL</span></div></div><div><div><div>31</div></div><div><span><span>    </span></span><span>AL</span><span> </span><span>=</span><span> </span><span>sigmoid</span><span>(</span><span>ZL</span><span>)</span></div></div><div><div><div>32</div></div><div><span><span>    </span></span><span>cacheL </span><span>=</span><span> (</span><span>ZL</span><span>, </span><span>AL</span><span>)</span></div></div><div><div><div>33</div></div><div><span><span>    </span></span><span>caches.</span><span>append</span><span>(cacheL)</span></div></div><div><div><div>34</div></div><div>
</div></div><div><div><div>35</div></div><div><span>    </span><span>return</span><span><span> </span><span>AL</span><span>, caches</span></span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section><section><h3>损失函数<a href="#损失函数"><span>#</span></a></h3><p>计算损失函数是深度学习中的重要步骤，它用于衡量模型的预测结果与实际标签之间的差异。损失函数的作用是量化模型的预测误差，并通过最小化损失函数来优化模型的参数。</p><p>在分类问题中，常用的损失函数是交叉熵损失函数（Cross Entropy Loss）。交叉熵损失函数可以有效地衡量两个概率分布之间的差异，用于衡量模型的输出与实际标签之间的差异。常见的损失函数有均方误差损失函数和交叉熵损失函数。对于二分类问题，交叉熵损失函数的计算公式如下：</p><ul>
<li>
<p>均方误差损失函数公式：</p>
</li>
<li>
<p>交叉熵损失函数公式：</p>
</li>
</ul><section><h4>代码实现<a href="#代码实现-1"><span>#</span></a></h4><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>def</span><span> </span><span>compute_loss</span><span>(</span><span>AL</span><span>,</span><span><span> </span><span>Y</span></span><span>):</span></div></div><div><div><div>2</div></div><div><span>    </span><span>"""</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>计算交叉熵损失函数</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>参数：</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>AL - 输出层的激活值，维度为（1，样本数量）</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>Y - 实际标签，维度为（1，样本数量）</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>返回：</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>loss - 交叉熵损失</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>"""</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>m </span><span>=</span><span> Y.shape[</span><span>1</span><span>]  </span><span># 样本数量</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span>    </span><span># 计算交叉熵损失</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>loss </span><span>=</span><span> </span><span>-</span><span>1</span><span><span> </span><span>/</span><span> m </span><span>*</span><span> np.</span><span>sum</span><span>(Y </span><span>*</span><span> np.</span><span>log</span><span>(</span><span>AL</span><span>) </span><span>+</span><span> (</span></span><span>1</span><span><span> </span><span>-</span><span> Y) </span><span>*</span><span> np.</span><span>log</span><span>(</span></span><span>1</span><span><span> </span><span>-</span><span> </span><span>AL</span><span>))</span></span></div></div><div><div><div>16</div></div><div>
</div></div><div><div><div>17</div></div><div><span>    </span><span>return</span><span> loss</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>以上代码中，<code>compute_loss</code>函数接受输出层的激活值<code>AL</code>和实际标签<code>Y</code>作为输入，通过交叉熵损失函数的计算公式，计算出交叉熵损失值。最后，返回计算得到的交叉熵损失值<code>loss</code>。</p></section></section><section><h3>反向传播<a href="#反向传播"><span>#</span></a></h3><p>反向传播是神经网络中的一种训练算法，通过计算梯度来更新权重和偏置。它利用链式法则将误差从输出层传播回输入层，并根据梯度下降算法更新模型参数。</p><p>反向传播的计算流程为：</p><p>…</p><p>其中， 表示第 l 层的梯度， 和  分别表示第 l 层的权重和偏置的梯度， 表示第 l 层激活函数的导数， 表示第 l 层的权重。</p><section><h4>代码实现<a href="#代码实现-2"><span>#</span></a></h4><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>def</span><span> </span><span>backward_propagation</span><span>(</span><span>AL</span><span>,</span><span><span> </span><span>Y</span></span><span>,</span><span><span> </span><span>caches</span></span><span>):</span></div></div><div><div><div>2</div></div><div><span>    </span><span>"""</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>N层神经网络的反向传播</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>参数：</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>AL - 神经网络的输出，维度为（输出层大小，样本数量）</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>Y - 实际标签，维度为（输出层大小，样本数量）</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>caches - 包含前向传播过程中的缓存值的列表</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>返回：</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>grads - 包含模型参数相对于损失函数的梯度的字典</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>"""</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>grads </span><span>=</span><span> {}</span></div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>L </span><span>=</span><span> </span><span>len</span><span>(caches)  </span><span># 网络层数</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>m </span><span>=</span><span> </span><span>AL</span><span>.shape[</span><span>1</span><span>]  </span><span># 样本数量</span></div></div><div><div><div>16</div></div><div><span><span>    </span></span><span>Y </span><span>=</span><span> Y.</span><span>reshape</span><span>(</span><span>AL</span><span>.shape)  </span><span># 保证Y和AL维度相同</span></div></div><div><div><div>17</div></div><div>
</div></div><div><div><div>18</div></div><div><span>    </span><span># 计算输出层的梯度</span></div></div><div><div><div>19</div></div><div><span><span>    </span></span><span>dAL </span><span>=</span><span> </span><span>-</span><span> (np.</span><span>divide</span><span>(Y, </span><span>AL</span><span>) </span><span>-</span><span> np.</span><span>divide</span><span>(</span><span>1</span><span><span> </span><span>-</span><span> Y, </span></span><span>1</span><span><span> </span><span>-</span><span> </span><span>AL</span><span>))</span></span></div></div><div><div><div>20</div></div><div>
</div></div><div><div><div>21</div></div><div><span>    </span><span># 反向传播</span></div></div><div><div><div>22</div></div><div><span><span>    </span></span><span>current_cache </span><span>=</span><span> caches[L </span><span>-</span><span> </span><span>1</span><span>]  </span><span># 最后一层的缓存值</span></div></div><div><div><div>23</div></div><div><span><span>    </span></span><span>grads[</span><span>"dA"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span>(L)], grads[</span><span>"dW"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span>(L)], grads[</span><span>"db"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span><span>(L)] </span><span>=</span><span> </span><span>linear_activation_backward</span><span>(dAL, current_cache, </span></span><span>activation</span><span>=</span><span>"sigmoid"</span><span>)</span></div></div><div><div><div>24</div></div><div>
</div></div><div><div><div>25</div></div><div><span>    </span><span># 从倒数第二层开始反向传播</span></div></div><div><div><div>26</div></div><div><span>    </span><span>for</span><span> l </span><span>in</span><span> </span><span>reversed</span><span>(</span><span>range</span><span><span>(L </span><span>-</span><span> </span></span><span>1</span><span>)):</span></div></div><div><div><div>27</div></div><div><span><span>        </span></span><span>current_cache </span><span>=</span><span> caches  </span><span># 当前层的缓存值</span></div></div><div><div><div>28</div></div><div><span><span>        </span></span><span>dA_prev_temp, dW_temp, db_temp </span><span>=</span><span> </span><span>linear_activation_backward</span><span>(grads[</span><span>"dA"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span><span>(l </span><span>+</span><span> </span></span><span>2</span><span>)], current_cache, </span><span>activation</span><span>=</span><span>"relu"</span><span>)</span></div></div><div><div><div>29</div></div><div><span><span>        </span></span><span>grads[</span><span>"dA"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span><span>(l </span><span>+</span><span> </span></span><span>1</span><span><span>)] </span><span>=</span><span> dA_prev_temp</span></span></div></div><div><div><div>30</div></div><div><span><span>        </span></span><span>grads[</span><span>"dW"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span><span>(l </span><span>+</span><span> </span></span><span>1</span><span><span>)] </span><span>=</span><span> dW_temp</span></span></div></div><div><div><div>31</div></div><div><span><span>        </span></span><span>grads[</span><span>"db"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span><span>(l </span><span>+</span><span> </span></span><span>1</span><span><span>)] </span><span>=</span><span> db_temp</span></span></div></div><div><div><div>32</div></div><div>
</div></div><div><div><div>33</div></div><div><span>    </span><span>return</span><span> grads</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>在上述代码中，<code>backward_propagation</code>函数接受神经网络的输出<code>AL</code>、实际标签<code>Y</code>和前向传播过程中的缓存值<code>caches</code>作为输入。根据反向传播的计算公式，首先计算输出层的梯度<code>dAL</code>，然后从最后一层开始，依次进行反向传播，计算每一层的梯度<code>dA_prev</code>、<code>dW</code>和<code>db</code>。其中，<code>linear_activation_backward</code>函数用于计算每一层的线性部分和激活函数的梯度。</p><p>最后，将计算得到的梯度保存到字典 <code>grads</code> 中并返回。这些梯度可以用于更新模型的参数。通过反向传播，梯度会从输出层逐渐传播回输入层，从而计算模型参数的梯度。</p></section></section><section><h3>参数更新<a href="#参数更新"><span>#</span></a></h3><p>在神经网络中，通常使用梯度下降法来更新参数。</p><p>其中，表示参数，表示学习率，表示损失函数关于参数的梯度。</p><section><h4>代码实现<a href="#代码实现-3"><span>#</span></a></h4><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>def</span><span> </span><span>update_parameters</span><span>(</span><span>parameters</span><span>,</span><span><span> </span><span>grads</span></span><span>,</span><span><span> </span><span>learning_rate</span></span><span>):</span></div></div><div><div><div>2</div></div><div><span>    </span><span>"""</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>使用梯度下降更新模型参数</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>参数：</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>parameters - 包含模型参数的字典</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>grads - 包含模型参数相对于损失函数的梯度的字典</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>learning_rate - 学习率</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>返回：</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>parameters - 更新后的模型参数字典</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>"""</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>L </span><span>=</span><span> </span><span>len</span><span><span>(parameters) </span><span>//</span><span> </span></span><span>2</span><span>  </span><span># 网络层数</span></div></div><div><div><div>14</div></div><div>
</div></div><div><div><div>15</div></div><div><span>    </span><span># 更新每一层的参数</span></div></div><div><div><div>16</div></div><div><span>    </span><span>for</span><span> l </span><span>in</span><span> </span><span>range</span><span>(L):</span></div></div><div><div><div>17</div></div><div><span><span>        </span></span><span>parameters[</span><span>"W"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span><span>(l </span><span>+</span><span> </span></span><span>1</span><span><span>)] </span><span>=</span><span> parameters[</span></span><span>"W"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span><span>(l </span><span>+</span><span> </span></span><span>1</span><span><span>)] </span><span>-</span><span> learning_rate </span><span>*</span><span> grads[</span></span><span>"dW"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span><span>(l </span><span>+</span><span> </span></span><span>1</span><span>)]</span></div></div><div><div><div>18</div></div><div><span><span>        </span></span><span>parameters[</span><span>"b"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span><span>(l </span><span>+</span><span> </span></span><span>1</span><span><span>)] </span><span>=</span><span> parameters[</span></span><span>"b"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span><span>(l </span><span>+</span><span> </span></span><span>1</span><span><span>)] </span><span>-</span><span> learning_rate </span><span>*</span><span> grads[</span></span><span>"db"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span><span>(l </span><span>+</span><span> </span></span><span>1</span><span>)]</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span>    </span><span>return</span><span> parameters</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>在上述代码中，<code>update_parameters</code>函数接受模型的参数字典<code>parameters</code>、模型参数相对于损失函数的梯度字典<code>grads</code>和学习率<code>learning_rate</code>作为输入。根据梯度下降的更新规则，对每一层的参数进行更新。</p><p>通过循环遍历每一层，更新参数<code>W</code>和<code>b</code>。更新公式为 <code>parameter = parameter - learning_rate * gradient</code>，其中<code>parameter</code>表示参数，<code>learning_rate</code>表示学习率，<code>gradient</code>表示对应的梯度。</p><p>最后，返回更新后的模型参数字典<code>parameters</code>。这些更新后的参数可以用于下一轮的前向传播和反向传播过程。</p><p>参数更新是神经网络训练的关键步骤，通过不断更新参数，使模型逐渐优化，减小损失函数，提高预测准确率。学习率<code>learning_rate</code>控制着每次更新的步长，需要合适的学习率来保证模型能够收敛到最优解。</p></section></section><section><h3>构建深层神经网络模型<a href="#构建深层神经网络模型"><span>#</span></a></h3><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>layers_dims </span><span>=</span><span> [</span></span><span>12288</span><span>, </span><span>20</span><span>, </span><span>7</span><span>, </span><span>5</span><span>, </span><span>1</span><span>] </span><span>#  5-layer model</span></div></div><div><div><div>2</div></div><div><span>def</span><span> </span><span>L_layer_model</span><span>(</span><span>X</span><span>,</span><span><span> </span><span>Y</span></span><span>,</span><span><span> </span><span>layers_dims</span></span><span>,</span><span><span> </span><span>learning_rate</span></span><span>=</span><span>0.0075</span><span>,</span><span><span> </span><span>num_iterations</span></span><span>=</span><span>3000</span><span>,</span><span><span> </span><span>print_cost</span></span><span>=</span><span>False</span><span>):</span></div></div><div><div><div>3</div></div><div><span>    </span><span>"""</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>实现一个L层神经网络模型的训练</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>参数：</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>X - 输入特征数据，维度为 (输入特征数, 样本数)</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>Y - 标签数据，维度为 (1, 样本数)</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>layers_dims - 列表，包含输入层、隐藏层和输出层的神经元数量</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>learning_rate - 学习率</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>num_iterations - 迭代次数</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>print_cost - 是否打印成本值</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>返回：</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>parameters - 训练后的模型参数</span></div></div><div><div><div>16</div></div><div><span><span>    </span></span><span>"""</span></div></div><div><div><div>17</div></div><div><span><span>    </span></span><span>np.random.</span><span>seed</span><span>(</span><span>1</span><span>)</span></div></div><div><div><div>18</div></div><div><span><span>    </span></span><span>costs </span><span>=</span><span> []  </span><span># 用于保存成本值</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span>    </span><span># 初始化参数</span></div></div><div><div><div>21</div></div><div><span><span>    </span></span><span>parameters </span><span>=</span><span> </span><span>initialize_parameters_random</span><span>(layers_dims)</span></div></div><div><div><div>22</div></div><div>
</div></div><div><div><div>23</div></div><div><span>    </span><span># 迭代训练</span></div></div><div><div><div>24</div></div><div><span>    </span><span>for</span><span> i </span><span>in</span><span> </span><span>range</span><span>(num_iterations):</span></div></div><div><div><div>25</div></div><div><span>        </span><span># 前向传播</span></div></div><div><div><div>26</div></div><div><span><span>        </span></span><span>AL</span><span>, caches </span><span>=</span><span> </span><span>forward_propagation</span><span>(X, parameters)</span></div></div><div><div><div>27</div></div><div>
</div></div><div><div><div>28</div></div><div><span>        </span><span># 计算成本</span></div></div><div><div><div>29</div></div><div><span><span>        </span></span><span>cost </span><span>=</span><span> </span><span>compute_loss</span><span>(</span><span>AL</span><span>, Y)</span></div></div><div><div><div>30</div></div><div>
</div></div><div><div><div>31</div></div><div><span>        </span><span># 反向传播</span></div></div><div><div><div>32</div></div><div><span><span>        </span></span><span>grads </span><span>=</span><span> </span><span>backward_propagation</span><span>(</span><span>AL</span><span>, Y, caches)</span></div></div><div><div><div>33</div></div><div>
</div></div><div><div><div>34</div></div><div><span>        </span><span># 参数更新</span></div></div><div><div><div>35</div></div><div><span><span>        </span></span><span>parameters </span><span>=</span><span> </span><span>update_parameters</span><span>(parameters, grads, learning_rate)</span></div></div><div><div><div>36</div></div><div>
</div></div><div><div><div>37</div></div><div><span>        </span><span># 打印成本值</span></div></div><div><div><div>38</div></div><div><span>        </span><span>if</span><span> print_cost </span><span>and</span><span><span> i </span><span>%</span><span> </span></span><span>100</span><span><span> </span><span>==</span><span> </span></span><span>0</span><span>:</span></div></div><div><div><div>39</div></div><div><span>            </span><span>print</span><span>(</span><span>"Cost after iteration </span><span>{}</span><span>: </span><span>{}</span><span>"</span><span><span>.</span><span>format</span><span>(i, cost))</span></span></div></div><div><div><div>40</div></div><div><span>        </span><span>if</span><span><span> i </span><span>%</span><span> </span></span><span>100</span><span><span> </span><span>==</span><span> </span></span><span>0</span><span>:</span></div></div><div><div><div>41</div></div><div><span><span>            </span></span><span>costs.</span><span>append</span><span>(cost)</span></div></div><div><div><div>42</div></div><div>
</div></div><div><div><div>43</div></div><div><span>    </span><span># 绘制成本曲线</span></div></div><div><div><div>44</div></div><div><span><span>    </span></span><span>plt.</span><span>plot</span><span>(np.</span><span>squeeze</span><span>(costs))</span></div></div><div><div><div>45</div></div><div><span><span>    </span></span><span>plt.</span><span>ylabel</span><span>(</span><span>'Cost'</span><span>)</span></div></div><div><div><div>46</div></div><div><span><span>    </span></span><span>plt.</span><span>xlabel</span><span>(</span><span>'Iterations (per tens)'</span><span>)</span></div></div><div><div><div>47</div></div><div><span><span>    </span></span><span>plt.</span><span>title</span><span>(</span><span>"Learning rate ="</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span>(learning_rate))</span></div></div><div><div><div>48</div></div><div><span><span>    </span></span><span>plt.</span><span>show</span><span>()</span></div></div><div><div><div>49</div></div><div>
</div></div><div><div><div>50</div></div><div><span>    </span><span>return</span><span> parameters</span></div></div><div><div><div>51</div></div><div>
</div></div><div><div><div>52</div></div><div><span><span>parameters </span><span>=</span><span> </span><span>L_layer_model</span><span>(train_x, train_y, layers_dims, </span></span><span>num_iterations</span><span><span> </span><span>=</span><span> </span></span><span>2500</span><span>, </span><span>print_cost</span><span><span> </span><span>=</span><span> </span></span><span>True</span><span>)</span><span>#训练模型</span></div></div><div><div><div>53</div></div><div><span><span>pred_train </span><span>=</span><span> </span><span>predict</span><span>(train_x, train_y, parameters)</span></span><span>#训练集验证</span></div></div><div><div><div>54</div></div><div><span><span>pred_test </span><span>=</span><span> </span><span>predict</span><span>(test_x, test_y, parameters)</span></span><span>#测试集验证</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>该函数接受输入特征数据 <code>X</code>，标签数据 <code>Y</code>，神经网络层的维度 <code>layers_dims</code>，学习率 <code>learning_rate</code>，迭代次数 <code>num_iterations</code> 和是否打印成本值 <code>print_cost</code> 作为参数。</p><p>函数首先初始化模型的参数，然后通过迭代训练的方式进行模型优化。在每次迭代中，函数执行以下步骤：</p><ol>
<li>前向传播：通过调用 <code>L_model_forward</code> 函数实现，计算预测值 <code>AL</code> 和缓存值 <code>caches</code>。</li>
<li>计算成本：通过调用 <code>compute_cost</code> 函数实现，计算模型的损失函数成本。</li>
<li>反向传播：通过调用 <code>L_model_backward</code> 函数实现，计算模型参数相对于损失函数的梯度。</li>
<li>参数更新：通过调用 <code>update_parameters</code> 函数实现，根据梯度下降的更新规则更新模型的参数。</li>
<li>打印成本值：根据设定的条件，打印每一百次迭代的成本值。</li>
<li>绘制成本</li>
</ol><p>这样就完成了深度神经网络的构建。</p><p>学习视频：<a href="https://www.coursera.org/deeplearning-ai" target="_blank">https://www.coursera.org/deeplearning-ai</a></p><p>笔记资料：<a href="https://github.com/fengdu78/deeplearning_ai_books" target="_blank">fengdu78/deeplearning_ai_books: deeplearning.ai（吴恩达老师的深度学习课程笔记及资源） (github.com)</a></p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/464/</id>
      <title type="text">铣削加工机器人（一）：机器人运动学</title>
      <published>2023-06-04T08:50:26.000Z</published>
      <updated>2024-06-22T17:41:19.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/464/"/>
      <summary type="text">机器人学 1.1 空间形位与齐次变换 机器人在空间的位姿通常有两种表达方式，一种是在笛卡尔空间表示，通过在世界坐标系和机器人末端上建立坐标系，使用笛卡尔坐标描述机器人的位姿；另一种是通过关节空间表示，使用机器人六个关节的角度来描述机器人的形</summary>
      <content type="html"><![CDATA[<section><h1>机器人学<a href="#机器人学"><span>#</span></a></h1><section><h2>1.1 空间形位与齐次变换<a href="#11-空间形位与齐次变换"><span>#</span></a></h2><p>机器人在空间的位姿通常有两种表达方式，一种是在笛卡尔空间表示，通过在世界坐标系和机器人末端上建立坐标系，使用笛卡尔坐标描述机器人的位姿；另一种是通过关节空间表示，使用机器人六个关节的角度来描述机器人的形位。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306021438479.png" alt="image-20230602143835217" /><figcaption>image-20230602143835217</figcaption></figure><p></p><p>KUKA KR60-3机器人的姿态通常使用笛卡尔坐标进行控制，机器人基坐标系为<em>XB-YB-ZB</em>，在机器人刀尖上建立工具坐标系<em>XT-YT-ZT</em>，则末端工具在基坐标系中的位姿就可以用<em>XT-YT-ZT</em>相对于<em>XB-YB-ZB</em>的位姿描述。工具坐标系在基坐标系的位姿关系可以用一个 的齐次变换矩阵<em><strong>T</strong></em>表示:</p></section><section><h2>1.2机器人运动学建模<a href="#12机器人运动学建模"><span>#</span></a></h2><section><h3>1.2.1 基于旋量法的运动学建模<a href="#121-基于旋量法的运动学建模"><span>#</span></a></h3><p>KUKA KR60-3结构简图如图所示，<em>XB-YB-ZB</em>为基坐标系，<em>XT-YT-ZT</em>为末端工具坐标系，<em>L</em>1~<em>L</em>6为机器人的结构参数， 分别为六个关节的旋量坐标，<em>r</em>1<em>~r</em>6 分别为关节轴线上任意一点，其中<em>r</em>4*、r<em>5</em>、r*6为同一点，即后三关节轴线交点。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306021445104.png" alt="image-20230602144531023" /><figcaption>image-20230602144531023</figcaption></figure><p></p><p>在旋量理论中，刚体在笛卡尔空间中的运动速度由角速度和线速度组成，这个向量被称为运动旋量，把运动旋量写成螺旋轴S与绕该转轴速度的合成形式，即：</p><p>对于纯转动关节，机器人上一点的形位的变换可以由指数坐标表示，也可以将其写为4×4的齐次变换矩阵形式：</p><p>由机器人的结构参数可以得到机器人的旋量参数，如表所示。</p><figure><table>
<thead>
<tr><th></th><th></th><th></th><th></th></tr></thead>
<tbody><tr><td>1</td><td>[0,0,-1]</td><td>[0,0,0]</td><td>[0,0,0]</td></tr><tr><td>2</td><td>[0,1,0]</td><td>[350,0,815]</td><td>[-815,0,350]</td></tr><tr><td>3</td><td>[0,1,0]</td><td>[1200,0,815]</td><td>[-815,0,1200]</td></tr><tr><td>4</td><td>[-1,0,0]</td><td>[2020,0,960]</td><td>[0,-960,0]</td></tr><tr><td>5</td><td>[0,1,0]</td><td>[2020,0,960]</td><td>[-960,0,2020]</td></tr><tr><td>6</td><td>[-1,0,0]</td><td>[2020,0,960]</td><td>[0,-960,0]</td></tr></tbody>
</table></figure><p>在KUKA KR60-3工业机器人中，每个连杆通过关节的螺旋运动施加运动给后面的连杆。末端坐标系经由6个关节串联的运动链，做多次螺旋运动，从初始位姿<em><strong>M</strong></em>变换到当前位姿<em><strong>T</strong></em>。在确定基坐标系和机器人初始位姿后，在完成指定的关节运动后，可以通过正向运动学表达式表示机械臂的末端坐标系：</p></section><section><h3>1.2.2 正运动学代码实现<a href="#122-正运动学代码实现"><span>#</span></a></h3><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>#Normalizes a vector</span></div></div><div><div><div>2</div></div><div><span>def</span><span> </span><span>Normalize</span><span>(</span><span>V</span><span>):</span></div></div><div><div><div>3</div></div><div><span>    </span><span>return</span><span><span> V </span><span>/</span><span> np.linalg.</span><span>norm</span><span>(V)</span></span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span>#Converts an so(3) representation to a 3-vector</span></div></div><div><div><div>6</div></div><div><span>def</span><span> </span><span>so3ToVec</span><span>(</span><span>so3mat</span><span>):</span></div></div><div><div><div>7</div></div><div><span>    </span><span>return</span><span><span> np.</span><span>array</span><span>([</span></span><span>1</span><span>], so3mat[</span><span>0</span><span>][</span><span>2</span><span>], so3mat[</span><span>1</span><span>][</span><span>0</span><span>]])</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>#Converts a spatial velocity vector into a 4x4 matrix in se3</span></div></div><div><div><div>10</div></div><div><span>def</span><span> </span><span>VecTose3</span><span>(</span><span>V</span><span>):</span></div></div><div><div><div>11</div></div><div><span>    </span><span>return</span><span> np.r_, V[</span><span>1</span><span>], V[</span><span>2</span><span>]]), [V[</span><span>3</span><span>], V[</span><span>4</span><span>], V[</span><span>5</span><span>]]],</span></div></div><div><div><div>12</div></div><div><span><span>                 </span></span><span>np.</span><span>zeros</span><span>((</span><span>1</span><span>, </span><span>4</span><span>))]</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span>#Converts a 3-vector of exponential coordinates for rotation into axis-angle form</span></div></div><div><div><div>15</div></div><div><span>def</span><span> </span><span>AxisAng3</span><span>(</span><span>expc3</span><span>):</span></div></div><div><div><div>16</div></div><div><span>    </span><span>return</span><span><span> (</span><span>Normalize</span><span>(expc3), np.linalg.</span><span>norm</span><span>(expc3))</span></span></div></div><div><div><div>17</div></div><div>
</div></div><div><div><div>18</div></div><div><span>#Computes the matrix exponential of a matrix in so(3)</span></div></div><div><div><div>19</div></div><div><span>def</span><span> </span><span>MatrixExp3</span><span>(</span><span>so3mat</span><span>):</span></div></div><div><div><div>20</div></div><div><span><span>    </span></span><span>omgtheta </span><span>=</span><span> </span><span>so3ToVec</span><span>(so3mat)</span></div></div><div><div><div>21</div></div><div><span>    </span><span>if</span><span><span> </span><span>NearZero</span><span>(np.linalg.</span><span>norm</span><span>(omgtheta)):</span></span></div></div><div><div><div>22</div></div><div><span>        </span><span>return</span><span><span> np.</span><span>eye</span><span>(</span></span><span>3</span><span>)</span></div></div><div><div><div>23</div></div><div><span>    </span><span>else</span><span>:</span></div></div><div><div><div>24</div></div><div><span><span>        </span></span><span>theta </span><span>=</span><span> </span><span>AxisAng3</span><span>(omgtheta)[</span><span>1</span><span>]</span></div></div><div><div><div>25</div></div><div><span><span>        </span></span><span>omgmat </span><span>=</span><span> so3mat </span><span>/</span><span> theta</span></div></div><div><div><div>26</div></div><div><span>        </span><span>return</span><span><span> np.</span><span>eye</span><span>(</span></span><span>3</span><span><span>) </span><span>+</span><span> np.</span><span>sin</span><span>(theta) </span><span>*</span><span> omgmat \</span></span></div></div><div><div><div>27</div></div><div><span><span>               </span></span><span>+</span><span> (</span><span>1</span><span><span> </span><span>-</span><span> np.</span><span>cos</span><span>(theta)) </span><span>*</span><span> np.</span><span>dot</span><span>(omgmat, omgmat)</span></span></div></div><div><div><div>28</div></div><div>
</div></div><div><div><div>29</div></div><div><span>#Computes the matrix exponential of an se3 representation of exponential coordinates</span></div></div><div><div><div>30</div></div><div><span>def</span><span> </span><span>MatrixExp6</span><span>(</span><span>se3mat</span><span>):</span></div></div><div><div><div>31</div></div><div><span><span>    </span></span><span>se3mat </span><span>=</span><span> np.</span><span>array</span><span>(se3mat)</span></div></div><div><div><div>32</div></div><div><span><span>    </span></span><span>omgtheta </span><span>=</span><span> </span><span>so3ToVec</span><span>(se3mat[</span><span>0</span><span>: </span><span>3</span><span>, </span><span>0</span><span>: </span><span>3</span><span>])</span></div></div><div><div><div>33</div></div><div><span>    </span><span>if</span><span><span> </span><span>NearZero</span><span>(np.linalg.</span><span>norm</span><span>(omgtheta)):</span></span></div></div><div><div><div>34</div></div><div><span>        </span><span>return</span><span> np.r_], [[</span><span>0</span><span>, </span><span>0</span><span>, </span><span>0</span><span>, </span><span>1</span><span>]]]</span></div></div><div><div><div>35</div></div><div><span>    </span><span>else</span><span>:</span></div></div><div><div><div>36</div></div><div><span><span>        </span></span><span>theta </span><span>=</span><span> </span><span>AxisAng3</span><span>(omgtheta)[</span><span>1</span><span>]</span></div></div><div><div><div>37</div></div><div><span><span>        </span></span><span>omgmat </span><span>=</span><span> se3mat[</span><span>0</span><span>: </span><span>3</span><span>, </span><span>0</span><span>: </span><span>3</span><span><span>] </span><span>/</span><span> theta</span></span></div></div><div><div><div>38</div></div><div><span>        </span><span>return</span><span> np.r_),</span></div></div><div><div><div>39</div></div><div><span><span>                           </span></span><span>np.</span><span>dot</span><span>(np.</span><span>eye</span><span>(</span><span>3</span><span><span>) </span><span>*</span><span> theta \</span></span></div></div><div><div><div>40</div></div><div><span><span>                                  </span></span><span>+</span><span> (</span><span>1</span><span><span> </span><span>-</span><span> np.</span><span>cos</span><span>(theta)) </span><span>*</span><span> omgmat \</span></span></div></div><div><div><div>41</div></div><div><span><span>                                  </span></span><span>+</span><span> (theta </span><span>-</span><span> np.</span><span>sin</span><span>(theta)) \</span></div></div><div><div><div>42</div></div><div><span><span>                                    </span></span><span>* np.</span><span>dot</span><span>(omgmat,omgmat),</span></div></div><div><div><div>43</div></div><div><span><span>                                  </span></span><span>se3mat[</span><span>0</span><span>: </span><span>3</span><span>, </span><span>3</span><span><span>]) </span><span>/</span><span> theta],</span></span></div></div><div><div><div>44</div></div><div><span><span>                     </span></span><span>[[</span><span>0</span><span>, </span><span>0</span><span>, </span><span>0</span><span>, </span><span>1</span><span>]]]</span></div></div><div><div><div>45</div></div><div><span>#空间坐标系下位姿计算</span></div></div><div><div><div>46</div></div><div><span>def</span><span> </span><span>FKinBody</span><span>(</span><span>M</span><span>,</span><span><span> </span><span>Blist</span></span><span>,</span><span><span> </span><span>thetalist</span></span><span>):</span></div></div><div><div><div>47</div></div><div><span><span>    </span></span><span>T </span><span>=</span><span> np.</span><span>array</span><span>(M)</span></div></div><div><div><div>48</div></div><div><span>    </span><span>for</span><span> i </span><span>in</span><span> </span><span>range</span><span>(</span><span>len</span><span>(thetalist)):</span></div></div><div><div><div>49</div></div><div><span><span>        </span></span><span>T </span><span>=</span><span> np.</span><span>dot</span><span>(T, </span><span>MatrixExp6</span><span>(</span><span>VecTose3</span><span>(np.</span><span>array</span><span>(Blist)[:, i] \</span></div></div><div><div><div>50</div></div><div><span><span>                                          </span></span><span>* thetalist)))</span></div></div><div><div><div>51</div></div><div><span>    </span><span>return</span><span> T</span></div></div><div><div><div>52</div></div><div><span>#末端坐标系下位姿计算</span></div></div><div><div><div>53</div></div><div><span>def</span><span> </span><span>FKinSpace</span><span>(</span><span>M</span><span>,</span><span><span> </span><span>Slist</span></span><span>,</span><span><span> </span><span>thetalist</span></span><span>):</span></div></div><div><div><div>54</div></div><div><span><span>    </span></span><span>T </span><span>=</span><span> np.</span><span>array</span><span>(M)</span></div></div><div><div><div>55</div></div><div><span>    </span><span>for</span><span> i </span><span>in</span><span> </span><span>range</span><span>(</span><span>len</span><span><span>(thetalist) </span><span>-</span><span> </span></span><span>1</span><span><span>, </span><span>-</span></span><span>1</span><span><span>, </span><span>-</span></span><span>1</span><span>):</span></div></div><div><div><div>56</div></div><div><span><span>        </span></span><span>T </span><span>=</span><span> np.</span><span>dot</span><span>(</span><span>MatrixExp6</span><span>(</span><span>VecTose3</span><span>(np.</span><span>array</span><span>(Slist)[:, i] \</span></div></div><div><div><div>57</div></div><div><span><span>                                       </span></span><span>* thetalist)), T)</span></div></div><div><div><div>58</div></div><div><span>    </span><span>return</span><span> T</span></div></div><div><div><div>59</div></div><div><span>#旋量坐标</span></div></div><div><div><div>60</div></div><div><span><span>Slist</span><span>=</span><span>np.</span><span>array</span><span>([[   </span></span><span>0</span><span>,    </span><span>0</span><span>,    </span><span>0</span><span><span>,   </span><span>-</span></span><span>1</span><span>,    </span><span>0</span><span><span>,   </span><span>-</span></span><span>1</span><span>],</span></div></div><div><div><div>61</div></div><div><span><span>                </span></span><span>[   </span><span>0</span><span>,    </span><span>1</span><span>,    </span><span>1</span><span>,    </span><span>0</span><span>,    </span><span>1</span><span>,    </span><span>0</span><span>],</span></div></div><div><div><div>62</div></div><div><span><span>                </span></span><span>[  </span><span>-</span><span>1</span><span>,    </span><span>0</span><span>,    </span><span>0</span><span>,    </span><span>0</span><span>,    </span><span>0</span><span>,    </span><span>0</span><span>],</span></div></div><div><div><div>63</div></div><div><span><span>                </span></span><span>[   </span><span>0</span><span><span>, </span><span>-</span></span><span>815</span><span><span>, </span><span>-</span></span><span>815</span><span>,    </span><span>0</span><span><span>, </span><span>-</span></span><span>960</span><span>,    </span><span>0</span><span>],</span></div></div><div><div><div>64</div></div><div><span><span>                </span></span><span>[   </span><span>0</span><span>,    </span><span>0</span><span>,    </span><span>0</span><span><span>, </span><span>-</span></span><span>960</span><span>,    </span><span>0</span><span><span>, </span><span>-</span></span><span>960</span><span>],</span></div></div><div><div><div>65</div></div><div><span><span>                </span></span><span>[   </span><span>0</span><span>,  </span><span>350</span><span>, </span><span>1200</span><span>,    </span><span>0</span><span>, </span><span>2020</span><span>,    </span><span>0</span><span>]])</span></div></div><div><div><div>66</div></div><div><span>#法兰相对于基座标系姿态</span></div></div><div><div><div>67</div></div><div><span><span>M</span><span>=</span><span>np.</span><span>array</span><span>([[ </span></span><span>0</span><span>,    </span><span>0</span><span>,    </span><span>1</span><span>,  </span><span>2190</span><span>],</span></div></div><div><div><div>68</div></div><div><span><span>            </span></span><span>[ </span><span>0</span><span>,    </span><span>1</span><span>,    </span><span>0</span><span>,     </span><span>0</span><span>],</span></div></div><div><div><div>69</div></div><div><span><span>            </span></span><span>[</span><span>-</span><span>1</span><span>,    </span><span>0</span><span>,    </span><span>0</span><span>,   </span><span>960</span><span>],</span></div></div><div><div><div>70</div></div><div><span><span>            </span></span><span>[ </span><span>0</span><span>,    </span><span>0</span><span>,    </span><span>0</span><span>,     </span><span>1</span><span>]])</span></div></div><div><div><div>71</div></div><div><span>#关节角</span></div></div><div><div><div>72</div></div><div><span><span>thetalist</span><span>=</span><span>np.</span><span>array</span><span>([</span></span><span>0</span><span><span>,</span><span>-</span></span><span>90</span><span>/</span><span>180</span><span><span>*</span><span>pi,</span></span><span>90</span><span>/</span><span>180</span><span><span>*</span><span>pi,</span></span><span>0</span><span>,</span><span>0</span><span>,</span><span>0</span><span>])</span></div></div><div><div><div>73</div></div><div><span>#末端位姿计算</span></div></div><div><div><div>74</div></div><div><span><span>T </span><span>=</span><span> </span><span>FKinSpace</span><span>(M,Slist,thetalist)</span></span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section><section><h2>1.3 基于旋量法的逆运动学求解<a href="#13-基于旋量法的逆运动学求解"><span>#</span></a></h2><section><h4>1.3.1 PK子问题<a href="#131-pk子问题"><span>#</span></a></h4><p>对于六自由度串联机器人而言，逆运动学可以描述成：已知机器人末端工具坐标系位姿，求解满足当前位姿的一组或多组关节角。由KR60-3机器人后三轴相交与一点的特性，利用Paden-Kahan子问题推导机器人关节逆解解析式。Paden-Kahan子问题是基于旋量理论的指数积公式求解各关节旋转角度的几何方法。基于旋量理论的运动学逆解可以分为三个Paden-Kahan子问题，分别是绕单轴旋转、绕两个轴旋转和旋转到给定距离，目前KR60-3的逆运动学求解中只用到了两类子问题，所以本文只介绍子问题1和子问题2，如图所示。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306032017628.png" alt="image-20230603201716446" /><figcaption>image-20230603201716446</figcaption></figure><p></p><p><code>PK子问题1</code>为一个点绕定轴旋转。描述为空间中一点<em><strong>p</strong></em>绕给定的轴线旋转到<em><strong>q</strong></em>点位置，求解旋转角度，可用旋量法表示为</p><p>通过向量之间的几何关系，旋转角可以由以下公式计算：</p><p>，</p><p><code>PK子问题2</code>为一个点绕两个相交轴连续旋转。描述为空间中一点<em><strong>p</strong></em>，绕两相交轴和 进行旋转，先将<em><strong>p</strong></em>点绕旋转轴旋转 运动到<em><strong>s</strong></em>点，然后再绕旋转轴旋转运动到<em><strong>q</strong></em>点，和 分别为轴线和 的方向向量。设，，，用公式表示为：</p><p>若两个旋转轴重合，问题就变成了PK子问题1，若两个旋转轴不重合，可通过几何关系求解出中间点<em><strong>z</strong></em>，将子问题2分解为两个子问题1进行求解。</p></section><section><h4>1.3.2 KUKA KR60-3逆运动学求解<a href="#132-kuka-kr60-3逆运动学求解"><span>#</span></a></h4><p>由螺旋理论可知，位于螺旋轴上的点不会受到螺旋运动的影响，即。由KR60-3机器人结构简图可知，4、5、6关节轴线相交于同一点，在正运动学公式中右乘，就可以消除正运动学公式中4、5、6关节的影响，将6个关节的逆运动学求解分为两部分进行。</p><p>上式表示腕部中心点在前三关节中螺旋运动，指经过前三个关节的运动到达。由此可使用Paden-Kahan子问题1，对前3个关节逐一进行求解。基于几何法，使用PK子问题1即可求解出前三个关节的关节角，得到：</p><p>其中，上述公式中、、和的表达式如下：</p><p>在得到前三个关节的关节角后，将上一步求取的前三个关节带入公式(2-10)中，然后在原公式中取在轴6上但不在4、5轴上一点进行解耦，即可消除第六轴的影响，将后三轴转换为一个子问题2和一个子问题1进行求解，在公式两边同乘以在轴6上但不在4、5轴上一点。</p><p>上式可以看成一个子问题2，绕后4、5关节连续旋转，经过中间点，移动到位置，4、5关节轴线交点为。使用子问题2求解出中间点即可将问题转换为两个子问题1，对关节5、6进行求解。在求出关节角、后，代入公式，并取关节6轴线外一点，计算得到绕关节6旋转后的，根据旋量理论将公式进行解耦，即可求出关节角，关节角、、表达式如下：</p></section><section><h4>1.3.3 基于旋量法的逆运动学数值求解<a href="#133-基于旋量法的逆运动学数值求解"><span>#</span></a></h4><p>如果逆运动学方程无解析解时，可采用迭代数值方法求解。即使存在解析解,数值算法也经常用于改善求解的精度。</p><p>许多迭代方法可用于非线性方程的求解，’而是将运动学逆解方程转换成现有数值方法可解的形式。为此，将多次使用求解非线性方程的基本方法&lt;牛顿-拉夫森法&gt;。此外，也将引入其他一些优化方法，以应对精确解不存在的情况，并利用这些方法得到最接近真实值的解或者相反情况，存在无穷多个运动学逆解（例如，运动学冗余情况）。为此，需要找到相对某种指标的最优解。因此， 下面首先讨论用于求解非线性方程的<code>牛顿-拉夫森法</code>，接下来讨论优化第一必要条件。</p><section><h5>（1）牛顿-拉夫森法<a href="#1牛顿-拉夫森法"><span>#</span></a></h5><p>对于给定的微分方程方程，数值求解方程，假设为初值，利用泰勒级数在处展开，并截取到第一项，得：</p><p>若只保留到第—阶，令，求解得到：</p><p>再将上式求得的值作为初值，代人上述方程中，重复求解，得到下述方程：</p><p>上述过程不断迭代，直到满足某个指标值。例如，给定预先设定好的阂值满足：</p><p>对于KUKA KR60-3六自由度串联机器人，假设我们用坐标向量及其正向运动学方程表示末端坐标，自然会得到一个从个关节坐标到个末端坐标的非线性向量方程。令为预期的末端坐标，牛顿-拉夫森法中的可以定义成, 目标是找到关节 坐标且保证：</p><p>已知初始估计值接近真实解，运动学可以写成泰勒展开的形式，即：</p><p>截取泰勒展开第一项，假设可逆，使用下式求解，即：</p><p>若正向运动学是的线性函数，这时新的估计值 精确满足。相反，若正向运动学是的非线性函数，就如通常情况,这时新的估计值比更接近真实值，迭代过程不断重复，最终在处收敛。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306041514035.png" alt="image-20230604151422884" /><figcaption>image-20230604151422884</figcaption></figure><p></p></section><section><h5>（2）逆运动学的数值算法<a href="#2逆运动学的数值算法"><span>#</span></a></h5><p>实际上，由于计算效率等原因，经常不采用求逆的方式来求解。可以找到更高效的方法求解线性方程＝中的。例如，对于可逆阵，基于的分解可以用更少的运算得到。或者将替换成<code>Moore-Penrose</code>伪逆形式。</p><p>修改上述算法，使之能应用在预期末端位形为而不是坐标向量 的情况。可将关节坐标雅可比替换成末端物体雅可比。注意，由于向量表示的是从当前估计值（由正向运动学得到）到预期末端位形。不能简单地替换成；的伪逆应该作为物体速度旋量。为找到一个合理的对比，我们可以想象为一个速度向量，如果遵循单位时间，可使运动从 到。类似的，我们应该能够找到—个速度旋量，如果遵循单位时间，可使运动从到预期行为。</p><p>为找到这个，首先需计算相对物体坐标系的预期位形，即</p><p>然后,利用矩阵对数确定即:</p><p>由此可以给出逆运动学算法：</p><p>（a）初始化：已知，初始估计值，设定;</p><p>（b）计算，当或者时：</p><ul>
<li>计算</li>
</ul><p>完成一定次数的迭代后，就都能获得真实值的近似解。</p></section><section><h5>（3） 数值解代码实现<a href="#3-数值解代码实现"><span>#</span></a></h5><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>def</span><span> </span><span>IKinBody</span><span>(</span><span>Blist</span><span>,</span><span><span> </span><span>M</span></span><span>,</span><span><span> </span><span>T</span></span><span>,</span><span><span> </span><span>thetalist0</span></span><span>,</span><span><span> </span><span>eomg</span></span><span>,</span><span><span> </span><span>ev</span></span><span>):</span></div></div><div><div><div>2</div></div><div><span>    </span><span>#Computes inverse kinematics in the body frame for an open chain robot</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>thetalist </span><span>=</span><span> np.</span><span>array</span><span>(thetalist0).</span><span>copy</span><span>()</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>i </span><span>=</span><span> </span><span>0</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>maxiterations </span><span>=</span><span> </span><span>20</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>Vb </span><span>=</span><span> </span><span>se3ToVec</span><span>(</span><span>MatrixLog6</span><span>(np.</span><span>dot</span><span>(</span><span>TransInv</span><span>(</span><span>FKinBody</span><span>(M, Blist, \</span></div></div><div><div><div>8</div></div><div><span><span>                                                      </span></span><span>thetalist)), T)))</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>err </span><span>=</span><span> np.linalg.</span><span>norm</span><span>([Vb[</span><span>0</span><span>], Vb[</span><span>1</span><span>], Vb[</span><span>2</span><span><span>]]) </span><span>&gt;</span><span> eomg \</span></span></div></div><div><div><div>10</div></div><div><span>          </span><span>or</span><span><span> np.linalg.</span><span>norm</span><span>([Vb[</span></span><span>3</span><span>], Vb[</span><span>4</span><span>], Vb[</span><span>5</span><span><span>]]) </span><span>&gt;</span><span> ev</span></span></div></div><div><div><div>11</div></div><div><span>    </span><span>while</span><span> err </span><span>and</span><span><span> i </span><span>&lt;</span><span> maxiterations:</span></span></div></div><div><div><div>12</div></div><div><span><span>        </span></span><span>thetalist </span><span>=</span><span> thetalist \</span></div></div><div><div><div>13</div></div><div><span><span>                    </span></span><span>+</span><span> np.</span><span>dot</span><span>(np.linalg.</span><span>pinv</span><span>(</span><span>JacobianBody</span><span>(Blist, \</span></div></div><div><div><div>14</div></div><div><span><span>                                                         </span></span><span>thetalist)), Vb)</span></div></div><div><div><div>15</div></div><div><span><span>        </span></span><span>i </span><span>=</span><span> i </span><span>+</span><span> </span><span>1</span></div></div><div><div><div>16</div></div><div><span><span>        </span></span><span>Vb \</span></div></div><div><div><div>17</div></div><div><span><span>        </span></span><span>=</span><span> </span><span>se3ToVec</span><span>(</span><span>MatrixLog6</span><span>(np.</span><span>dot</span><span>(</span><span>TransInv</span><span>(</span><span>FKinBody</span><span>(M, Blist, \</span></div></div><div><div><div>18</div></div><div><span><span>                                                       </span></span><span>thetalist)), T)))</span></div></div><div><div><div>19</div></div><div><span><span>        </span></span><span>err </span><span>=</span><span> np.linalg.</span><span>norm</span><span>([Vb[</span><span>0</span><span>], Vb[</span><span>1</span><span>], Vb[</span><span>2</span><span><span>]]) </span><span>&gt;</span><span> eomg \</span></span></div></div><div><div><div>20</div></div><div><span>              </span><span>or</span><span><span> np.linalg.</span><span>norm</span><span>([Vb[</span></span><span>3</span><span>], Vb[</span><span>4</span><span>], Vb[</span><span>5</span><span><span>]]) </span><span>&gt;</span><span> ev</span></span></div></div><div><div><div>21</div></div><div><span>    </span><span>return</span><span> (thetalist, </span><span>not</span><span> err)</span></div></div><div><div><div>22</div></div><div>
</div></div><div><div><div>23</div></div><div><span>def</span><span> </span><span>IKinSpace</span><span>(</span><span>Slist</span><span>,</span><span><span> </span><span>M</span></span><span>,</span><span><span> </span><span>T</span></span><span>,</span><span><span> </span><span>thetalist0</span></span><span>,</span><span><span> </span><span>eomg</span></span><span>,</span><span><span> </span><span>ev</span></span><span>):</span></div></div><div><div><div>24</div></div><div><span>    </span><span>#Computes inverse kinematics in the space frame for an open chain robot</span></div></div><div><div><div>25</div></div><div><span><span>    </span></span><span>thetalist </span><span>=</span><span> np.</span><span>array</span><span>(thetalist0).</span><span>copy</span><span>()</span></div></div><div><div><div>26</div></div><div><span><span>    </span></span><span>i </span><span>=</span><span> </span><span>0</span></div></div><div><div><div>27</div></div><div><span><span>    </span></span><span>maxiterations </span><span>=</span><span> </span><span>20</span></div></div><div><div><div>28</div></div><div><span><span>    </span></span><span>Tsb </span><span>=</span><span> </span><span>FKinSpace</span><span>(M,Slist, thetalist)</span></div></div><div><div><div>29</div></div><div><span><span>    </span></span><span>Vs </span><span>=</span><span> np.</span><span>dot</span><span>(</span><span>Adjoint</span><span>(Tsb), \</span></div></div><div><div><div>30</div></div><div><span><span>                </span></span><span>se3ToVec</span><span>(</span><span>MatrixLog6</span><span>(np.</span><span>dot</span><span>(</span><span>TransInv</span><span>(Tsb), T))))</span></div></div><div><div><div>31</div></div><div><span><span>    </span></span><span>err </span><span>=</span><span> np.linalg.</span><span>norm</span><span>([Vs[</span><span>0</span><span>], Vs[</span><span>1</span><span>], Vs[</span><span>2</span><span><span>]]) </span><span>&gt;</span><span> eomg \</span></span></div></div><div><div><div>32</div></div><div><span>          </span><span>or</span><span><span> np.linalg.</span><span>norm</span><span>([Vs[</span></span><span>3</span><span>], Vs[</span><span>4</span><span>], Vs[</span><span>5</span><span><span>]]) </span><span>&gt;</span><span> ev</span></span></div></div><div><div><div>33</div></div><div><span>    </span><span>while</span><span> err </span><span>and</span><span><span> i </span><span>&lt;</span><span> maxiterations:</span></span></div></div><div><div><div>34</div></div><div><span><span>        </span></span><span>thetalist </span><span>=</span><span> thetalist \</span></div></div><div><div><div>35</div></div><div><span><span>                    </span></span><span>+</span><span> np.</span><span>dot</span><span>(np.linalg.</span><span>pinv</span><span>(</span><span>JacobianSpace</span><span>(Slist, \</span></div></div><div><div><div>36</div></div><div><span><span>                                                          </span></span><span>thetalist)), Vs)</span></div></div><div><div><div>37</div></div><div><span><span>        </span></span><span>i </span><span>=</span><span> i </span><span>+</span><span> </span><span>1</span></div></div><div><div><div>38</div></div><div><span><span>        </span></span><span>Tsb </span><span>=</span><span> </span><span>FKinSpace</span><span>(M, Slist, thetalist)</span></div></div><div><div><div>39</div></div><div><span><span>        </span></span><span>Vs </span><span>=</span><span> np.</span><span>dot</span><span>(</span><span>Adjoint</span><span>(Tsb), \</span></div></div><div><div><div>40</div></div><div><span><span>                    </span></span><span>se3ToVec</span><span>(</span><span>MatrixLog6</span><span>(np.</span><span>dot</span><span>(</span><span>TransInv</span><span>(Tsb), T))))</span></div></div><div><div><div>41</div></div><div><span><span>        </span></span><span>err </span><span>=</span><span> np.linalg.</span><span>norm</span><span>([Vs[</span><span>0</span><span>], Vs[</span><span>1</span><span>], Vs[</span><span>2</span><span><span>]]) </span><span>&gt;</span><span> eomg \</span></span></div></div><div><div><div>42</div></div><div><span>              </span><span>or</span><span><span> np.linalg.</span><span>norm</span><span>([Vs[</span></span><span>3</span><span>], Vs[</span><span>4</span><span>], Vs[</span><span>5</span><span><span>]]) </span><span>&gt;</span><span> ev</span></span></div></div><div><div><div>43</div></div><div><span>    </span><span>return</span><span> (thetalist, </span><span>not</span><span> err)</span></div></div><div><div><div>44</div></div><div>
</div></div><div><div><div>45</div></div><div><span><span>eomg </span><span>=</span><span> </span></span><span>0.01</span></div></div><div><div><div>46</div></div><div><span><span>ev </span><span>=</span><span> </span></span><span>0.01</span></div></div><div><div><div>47</div></div><div><span><span>initial </span><span>=</span><span> np.</span><span>array</span><span>([</span></span><span>40.050000</span><span><span>, </span><span>-</span></span><span>50.910000</span><span>, </span><span>110.140000</span><span>, </span><span>120.540000</span><span><span>, </span><span>-</span></span><span>11.390000</span><span>, </span><span>97.930000</span><span><span>])</span><span>/</span></span><span>180</span><span><span>*</span><span>math.pi</span></span></div></div><div><div><div>48</div></div><div><span><span>T </span><span>=</span><span> np.</span><span>array</span><span>([     [</span></span><span>0.410150</span><span><span>,    </span><span>-</span></span><span>0.123729</span><span><span>,    </span><span>-</span></span><span>0.903586</span><span>,  </span><span>1183.631143</span><span>] ,</span></div></div><div><div><div>49</div></div><div><span><span>                </span></span><span>[</span><span>-</span><span>0.190306</span><span><span>,    </span><span>-</span></span><span>0.980556</span><span>,     </span><span>0.047886</span><span><span>, </span><span>-</span></span><span>1137.765860</span><span>] ,</span></div></div><div><div><div>50</div></div><div><span><span>                 </span></span><span>[</span><span>-</span><span>0.891942</span><span>,     </span><span>0.152317</span><span><span>,    </span><span>-</span></span><span>0.425722</span><span>,   </span><span>756.413634</span><span> ],</span></div></div><div><div><div>51</div></div><div><span><span>                </span></span><span>[ </span><span>0.000000</span><span>,     </span><span>0.000000</span><span>,     </span><span>0.000000</span><span>,     </span><span>1.000000</span><span>] ])</span></div></div><div><div><div>52</div></div><div><span><span> </span></span><span>=</span><span> mr.</span><span>IKinSpace</span><span>(Slist,M,T,initial,eomg,ev)</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section></section><section><h2>1.4 机器人运动学<a href="#14-机器人运动学"><span>#</span></a></h2><section><h3>1.4.1 雅可比矩阵<a href="#141-雅可比矩阵"><span>#</span></a></h3><p>除了关节角度和机器人末端执行器位置之间的关系外，还需要研究关节和末端执行器速度之间的关系。在本节中，推导了这种关系的公式，并研究其结构和性质，还研究了连杆之间力传递的关系。由第2章的公式(2-5)，当给定一组关节角时，可以确定机器人末端的位置与姿态：</p><p>其中，，将公式两边进行求导，可以得到：</p><p>式中，为雅可比矩阵。</p><p>一般情况下，雅可比矩阵通过矢量差乘积法、微分变换法得到。而使用指数积公式表示正运动学，可以更加明确、优雅的推导出雅可比矩阵。在机器人正运动学的指数积公式下，末端的速度的表达式为：</p><p>带入机器人正运动学公式，并使用伴随映射将上式写成向量形式，即：</p><p>式中，对于任意，与相关联的伴随映射为:</p></section><section><h3>1.4.2 雅可比矩阵代码实现<a href="#142-雅可比矩阵代码实现"><span>#</span></a></h3><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>def</span><span> </span><span>JacobianBody</span><span>(</span><span>Blist</span><span>,</span><span><span> </span><span>thetalist</span></span><span>):</span></div></div><div><div><div>2</div></div><div><span>    </span><span>#Computes the body Jacobian for an open chain robot</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>Jb </span><span>=</span><span> np.</span><span>array</span><span>(Blist).</span><span>copy</span><span>().</span><span>astype</span><span>(np.float)</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>T </span><span>=</span><span> np.</span><span>eye</span><span>(</span><span>4</span><span>)</span></div></div><div><div><div>5</div></div><div><span>    </span><span>for</span><span> i </span><span>in</span><span> </span><span>range</span><span>(</span><span>len</span><span><span>(thetalist) </span><span>-</span><span> </span></span><span>2</span><span><span>, </span><span>-</span></span><span>1</span><span><span>, </span><span>-</span></span><span>1</span><span>):</span></div></div><div><div><div>6</div></div><div><span><span>        </span></span><span>T </span><span>=</span><span> np.</span><span>dot</span><span>(T,</span><span>MatrixExp6</span><span>(</span><span>VecTose3</span><span>(np.</span><span>array</span><span>(Blist)[:, i </span><span>+</span><span> </span><span>1</span><span>] \</span></div></div><div><div><div>7</div></div><div><span><span>                                         </span></span><span>* </span><span>-</span><span>thetalist)))</span></div></div><div><div><div>8</div></div><div><span><span>        </span></span><span>Jb[:, i] </span><span>=</span><span> np.</span><span>dot</span><span>(</span><span>Adjoint</span><span>(T), np.</span><span>array</span><span>(Blist)[:, i])</span></div></div><div><div><div>9</div></div><div><span>    </span><span>return</span><span> Jb</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>def</span><span> </span><span>JacobianSpace</span><span>(</span><span>Slist</span><span>,</span><span><span> </span><span>thetalist</span></span><span>):</span></div></div><div><div><div>12</div></div><div><span>   </span><span>#Computes the space Jacobian for an open chain robot</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>Js </span><span>=</span><span> np.</span><span>array</span><span>(Slist).</span><span>copy</span><span>().</span><span>astype</span><span>(np.float)</span></div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>T </span><span>=</span><span> np.</span><span>eye</span><span>(</span><span>4</span><span>)</span></div></div><div><div><div>15</div></div><div><span>    </span><span>for</span><span> i </span><span>in</span><span> </span><span>range</span><span>(</span><span>1</span><span>, </span><span>len</span><span>(thetalist)):</span></div></div><div><div><div>16</div></div><div><span><span>        </span></span><span>T </span><span>=</span><span> np.</span><span>dot</span><span>(T, </span><span>MatrixExp6</span><span>(</span><span>VecTose3</span><span>(np.</span><span>array</span><span>(Slist)[:, i </span><span>-</span><span> </span><span>1</span><span>] \</span></div></div><div><div><div>17</div></div><div><span><span>                                </span></span><span>* thetalist)))</span></div></div><div><div><div>18</div></div><div><span><span>        </span></span><span>Js[:, i] </span><span>=</span><span> np.</span><span>dot</span><span>(</span><span>Adjoint</span><span>(T), np.</span><span>array</span><span>(Slist)[:, i])</span></div></div><div><div><div>19</div></div><div><span>    </span><span>return</span><span> Js</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section><section><h2>1.5 涉及的函数说明<a href="#15-涉及的函数说明"><span>#</span></a></h2><section><h3>1.5.1 空间变换与齐次矩阵<a href="#151-空间变换与齐次矩阵"><span>#</span></a></h3><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>1.</span><span>计算旋转矩阵的逆</span></div></div><div><div><div>2</div></div><div><span><span>invR </span><span>=</span><span> </span><span>RotInv</span><span>(R)</span></span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span>2.</span><span><span>将三维向量转换为3</span><span>*</span></span><span>3反对称矩阵</span></div></div><div><div><div>5</div></div><div><span><span>so3mat </span><span>=</span><span> </span><span>VecToso3</span><span>(omg)</span></span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>3.</span><span><span>将3</span><span>*</span></span><span>3反对称矩阵转换为三维向量</span></div></div><div><div><div>8</div></div><div><span><span>omg </span><span>=</span><span> </span><span>so3ToVec</span><span>(so3mat)</span></span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span>4.</span><span>从旋转的三维指数坐标中提取出轴线和角度</span></div></div><div><div><div>11</div></div><div><span><span> </span></span><span>=</span><span> </span><span>AxisAng3</span><span>(expc3)</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>5.</span><span>计算矩阵指数对应的旋转矩阵</span></div></div><div><div><div>14</div></div><div><span><span>R </span><span>=</span><span> </span><span>MatrixExp3</span><span>(so3mat)</span></span></div></div><div><div><div>15</div></div><div>
</div></div><div><div><div>16</div></div><div><span>6.</span><span>计算旋转矩阵对应的矩阵对数</span></div></div><div><div><div>17</div></div><div><span><span>so3mat </span><span>=</span><span> </span><span>MatrixLog3</span><span>(R)</span></span></div></div><div><div><div>18</div></div><div>
</div></div><div><div><div>19</div></div><div><span>7.</span><span>M到SO（</span><span>3</span><span>）旋转矩阵的空间距离的度量</span></div></div><div><div><div>20</div></div><div><span><span>d </span><span>=</span><span> </span><span>DistanceToSO3</span><span>(mat)</span></span></div></div><div><div><div>21</div></div><div>
</div></div><div><div><div>22</div></div><div><span>8.</span><span>判断M是否为旋转矩阵</span></div></div><div><div><div>23</div></div><div><span><span>judge </span><span>=</span><span> </span><span>TestIfSO3</span><span>(mat)</span></span></div></div><div><div><div>24</div></div><div>
</div></div><div><div><div>25</div></div><div><span>9.</span><span>返回与M最近的旋转矩阵</span></div></div><div><div><div>26</div></div><div><span><span>R </span><span>=</span><span> </span><span>ProjectToSO3</span><span>(mat)</span></span></div></div><div><div><div>27</div></div><div>
</div></div><div><div><div>28</div></div><div><span>10.</span><span>将旋转矩阵和位置向量转换为变换矩阵</span></div></div><div><div><div>29</div></div><div><span><span>T </span><span>=</span><span> </span><span>RpToTrans</span><span>(R,p)</span></span></div></div><div><div><div>30</div></div><div>
</div></div><div><div><div>31</div></div><div><span>11.</span><span>从变换矩阵中分离出旋转矩阵和位置向量</span></div></div><div><div><div>32</div></div><div><span><span>[R,p] </span><span>=</span><span> </span><span>TransToRp</span><span>(T)</span></span></div></div><div><div><div>33</div></div><div>
</div></div><div><div><div>34</div></div><div><span>12.</span><span>变换矩阵求逆</span></div></div><div><div><div>35</div></div><div><span><span>invT </span><span>=</span><span> </span><span>TransInv</span><span>(T)</span></span></div></div><div><div><div>36</div></div><div>
</div></div><div><div><div>37</div></div><div><span>13.</span><span>构造与六维向量形式的运动旋量V对应的</span></div></div><div><div><div>38</div></div><div><span><span>se3mat </span><span>=</span><span> </span><span>VecTose3</span><span>(V)</span></span></div></div><div><div><div>39</div></div><div>
</div></div><div><div><div>40</div></div><div><span>14.</span><span><span>构造与se</span><span>(</span></span><span>3</span><span>)矩阵对应的六维向量形式的运动旋量V</span></div></div><div><div><div>41</div></div><div><span><span>V </span><span>=</span><span> </span><span>se3ToVec</span><span>(se3mat)</span></span></div></div><div><div><div>42</div></div><div>
</div></div><div><div><div>43</div></div><div><span>15.</span><span><span>计算变换矩阵T的6</span><span>*</span></span><span>6的伴随矩阵</span></div></div><div><div><div>44</div></div><div><span><span>AdT </span><span>=</span><span> </span><span>Adjoint</span><span>(T)</span></span></div></div><div><div><div>45</div></div><div>
</div></div><div><div><div>46</div></div><div><span>16.</span><span>返回正则化的螺旋轴表达式</span></div></div><div><div><div>47</div></div><div><span><span>S </span><span>=</span><span> </span><span>ScrewToAxis</span><span>(q,s,h)</span></span></div></div><div><div><div>48</div></div><div>
</div></div><div><div><div>49</div></div><div><span>17.</span><span>从六位向量形式的指数坐标中提取出螺旋轴和沿轴线移动的距离</span></div></div><div><div><div>50</div></div><div><span><span>[S,theta] </span><span>=</span><span> </span><span>AxisAng6</span><span>(expc6)</span></span></div></div><div><div><div>51</div></div><div>
</div></div><div><div><div>52</div></div><div><span>18.</span><span>计算矩阵指数对应的变换矩阵</span></div></div><div><div><div>53</div></div><div><span><span>T </span><span>=</span><span> </span><span>MatrixExp6</span><span>(se3mat)</span></span></div></div><div><div><div>54</div></div><div>
</div></div><div><div><div>55</div></div><div><span>19.</span><span>计算变换矩阵对应的矩阵对数</span></div></div><div><div><div>56</div></div><div><span><span>se3mat </span><span>=</span><span> </span><span>MatrixLog6</span><span>(T)</span></span></div></div><div><div><div>57</div></div><div>
</div></div><div><div><div>58</div></div><div><span>20.</span><span>M到变换矩阵的空间距离</span></div></div><div><div><div>59</div></div><div><span><span>d </span><span>=</span><span> </span><span>DistanceToSE3</span><span>(mat)</span></span></div></div><div><div><div>60</div></div><div>
</div></div><div><div><div>61</div></div><div><span>21.</span><span>判断是否为SE3变换矩阵</span></div></div><div><div><div>62</div></div><div><span><span>judge </span><span>=</span><span> </span><span>TestIfSE3</span><span>(mat)</span></span></div></div><div><div><div>63</div></div><div>
</div></div><div><div><div>64</div></div><div><span>22.</span><span>离M最近的变换矩阵</span></div></div><div><div><div>65</div></div><div><span><span>T </span><span>=</span><span> </span><span>ProjectToSE3</span><span>(mat)</span></span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h3>1.5.2 运动学<a href="#152-运动学"><span>#</span></a></h3><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>#正运动学</span></div></div><div><div><div>2</div></div><div><span>末端坐标系下。给定初始形位，关节旋量以及关节值，计算末端坐标系</span></div></div><div><div><div>3</div></div><div><span><span>T </span><span>=</span><span> </span><span>FKinBody</span><span>(M,Blist,thetalist)</span></span></div></div><div><div><div>4</div></div><div><span>空间坐标系下。给定初始形位，关节旋量以及关节值，计算末端坐标系</span></div></div><div><div><div>5</div></div><div><span><span>T </span><span>=</span><span> </span><span>FKinSpace</span><span>(M,Slist,thetalist)</span></span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>#雅可比矩阵</span></div></div><div><div><div>8</div></div><div><span>给定物体坐标系下描述的各关节旋量Blist及关节角，计算物体雅可比JB</span></div></div><div><div><div>9</div></div><div><span><span>Jb</span><span>=</span><span>JacobianBody</span><span>(Blist,thetalist)</span></span></div></div><div><div><div>10</div></div><div><span>给定物体坐标系下描述的各关节旋量Slist及关节角，计算物体雅可比Js</span></div></div><div><div><div>11</div></div><div><span><span>J</span><span>=</span><span>JacobianSpace</span><span>(Slist,thetalist)</span></span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>#逆运动学</span></div></div><div><div><div>14</div></div><div><span>［theta11st,success］＝IKinBody（B1ist,M,T,theta1ist,eomg,ev）</span></div></div><div><div><div>15</div></div><div><span>［theta11st,success］＝IKinSpace（B1ist,M,T,theta1ist,eomg,ev）</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section><section><h2>1.6 参考链接<a href="#16-参考链接"><span>#</span></a></h2><p>机器人POE运动学代码网址：<a href="https://github.com/NxRLab/ModernRobotics" target="_blank">NxRLab/ModernRobotics: Modern Robotics: Mechanics, Planning, and Control Code Library --- The primary purpose of the provided software is to be easy to read and educational, reinforcing the concepts in the book. The code is optimized neither for efficiency nor robustness. (github.com)</a></p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/427/</id>
      <title type="text">导航页搭建</title>
      <published>2023-06-01T13:18:16.000Z</published>
      <updated>2024-06-06T04:28:50.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/427/"/>
      <summary type="text">这两天一直在折腾个人主页，在GitHub上找了不少的开源项目，最后选择了imsyy大佬的项目，大佬的界面非常简约和美观，非常适合做个人导航页。我也是化成CV工程师直接照搬了，hhh 主页搭建 我是在宝塔上进行搭建的，对于我这种不怎么懂代码的</summary>
      <content type="html"><![CDATA[<p>这两天一直在折腾个人主页，在GitHub上找了不少的开源项目，最后选择了<a href="https://github.com/imsyy" target="_blank">imsyy</a>大佬的项目，大佬的界面非常简约和美观，非常适合做个人导航页。我也是化成CV工程师直接照搬了，hhh</p>
<section><h3>主页搭建<a href="#主页搭建"><span>#</span></a></h3><p>我是在宝塔上进行搭建的，对于我这种不怎么懂代码的人来说，宝塔提供了不少自动化工具，省去了不少环境配置的功夫。</p><blockquote><p>环境配置起来是真的折磨，还是别人的一键脚本香。</p></blockquote><p>项目地址：<a href="https://github.com/imsyy/home" target="_blank">imsyy/home: 个人主页，我的个人主页，个人主页源码，主页模板，homepage (github.com)</a></p><p>搭建后的整体效果大概是这样</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306011705834.png" alt="image-20230601170508138" /><figcaption>image-20230601170508138</figcaption></figure><p></p><section><h4>1、部署环境<a href="#1部署环境"><span>#</span></a></h4><p>在安装宝塔的时候，一般都会自动安装好<code>LNMP(Linux+NGINX+MySQL+PHP)</code>环境，如果版本不同，也可以在宝塔的应用商店里进行安装。</p><img src="http://imgbed.leihub.cn/img/202306011805949.png" alt="image-20230601180528769" /><p>接下来就是安装node环境，这一步可以使用宝塔上的<code>node.js版本管理器</code>应用进行安装，</p><blockquote><p>node &gt; 16.16.0</p><p>npm &gt; 8.15.0</p></blockquote><blockquote><p>最好安装最新的稳定版</p><p>如果在列表中没有看到最近的版本，可以更新一下版本列表。</p><p>有时候命令行的node不是所需的版本，记得在箭头所指的命令行版本处进行选择。</p></blockquote><p>在安装node的时候，会一起把<code>yarn</code>、<code>npm</code>、<code>pm2</code>等模块也一起安装好</p><img src="http://imgbed.leihub.cn/img/202306011809185.png" alt="image-20230601180900976" /></section><section><h4>2、创建网页<a href="#2创建网页"><span>#</span></a></h4><p>在宝塔左侧边栏的<code>网页</code>应用中，点击<code>添加站点</code>创建网页应用。需要一个域名指向服务器的<code>ip地址</code>，<code>备注</code>可以随便填，根目录表示网页文件存储的位置，到时候我们的导航页文件就要放在这个文件夹中。后面的<code>PHP、数据库</code>等选项可以 保持默认，但是版本最好不要太低。</p><img src="http://imgbed.leihub.cn/img/202306011848922.png" alt="image-20230601184842793" /></section><section><h4>3、下载导航页安装包<a href="#3下载导航页安装包"><span>#</span></a></h4><p>下载安装包有两种选择，一种是利用ssh进行操作，另一种是下载安装包通过宝塔面板进行上传。</p><ul>
<li>
<p>接下来，我通过ssh进行安装，首先复制仓库地址</p>
<img src="http://imgbed.leihub.cn/img/202306011905501.png" alt="image-20230601190506440" />
</li>
<li>
<p>切换目录到上面创建的网页文件夹中,使用<code>git clone</code>指令下载安装包</p>
<blockquote><p>现在国内的服务器连接github都很不稳定，可以通过使用代理来加速下载，使用上一篇博客中搭建的代理进行加速</p></blockquote>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>cd</span><span> </span><span>/www/wwwroot/test</span></div></div><div><div><div>2</div></div><div><span>$</span><span> </span><span>git</span><span> </span><span>clone</span><span> </span><span>https://github.com/imsyy/home.git</span><span>  </span><span>#不使用代理</span></div></div><div><div><div>3</div></div><div><span>$</span><span> </span><span>git</span><span> </span><span>clone</span><span> </span><span>https://github.leitingtool.cf/https://github.com/imsyy/home.git</span><span> </span><span>#使用自建代理</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
</li>
</ul><img src="http://imgbed.leihub.cn/img/202306011920315.png" alt="image-20230601192021269" /></section><section><h4>4、安装导航页<a href="#4安装导航页"><span>#</span></a></h4><p>将下载的<code>home文件夹</code>中的文件复制到网站根目录下（即<code>test文件夹</code>）</p><ul>
<li>
<p>在<code>网站根目录</code>下安装依赖  <code>yarn install</code></p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>yarn</span><span> </span><span>install</span></div></div><div><div><div>2</div></div><div><span>#如果未安装yarn，需要先执行 npm install yarn -g</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
<p></p><figure><img src="http://imgbed.leihub.cn/img/202306011939546.png" alt="image-20230601193937469" /><figcaption>image-20230601193937469</figcaption></figure><p></p>
</li>
<li>
<p>执行<code>yarn build</code>，将网站文件进行打包，打包后的文件默认在<code>dist</code>目录中,</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>yarn</span><span> </span><span>build</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div>
<p></p><figure><img src="http://imgbed.leihub.cn/img/202306011940260.png" alt="image-20230601194036193" /><figcaption>image-20230601194036193</figcaption></figure><p></p>
<blockquote><p>这一步容易因为服务器内存不足而报错，请保证服务器内存充足时重试或者在本地计算机进行打包后再上传至服务器</p></blockquote>
</li>
<li>
<p>构建完成后，就可以前往宝塔的网站设置页面，将网站目录设置到<code>dist</code>文件夹，即可访问站点了</p>
<img src="http://imgbed.leihub.cn/img/202306011944850.png" alt="image-20230601194420718" />
</li>
</ul></section><section><h4>5、更新<a href="#5更新"><span>#</span></a></h4><p>后续如果对网站文件进行改动，只需<code>yarn build</code> 重新对网站文件进行打包，即可实现更新。</p></section></section>
<section><h3>主页文件修改<a href="#主页文件修改"><span>#</span></a></h3><p>在网页根目录下的<code>.env</code>文件中进行修改，即可对网站进行调整。</p><section><h4>1、自定义站点名称对界面进行调整<a href="#1自定义站点名称对界面进行调整"><span>#</span></a></h4><img src="http://imgbed.leihub.cn/img/202306011955574.png" alt="image-20230601195545446" /></section><section><h4>2、设置天气API<a href="#2设置天气api"><span>#</span></a></h4><p>天气及地区获取需要 <code>高德开放平台</code> 相关 API</p><ul>
<li>
<p>前往 <a href="https://console.amap.com/dev/index" target="_blank">高德开放平台控制台</a> 创建一个 <code>Web 服务</code> 类型的 <code>Key</code>，并将 <code>Key</code> 填入 <code>.env</code> 中的 <code>VITE_WEATHER_KEY</code> 中。</p>
</li>
<li>
<p>高德开放平台 - 应用管理 - 我的应用 - 创建新应用 - web服务</p>
<blockquote><p>记得是web服务，不是web端，我当时就搞错了</p></blockquote>
<img src="http://imgbed.leihub.cn/img/202306012003371.png" alt="image-20230601200304229" />
</li>
</ul></section><section><h4>3、歌曲API<a href="#3歌曲api"><span>#</span></a></h4><p>参照 <a href="https://github.com/xizeyoupan/Meting-API#deno-deploy" target="_blank">https://github.com/xizeyoupan/Meting-API#deno-deploy</a> 进行 API 服务部署</p><p>我使用的方法是部署到<code>Vercel  </code>,<code>Vercel </code>是一个免费的代码托管网站，还能与<code>github</code>进行协同，大佬们的开源项目直接<code>fork</code>过来，可以直接一键部署到<code>Vercel </code>，而且每次对仓库的修改都会实时重新部署到<code>Vercel </code>，实在是懒人的福音。</p><ul>
<li>
<p>首先将<code>Vercel </code>和<code>github</code>进行绑定</p>
</li>
<li>
<p>将<a href="https://github.com/xizeyoupan/Meting-API#deno-deploy" target="_blank">Meting-API</a>仓库fork到自己仓库</p>
</li>
<li>
<p>到<code>Vercel </code>界面，Add New - Project，选择import自己相应的仓库</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/202306012016025.png" alt="image-20230601201608507" /><figcaption>image-20230601201608507</figcaption></figure><p></p>
</li>
<li>
<p>修改 <code>Project Name</code>后就可以点击<code>Deploy</code>进行部署</p>
</li>
</ul><p></p><figure><img src="http://imgbed.leihub.cn/img/202306012018173.png" alt="image-20230601201802072" /><figcaption>image-20230601201802072</figcaption></figure><p></p><ul>
<li>
<p><code>Vercel </code>官方提供的域名被阻断，可以绑定自定义域名，即可实现国内访问。</p>
<p>在需要绑定的域名解析中添加Vercel 所需的CNAME记录，便可将子域名和Vercel 绑定，而且还可以自动帮你申请域名的ssl证书</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/202306012023305.png" alt="image-20230601202321205" /><figcaption>image-20230601202321205</figcaption></figure><p></p>
</li>
<li>
<p>通过定义的子域名即可实现国内访问，访问网页显示如图所示就表示部署成功。</p>
</li>
<li>
<p>将<code>https://域名/api</code>填入<code>.env</code>的<code>VITE_SONG_API</code>中即可。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/202306012025104.png" alt="image-20230601202549070" /><figcaption>image-20230601202549070</figcaption></figure><p></p>
</li>
</ul><div><div><div><figure><figcaption><span></span><span>Terminal window</span><span>展开</span><span>收起</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 站点名称</span></div></div><div><div><div>2</div></div><div><span>VITE_SITE_NAME</span><span> </span><span>=</span><span> </span><span>"阿雷の主页"</span></div></div><div><div><div>3</div></div><div><span>VITE_SITE_ANTHOR</span><span> </span><span>=</span><span> </span><span>"阿雷"</span></div></div><div><div><div>4</div></div><div><span>VITE_SITE_KEYWORDS</span><span> </span><span>=</span><span> </span><span>"阿雷,个人主页"</span></div></div><div><div><div>5</div></div><div><span>VITE_SITE_DES</span><span> </span><span>=</span><span> </span><span>"一个默默无闻的主页"</span></div></div><div><div><div>6</div></div><div><span>VITE_SITE_URL</span><span> </span><span>=</span><span> </span><span>"leiting2020.top"</span></div></div><div><div><div>7</div></div><div><span>VITE_SITE_LOGO</span><span> </span><span>=</span><span> </span><span>"/images/icon/logo.png"</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span># 百度统计（若不需要可不填）</span></div></div><div><div><div>10</div></div><div><span>VITE_SITE_BAIDUTONGJI</span><span> </span><span>=</span><span> </span><span>"14e9f35ff8bc67fd4bcb5f07a6e6655a"</span></div></div><div><div><div>11</div></div><div>
</div></div><div><div><div>12</div></div><div><span># 简介文本</span></div></div><div><div><div>13</div></div><div><span>VITE_DESC_HELLO</span><span> </span><span>=</span><span> </span><span>"Hello World !"</span></div></div><div><div><div>14</div></div><div><span>VITE_DESC_TEXT</span><span> </span><span>=</span><span> </span><span>"一个建立于 21 世纪的小站，存活于互联网的边缘"</span></div></div><div><div><div>15</div></div><div><span>VITE_DESC_HELLO_OTHER</span><span> </span><span>=</span><span> </span><span>"Oops !"</span></div></div><div><div><div>16</div></div><div><span>VITE_DESC_TEXT_OTHER</span><span> </span><span>=</span><span> </span><span>"哎呀，这都被你发现了（ 再点击一次可关闭 ）"</span></div></div><div><div><div>17</div></div><div>
</div></div><div><div><div>18</div></div><div><span># 社交链接</span></div></div><div><div><div>19</div></div><div><span>## 请在 public 目录下的 socialLinks.json 文件中配置</span></div></div><div><div><div>20</div></div><div>
</div></div><div><div><div>21</div></div><div><span># 网站链接</span></div></div><div><div><div>22</div></div><div><span>## 请在 src/components/Links/index.vue 文件中配置</span></div></div><div><div><div>23</div></div><div>
</div></div><div><div><div>24</div></div><div><span># 天气 Key</span></div></div><div><div><div>25</div></div><div><span>## 请前往高德开放平台注册 Web服务 Key（免费的）</span></div></div><div><div><div>26</div></div><div><span>## 请各位大佬行行好，别再让我超量了</span></div></div><div><div><div>27</div></div><div><span>VITE_WEATHER_KEY</span><span> </span><span>=</span><span> </span><span>"0d8df746afc98c95ec709073c69dc22e"</span></div></div><div><div><div>28</div></div><div>
</div></div><div><div><div>29</div></div><div><span># 建站日期</span></div></div><div><div><div>30</div></div><div><span>## 请按照 YYYY-MM-DD 格式填写</span></div></div><div><div><div>31</div></div><div><span>VITE_SITE_START</span><span> </span><span>=</span><span> </span><span>"2023-5-28"</span></div></div><div><div><div>32</div></div><div>
</div></div><div><div><div>33</div></div><div><span># 歌曲 API 地址</span></div></div><div><div><div>34</div></div><div><span>## 请参照 https://github.com/xizeyoupan/Meting-API#deno-deploy 进行 API 服务部署</span></div></div><div><div><div>35</div></div><div><span>## 此处提供的服务可能会超量从而无法访问，请自行部署</span></div></div><div><div><div>36</div></div><div><span>## 若使用QQ音乐歌单，歌曲数量最好不要超出50首</span></div></div><div><div><div>37</div></div><div><span>## 备用：https://api.wuenci.com/meting/api/</span></div></div><div><div><div>38</div></div><div><span>VITE_SONG_API</span><span> </span><span>=</span><span> </span><span>"https://api-meting.leitingtool.cf/api"</span></div></div><div><div><div>39</div></div><div><span># 歌曲服务器 ( netease-网易云, tencent-qq音乐 )</span></div></div><div><div><div>40</div></div><div><span>VITE_SONG_SERVER</span><span> </span><span>=</span><span> </span><span>"netease"</span></div></div><div><div><div>41</div></div><div><span># 播放类型 ( song-歌曲, playlist-播放列表, album-专辑, search-搜索, artist-艺术家 )</span></div></div><div><div><div>42</div></div><div><span>VITE_SONG_TYPE</span><span> </span><span>=</span><span> </span><span>"playlist"</span></div></div><div><div><div>43</div></div><div><span># 播放 ID</span></div></div><div><div><div>44</div></div><div><span>VITE_SONG_ID</span><span> </span><span>=</span><span> </span><span>"8440101601"</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h4>4、页脚信息<a href="#4页脚信息"><span>#</span></a></h4><p>页脚的网站和备案信息在网站根目录下的<code>./src/components/Footer/index.vue</code>中进行修改</p></section><section><h4>5、导航网站链接<a href="#5导航网站链接"><span>#</span></a></h4><p>导航的网站列表在网站根目录下的<code>./src/components/Links/index.vue</code>中进行修改</p></section><section><h4>6、社交链接<a href="#6社交链接"><span>#</span></a></h4><p>社交链接的配置文件在网站根目录下<code>./public/socialLinks.json</code>中。</p></section></section>
<section><h3>SPlayer音乐播放器<a href="#splayer音乐播放器"><span>#</span></a></h3><section><h4>1、SPlayer搭建<a href="#1splayer搭建"><span>#</span></a></h4><blockquote><p>Vercel  等托管平台可在 Fork 后一键导入并自动部署，并绑定好自己的域名</p></blockquote><p>Vercel部署地址：<a href="https://music.leitingtool.cf/" target="_blank">SPlayer (leitingtool.cf)</a></p><p>也可以通过node进行安装</p><p>SPlayer项目地址：<a href="https://github.com/imsyy/SPlayer" target="_blank">imsyy/SPlayer: 🎉 一个简约的在线音乐播放器，支持网易云音乐账号登录，逐字歌词，下载歌曲，展示评论区，音乐频谱，音乐云盘及歌单管理，移动端基础适配 (github.com)</a></p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>yarn</span><span> </span><span>install</span></div></div><div><div><div>2</div></div><div><span>yarn</span><span> </span><span>build</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>构建完成后可将生成的 <code>dist</code> 文件夹内的文件上传至服务器</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306012056341.png" alt="image-20230601205147355" /><figcaption>image-20230601205147355</figcaption></figure><p></p></section><section><h4>2、API 服务（必需）<a href="#2api-服务必需"><span>#</span></a></h4><blockquote><p>SPlayer依赖 <a href="https://github.com/Binaryify/NeteaseCloudMusicApi" target="_blank">NeteaseCloudMusicApi</a> 运行，请确保您已成功部署该项目</p></blockquote><p>NeteaseCloudMusicApi项目地址：<a href="https://github.com/Binaryify/NeteaseCloudMusicApi" target="_blank">Binaryify/NeteaseCloudMusicApi: 网易云音乐 Node.js API service (github.com)</a></p><p>Vercel 部署地址：<a href="https://music-api.leitingtool.cf/" target="_blank">网易云音乐 API (leitingtool.cf)</a></p><section><h5>Vercel 部署<a href="#vercel-部署"><span>#</span></a></h5><ol>
<li>fork 此项目</li>
<li>在 Vercel 官网点击 <code>New Project</code></li>
<li>点击 <code>Import Git Repository</code> 并选择你 fork 的此项目并点击<code>import</code></li>
<li>点击 <code>PERSONAL ACCOUNT</code> 的 <code>select</code></li>
<li>直接点<code>Continue</code></li>
<li><code>PROJECT NAME</code>自己填,<code>FRAMEWORK PRESET</code> 选 <code>Other</code> 然后直接点 <code>Deploy</code> 接着等部署完成</li>
<li>绑定自定义域名即可</li>
</ol><p>部署成功后，网站如图所示</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306012105609.png" alt="image-20230601210542549" /><figcaption>image-20230601210542549</figcaption></figure><p></p></section></section><section><h4>3、配置<a href="#3配置"><span>#</span></a></h4><p>在根目录下的 <code>.env</code> 文件中的 <code>VITE_MUSIC_API</code> 中填入 API 地址（必需）</p><div><div><div><figure><figcaption><span></span><span>Terminal window</span><span>展开</span><span>收起</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 全局 API 地址</span></div></div><div><div><div>2</div></div><div><span>## 需部署 API，详见 https://github.com/Binaryify/NeteaseCloudMusicApi</span></div></div><div><div><div>3</div></div><div><span>VITE_MUSIC_API</span><span> </span><span>=</span><span> </span><span>"https://music-api.leitingtool.cf"</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span># 网易云解灰 API 地址（可选功能）</span></div></div><div><div><div>6</div></div><div><span>## 需部署 API，详见 https://github.com/imsyy/UNM-Server#%E8%BF%90%E8%A1%8C</span></div></div><div><div><div>7</div></div><div><span>VITE_UNM_API</span><span> </span><span>=</span><span> </span><span>"https://api-unm.imsyy.top/"</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span># 站点标题</span></div></div><div><div><div>10</div></div><div><span>VITE_SITE_TITLE</span><span> </span><span>=</span><span> </span><span>"SPlayer"</span></div></div><div><div><div>11</div></div><div><span>VITE_SITE_ANTHOR</span><span> </span><span>=</span><span> </span><span>"阿雷"</span></div></div><div><div><div>12</div></div><div><span>VITE_SITE_KEYWORDS</span><span> </span><span>=</span><span> </span><span>"SPlayer,云音乐,播放器,在线音乐,在线播放器,音乐播放器,在线音乐播放器"</span></div></div><div><div><div>13</div></div><div><span>VITE_SITE_DES</span><span> </span><span>=</span><span> </span><span>"一个简约的在线音乐播放器，具有音乐搜索、播放、每日推荐、私人FM、歌词显示、歌曲评论、网易云登录与云盘等功能"</span></div></div><div><div><div>14</div></div><div><span>VITE_SITE_URL</span><span> </span><span>=</span><span> </span><span>"leiting2020.top"</span></div></div><div><div><div>15</div></div><div><span>VITE_SITE_LOGO</span><span> </span><span>=</span><span> </span><span>"/images/logo/favicon.svg"</span></div></div><div><div><div>16</div></div><div>
</div></div><div><div><div>17</div></div><div><span># 百度统计（若不需要，请设为空即可）</span></div></div><div><div><div>18</div></div><div><span>VITE_SITE_BAIDUTONGJI</span><span> </span><span>=</span><span> </span><span>"c6579e9a33cbc5260fc90231678556ec"</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span># ICP 备案号</span></div></div><div><div><div>21</div></div><div><span>## 若不需要，请设为空即可</span></div></div><div><div><div>22</div></div><div><span>VITE_ICP</span><span> </span><span>=</span><span> </span><span>"湘ICP备2021004011号-1"</span></div></div><div><div><div>23</div></div><div>
</div></div><div><div><div>24</div></div><div><span># 公告配置</span></div></div><div><div><div>25</div></div><div><span>## 若无需公告，请将任意一项设为空即可</span></div></div><div><div><div>26</div></div><div><span>## 公告标题</span></div></div><div><div><div>27</div></div><div><span>VITE_ANN_TITLE</span><span> </span><span>=</span><span> </span><span>""</span></div></div><div><div><div>28</div></div><div><span>## 公告内容</span></div></div><div><div><div>29</div></div><div><span>VITE_ANN_CONTENT</span><span> </span><span>=</span><span> </span><span>""</span></div></div><div><div><div>30</div></div><div><span>## 公告时长（毫秒）不可超过 999999</span></div></div><div><div><div>31</div></div><div><span>VITE_ANN_DURATION</span><span> </span><span>=</span><span> </span><span>3000</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section>
<section><h3>起始页<a href="#起始页"><span>#</span></a></h3><p>项目地址：<a href="https://github.com/imsyy/Snavigation" target="_blank">imsyy/Snavigation: 【待重构】Snavigation 一个简约的起始页 | 支持自定义搜索引擎，自定义快捷方式，自定义壁纸以及数据备份 (github.com)</a></p><p>直接在宝塔中创建网站，将项目文件git clone到网站根目录下即可。</p><blockquote><p>目前还未对界面配置进行修改</p></blockquote><p>起始页网址：<a href="https://nav.leiting2020.top/" target="_blank">Snavigation</a></p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306012114208.png" alt="image-20230601211401563" /><figcaption>image-20230601211401563</figcaption></figure><p></p></section>
<section><h3>网址集<a href="#网址集"><span>#</span></a></h3><p>项目地址：<a href="https://github.com/imsyy/OneNav" target="_blank">imsyy/OneNav: OneNav 一个网址导航 | 基于 WebStackPage (github.com)</a></p><p>直接在宝塔中创建网站，将项目文件git clone到网站根目录下即可。</p><blockquote><p>目前还未对界面配置进行修改</p></blockquote><p>起始页网址：[<a href="https://web.leiting2020.top/" target="_blank">一个导航 - OneNav</a>](<a href="https://nav.leiting2020.top/" target="_blank">https://nav.leiting2020.top/</a>)</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306012117967.png" alt="image-20230601211720826" /><figcaption>image-20230601211720826</figcaption></figure><p></p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/416/</id>
      <title type="text">使用Cloudflare自建github代理</title>
      <published>2023-06-01T06:26:01.000Z</published>
      <updated>2025-11-14T15:22:02.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/416/"/>
      <summary type="text">通过cloudflare进行自建代理，部署简单并且可以完全白嫖，但是缺点就是Workers子域名已经被国内墙了，需要绑定自定义域名才可以实现国内访问。 域名购买可以在腾讯云、阿里云等厂商购买，像是.top等后缀的域名价格十分便宜，一年在30</summary>
      <content type="html"><![CDATA[<p>通过cloudflare进行自建代理，部署简单并且可以完全白嫖，但是缺点就是Workers子域名已经被国内墙了，需要绑定自定义域名才可以实现国内访问。</p>
<p>域名购买可以在腾讯云、阿里云等厂商购买，像是.top等后缀的域名价格十分便宜，一年在30块左右。如果不想花钱也可以去<a href="https://www.freenom.com/" target="_blank">freenom</a>白嫖域名，freenom提供了一些冷门国家的域名给用户免费使用一年，但是可以不断续约下去。</p>
<p>可以在freenom白嫖域名后，可以挂在cloudflare进行DNS解析，还免费提供cdn服务，后续部署代理也更加方便。</p>
<section><h3>注册 Cloudflare<a href="#注册-cloudflare"><span>#</span></a></h3><p><a href="https://dash.cloudflare.com/sign-up" target="_blank">https://dash.cloudflare.com/sign-up</a></p><p>如果已有账号则忽略该步骤，直接进行下一步（可能部分地区官网访问较慢，注册账号需要邮件验证）</p></section>
<section><h3>创建Workers<a href="#创建workers"><span>#</span></a></h3><p>1、进入cloudflare面板，点击Worker概述进入图示界面，选择创建应用程序</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306011352039.png" alt="image-20230601135253949" /><figcaption>image-20230601135253949</figcaption></figure><p></p><p>2、将名称改为git或者github等自己容易辨别的名字，点击部署即可。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306011359990.png" alt="image-20230601135931865" /><figcaption>image-20230601135931865</figcaption></figure><p></p><p>3、创建应用程序后，进入快速编辑</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306011401727.png" alt="image-20230601140146588" /><figcaption>image-20230601140146588</figcaption></figure><p></p><p>4、复制以下代码，覆盖掉上图中1所示的默认内容</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>'use strict'</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>/**</span></div></div><div><div><div>4</div></div><div><span><span> </span></span><span>* static files (404.html, sw.js, conf.js)</span></div></div><div><div><div>5</div></div><div><span><span> </span></span><span>*/</span></div></div><div><div><div>6</div></div><div><span>const</span><span> </span><span>ASSET_URL</span><span> </span><span>=</span><span> </span><span>'https://github.com/'</span></div></div><div><div><div>7</div></div><div><span>// 前缀，如果自定义路由为example.com/gh/*，将PREFIX改为 '/gh/'，注意，少一个杠都会错！</span></div></div><div><div><div>8</div></div><div><span>const</span><span> </span><span>PREFIX</span><span> </span><span>=</span><span> </span><span>'/'</span></div></div><div><div><div>9</div></div><div><span>const</span><span> </span><span>Config</span><span> </span><span>=</span><span> {</span></div></div><div><div><div>10</div></div><div><span>    </span><span>jsdelivr</span><span>:</span><span> </span><span>0</span><span>,</span></div></div><div><div><div>11</div></div><div><span>    </span><span>cnpmjs</span><span>:</span><span> </span><span>0</span></div></div><div><div><div>12</div></div><div><span>}</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span>/** </span><span>@</span><span>type</span><span> </span><span>{RequestInit}</span><span> */</span></div></div><div><div><div>15</div></div><div><span>const</span><span> </span><span>PREFLIGHT_INIT</span><span> </span><span>=</span><span> {</span></div></div><div><div><div>16</div></div><div><span>    </span><span>status</span><span>:</span><span> </span><span>204</span><span>,</span></div></div><div><div><div>17</div></div><div><span>    </span><span>headers</span><span>:</span><span> </span><span>new</span><span> </span><span>Headers</span><span>({</span></div></div><div><div><div>18</div></div><div><span>        </span><span>'access-control-allow-origin'</span><span>:</span><span> </span><span>'*'</span><span>,</span></div></div><div><div><div>19</div></div><div><span>        </span><span>'access-control-allow-methods'</span><span>:</span><span> </span><span>'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS'</span><span>,</span></div></div><div><div><div>20</div></div><div><span>        </span><span>'access-control-max-age'</span><span>:</span><span> </span><span>'1728000'</span><span>,</span></div></div><div><div><div>21</div></div><div><span><span>    </span></span><span>}),</span></div></div><div><div><div>22</div></div><div><span>}</span></div></div><div><div><div>23</div></div><div>
</div></div><div><div><div>24</div></div><div><span>const</span><span> </span><span>exp1</span><span> </span><span>=</span><span> /</span><span>^</span><span><span>(?:https</span><span>?</span><span>:</span><span>\/\/</span><span>)</span><span>?</span><span>github</span><span>\.</span><span>com</span><span>\/</span></span><span>.</span><span><span>+?</span><span>\/</span></span><span>.</span><span><span>+?</span><span>\/</span><span>(?:releases</span><span>|</span><span>archive)</span><span>\/</span></span><span>.</span><span>*</span><span>$</span><span>/</span><span>i</span></div></div><div><div><div>25</div></div><div><span>const</span><span> </span><span>exp2</span><span> </span><span>=</span><span> /</span><span>^</span><span><span>(?:https</span><span>?</span><span>:</span><span>\/\/</span><span>)</span><span>?</span><span>github</span><span>\.</span><span>com</span><span>\/</span></span><span>.</span><span><span>+?</span><span>\/</span></span><span>.</span><span><span>+?</span><span>\/</span><span>(?:blob</span><span>|</span><span>raw)</span><span>\/</span></span><span>.</span><span>*</span><span>$</span><span>/</span><span>i</span></div></div><div><div><div>26</div></div><div><span>const</span><span> </span><span>exp3</span><span> </span><span>=</span><span> /</span><span>^</span><span><span>(?:https</span><span>?</span><span>:</span><span>\/\/</span><span>)</span><span>?</span><span>github</span><span>\.</span><span>com</span><span>\/</span></span><span>.</span><span><span>+?</span><span>\/</span></span><span>.</span><span><span>+?</span><span>\/</span><span>(?:info</span><span>|</span><span>git-)</span></span><span>.</span><span>*</span><span>$</span><span>/</span><span>i</span></div></div><div><div><div>27</div></div><div><span>const</span><span> </span><span>exp4</span><span> </span><span>=</span><span> /</span><span>^</span><span><span>(?:https</span><span>?</span><span>:</span><span>\/\/</span><span>)</span><span>?</span><span>raw</span><span>\.</span><span>(?:githubusercontent</span><span>|</span><span>github)</span><span>\.</span><span>com</span><span>\/</span></span><span>.</span><span><span>+?</span><span>\/</span></span><span>.</span><span><span>+?</span><span>\/</span></span><span>.</span><span><span>+?</span><span>\/</span></span><span>.</span><span>+</span><span>$</span><span>/</span><span>i</span></div></div><div><div><div>28</div></div><div><span>const</span><span> </span><span>exp5</span><span> </span><span>=</span><span> /</span><span>^</span><span><span>(?:https</span><span>?</span><span>:</span><span>\/\/</span><span>)</span><span>?</span><span>gist</span><span>\.</span><span>(?:githubusercontent</span><span>|</span><span>github)</span><span>\.</span><span>com</span><span>\/</span></span><span>.</span><span><span>+?</span><span>\/</span></span><span>.</span><span><span>+?</span><span>\/</span></span><span>.</span><span>+</span><span>$</span><span>/</span><span>i</span></div></div><div><div><div>29</div></div><div>
</div></div><div><div><div>30</div></div><div><span>/**</span></div></div><div><div><div>31</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{any}</span><span> </span><span>body</span></div></div><div><div><div>32</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{number}</span><span> </span><span>status</span></div></div><div><div><div>33</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{Object&lt;string, string&gt;}</span><span> </span><span>headers</span></div></div><div><div><div>34</div></div><div><span><span> </span></span><span>*/</span></div></div><div><div><div>35</div></div><div><span>function</span><span> </span><span>makeRes</span><span><span>(</span><span>body</span><span>, </span><span>status</span><span> </span></span><span>=</span><span> </span><span>200</span><span><span>, </span><span>headers</span><span> </span></span><span>=</span><span> {}) {</span></div></div><div><div><div>36</div></div><div><span><span>    </span></span><span>headers</span><span>[</span><span>'access-control-allow-origin'</span><span>] </span><span>=</span><span> </span><span>'*'</span></div></div><div><div><div>37</div></div><div><span>    </span><span>return</span><span> </span><span>new</span><span> </span><span>Response</span><span><span>(</span><span>body</span><span>, {</span><span>status</span><span>, </span><span>headers</span><span>})</span></span></div></div><div><div><div>38</div></div><div><span>}</span></div></div><div><div><div>39</div></div><div>
</div></div><div><div><div>40</div></div><div><span>/**</span></div></div><div><div><div>41</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{string}</span><span> </span><span>urlStr</span></div></div><div><div><div>42</div></div><div><span><span> </span></span><span>*/</span></div></div><div><div><div>43</div></div><div><span>function</span><span> </span><span>newUrl</span><span><span>(</span><span>urlStr</span><span>) {</span></span></div></div><div><div><div>44</div></div><div><span>    </span><span>try</span><span> {</span></div></div><div><div><div>45</div></div><div><span>        </span><span>return</span><span> </span><span>new</span><span> </span><span>URL</span><span><span>(</span><span>urlStr</span><span>)</span></span></div></div><div><div><div>46</div></div><div><span><span>    </span></span><span>} </span><span>catch</span><span><span> (</span><span>err</span><span>) {</span></span></div></div><div><div><div>47</div></div><div><span>        </span><span>return</span><span> </span><span>null</span></div></div><div><div><div>48</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>49</div></div><div><span>}</span></div></div><div><div><div>50</div></div><div>
</div></div><div><div><div>51</div></div><div><span>addEventListener</span><span>(</span><span>'fetch'</span><span><span>, </span><span>e</span><span> </span></span><span>=&gt;</span><span> {</span></div></div><div><div><div>52</div></div><div><span>    </span><span>const</span><span> </span><span>ret</span><span> </span><span>=</span><span> </span><span>fetchHandler</span><span><span>(</span><span>e</span><span>)</span></span></div></div><div><div><div>53</div></div><div><span><span>        </span></span><span>.</span><span>catch</span><span><span>(</span><span>err</span><span> </span></span><span>=&gt;</span><span> </span><span>makeRes</span><span>(</span><span>'cfworker error:</span><span>\n</span><span>'</span><span> </span><span>+</span><span><span> </span><span>err</span><span>.</span></span><span>stack</span><span>, </span><span>502</span><span>))</span></div></div><div><div><div>54</div></div><div><span><span>    </span></span><span>e</span><span>.</span><span>respondWith</span><span><span>(</span><span>ret</span><span>)</span></span></div></div><div><div><div>55</div></div><div><span>})</span></div></div><div><div><div>56</div></div><div>
</div></div><div><div><div>57</div></div><div><span>function</span><span> </span><span>checkUrl</span><span><span>(</span><span>u</span><span>) {</span></span></div></div><div><div><div>58</div></div><div><span>    </span><span>for</span><span> (</span><span>let</span><span><span> </span><span>i</span><span> </span></span><span>of</span><span><span> [</span><span>exp1</span><span>, </span><span>exp2</span><span>, </span><span>exp3</span><span>, </span><span>exp4</span><span>, </span><span>exp5</span><span>, ]) {</span></span></div></div><div><div><div>59</div></div><div><span>        </span><span>if</span><span><span> (</span><span>u</span><span>.</span></span><span>search</span><span><span>(</span><span>i</span><span>) </span></span><span>===</span><span> </span><span>0</span><span>) {</span></div></div><div><div><div>60</div></div><div><span>            </span><span>return</span><span> </span><span>true</span></div></div><div><div><div>61</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>62</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>63</div></div><div><span>    </span><span>return</span><span> </span><span>false</span></div></div><div><div><div>64</div></div><div><span>}</span></div></div><div><div><div>65</div></div><div>
</div></div><div><div><div>66</div></div><div><span>/**</span></div></div><div><div><div>67</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{FetchEvent}</span><span> </span><span>e</span></div></div><div><div><div>68</div></div><div><span><span> </span></span><span>*/</span></div></div><div><div><div>69</div></div><div><span>async</span><span> </span><span>function</span><span> </span><span>fetchHandler</span><span><span>(</span><span>e</span><span>) {</span></span></div></div><div><div><div>70</div></div><div><span>    </span><span>const</span><span> </span><span>req</span><span> </span><span>=</span><span><span> </span><span>e</span><span>.</span></span><span>request</span></div></div><div><div><div>71</div></div><div><span>    </span><span>const</span><span> </span><span>urlStr</span><span> </span><span>=</span><span><span> </span><span>req</span><span>.</span></span><span>url</span></div></div><div><div><div>72</div></div><div><span>    </span><span>const</span><span> </span><span>urlObj</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>URL</span><span><span>(</span><span>urlStr</span><span>)</span></span></div></div><div><div><div>73</div></div><div><span>    </span><span>let</span><span><span> </span><span>path</span><span> </span></span><span>=</span><span><span> </span><span>urlObj</span><span>.</span></span><span>searchParams</span><span>.</span><span>get</span><span>(</span><span>'q'</span><span>)</span></div></div><div><div><div>74</div></div><div><span>    </span><span>if</span><span><span> (</span><span>path</span><span>) {</span></span></div></div><div><div><div>75</div></div><div><span>        </span><span>return</span><span><span> </span><span>Response</span><span>.</span></span><span>redirect</span><span>(</span><span>'https://'</span><span> </span><span>+</span><span><span> </span><span>urlObj</span><span>.</span></span><span>host</span><span> </span><span>+</span><span> </span><span>PREFIX</span><span> </span><span>+</span><span><span> </span><span>path</span><span>, </span></span><span>301</span><span>)</span></div></div><div><div><div>76</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>77</div></div><div><span>    </span><span>// cfworker 会把路径中的 `//` 合并成 `/`</span></div></div><div><div><div>78</div></div><div><span><span>    </span></span><span>path</span><span> </span><span>=</span><span><span> </span><span>urlObj</span><span>.</span></span><span>href</span><span>.</span><span>substr</span><span><span>(</span><span>urlObj</span><span>.</span></span><span>origin</span><span>.</span><span>length</span><span> </span><span>+</span><span> </span><span>PREFIX</span><span>.</span><span>length</span><span>).</span><span>replace</span><span>(</span><span>/</span><span>^</span><span><span>https</span><span>?</span><span>:</span><span>\/</span><span>+</span><span>/</span></span><span>, </span><span>'https://'</span><span>)</span></div></div><div><div><div>79</div></div><div><span>    </span><span>if</span><span><span> (</span><span>path</span><span>.</span></span><span>search</span><span><span>(</span><span>exp1</span><span>) </span></span><span>===</span><span> </span><span>0</span><span> </span><span>||</span><span><span> </span><span>path</span><span>.</span></span><span>search</span><span><span>(</span><span>exp5</span><span>) </span></span><span>===</span><span> </span><span>0</span><span> </span><span>||</span><span> </span><span>!</span><span><span>Config</span><span>.</span></span><span>cnpmjs</span><span> </span><span>&amp;&amp;</span><span><span> (</span><span>path</span><span>.</span></span><span>search</span><span><span>(</span><span>exp3</span><span>) </span></span><span>===</span><span> </span><span>0</span><span> </span><span>||</span><span><span> </span><span>path</span><span>.</span></span><span>search</span><span><span>(</span><span>exp4</span><span>) </span></span><span>===</span><span> </span><span>0</span><span>)) {</span></div></div><div><div><div>80</div></div><div><span>        </span><span>return</span><span> </span><span>httpHandler</span><span><span>(</span><span>req</span><span>, </span><span>path</span><span>)</span></span></div></div><div><div><div>81</div></div><div><span><span>    </span></span><span>} </span><span>else</span><span> </span><span>if</span><span><span> (</span><span>path</span><span>.</span></span><span>search</span><span><span>(</span><span>exp2</span><span>) </span></span><span>===</span><span> </span><span>0</span><span>) {</span></div></div><div><div><div>82</div></div><div><span>        </span><span>if</span><span><span> (</span><span>Config</span><span>.</span></span><span>jsdelivr</span><span>) {</span></div></div><div><div><div>83</div></div><div><span>            </span><span>const</span><span> </span><span>newUrl</span><span> </span><span>=</span><span><span> </span><span>path</span><span>.</span></span><span>replace</span><span>(</span><span>'/blob/'</span><span>, </span><span>'@'</span><span>).</span><span>replace</span><span>(</span><span>/</span><span>^</span><span><span>(?:https</span><span>?</span><span>:</span><span>\/\/</span><span>)</span><span>?</span><span>github</span><span>\.</span><span>com/</span></span><span>, </span><span>'https://cdn.jsdelivr.net/gh'</span><span>)</span></div></div><div><div><div>84</div></div><div><span>            </span><span>return</span><span><span> </span><span>Response</span><span>.</span></span><span>redirect</span><span><span>(</span><span>newUrl</span><span>, </span></span><span>302</span><span>)</span></div></div><div><div><div>85</div></div><div><span><span>        </span></span><span>} </span><span>else</span><span> {</span></div></div><div><div><div>86</div></div><div><span><span>            </span></span><span>path</span><span> </span><span>=</span><span><span> </span><span>path</span><span>.</span></span><span>replace</span><span>(</span><span>'/blob/'</span><span>, </span><span>'/raw/'</span><span>)</span></div></div><div><div><div>87</div></div><div><span>            </span><span>return</span><span> </span><span>httpHandler</span><span><span>(</span><span>req</span><span>, </span><span>path</span><span>)</span></span></div></div><div><div><div>88</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>89</div></div><div><span><span>    </span></span><span>} </span><span>else</span><span> </span><span>if</span><span><span> (</span><span>path</span><span>.</span></span><span>search</span><span><span>(</span><span>exp3</span><span>) </span></span><span>===</span><span> </span><span>0</span><span>) {</span></div></div><div><div><div>90</div></div><div><span>        </span><span>const</span><span> </span><span>newUrl</span><span> </span><span>=</span><span><span> </span><span>path</span><span>.</span></span><span>replace</span><span>(</span><span>/</span><span>^</span><span><span>(?:https</span><span>?</span><span>:</span><span>\/\/</span><span>)</span><span>?</span><span>github</span><span>\.</span><span>com/</span></span><span>, </span><span>'https://github.com.cnpmjs.org'</span><span>)</span></div></div><div><div><div>91</div></div><div><span>        </span><span>return</span><span><span> </span><span>Response</span><span>.</span></span><span>redirect</span><span><span>(</span><span>newUrl</span><span>, </span></span><span>302</span><span>)</span></div></div><div><div><div>92</div></div><div><span><span>    </span></span><span>} </span><span>else</span><span> </span><span>if</span><span><span> (</span><span>path</span><span>.</span></span><span>search</span><span><span>(</span><span>exp4</span><span>) </span></span><span>===</span><span> </span><span>0</span><span>) {</span></div></div><div><div><div>93</div></div><div><span>        </span><span>const</span><span> </span><span>newUrl</span><span> </span><span>=</span><span><span> </span><span>path</span><span>.</span></span><span>replace</span><span>(</span><span><span>/(?&lt;=com</span><span>\/</span></span><span>.</span><span><span>+?</span><span>\/</span></span><span>.</span><span><span>+?</span><span>)</span><span>\/</span><span>(</span></span><span>.</span><span><span>+?</span><span>\/</span><span>)/</span></span><span>, </span><span>'@$1'</span><span>).</span><span>replace</span><span>(</span><span>/</span><span>^</span><span><span>(?:https</span><span>?</span><span>:</span><span>\/\/</span><span>)</span><span>?</span><span>raw</span><span>\.</span><span>(?:githubusercontent</span><span>|</span><span>github)</span><span>\.</span><span>com/</span></span><span>, </span><span>'https://cdn.jsdelivr.net/gh'</span><span>)</span></div></div><div><div><div>94</div></div><div><span>        </span><span>return</span><span><span> </span><span>Response</span><span>.</span></span><span>redirect</span><span><span>(</span><span>newUrl</span><span>, </span></span><span>302</span><span>)</span></div></div><div><div><div>95</div></div><div><span><span>    </span></span><span>} </span><span>else</span><span> {</span></div></div><div><div><div>96</div></div><div><span>        </span><span>return</span><span> </span><span>fetch</span><span>(</span><span>ASSET_URL</span><span> </span><span>+</span><span><span> </span><span>path</span><span>)</span></span></div></div><div><div><div>97</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>98</div></div><div><span>}</span></div></div><div><div><div>99</div></div><div>
</div></div><div><div><div>100</div></div><div><span>/**</span></div></div><div><div><div>101</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{Request}</span><span> </span><span>req</span></div></div><div><div><div>102</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{string}</span><span> </span><span>pathname</span></div></div><div><div><div>103</div></div><div><span><span> </span></span><span>*/</span></div></div><div><div><div>104</div></div><div><span>function</span><span> </span><span>httpHandler</span><span><span>(</span><span>req</span><span>, </span><span>pathname</span><span>) {</span></span></div></div><div><div><div>105</div></div><div><span>    </span><span>const</span><span> </span><span>reqHdrRaw</span><span> </span><span>=</span><span><span> </span><span>req</span><span>.</span></span><span>headers</span></div></div><div><div><div>106</div></div><div>
</div></div><div><div><div>107</div></div><div><span>    </span><span>// preflight</span></div></div><div><div><div>108</div></div><div><span>    </span><span>if</span><span><span> (</span><span>req</span><span>.</span></span><span>method</span><span> </span><span>===</span><span> </span><span>'OPTIONS'</span><span> </span><span>&amp;&amp;</span></div></div><div><div><div>109</div></div><div><span><span>        </span></span><span>reqHdrRaw</span><span>.</span><span>has</span><span>(</span><span>'access-control-request-headers'</span><span>)</span></div></div><div><div><div>110</div></div><div><span><span>    </span></span><span>) {</span></div></div><div><div><div>111</div></div><div><span>        </span><span>return</span><span> </span><span>new</span><span> </span><span>Response</span><span>(</span><span>null</span><span>, </span><span>PREFLIGHT_INIT</span><span>)</span></div></div><div><div><div>112</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>113</div></div><div>
</div></div><div><div><div>114</div></div><div><span>    </span><span>const</span><span> </span><span>reqHdrNew</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>Headers</span><span><span>(</span><span>reqHdrRaw</span><span>)</span></span></div></div><div><div><div>115</div></div><div>
</div></div><div><div><div>116</div></div><div><span>    </span><span>let</span><span><span> </span><span>urlStr</span><span> </span></span><span>=</span><span><span> </span><span>pathname</span></span></div></div><div><div><div>117</div></div><div><span>    </span><span>if</span><span><span> (</span><span>urlStr</span><span>.</span></span><span>startsWith</span><span>(</span><span>'github'</span><span>)) {</span></div></div><div><div><div>118</div></div><div><span><span>        </span></span><span>urlStr</span><span> </span><span>=</span><span> </span><span>'https://'</span><span> </span><span>+</span><span><span> </span><span>urlStr</span></span></div></div><div><div><div>119</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>120</div></div><div><span>    </span><span>const</span><span> </span><span>urlObj</span><span> </span><span>=</span><span> </span><span>newUrl</span><span><span>(</span><span>urlStr</span><span>)</span></span></div></div><div><div><div>121</div></div><div>
</div></div><div><div><div>122</div></div><div><span>    </span><span>/** </span><span>@</span><span>type</span><span> </span><span>{RequestInit}</span><span> */</span></div></div><div><div><div>123</div></div><div><span>    </span><span>const</span><span> </span><span>reqInit</span><span> </span><span>=</span><span> {</span></div></div><div><div><div>124</div></div><div><span>        </span><span>method</span><span>:</span><span><span> </span><span>req</span><span>.</span></span><span>method</span><span>,</span></div></div><div><div><div>125</div></div><div><span>        </span><span>headers</span><span>:</span><span><span> </span><span>reqHdrNew</span><span>,</span></span></div></div><div><div><div>126</div></div><div><span>        </span><span>redirect</span><span>:</span><span> </span><span>'manual'</span><span>,</span></div></div><div><div><div>127</div></div><div><span>        </span><span>body</span><span>:</span><span><span> </span><span>req</span><span>.</span></span><span>body</span></div></div><div><div><div>128</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>129</div></div><div><span>    </span><span>return</span><span> </span><span>proxy</span><span><span>(</span><span>urlObj</span><span>, </span><span>reqInit</span><span>)</span></span></div></div><div><div><div>130</div></div><div><span>}</span></div></div><div><div><div>131</div></div><div>
</div></div><div><div><div>132</div></div><div><span>/**</span></div></div><div><div><div>133</div></div><div><span><span> </span></span><span>*</span></div></div><div><div><div>134</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{URL}</span><span> </span><span>urlObj</span></div></div><div><div><div>135</div></div><div><span><span> </span></span><span>* </span><span>@</span><span>param</span><span> </span><span>{RequestInit}</span><span> </span><span>reqInit</span></div></div><div><div><div>136</div></div><div><span><span> </span></span><span>*/</span></div></div><div><div><div>137</div></div><div><span>async</span><span> </span><span>function</span><span> </span><span>proxy</span><span><span>(</span><span>urlObj</span><span>, </span><span>reqInit</span><span>) {</span></span></div></div><div><div><div>138</div></div><div><span>    </span><span>const</span><span> </span><span>res</span><span> </span><span>=</span><span> </span><span>await</span><span> </span><span>fetch</span><span><span>(</span><span>urlObj</span><span>.</span></span><span>href</span><span><span>, </span><span>reqInit</span><span>)</span></span></div></div><div><div><div>139</div></div><div><span>    </span><span>const</span><span> </span><span>resHdrOld</span><span> </span><span>=</span><span><span> </span><span>res</span><span>.</span></span><span>headers</span></div></div><div><div><div>140</div></div><div><span>    </span><span>const</span><span> </span><span>resHdrNew</span><span> </span><span>=</span><span> </span><span>new</span><span> </span><span>Headers</span><span><span>(</span><span>resHdrOld</span><span>)</span></span></div></div><div><div><div>141</div></div><div>
</div></div><div><div><div>142</div></div><div><span>    </span><span>const</span><span> </span><span>status</span><span> </span><span>=</span><span><span> </span><span>res</span><span>.</span></span><span>status</span></div></div><div><div><div>143</div></div><div>
</div></div><div><div><div>144</div></div><div><span>    </span><span>if</span><span><span> (</span><span>resHdrNew</span><span>.</span></span><span>has</span><span>(</span><span>'location'</span><span>)) {</span></div></div><div><div><div>145</div></div><div><span>        </span><span>let</span><span><span> </span><span>_location</span><span> </span></span><span>=</span><span><span> </span><span>resHdrNew</span><span>.</span></span><span>get</span><span>(</span><span>'location'</span><span>)</span></div></div><div><div><div>146</div></div><div><span>        </span><span>if</span><span> (</span><span>checkUrl</span><span><span>(</span><span>_location</span><span>))</span></span></div></div><div><div><div>147</div></div><div><span><span>            </span></span><span>resHdrNew</span><span>.</span><span>set</span><span>(</span><span>'location'</span><span>, </span><span>PREFIX</span><span> </span><span>+</span><span><span> </span><span>_location</span><span>)</span></span></div></div><div><div><div>148</div></div><div><span>        </span><span>else</span><span> {</span></div></div><div><div><div>149</div></div><div><span><span>            </span></span><span>reqInit</span><span>.</span><span>redirect</span><span> </span><span>=</span><span> </span><span>'follow'</span></div></div><div><div><div>150</div></div><div><span>            </span><span>return</span><span> </span><span>proxy</span><span>(</span><span>newUrl</span><span><span>(</span><span>_location</span><span>), </span><span>reqInit</span><span>)</span></span></div></div><div><div><div>151</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>152</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>153</div></div><div><span><span>    </span></span><span>resHdrNew</span><span>.</span><span>set</span><span>(</span><span>'access-control-expose-headers'</span><span>, </span><span>'*'</span><span>)</span></div></div><div><div><div>154</div></div><div><span><span>    </span></span><span>resHdrNew</span><span>.</span><span>set</span><span>(</span><span>'access-control-allow-origin'</span><span>, </span><span>'*'</span><span>)</span></div></div><div><div><div>155</div></div><div>
</div></div><div><div><div>156</div></div><div><span><span>    </span></span><span>resHdrNew</span><span>.</span><span>delete</span><span>(</span><span>'content-security-policy'</span><span>)</span></div></div><div><div><div>157</div></div><div><span><span>    </span></span><span>resHdrNew</span><span>.</span><span>delete</span><span>(</span><span>'content-security-policy-report-only'</span><span>)</span></div></div><div><div><div>158</div></div><div><span><span>    </span></span><span>resHdrNew</span><span>.</span><span>delete</span><span>(</span><span>'clear-site-data'</span><span>)</span></div></div><div><div><div>159</div></div><div>
</div></div><div><div><div>160</div></div><div><span>    </span><span>return</span><span> </span><span>new</span><span> </span><span>Response</span><span><span>(</span><span>res</span><span>.</span></span><span>body</span><span>, {</span></div></div><div><div><div>161</div></div><div><span><span>        </span></span><span>status</span><span>,</span></div></div><div><div><div>162</div></div><div><span>        </span><span>headers</span><span>:</span><span><span> </span><span>resHdrNew</span><span>,</span></span></div></div><div><div><div>163</div></div><div><span><span>    </span></span><span>})</span></div></div><div><div><div>164</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>5、点击发送2所示按钮，测试反代是否成功，如果显示如图所示的<code>200 OK</code>,表示反代成功，点击保存并部署，退出界面。</p><p>6、由于Cloudflare默认的Workers子域名已经被墙了，导致无法访问。因此可以通过添加自定义域名，来实现国内的访问。</p><p>我添加了托管在Cloudflare上的域名，系统会自动申请ssl证书，帮我省下了一点功夫。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306011407529.png" alt="image-20230601140717301" /><figcaption>image-20230601140717301</figcaption></figure><p></p><p>7、到这里就搭建完成了，搭建的代理链接就是自己设置的子域名，我设置代理链接的为：<a href="https://github.leitingtool.cf/" target="_blank">https://github.leitingtool.cf/</a></p></section>
<section><h3>使用方法<a href="#使用方法"><span>#</span></a></h3><p>以fatedier大佬的frp仓库为例，原本的仓库地址为：<a href="https://github.com/fatedier/frp.git" target="_blank">https://github.com/fatedier/frp.git</a></p><p>在原来的仓库连接前加上自己的代理地址，你的代理链接就是：<a href="https://github.leitingtool.cf/https://github.com/fatedier/frp.git" target="_blank">https://github.leitingtool.cf/https://github.com/fatedier/frp.git</a></p></section>
<section><h3>参考链接<a href="#参考链接"><span>#</span></a></h3><p>freenom：<a href="https://www.freenom.com" target="_blank">https://www.freenom.com</a></p><p>cloudflare：<a href="https://www.cloudflare.com" target="_blank">https://www.cloudflare.com</a></p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/409/</id>
      <title type="text">wordpress-argon主题</title>
      <published>2023-05-30T13:43:10.000Z</published>
      <updated>2024-06-06T04:29:18.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/409/"/>
      <summary type="text">日志 2023-08-29：新增主题安装 前言 想要做好一个博客，一个漂亮的主题是少不了的。为了寻找一个合适的博客，可花了我不少功夫，最后选择了人气主题Argon。通过到处寻找教程，搜集到了不少美化主题的方法和代码，希望能给大家带来帮助。 </summary>
      <content type="html"><![CDATA[<section><h1>日志<a href="#日志"><span>#</span></a></h1><ul>
<li>2023-08-29：新增主题安装</li>
</ul></section>
<section><h1>前言<a href="#前言"><span>#</span></a></h1><p>想要做好一个博客，一个漂亮的主题是少不了的。为了寻找一个合适的博客，可花了我不少功夫，最后选择了人气主题Argon。通过到处寻找教程，搜集到了不少美化主题的方法和代码，希望能给大家带来帮助。</p></section>
<section><h1>主题资源<a href="#主题资源"><span>#</span></a></h1><p>链接：<a href="https://github.com/solstice23/argon-theme" target="_blank">solstice23/argon-theme: 📖 Argon - 一个轻盈、简洁的 WordPress 主题 (github.com)</a></p><p>将主题压缩包下载下来，在wordpress后台上传进行安装即可。</p><p>虽然Argon主题已经停止更新了，但对我来说已经够用了。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202305302054646.png" alt="image-20230530205437120" /><figcaption>image-20230530205437120</figcaption></figure><p></p></section>
<section><h1>主题安装<a href="#主题安装"><span>#</span></a></h1><p>进入wordpress网站后台，在外观-主题中，选择安装主题</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829223016925.png" alt="image-20230829223016925" /><figcaption>image-20230829223016925</figcaption></figure><p></p><p>选择上传主题，上传下载的Argon主题压缩包，点击立即安装</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829223249401.png" alt="image-20230829223249401" /><figcaption>image-20230829223249401</figcaption></figure><p></p><p>等待一会，就会提示argon主题安装成功，点击启用主题即可。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20230829223352866.png" alt="image-20230829223352866" /><figcaption>image-20230829223352866</figcaption></figure><p></p></section>
<section><h1>Argon主题选项<a href="#argon主题选项"><span>#</span></a></h1><p>在主题选项界面里，可以通过一些设置和脚本对博客界面进行美化。</p><p>Argon文档链接：<a href="https://argon-docs.solstice23.top/#/" target="_blank">Argon Theme Docs (solstice23.top)</a></p><p></p><figure><img src="http://imgbed.leihub.cn/img/202305302022364.png" alt="image-20230530202252155" /><figcaption>image-20230530202252155</figcaption></figure><p></p><section><h2>网站底部信息<a href="#网站底部信息"><span>#</span></a></h2><p>网站的页脚信息，如备案、运行时间等内容可在页脚内容里进行配置，使用HTML语言，也支持script标签，我的页脚内容配置如下：</p><blockquote><p>HTML(底部信息)</p></blockquote><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>div</span><span> </span><span>class</span><span>=</span><span>"github-badge-big"</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>        </span></span><span>&lt;</span><span>span</span><span> </span><span>class</span><span>=</span><span>"badge-subject"</span><span>&gt;&lt;</span><span>i</span><span> </span><span>class</span><span>=</span><span>"fa fa-id-card"</span><span>&gt;&lt;/</span><span>i</span><span>&gt; 备案号 &lt;/</span><span>span</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>        </span></span><span>&lt;</span><span>span</span><span> </span><span>class</span><span>=</span><span>"badge-value bg-orange"</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span>            </span><span>&lt;!-- 备案链接 --&gt;</span></div></div><div><div><div>5</div></div><div><span><span>            </span></span><span>&lt;</span><span>a</span><span> </span><span>href</span><span>=</span><span>"https://beian.miit.gov.cn/"</span><span> </span><span>target</span><span>=</span><span>"_blank"</span><span> </span><span>one-link-mark</span><span>=</span><span>"yes"</span><span>&gt;湘ICP备2021004011号-1&lt;/</span><span>a</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span><span>        </span></span><span>&lt;/</span><span>span</span><span>&gt;</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>&lt;/</span><span>div</span><span>&gt;</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>&lt;</span><span>div</span><span> </span><span>class</span><span>=</span><span>"github-badge-big"</span><span>&gt;</span></div></div><div><div><div>11</div></div><div><span><span>        </span></span><span>&lt;</span><span>span</span><span> </span><span>class</span><span>=</span><span>"badge-subject"</span><span>&gt;&lt;</span><span>i</span><span> </span><span>class</span><span>=</span><span>"fa fa-copyright"</span><span> </span><span>aria-hidden</span><span>=</span><span>"true"</span><span>&gt;&lt;/</span><span>i</span><span>&gt;Copyright &lt;/</span><span>span</span><span>&gt;</span></div></div><div><div><div>12</div></div><div><span><span>        </span></span><span>&lt;</span><span>span</span><span> </span><span>class</span><span>=</span><span>"badge-value bg-red"</span><span>&gt;2022-2023&lt;/</span><span>i</span><span>&gt;</span></div></div><div><div><div>13</div></div><div><span><span>            </span></span><span>&lt;</span><span>a</span><span> </span><span>href</span><span>=</span><span>"https://blog.leihub.cn"</span><span> </span><span>target</span><span>=</span><span>"_blank"</span><span> </span><span>one-link-mark</span><span>=</span><span>"yes"</span><span>&gt;@ Lei</span></div></div><div><div><div>14</div></div><div><span><span>        </span></span><span>&lt;/</span><span>span</span><span>&gt;</span></div></div><div><div><div>15</div></div><div><span><span>        </span></span><span>&lt;/</span><span>script</span><span>&gt;</span></div></div><div><div><div>16</div></div><div><span><span>    </span></span><span>&lt;/</span><span>div</span><span>&gt;</span></div></div><div><div><div>17</div></div><div>
</div></div><div><div><div>18</div></div><div><span>  </span><span>&lt;!-- 运行时间 --&gt;</span></div></div><div><div><div>19</div></div><div><span><span>    </span></span><span>&lt;</span><span>div</span><span> </span><span>class</span><span>=</span><span>"github-badge-big"</span><span>&gt;</span></div></div><div><div><div>20</div></div><div><span><span>        </span></span><span>&lt;</span><span>span</span><span> </span><span>class</span><span>=</span><span>"badge-subject"</span><span>&gt;&lt;</span><span>i</span><span> </span><span>class</span><span>=</span><span>"fa fa-clock-o"</span><span>&gt;&lt;/</span><span>i</span><span>&gt; Running Time&lt;/</span><span>span</span><span>&gt;</span></div></div><div><div><div>21</div></div><div><span><span>        </span></span><span>&lt;</span><span>span</span><span> </span><span>class</span><span>=</span><span>"badge-value bg-green"</span><span>&gt;&lt;</span><span>span</span><span> </span><span>id</span><span>=</span><span>"blog_running_days"</span><span> </span><span>class</span><span>=</span><span>"odometer odometer-auto-theme"</span><span>&gt;&lt;/</span><span>span</span><span>&gt;</span></div></div><div><div><div>22</div></div><div><span><span>            </span></span><span>天</span></div></div><div><div><div>23</div></div><div><span><span>            </span></span><span>&lt;</span><span>span</span><span> </span><span>id</span><span>=</span><span>"blog_running_hours"</span><span> </span><span>class</span><span>=</span><span>"odometer odometer-auto-theme"</span><span>&gt;&lt;/</span><span>span</span><span>&gt;</span></div></div><div><div><div>24</div></div><div><span><span>            </span></span><span>小时</span></div></div><div><div><div>25</div></div><div><span><span>            </span></span><span>&lt;</span><span>span</span><span> </span><span>id</span><span>=</span><span>"blog_running_mins"</span><span> </span><span>class</span><span>=</span><span>"odometer odometer-auto-theme"</span><span>&gt;&lt;/</span><span>span</span><span>&gt;</span></div></div><div><div><div>26</div></div><div><span><span>            </span></span><span>分钟</span></div></div><div><div><div>27</div></div><div><span><span>            </span></span><span>&lt;</span><span>span</span><span> </span><span>id</span><span>=</span><span>"blog_running_secs"</span><span> </span><span>class</span><span>=</span><span>"odometer odometer-auto-theme"</span><span>&gt;&lt;/</span><span>span</span><span>&gt;</span></div></div><div><div><div>28</div></div><div><span><span>             </span></span><span>秒</span></div></div><div><div><div>29</div></div><div><span><span>        </span></span><span>&lt;/</span><span>span</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><blockquote><p>CSS（样式表）</p></blockquote><p>也可以通过CSS对底部信息进行美化</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>style</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span>/* 核心样式 */</span></div></div><div><div><div>3</div></div><div><span>.github-badge</span><span> {</span></div></div><div><div><div>4</div></div><div><span><span>display: </span><span>inline-block</span><span>;</span></span></div></div><div><div><div>5</div></div><div><span>border-radius: </span><span><span>4</span><span>px</span></span><span>;</span></div></div><div><div><div>6</div></div><div><span><span>text-shadow: </span><span>none</span><span>;</span></span></div></div><div><div><div>7</div></div><div><span>font-size: </span><span><span>13.1</span><span>px</span></span><span>;</span></div></div><div><div><div>8</div></div><div><span>color: </span><span>#</span><span>fff</span><span>;</span></div></div><div><div><div>9</div></div><div><span>line-height: </span><span><span>15</span><span>px</span></span><span>;</span></div></div><div><div><div>10</div></div><div><span>margin-bottom: </span><span><span>5</span><span>px</span></span><span>;</span></div></div><div><div><div>11</div></div><div><span>font-family: </span><span>"Open Sans"</span><span>, </span><span>sans-serif</span><span>;</span></div></div><div><div><div>12</div></div><div><span>}</span></div></div><div><div><div>13</div></div><div><span>.github-badge</span><span> </span><span>.badge-subject</span><span> {</span></div></div><div><div><div>14</div></div><div><span><span>display: </span><span>inline-block</span><span>;</span></span></div></div><div><div><div>15</div></div><div><span>background-color: </span><span>#</span><span>4d4d4d</span><span>;</span></div></div><div><div><div>16</div></div><div><span>padding: </span><span><span>4</span><span>px</span></span><span> </span><span><span>4</span><span>px</span></span><span> </span><span><span>4</span><span>px</span></span><span> </span><span><span>6</span><span>px</span></span><span>;</span></div></div><div><div><div>17</div></div><div><span>border-top-left-radius: </span><span><span>4</span><span>px</span></span><span>;</span></div></div><div><div><div>18</div></div><div><span>border-bottom-left-radius: </span><span><span>4</span><span>px</span></span><span>;</span></div></div><div><div><div>19</div></div><div><span>font-family: </span><span>"Open Sans"</span><span>, </span><span>sans-serif</span><span>;</span></div></div><div><div><div>20</div></div><div><span>}</span></div></div><div><div><div>21</div></div><div><span>.github-badge</span><span> </span><span>.badge-value</span><span> {</span></div></div><div><div><div>22</div></div><div><span><span>display: </span><span>inline-block</span><span>;</span></span></div></div><div><div><div>23</div></div><div><span>padding: </span><span><span>4</span><span>px</span></span><span> </span><span><span>6</span><span>px</span></span><span> </span><span><span>4</span><span>px</span></span><span> </span><span><span>4</span><span>px</span></span><span>;</span></div></div><div><div><div>24</div></div><div><span>border-top-right-radius: </span><span><span>4</span><span>px</span></span><span>;</span></div></div><div><div><div>25</div></div><div><span>border-bottom-right-radius: </span><span><span>4</span><span>px</span></span><span>;</span></div></div><div><div><div>26</div></div><div><span>font-family: </span><span>"Open Sans"</span><span>, </span><span>sans-serif</span><span>;</span></div></div><div><div><div>27</div></div><div><span>}</span></div></div><div><div><div>28</div></div><div><span>.github-badge-big</span><span> {</span></div></div><div><div><div>29</div></div><div><span><span>display: </span><span>inline-block</span><span>;</span></span></div></div><div><div><div>30</div></div><div><span>border-radius: </span><span><span>6</span><span>px</span></span><span>;</span></div></div><div><div><div>31</div></div><div><span><span>text-shadow: </span><span>none</span><span>;</span></span></div></div><div><div><div>32</div></div><div><span>font-size: </span><span><span>14.1</span><span>px</span></span><span>;</span></div></div><div><div><div>33</div></div><div><span>color: </span><span>#</span><span>fff</span><span>;</span></div></div><div><div><div>34</div></div><div><span>line-height: </span><span><span>18</span><span>px</span></span><span>;</span></div></div><div><div><div>35</div></div><div><span>margin-bottom: </span><span><span>7</span><span>px</span></span><span>;</span></div></div><div><div><div>36</div></div><div><span>}</span></div></div><div><div><div>37</div></div><div><span>.github-badge-big</span><span> </span><span>.badge-subject</span><span> {</span></div></div><div><div><div>38</div></div><div><span><span>display: </span><span>inline-block</span><span>;</span></span></div></div><div><div><div>39</div></div><div><span>background-color: </span><span>#</span><span>4d4d4d</span><span>;</span></div></div><div><div><div>40</div></div><div><span>padding: </span><span><span>4</span><span>px</span></span><span> </span><span><span>4</span><span>px</span></span><span> </span><span><span>4</span><span>px</span></span><span> </span><span><span>6</span><span>px</span></span><span>;</span></div></div><div><div><div>41</div></div><div><span>border-top-left-radius: </span><span><span>4</span><span>px</span></span><span>;</span></div></div><div><div><div>42</div></div><div><span>border-bottom-left-radius: </span><span><span>4</span><span>px</span></span><span>;</span></div></div><div><div><div>43</div></div><div><span>}</span></div></div><div><div><div>44</div></div><div><span>.github-badge-big</span><span> </span><span>.badge-value</span><span> {</span></div></div><div><div><div>45</div></div><div><span><span>display: </span><span>inline-block</span><span>;</span></span></div></div><div><div><div>46</div></div><div><span>padding: </span><span><span>4</span><span>px</span></span><span> </span><span><span>6</span><span>px</span></span><span> </span><span><span>4</span><span>px</span></span><span> </span><span><span>4</span><span>px</span></span><span>;</span></div></div><div><div><div>47</div></div><div><span>border-top-right-radius: </span><span><span>4</span><span>px</span></span><span>;</span></div></div><div><div><div>48</div></div><div><span>border-bottom-right-radius: </span><span><span>4</span><span>px</span></span><span>;</span></div></div><div><div><div>49</div></div><div><span>}</span></div></div><div><div><div>50</div></div><div><span>.bg-orange</span><span> {</span></div></div><div><div><div>51</div></div><div><span>background-color: </span><span>#</span><span>ec8a64</span><span> </span><span>!important</span><span>;</span></div></div><div><div><div>52</div></div><div><span>}</span></div></div><div><div><div>53</div></div><div><span>.bg-red</span><span> {</span></div></div><div><div><div>54</div></div><div><span>background-color: </span><span>#</span><span>cb7574</span><span> </span><span>!important</span><span>;</span></div></div><div><div><div>55</div></div><div><span>}</span></div></div><div><div><div>56</div></div><div><span>.bg-apricots</span><span> {</span></div></div><div><div><div>57</div></div><div><span>background-color: </span><span>#</span><span>f7c280</span><span> </span><span>!important</span><span>;</span></div></div><div><div><div>58</div></div><div><span>}</span></div></div><div><div><div>59</div></div><div><span>.bg-casein</span><span> {</span></div></div><div><div><div>60</div></div><div><span>background-color: </span><span>#</span><span>dfe291</span><span> </span><span>!important</span><span>;</span></div></div><div><div><div>61</div></div><div><span>}</span></div></div><div><div><div>62</div></div><div><span>.bg-shallots</span><span> {</span></div></div><div><div><div>63</div></div><div><span>background-color: </span><span>#</span><span>97c3c6</span><span> </span><span>!important</span><span>;</span></div></div><div><div><div>64</div></div><div><span>}</span></div></div><div><div><div>65</div></div><div><span>.bg-ogling</span><span> {</span></div></div><div><div><div>66</div></div><div><span>background-color: </span><span>#</span><span>95c7e0</span><span> </span><span>!important</span><span>;</span></div></div><div><div><div>67</div></div><div><span>}</span></div></div><div><div><div>68</div></div><div><span>.bg-haze</span><span> {</span></div></div><div><div><div>69</div></div><div><span>background-color: </span><span>#</span><span>9aaec7</span><span> </span><span>!important</span><span>;</span></div></div><div><div><div>70</div></div><div><span>}</span></div></div><div><div><div>71</div></div><div><span>.bg-mountain-terrier</span><span> {</span></div></div><div><div><div>72</div></div><div><span>background-color: </span><span>#</span><span>99a5cd</span><span> </span><span>!important</span><span>;</span></div></div><div><div><div>73</div></div><div><span>}</span></div></div><div><div><div>74</div></div><div><span>&lt;/</span><span>style</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>实际效果如图</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202305302054344.png" alt="image-20230530205403215" /><figcaption>image-20230530205403215</figcaption></figure><p></p></section><section><h2>小工具<a href="#小工具"><span>#</span></a></h2><blockquote><p>年度倒计时显示（左侧栏）</p></blockquote><p></p><figure><img src="http://imgbed.leihub.cn/img/202305302056826.png" alt="image-20230530205634781" /><figcaption>image-20230530205634781</figcaption></figure><p></p><p>打开主题自定义，在左侧栏里添加工具-简码，将以下代码复制粘贴进去</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>div</span><span> </span><span>class</span><span>=</span><span>"progress-wrapper"</span><span> </span><span>style</span><span>=</span><span>"</span><span>padding: 0</span><span>"</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span>&lt;</span><span>div</span><span> </span><span>class</span><span>=</span><span>"progress-info"</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span>&lt;</span><span>div</span><span> </span><span>class</span><span>=</span><span>"progress-label"</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span>&lt;</span><span>span</span><span> </span><span>id</span><span>=</span><span>"yearprogress_yearname"</span><span>&gt;&lt;/</span><span>span</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span>&lt;/</span><span>div</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span>&lt;</span><span>div</span><span> </span><span>id</span><span>=</span><span>"yearprogress_text_container"</span><span> </span><span>class</span><span>=</span><span>"progress-percentage"</span><span>&gt;</span></div></div><div><div><div>7</div></div><div><span>&lt;</span><span>span</span><span> </span><span>id</span><span>=</span><span>"yearprogress_progresstext"</span><span>&gt;&lt;/</span><span>span</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span>&lt;</span><span>span</span><span> </span><span>id</span><span>=</span><span>"yearprogress_progresstext_full"</span><span>&gt;&lt;/</span><span>span</span><span>&gt;</span></div></div><div><div><div>9</div></div><div><span>&lt;/</span><span>div</span><span>&gt;</span></div></div><div><div><div>10</div></div><div><span>&lt;/</span><span>div</span><span>&gt;</span></div></div><div><div><div>11</div></div><div><span>&lt;</span><span>div</span><span> </span><span>class</span><span>=</span><span>"progress"</span><span>&gt;</span></div></div><div><div><div>12</div></div><div><span>&lt;</span><span>div</span><span> </span><span>id</span><span>=</span><span>"yearprogress_progressbar"</span><span> </span><span>class</span><span>=</span><span>"progress-bar bg-primary"</span><span>&gt;&lt;/</span><span>div</span><span>&gt;</span></div></div><div><div><div>13</div></div><div><span>&lt;/</span><span>div</span><span>&gt;</span></div></div><div><div><div>14</div></div><div><span>&lt;/</span><span>div</span><span>&gt;</span></div></div><div><div><div>15</div></div><div><span>&lt;</span><span>script</span><span> </span><span>no-pjax</span><span>=</span><span>""</span><span>&gt;</span></div></div><div><div><div>16</div></div><div><span>function</span><span> </span><span>yearprogress_refresh</span><span>() {</span></div></div><div><div><div>17</div></div><div><span>let</span><span><span> </span><span>year</span><span> </span></span><span>=</span><span> </span><span>new</span><span> </span><span>Date</span><span>().</span><span>getFullYear</span><span>();</span></div></div><div><div><div>18</div></div><div><span>$</span><span>(</span><span>"#yearprogress_yearname"</span><span>).</span><span>text</span><span><span>(</span><span>year</span><span>);</span></span></div></div><div><div><div>19</div></div><div><span>let</span><span><span> </span><span>from</span><span> </span></span><span>=</span><span> </span><span>new</span><span> </span><span>Date</span><span><span>(</span><span>year</span><span>, </span></span><span>0</span><span>, </span><span>1</span><span>, </span><span>0</span><span>, </span><span>0</span><span>, </span><span>0</span><span>);</span></div></div><div><div><div>20</div></div><div><span>let</span><span><span> </span><span>to</span><span> </span></span><span>=</span><span> </span><span>new</span><span> </span><span>Date</span><span><span>(</span><span>year</span><span>, </span></span><span>11</span><span>, </span><span>31</span><span>, </span><span>23</span><span>, </span><span>59</span><span>, </span><span>59</span><span>);</span></div></div><div><div><div>21</div></div><div><span>let</span><span><span> </span><span>now</span><span> </span></span><span>=</span><span> </span><span>new</span><span> </span><span>Date</span><span>();</span></div></div><div><div><div>22</div></div><div><span>let</span><span><span> </span><span>progress</span><span> </span></span><span>=</span><span><span> (((</span><span>now</span><span> </span></span><span>-</span><span><span> </span><span>from</span><span>) </span></span><span>/</span><span><span> (</span><span>to</span><span> </span></span><span>-</span><span><span> </span><span>from</span><span> </span></span><span>+</span><span> </span><span>1</span><span>)) </span><span>*</span><span> </span><span>100</span><span>).</span><span>toFixed</span><span>(</span><span>7</span><span>);</span></div></div><div><div><div>23</div></div><div><span>let</span><span><span> </span><span>progressshort</span><span> </span></span><span>=</span><span><span> (((</span><span>now</span><span> </span></span><span>-</span><span><span> </span><span>from</span><span>) </span></span><span>/</span><span><span> (</span><span>to</span><span> </span></span><span>-</span><span><span> </span><span>from</span><span> </span></span><span>+</span><span> </span><span>1</span><span>)) </span><span>*</span><span> </span><span>100</span><span>).</span><span>toFixed</span><span>(</span><span>2</span><span>);</span></div></div><div><div><div>24</div></div><div><span>$</span><span>(</span><span>"#yearprogress_progresstext"</span><span>).</span><span>text</span><span><span>(</span><span>progressshort</span><span> </span></span><span>+</span><span> </span><span>"%"</span><span>);</span></div></div><div><div><div>25</div></div><div><span>$</span><span>(</span><span>"#yearprogress_progresstext_full"</span><span>).</span><span>text</span><span><span>(</span><span>progress</span><span> </span></span><span>+</span><span> </span><span>"%"</span><span>);</span></div></div><div><div><div>26</div></div><div><span>$</span><span>(</span><span>"#yearprogress_progressbar"</span><span>).</span><span>css</span><span>(</span><span>"width"</span><span><span>, </span><span>progress</span><span> </span></span><span>+</span><span> </span><span>"%"</span><span>);</span></div></div><div><div><div>27</div></div><div><span>}</span></div></div><div><div><div>28</div></div><div><span>yearprogress_refresh</span><span>();</span></div></div><div><div><div>29</div></div><div><span>if</span><span> (</span><span>typeof</span><span><span> </span><span>yearProgressIntervalHasSet</span><span> </span></span><span>==</span><span> </span><span>"undefined"</span><span>) {</span></div></div><div><div><div>30</div></div><div><span>var</span><span><span> </span><span>yearProgressIntervalHasSet</span><span> </span></span><span>=</span><span> </span><span>true</span><span>;</span></div></div><div><div><div>31</div></div><div><span>setInterval</span><span>(</span><span>function</span><span> () {</span></div></div><div><div><div>32</div></div><div><span>yearprogress_refresh</span><span>();</span></div></div><div><div><div>33</div></div><div><span>}, </span><span>500</span><span>);</span></div></div><div><div><div>34</div></div><div><span>}</span></div></div><div><div><div>35</div></div><div><span>&lt;/</span><span>script</span><span>&gt;</span></div></div><div><div><div>36</div></div><div><span>&lt;</span><span>style</span><span>&gt;</span></div></div><div><div><div>37</div></div><div><span>#yearprogress_text_container</span><span> {</span></div></div><div><div><div>38</div></div><div><span>width: </span><span><span>100</span><span>%</span></span><span>;</span></div></div><div><div><div>39</div></div><div><span>height: </span><span><span>22</span><span>px</span></span><span>;</span></div></div><div><div><div>40</div></div><div><span><span>overflow: </span><span>hidden</span><span>;</span></span></div></div><div><div><div>41</div></div><div><span><span>user-select: </span><span>none</span><span>;</span></span></div></div><div><div><div>42</div></div><div><span>}</span></div></div><div><div><div>43</div></div><div><span>#yearprogress_text_container</span><span> </span><span>&gt;</span><span> </span><span>span</span><span> {</span></div></div><div><div><div>44</div></div><div><span><span>transition: </span><span>all</span><span> </span></span><span><span>0.3</span><span>s</span></span><span><span> </span><span>ease</span><span>;</span></span></div></div><div><div><div>45</div></div><div><span><span>display: </span><span>block</span><span>;</span></span></div></div><div><div><div>46</div></div><div><span>}</span></div></div><div><div><div>47</div></div><div><span>#yearprogress_text_container</span><span>:hover</span><span> </span><span>&gt;</span><span> </span><span>span</span><span> {</span></div></div><div><div><div>48</div></div><div><span>transform: </span><span>translateY</span><span>(</span><span><span>-20</span><span>px</span></span><span>);</span></div></div><div><div><div>49</div></div><div><span>}</span></div></div><div><div><div>50</div></div><div><span>&lt;/</span><span>style</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><blockquote><p>网站访问数据</p></blockquote><ol>
<li><strong>进入 Wordpress，点击插件，搜索并且下载 Wp Statistics</strong></li>
<li><strong>外观 —— 小工具 —— 站点额外内容 —— 旧版小工具 —— 统计</strong></li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/202305302058995.png" alt="image-20230530205833944" /><figcaption>image-20230530205833944</figcaption></figure><p></p></section><section><h2>音乐播放功能<a href="#音乐播放功能"><span>#</span></a></h2><p>在主题的脚本设置里，可以使用以下代码，设置音乐播放器。</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;!-- 音乐播放器 --&gt;</span></div></div><div><div><div>2</div></div><div><span>&lt;</span><span>link</span><span> </span><span>rel</span><span>=</span><span>"stylesheet"</span><span> </span><span>href</span><span>=</span><span>"https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css"</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span>&lt;</span><span>script</span><span> </span><span>src</span><span>=</span><span>"https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"</span><span>&gt;&lt;/</span><span>script</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span>&lt;</span><span>script</span><span> </span><span>src</span><span>=</span><span>"https://cdn.jsdelivr.net/npm/meting@2.0.1/dist/Meting.min.js"</span><span>&gt;&lt;/</span><span>script</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span>&lt;</span><span>meting-js</span></div></div><div><div><div>6</div></div><div><span>    </span><span>server</span><span>=</span><span>"netease"</span></div></div><div><div><div>7</div></div><div><span>    </span><span>type</span><span>=</span><span>"playlist"</span></div></div><div><div><div>8</div></div><div><span>    </span><span>id</span><span>=</span><span>"8440101601"</span></div></div><div><div><div>9</div></div><div><span>    </span><span>fixed</span><span>=</span><span>"true"</span></div></div><div><div><div>10</div></div><div><span>    </span><span>mini</span><span>=</span><span>"true"</span></div></div><div><div><div>11</div></div><div><span>    </span><span>order</span><span>=</span><span>"random"</span></div></div><div><div><div>12</div></div><div><span>    </span><span>loop</span><span>=</span><span>"all"</span></div></div><div><div><div>13</div></div><div><span>    </span><span>preload</span><span>=</span><span>"auto"</span></div></div><div><div><div>14</div></div><div><span>    </span><span>list-folded</span><span>=</span><span>"false"</span></div></div><div><div><div>15</div></div><div><span>    </span><span>autoplay</span><span>=</span><span>"true"</span><span>&gt;</span></div></div><div><div><div>16</div></div><div><span>&lt;/</span><span>meting-js</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><blockquote><p>上面的调用链接可能会突然失效，如有需要可参考官方文档</p><p><a href="https://ace520.github.io/blog/post/2020/05/26/aplayer/" target="_blank">APlayer HTML5 音乐播放器 | ACE-BLOG (ace520.github.io)</a></p></blockquote><p><strong><code>server="netease"</code> 指定音乐平台为网易云，<code>type="song"</code> 指单曲类型，<code>id="8440101601"</code> 为音乐的 id（这里的 id 为打开音乐歌单，网址显示的 id）</strong></p><p><strong>开启吸底模式 <code>fixed="true"</code>, 开启迷你模式</strong> <code>mini="true"</code>, 随机播放 <code>order="random"</code>, 关闭底部歌词 <code>lrc-type="0"</code></p><p><strong><code>注意</code></strong>：id 需要为自己创建的歌单，不能为我喜欢的音乐；server 可以改自己用的音乐平台，如 netease (网易云)、tencent (QQ 音乐)</p><p>具体参数设置点击此链接：<a href="https://yy.liveout.cn/article/Learn/front-end/aplayer%E5%8F%82%E6%95%B0.png" target="_blank">https://yy.liveout.cn/article/Learn/front-end/aplayer%E5%8F%82%E6%95%B0.png</a></p><p>Aplayer 播放器官网文档：<a href="https://ace520.github.io/blog/post/2020/05/26/aplayer/" target="_blank">APlayer HTML5 音乐播放器 | ACE-BLOG (ace520.github.io)</a></p><p>添加以上代码后，在博客首页左下方会出现一个音乐播放器，如图所示，因为浏览器原因可能无法自动播放。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202305302102184.png" alt="image-20230530210233103" /><figcaption>image-20230530210233103</figcaption></figure><p></p></section><section><h2>动态背景<a href="#动态背景"><span>#</span></a></h2><p><strong>背景可以通过更改 url 链接设置为自己的动态视频</strong>，<em>尽量不要太大，否则别人访问时会刷新许久</em></p><p>上传视频到云平台或媒体库，复制资源链接。我一开始也使用了动态背景，放在腾讯云cos里，结果一天就跑了1g多流量，后面还是取消了动态背景。</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>video</span></div></div><div><div><div>2</div></div><div><span>src</span><span>=</span><span>" "</span><span> </span><span>/*白天动态视频链接*/</span></div></div><div><div><div>3</div></div><div><span>class</span><span>=</span><span>"bg-video bg-video-day"</span></div></div><div><div><div>4</div></div><div><span>autoplay</span><span>=</span><span>""</span></div></div><div><div><div>5</div></div><div><span>loop</span><span>=</span><span>"loop"</span></div></div><div><div><div>6</div></div><div><span>muted</span><span>=</span><span>""</span></div></div><div><div><div>7</div></div><div><span>&gt;&lt;/</span><span>video</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span>&lt;</span><span>video</span></div></div><div><div><div>9</div></div><div><span>src</span><span>=</span><span>" "</span><span> </span><span>/*夜间动态视频链接*/</span></div></div><div><div><div>10</div></div><div><span>class</span><span>=</span><span>"bg-video bg-video-night"</span></div></div><div><div><div>11</div></div><div><span>autoplay</span><span>=</span><span>""</span></div></div><div><div><div>12</div></div><div><span>loop</span><span>=</span><span>"loop"</span></div></div><div><div><div>13</div></div><div><span>muted</span><span>=</span><span>""</span></div></div><div><div><div>14</div></div><div><span>&gt;&lt;/</span><span>video</span><span>&gt;</span></div></div><div><div><div>15</div></div><div><span>&lt;</span><span>style</span><span>&gt;</span></div></div><div><div><div>16</div></div><div><span>video</span><span>.bg-video</span><span> {</span></div></div><div><div><div>17</div></div><div><span><span>position: </span><span>fixed</span><span>;</span></span></div></div><div><div><div>18</div></div><div><span>z-index: </span><span>-1</span><span>;</span></div></div><div><div><div>19</div></div><div><span>left: </span><span>0</span><span>;</span></div></div><div><div><div>20</div></div><div><span>right: </span><span>0</span><span>;</span></div></div><div><div><div>21</div></div><div><span>top: </span><span>0</span><span>;</span></div></div><div><div><div>22</div></div><div><span>bottom: </span><span>0</span><span>;</span></div></div><div><div><div>23</div></div><div><span>width: </span><span><span>100</span><span>vw</span></span><span>;</span></div></div><div><div><div>24</div></div><div><span>height: </span><span><span>100</span><span>vh</span></span><span>;</span></div></div><div><div><div>25</div></div><div><span><span>object-fit: </span><span>cover</span><span>;</span></span></div></div><div><div><div>26</div></div><div><span><span>pointer-events: </span><span>none</span><span>;</span></span></div></div><div><div><div>27</div></div><div><span>}</span></div></div><div><div><div>28</div></div><div><span>html</span><span>.darkmode</span><span> </span><span>video</span><span>.bg-video.bg-video-day</span><span> {</span></div></div><div><div><div>29</div></div><div><span>opacity: </span><span>0</span><span>;</span></div></div><div><div><div>30</div></div><div><span>}</span></div></div><div><div><div>31</div></div><div><span>html</span><span>.darkmode</span><span> </span><span>video</span><span>.bg-video.bg-video-night</span><span> {</span></div></div><div><div><div>32</div></div><div><span>opacity: </span><span>1</span><span>;</span></div></div><div><div><div>33</div></div><div><span>}</span></div></div><div><div><div>34</div></div><div><span>video</span><span>.bg-video.bg-video-day</span><span> {</span></div></div><div><div><div>35</div></div><div><span>opacity: </span><span>1</span><span>;</span></div></div><div><div><div>36</div></div><div><span>}</span></div></div><div><div><div>37</div></div><div><span>video</span><span>.bg-video.bg-video-night</span><span> {</span></div></div><div><div><div>38</div></div><div><span>opacity: </span><span>0</span><span>;</span></div></div><div><div><div>39</div></div><div><span>}</span></div></div><div><div><div>40</div></div><div><span>#banner</span><span>,</span></div></div><div><div><div>41</div></div><div><span>#banner</span><span> </span><span>.shape</span><span> {</span></div></div><div><div><div>42</div></div><div><span><span>background: </span><span>transparent</span><span> </span></span><span>!important</span><span>;</span></div></div><div><div><div>43</div></div><div><span>}</span></div></div><div><div><div>44</div></div><div><span>*</span><span> {</span></div></div><div><div><div>45</div></div><div><span>font-family: </span><span>"Comfortaa"</span><span>, </span><span>"Open Sans"</span><span>, </span><span>-apple-system</span><span>, </span><span>system-ui</span><span>,</span></div></div><div><div><div>46</div></div><div><span>BlinkMacSystemFont, </span><span>"Segoe UI"</span><span>, Roboto, </span><span>"Helvetica Neue"</span><span>, </span><span>Helvetica</span><span>, </span><span>Arial</span><span>,</span></div></div><div><div><div>47</div></div><div><span>"PingFang SC"</span><span>, </span><span>"Hiragino Sans GB"</span><span>, </span><span>"Microsoft YaHei"</span><span>, SimSun, </span><span>sans-serif</span><span>;</span></div></div><div><div><div>48</div></div><div><span>}</span></div></div><div><div><div>49</div></div><div><span>&lt;/</span><span>style</span><span>&gt;</span></div></div><div><div><div>50</div></div><div><span>&lt;</span><span>script</span></div></div><div><div><div>51</div></div><div><span>src</span><span>=</span><span>"https://api.gcxstudio.cn/odometer/odometer.min.js"</span></div></div><div><div><div>52</div></div><div><span>integrity</span><span>=</span><span>"sha256-65R1G5irU1VT+k8L4coqgd3saSvO/Wufson/w+v2Idw="</span></div></div><div><div><div>53</div></div><div><span>crossorigin</span><span>=</span><span>"anonymous"</span></div></div><div><div><div>54</div></div><div><span>&gt;&lt;/</span><span>script</span><span>&gt;</span></div></div><div><div><div>55</div></div><div>
</div></div><div><div><div>56</div></div><div>
</div></div><div><div><div>57</div></div><div><span>&lt;</span><span>link</span><span> </span><span>rel</span><span>=</span><span>"stylesheet"</span><span> </span><span>href</span><span>=</span><span>"https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css"</span><span>&gt;</span></div></div><div><div><div>58</div></div><div><span>&lt;</span><span>script</span><span> </span><span>src</span><span>=</span><span>"https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"</span><span>&gt;&lt;/</span><span>script</span><span>&gt;</span></div></div><div><div><div>59</div></div><div>
</div></div><div><div><div>60</div></div><div><span>&lt;</span><span>div</span><span> </span><span>id</span><span>=</span><span>'aplayer'</span><span>&gt;&lt;/</span><span>div</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h2>看板娘<a href="#看板娘"><span>#</span></a></h2><p>在主题脚本中，添加以下代码，在博客右下角添加一个看板娘。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202305302109153.png" alt="image-20230530210929093" /><figcaption>image-20230530210929093</figcaption></figure><p></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>script</span><span> </span><span>src</span><span>=</span><span>"https://eqcn.ajz.miesnfu.com/wp-content/plugins/wp-3d-pony/live2dw/lib/L2Dwidget.min.js"</span><span>&gt;&lt;/</span><span>script</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span>&lt;</span><span>script</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>L2Dwidget</span><span>.</span><span>init</span><span>({</span></div></div><div><div><div>4</div></div><div><span>        </span><span>"model"</span><span>:</span><span> {</span></div></div><div><div><div>5</div></div><div><span>　　　　　　　</span><span>//jsonpath控制显示那个小萝莉模型，</span></div></div><div><div><div>6</div></div><div><span>            </span><span>//(切换模型需要改动)</span></div></div><div><div><div>7</div></div><div><span>//              "https://unpkg.com/(live2d-widget-model-koharu)@1.0.5/assets/(koharu).model.json"</span></div></div><div><div><div>8</div></div><div><span>            </span><span>jsonPath</span><span>:</span><span> </span><span>"https://unpkg.com/live2d-widget-model-koharu@1.0.5/assets/koharu.model.json"</span><span>,</span></div></div><div><div><div>9</div></div><div><span>            </span><span>"scale"</span><span>:</span><span> </span><span>1</span></div></div><div><div><div>10</div></div><div><span><span>        </span></span><span>},</span></div></div><div><div><div>11</div></div><div><span>        </span><span>"display"</span><span>:</span><span> {</span></div></div><div><div><div>12</div></div><div><span>            </span><span>"position"</span><span>:</span><span> </span><span>"right"</span><span>, </span><span>//看板娘的表现位置</span></div></div><div><div><div>13</div></div><div><span>            </span><span>"width"</span><span>:</span><span> </span><span>75</span><span>,  </span><span>//小萝莉的宽度</span></div></div><div><div><div>14</div></div><div><span>            </span><span>"height"</span><span>:</span><span> </span><span>150</span><span>, </span><span>//小萝莉的高度</span></div></div><div><div><div>15</div></div><div><span>            </span><span>"hOffset"</span><span>:</span><span> </span><span>0</span><span>,</span></div></div><div><div><div>16</div></div><div><span>            </span><span>"vOffset"</span><span>:</span><span> </span><span>-</span><span>20</span></div></div><div><div><div>17</div></div><div><span><span>        </span></span><span>},</span></div></div><div><div><div>18</div></div><div><span>        </span><span>"mobile"</span><span>:</span><span> {</span></div></div><div><div><div>19</div></div><div><span>            </span><span>"show"</span><span>:</span><span> </span><span>true</span><span>,</span></div></div><div><div><div>20</div></div><div><span>            </span><span>"scale"</span><span>:</span><span> </span><span>0.5</span></div></div><div><div><div>21</div></div><div><span><span>        </span></span><span>},</span></div></div><div><div><div>22</div></div><div><span>        </span><span>"react"</span><span>:</span><span> {</span></div></div><div><div><div>23</div></div><div><span>            </span><span>"opacityDefault"</span><span>:</span><span> </span><span>0.7</span><span>,</span></div></div><div><div><div>24</div></div><div><span>            </span><span>"opacityOnHover"</span><span>:</span><span> </span><span>0.2</span></div></div><div><div><div>25</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>26</div></div><div><span><span>    </span></span><span>});</span></div></div><div><div><div>27</div></div><div><span>&lt;/</span><span>script</span><span>&gt;</span></div></div><div><div><div>28</div></div><div>
</div></div><div><div><div>29</div></div><div><span><span>   </span></span><span>/*   小帅哥： https://unpkg.com/live2d-widget-model-chitose@1.0.5/assets/chitose.model.json</span></div></div><div><div><div>30</div></div><div><span><span>      </span></span><span>萌娘：https://unpkg.com/live2d-widget-model-shizuku@1.0.5/assets/shizuku.model.json</span></div></div><div><div><div>31</div></div><div><span><span>      </span></span><span>白猫：https://unpkg.com/live2d-widget-model-tororo@1.0.5/assets/tororo.model.json</span></div></div><div><div><div>32</div></div><div><span><span>      </span></span><span>黑猫： https://unpkg.com/live2d-widget-model-hijiki@1.0.5/assets/hijiki.model.json</span></div></div><div><div><div>33</div></div><div><span><span>      </span></span><span>小可爱（女）：https://unpkg.com/live2d-widget-model-koharu@1.0.5/assets/koharu.model.json</span></div></div><div><div><div>34</div></div><div><span><span>      </span></span><span>小可爱（男）：https://unpkg.com/live2d-widget-model-haruto@1.0.5/assets/haruto.model.json</span></div></div><div><div><div>35</div></div><div><span><span>      </span></span><span>初音：https://unpkg.com/live2d-widget-model-miku@1.0.5/assets/miku.model.json</span></div></div><div><div><div>36</div></div><div><span><span>      </span></span><span>圣职者妹妹：https://unpkg.com/live2d-widget-model-z16@1.0.5/assets/z16.model.json</span></div></div><div><div><div>37</div></div><div><span><span>      </span></span><span>茶杯犬：https://cdn.jsdelivr.net/npm/live2d-widget-model-wanko@1.0.5/assets/wanko.model.json</span></div></div><div><div><div>38</div></div><div><span><span>      </span></span><span>绿毛妹妹：https://unpkg.com/live2d-widget-model-tsumiki@1.0.5/assets/tsumiki.model.json</span></div></div><div><div><div>39</div></div><div><span><span>      </span></span><span>金龟子妹妹：https://unpkg.com/live2d-widget-model-unitychan@1.0.5/assets/unitychan.model.json</span></div></div><div><div><div>40</div></div><div><span><span>      </span></span><span>https://unpkg.com/live2d-widget-model-nito@1.0.5/assets/nito.model.json</span></div></div><div><div><div>41</div></div><div><span><span>      </span></span><span>https://unpkg.com/live2d-widget-model-ni-j@1.0.5/assets/ni-j.model.json</span></div></div><div><div><div>42</div></div><div><span><span>      </span></span><span>小阿狸： https://unpkg.com/live2d-widget-model-nico@1.0.5/assets/nico.model.json</span></div></div><div><div><div>43</div></div><div><span><span>      </span></span><span>https://unpkg.com/live2d-widget-model-nietzche@1.0.5/assets/nietzche.model.json</span></div></div><div><div><div>44</div></div><div><span><span>      </span></span><span>https://unpkg.com/live2d-widget-model-nipsilon@1.0.5/assets/nipsilon.model.json</span></div></div><div><div><div>45</div></div><div><span><span>      </span></span><span>女学生： https://unpkg.com/live2d-widget-model-hibiki@1.0.5/assets/hibiki.model.json */</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h2>博客透明<a href="#博客透明"><span>#</span></a></h2><p>添加到 <code>页尾脚本</code> 里，根据主题色自动透明，透明度可以在 op1、op2、op3….. 那里设置</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>script</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span>  </span><span>function</span><span> </span><span>hexToRgb</span><span><span>(</span><span>hex</span><span>,</span><span>op</span><span>){</span></span></div></div><div><div><div>3</div></div><div><span>    </span><span>let</span><span><span> </span><span>str</span><span> </span></span><span>=</span><span><span> </span><span>hex</span><span>.</span></span><span>slice</span><span>(</span><span>1</span><span>);</span></div></div><div><div><div>4</div></div><div><span>    </span><span>let</span><span><span> </span><span>arr</span><span>;</span></span></div></div><div><div><div>5</div></div><div><span>    </span><span>if</span><span><span> (</span><span>str</span><span>.</span></span><span>length</span><span> </span><span>===</span><span> </span><span>3</span><span><span>) </span><span>arr</span><span> </span></span><span>=</span><span><span> </span><span>str</span><span>.</span></span><span>split</span><span>(</span><span>''</span><span>).</span><span>map</span><span><span>(</span><span>d</span><span> </span></span><span>=&gt;</span><span> </span><span>parseInt</span><span><span>(</span><span>d</span><span>.</span></span><span>repeat</span><span>(</span><span>2</span><span>), </span><span>16</span><span>));</span></div></div><div><div><div>6</div></div><div><span>    </span><span>else</span><span><span> </span><span>arr</span><span> </span></span><span>=</span><span> [</span><span>parseInt</span><span><span>(</span><span>str</span><span>.</span></span><span>slice</span><span>(</span><span>0</span><span>, </span><span>2</span><span>), </span><span>16</span><span>), </span><span>parseInt</span><span><span>(</span><span>str</span><span>.</span></span><span>slice</span><span>(</span><span>2</span><span>, </span><span>4</span><span>), </span><span>16</span><span>), </span><span>parseInt</span><span><span>(</span><span>str</span><span>.</span></span><span>slice</span><span>(</span><span>4</span><span>, </span><span>6</span><span>), </span><span>16</span><span>)];</span></div></div><div><div><div>7</div></div><div><span>    </span><span>return</span><span>  </span><span>`rgb(</span><span>${</span><span>arr</span><span>.</span><span>join</span><span>(</span><span>'</span><span>, </span><span>'</span><span>)</span><span>}</span><span>, </span><span>${</span><span>op</span><span>}</span><span>)`</span><span>;</span></div></div><div><div><div>8</div></div><div><span>};</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span>  </span><span>let</span><span><span> </span><span>themeColorHex</span><span> </span></span><span>=</span><span> </span><span>getComputedStyle</span><span><span>(</span><span>document</span><span>.</span></span><span>documentElement</span><span>).</span><span>getPropertyValue</span><span>(</span><span>'--themecolor'</span><span>).</span><span>trim</span><span>();</span></div></div><div><div><div>11</div></div><div><span>  </span><span>let</span><span><span> </span><span>op1</span><span> </span></span><span>=</span><span> </span><span>0.6</span></div></div><div><div><div>12</div></div><div><span>  </span><span>let</span><span><span> </span><span>themeColorRgb</span><span> </span></span><span>=</span><span> </span><span>hexToRgb</span><span><span>(</span><span>themeColorHex</span><span>,</span><span>op1</span><span>);</span></span></div></div><div><div><div>13</div></div><div><span>  </span><span>let</span><span><span> </span><span>themecolorGradient</span><span> </span></span><span>=</span><span> </span><span>getComputedStyle</span><span><span>(</span><span>document</span><span>.</span></span><span>documentElement</span><span>).</span><span>getPropertyValue</span><span>(</span><span>'--themecolor-gradient'</span><span>)</span><span>*</span></div></div><div><div><div>14</div></div><div><span><span>  </span></span><span>document</span><span>.</span><span>documentElement</span><span>.</span><span>style</span><span>.</span><span>setProperty</span><span>(</span><span>'--themecolor-gradient'</span><span><span>,</span><span>themeColorRgb</span><span>)</span></span></div></div><div><div><div>15</div></div><div>
</div></div><div><div><div>16</div></div><div><span>  </span><span>let</span><span><span> </span><span>op2</span><span> </span></span><span>=</span><span> </span><span>0.8</span></div></div><div><div><div>17</div></div><div><span>  </span><span>// 方法一：</span></div></div><div><div><div>18</div></div><div><span>  </span><span>let</span><span><span> </span><span>colorTint92</span><span> </span></span><span>=</span><span> </span><span>getComputedStyle</span><span><span>(</span><span>document</span><span>.</span></span><span>documentElement</span><span>).</span><span>getPropertyValue</span><span>(</span><span>'--color-tint-92'</span><span>).</span><span>trim</span><span>();</span></div></div><div><div><div>19</div></div><div><span><span>  </span></span><span>colorTint92</span><span> </span><span>+=</span><span> </span><span>', '</span><span>+</span><span><span>op2</span><span>;</span></span></div></div><div><div><div>20</div></div><div><span><span>  </span></span><span>document</span><span>.</span><span>documentElement</span><span>.</span><span>style</span><span>.</span><span>setProperty</span><span>(</span><span>'--color-tint-92'</span><span><span>,</span><span>colorTint92</span><span>)</span></span></div></div><div><div><div>21</div></div><div><span>  </span><span>// 方法二：（无效）</span></div></div><div><div><div>22</div></div><div><span>  </span><span>// let colorForegroundHex = getComputedStyle(document.documentElement).getPropertyValue('--color-foreground').trim();</span></div></div><div><div><div>23</div></div><div><span>  </span><span>// let colorForeground = hexToRgb(colorForegroundHex,op2)</span></div></div><div><div><div>24</div></div><div><span>  </span><span>// 无效的原因是博客里的--color-fpreground是局部变量，不是:root里的全局变量，所以最好的办法是修改--color-tint-92，这个是全局的</span></div></div><div><div><div>25</div></div><div><span>  </span><span>// document.documentElement.style.setPrope。rty('--color-fpreground',colorForeground)</span></div></div><div><div><div>26</div></div><div><span>   </span><span>// 不要用下面这种cssText这种写法，会导致上面--themecolor-gradient的样式修改失效！</span></div></div><div><div><div>27</div></div><div><span>   </span><span>// document.documentElement.style.cssText = '--color-tint-92:'+colorTint92</span></div></div><div><div><div>28</div></div><div>
</div></div><div><div><div>29</div></div><div><span>  </span><span>let</span><span><span> </span><span>op3</span><span> </span></span><span>=</span><span> </span><span>0.65</span></div></div><div><div><div>30</div></div><div><span>  </span><span>let</span><span><span> </span><span>colorShade90</span><span> </span></span><span>=</span><span> </span><span>getComputedStyle</span><span><span>(</span><span>document</span><span>.</span></span><span>documentElement</span><span>).</span><span>getPropertyValue</span><span>(</span><span>'--color-shade-90'</span><span>).</span><span>trim</span><span>();</span></div></div><div><div><div>31</div></div><div><span><span>  </span></span><span>colorShade90</span><span> </span><span>+=</span><span> </span><span>', '</span><span> </span><span>+</span><span><span> </span><span>op3</span><span>;</span></span></div></div><div><div><div>32</div></div><div><span><span>  </span></span><span>document</span><span>.</span><span>documentElement</span><span>.</span><span>style</span><span>.</span><span>setProperty</span><span>(</span><span>'--color-shade-90'</span><span><span>,</span><span>colorShade90</span><span>)</span></span></div></div><div><div><div>33</div></div><div>
</div></div><div><div><div>34</div></div><div><span>  </span><span>let</span><span><span> </span><span>op4</span><span> </span></span><span>=</span><span> </span><span>0.8</span></div></div><div><div><div>35</div></div><div><span>  </span><span>let</span><span><span> </span><span>colorShade86</span><span> </span></span><span>=</span><span> </span><span>getComputedStyle</span><span><span>(</span><span>document</span><span>.</span></span><span>documentElement</span><span>).</span><span>getPropertyValue</span><span>(</span><span>'--color-shade-86'</span><span>).</span><span>trim</span><span>();</span></div></div><div><div><div>36</div></div><div><span><span>  </span></span><span>colorShade86</span><span> </span><span>+=</span><span> </span><span>', '</span><span> </span><span>+</span><span><span> </span><span>op4</span><span>;</span></span></div></div><div><div><div>37</div></div><div><span><span>  </span></span><span>document</span><span>.</span><span>documentElement</span><span>.</span><span>style</span><span>.</span><span>setProperty</span><span>(</span><span>'--color-shade-86'</span><span><span>,</span><span>colorShade86</span><span>)</span></span></div></div><div><div><div>38</div></div><div><span>&lt;/</span><span>script</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h2>字体<a href="#字体"><span>#</span></a></h2><p><a href="https://blognas.hwb0307.com/linux/docker/744#comment-918" target="_blank">Docker 系列 WordPress 系列 特效 – Bensz (hwb0307.com)</a></p><p><code>鼠标、输入特效</code>：<strong>这些特效可以访问以上友情链接</strong></p><blockquote><p>以下为Echo的额外 CSS，涉及字体、透明等博客样式</p></blockquote><p>ps: 字体链接需要上传到云端调用才能生效（下面字体链接已失效）</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>/*=========字体设置============*/</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>/*网站字体*/</span></div></div><div><div><div>4</div></div><div><span>/*原则上你可以设置多个字体，然后在不同的部位使用不同的字体。*/</span></div></div><div><div><div>5</div></div><div><span>@font-face</span><span>{</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>font-family:echo;</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>src:</span></div></div><div><div><div>8</div></div><div><span>    </span><span>url</span><span><span>(</span><span>https://fastly.jsdelivr.net/gh/huangwb8/bloghelper@latest/fonts/13.woff2</span><span>) </span></span><span>format</span><span>(</span><span>'woff2'</span><span>)</span></div></div><div><div><div>9</div></div><div><span>}</span></div></div><div><div><div>10</div></div><div><span>body</span><span>{</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>font-family:</span><span>"aLei"</span><span> </span><span>!important</span></div></div><div><div><div>12</div></div><div><span>}</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span>/*横幅字体大小*/</span></div></div><div><div><div>15</div></div><div><span>.banner-title</span><span> {</span></div></div><div><div><div>16</div></div><div><span><span>  </span></span><span>font-size: </span><span><span>2.5</span><span>em</span></span><span>;</span></div></div><div><div><div>17</div></div><div><span>}</span></div></div><div><div><div>18</div></div><div><span>.banner-subtitle</span><span>{</span></div></div><div><div><div>19</div></div><div><span><span>  </span></span><span>font-size: </span><span><span>27</span><span>px</span></span><span>;</span></div></div><div><div><div>20</div></div><div><span>}</span></div></div><div><div><div>21</div></div><div>
</div></div><div><div><div>22</div></div><div><span>/*文章标题字体大小*/</span></div></div><div><div><div>23</div></div><div><span>.post-title</span><span> {</span></div></div><div><div><div>24</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>25</span><span>px</span></span></div></div><div><div><div>25</div></div><div><span>}</span></div></div><div><div><div>26</div></div><div>
</div></div><div><div><div>27</div></div><div><span>/*正文字体大小（不包含代码）*/</span></div></div><div><div><div>28</div></div><div><span>.post-content</span><span> </span><span>p</span><span>{</span></div></div><div><div><div>29</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>1.25</span><span>rem</span></span><span>;</span></div></div><div><div><div>30</div></div><div><span>}</span></div></div><div><div><div>31</div></div><div><span>li</span><span>{</span></div></div><div><div><div>32</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>1.2</span><span>rem</span></span><span>;</span></div></div><div><div><div>33</div></div><div>
</div></div><div><div><div>34</div></div><div><span>}</span></div></div><div><div><div>35</div></div><div>
</div></div><div><div><div>36</div></div><div><span>/*评论区字体大小*/</span></div></div><div><div><div>37</div></div><div><span>p</span><span> {</span></div></div><div><div><div>38</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>1.2</span><span>rem</span></span></div></div><div><div><div>39</div></div><div>
</div></div><div><div><div>40</div></div><div><span>}</span></div></div><div><div><div>41</div></div><div>
</div></div><div><div><div>42</div></div><div><span>/*评论发送区字体大小*/</span></div></div><div><div><div>43</div></div><div><span>.form-control</span><span>{</span></div></div><div><div><div>44</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>1.2</span><span>rem</span></span></div></div><div><div><div>45</div></div><div><span>}</span></div></div><div><div><div>46</div></div><div>
</div></div><div><div><div>47</div></div><div><span>/*评论勾选项目字体大小*/</span></div></div><div><div><div>48</div></div><div><span>.custom-checkbox</span><span> </span><span>.custom-control-input</span><span>~</span><span>.custom-control-label</span><span>{</span></div></div><div><div><div>49</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>1.2</span><span>rem</span></span></div></div><div><div><div>50</div></div><div><span>}</span></div></div><div><div><div>51</div></div><div><span>/*评论区代码的强调色*/</span></div></div><div><div><div>52</div></div><div><span>code</span><span> {</span></div></div><div><div><div>53</div></div><div><span><span>  </span></span><span>color: </span><span>rgba</span><span>(</span><span>var</span><span>(</span><span>--themecolor-rgbstr</span><span>));</span></div></div><div><div><div>54</div></div><div><span>}</span></div></div><div><div><div>55</div></div><div>
</div></div><div><div><div>56</div></div><div><span>/*说说字体大小和颜色设置*/</span></div></div><div><div><div>57</div></div><div><span>.shuoshuo-title</span><span> {</span></div></div><div><div><div>58</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>25</span><span>px</span></span><span>;</span></div></div><div><div><div>59</div></div><div><span>/*  color: rgba(var(--themecolor-rgbstr)); */</span></div></div><div><div><div>60</div></div><div><span>}</span></div></div><div><div><div>61</div></div><div>
</div></div><div><div><div>62</div></div><div><span>/*尾注字体大小*/</span></div></div><div><div><div>63</div></div><div><span>.additional-content-after-post</span><span>{</span></div></div><div><div><div>64</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>1.2</span><span>rem</span></span></div></div><div><div><div>65</div></div><div><span>}</span></div></div><div><div><div>66</div></div><div>
</div></div><div><div><div>67</div></div><div><span>/* 公告居中 */</span></div></div><div><div><div>68</div></div><div><span>.leftbar-announcement-title</span><span> {</span></div></div><div><div><div>69</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>20</span><span>px</span></span><span>;</span></div></div><div><div><div>70</div></div><div><span><span>    </span></span><span>text-align: </span><span>center</span><span>;</span></div></div><div><div><div>71</div></div><div><span>}</span></div></div><div><div><div>72</div></div><div>
</div></div><div><div><div>73</div></div><div><span>.leftbar-announcement-content</span><span> {</span></div></div><div><div><div>74</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>15</span><span>px</span></span><span>;</span></div></div><div><div><div>75</div></div><div><span><span>    </span></span><span>line-height: </span><span>1.8</span><span>;</span></div></div><div><div><div>76</div></div><div><span><span>    </span></span><span>padding-top: </span><span><span>8</span><span>px</span></span><span>;</span></div></div><div><div><div>77</div></div><div><span><span>    </span></span><span>opacity: </span><span>0.9</span><span>;</span></div></div><div><div><div>78</div></div><div><span><span>    </span></span><span>text-align: </span><span>center</span><span>;</span></div></div><div><div><div>79</div></div><div><span>}</span></div></div><div><div><div>80</div></div><div>
</div></div><div><div><div>81</div></div><div><span>/* 一言居中 */</span></div></div><div><div><div>82</div></div><div><span>.leftbar-banner-title</span><span> {</span></div></div><div><div><div>83</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>20</span><span>px</span></span><span>;</span></div></div><div><div><div>84</div></div><div><span><span>    </span></span><span>display: </span><span>block</span><span>;</span></div></div><div><div><div>85</div></div><div><span><span>    </span></span><span>text-align: </span><span>center</span><span>;</span></div></div><div><div><div>86</div></div><div><span>}</span></div></div><div><div><div>87</div></div><div>
</div></div><div><div><div>88</div></div><div><span>/* 个性签名居中 */</span></div></div><div><div><div>89</div></div><div><span>.leftbar-banner-subtitle</span><span> {</span></div></div><div><div><div>90</div></div><div><span><span>    </span></span><span>margin-top: </span><span><span>15</span><span>px</span></span><span>;</span></div></div><div><div><div>91</div></div><div><span><span>    </span></span><span>margin-bottom: </span><span><span>8</span><span>px</span></span><span>;</span></div></div><div><div><div>92</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>13</span><span>px</span></span><span>;</span></div></div><div><div><div>93</div></div><div><span><span>    </span></span><span>opacity: </span><span>0.8</span><span>;</span></div></div><div><div><div>94</div></div><div><span><span>    </span></span><span>display: </span><span>block</span><span>;</span></div></div><div><div><div>95</div></div><div><span><span>    </span></span><span>text-align: </span><span>center</span><span>;</span></div></div><div><div><div>96</div></div><div><span>}</span></div></div><div><div><div>97</div></div><div>
</div></div><div><div><div>98</div></div><div><span>/*========颜色设置===========*/</span></div></div><div><div><div>99</div></div><div>
</div></div><div><div><div>100</div></div><div><span>/*文章或页面的正文颜色*/</span></div></div><div><div><div>101</div></div><div><span>body</span><span>{</span></div></div><div><div><div>102</div></div><div><span><span>    </span></span><span>color:</span><span>#</span><span>364863</span></div></div><div><div><div>103</div></div><div><span>}</span></div></div><div><div><div>104</div></div><div>
</div></div><div><div><div>105</div></div><div><span>/*引文属性设置*/</span></div></div><div><div><div>106</div></div><div><span>blockquote</span><span> {</span></div></div><div><div><div>107</div></div><div><span>    </span><span>/*添加弱主题色为背景色*/</span></div></div><div><div><div>108</div></div><div><span><span>    </span></span><span>background: </span><span>rgba</span><span>(</span><span>var</span><span>(</span><span>--themecolor-rgbstr</span><span>), </span><span>0.1</span><span>) </span><span>!important</span><span>;</span></div></div><div><div><div>109</div></div><div><span><span>    </span></span><span>width: </span><span><span>100</span><span>%</span></span></div></div><div><div><div>110</div></div><div><span>}</span></div></div><div><div><div>111</div></div><div>
</div></div><div><div><div>112</div></div><div><span>/*引文颜色 建议用主题色*/</span></div></div><div><div><div>113</div></div><div><span>:root</span><span> {</span></div></div><div><div><div>114</div></div><div><span>    </span><span>/*也可以用类似于--color-border-on-foreground-deeper: #009688;这样的命令*/</span></div></div><div><div><div>115</div></div><div><span>    </span><span>--color-border-on-foreground-deeper</span><span>: </span><span>rgba</span><span>(</span><span>var</span><span>(</span><span>--themecolor-rgbstr</span><span>));</span></div></div><div><div><div>116</div></div><div><span>}</span></div></div><div><div><div>117</div></div><div>
</div></div><div><div><div>118</div></div><div><span>/*左侧菜单栏突出颜色修改*/</span></div></div><div><div><div>119</div></div><div><span>.leftbar-menu-item</span><span> </span><span>&gt;</span><span> </span><span>a</span><span>:hover</span><span><span>,</span><span> </span></span><span>.leftbar-menu-item.current</span><span> </span><span>&gt;</span><span> </span><span>a</span><span>{</span></div></div><div><div><div>120</div></div><div><span><span>    </span></span><span>background-color: </span><span>#</span><span>f9f9f980</span><span>;</span></div></div><div><div><div>121</div></div><div><span>}</span></div></div><div><div><div>122</div></div><div>
</div></div><div><div><div>123</div></div><div><span>/*站点概览分隔线颜色修改*/</span></div></div><div><div><div>124</div></div><div><span>.site-state-item</span><span>{</span></div></div><div><div><div>125</div></div><div><span><span>    </span></span><span>border-left: </span><span><span>1</span><span>px</span></span><span><span> </span><span>solid</span><span> </span></span><span>#</span><span>aaa</span><span>;</span></div></div><div><div><div>126</div></div><div><span>}</span></div></div><div><div><div>127</div></div><div><span>.site-friend-links-title</span><span> {</span></div></div><div><div><div>128</div></div><div><span><span>    </span></span><span>border-top: </span><span><span>1</span><span>px</span></span><span><span> </span><span>dotted</span><span> </span></span><span>#</span><span>aaa</span><span>;</span></div></div><div><div><div>129</div></div><div><span>}</span></div></div><div><div><div>130</div></div><div><span>#leftbar_tab_tools</span><span> </span><span>ul</span><span> </span><span>li</span><span> {</span></div></div><div><div><div>131</div></div><div><span><span>    </span></span><span>padding-top: </span><span><span>3</span><span>px</span></span><span>;</span></div></div><div><div><div>132</div></div><div><span><span>    </span></span><span>padding-bottom: </span><span><span>3</span><span>px</span></span><span>;</span></div></div><div><div><div>133</div></div><div><span><span>    </span></span><span>border-bottom:</span><span>none</span><span>;</span></div></div><div><div><div>134</div></div><div><span>}</span></div></div><div><div><div>135</div></div><div><span>html</span><span>.darkmode</span><span> </span><span>#leftbar_tab_tools</span><span> </span><span>ul</span><span> </span><span>li</span><span> {</span></div></div><div><div><div>136</div></div><div><span><span>    </span></span><span>border-bottom:</span><span>none</span><span>;</span></div></div><div><div><div>137</div></div><div><span>}</span></div></div><div><div><div>138</div></div><div>
</div></div><div><div><div>139</div></div><div><span>/*左侧栏搜索框的颜色*/</span></div></div><div><div><div>140</div></div><div><span>button</span><span>#leftbar_search_container</span><span> {</span></div></div><div><div><div>141</div></div><div><span><span>    </span></span><span>background-color: </span><span>transparent</span><span>;</span></div></div><div><div><div>142</div></div><div><span>}</span></div></div><div><div><div>143</div></div><div>
</div></div><div><div><div>144</div></div><div><span>/*========透明设置===========*/</span></div></div><div><div><div>145</div></div><div>
</div></div><div><div><div>146</div></div><div><span>/*白天卡片背景透明*/</span></div></div><div><div><div>147</div></div><div><span>.card</span><span>{</span></div></div><div><div><div>148</div></div><div><span><span>    </span></span><span>background-color:</span><span>rgba</span><span>(</span><span>255</span><span>, </span><span>255</span><span>, </span><span>255</span><span>, </span><span>0.8</span><span>) </span><span>!important</span><span>;</span></div></div><div><div><div>149</div></div><div><span>    </span><span>/*backdrop-filter:blur(6px);*//*毛玻璃效果主要属性*/</span></div></div><div><div><div>150</div></div><div><span>    </span><span>-webkit-backdrop-filter</span><span>:</span><span>blur</span><span>(</span><span><span>6</span><span>px</span></span><span>);</span></div></div><div><div><div>151</div></div><div><span>}</span></div></div><div><div><div>152</div></div><div>
</div></div><div><div><div>153</div></div><div><span>/*小工具栏背景完全透明*/</span></div></div><div><div><div>154</div></div><div><span>/*小工具栏是card的子元素，如果用同一个透明度会叠加变色，故改为完全透明*/</span></div></div><div><div><div>155</div></div><div><span>.card</span><span> </span><span>.widget</span><span>,</span><span>.darkmode</span><span> </span><span>.card</span><span> </span><span>.widget</span><span>,</span><span>#post_content</span><span> </span><span>&gt;</span><span> </span><span>div</span><span> </span><span>&gt;</span><span> </span><span>div</span><span> </span><span>&gt;</span><span> </span><span>div</span><span>.argon-timeline-card.card.bg-gradient-secondary.archive-timeline-title</span><span>{</span></div></div><div><div><div>156</div></div><div><span><span>    </span></span><span>background-color:</span><span>#</span><span>ffffff00</span><span> </span><span>!important</span><span>;</span></div></div><div><div><div>157</div></div><div><span><span>    </span></span><span>backdrop-filter:</span><span>none</span><span>;</span></div></div><div><div><div>158</div></div><div><span>    </span><span>-webkit-backdrop-filter</span><span><span>:</span><span>none</span><span>;</span></span></div></div><div><div><div>159</div></div><div><span>}</span></div></div><div><div><div>160</div></div><div><span>.emotion-keyboard</span><span>,</span><span>#fabtn_blog_settings_popup</span><span>{</span></div></div><div><div><div>161</div></div><div><span><span>    </span></span><span>background-color:</span><span>rgba</span><span>(</span><span>255</span><span>, </span><span>255</span><span>, </span><span>255</span><span>, </span><span>0.95</span><span>) </span><span>!important</span><span>;</span></div></div><div><div><div>162</div></div><div><span>}</span></div></div><div><div><div>163</div></div><div>
</div></div><div><div><div>164</div></div><div><span>/*分类卡片透明*/</span></div></div><div><div><div>165</div></div><div><span>.bg-gradient-secondary</span><span>{</span></div></div><div><div><div>166</div></div><div><span><span>    </span></span><span>background:</span><span>rgba</span><span>(</span><span>255</span><span>, </span><span>255</span><span>, </span><span>255</span><span>, </span><span>0.1</span><span>) </span><span>!important</span><span>;</span></div></div><div><div><div>167</div></div><div><span><span>    </span></span><span>backdrop-filter: </span><span>blur</span><span>(</span><span><span>10</span><span>px</span></span><span>);</span></div></div><div><div><div>168</div></div><div><span>    </span><span>-webkit-backdrop-filter</span><span>:</span><span>blur</span><span>(</span><span><span>10</span><span>px</span></span><span>);</span></div></div><div><div><div>169</div></div><div><span>}</span></div></div><div><div><div>170</div></div><div>
</div></div><div><div><div>171</div></div><div><span>/*夜间透明*/</span></div></div><div><div><div>172</div></div><div><span>html</span><span>.darkmode.bg-white</span><span>,</span><span>html</span><span>.darkmode</span><span> </span><span>.card</span><span>,</span><span>html</span><span>.darkmode</span><span> </span><span>#footer</span><span>{</span></div></div><div><div><div>173</div></div><div><span><span>    </span></span><span>background:</span><span>rgba</span><span>(</span><span>66</span><span>, </span><span>66</span><span>, </span><span>66</span><span>, </span><span>0.9</span><span>) </span><span>!important</span><span>;</span></div></div><div><div><div>174</div></div><div><span>}</span></div></div><div><div><div>175</div></div><div><span>html</span><span>.darkmode</span><span> </span><span>#fabtn_blog_settings_popup</span><span>{</span></div></div><div><div><div>176</div></div><div><span><span>    </span></span><span>background:</span><span>rgba</span><span>(</span><span>66</span><span>, </span><span>66</span><span>, </span><span>66</span><span>, </span><span>0.95</span><span>) </span><span>!important</span><span>;</span></div></div><div><div><div>177</div></div><div><span>}</span></div></div><div><div><div>178</div></div><div>
</div></div><div><div><div>179</div></div><div><span>/*标签背景</span></div></div><div><div><div>180</div></div><div><span>.post-meta-detail-tag {</span></div></div><div><div><div>181</div></div><div><span><span>    </span></span><span>background:rgba(255, 255, 255, 0.5)!important;</span></div></div><div><div><div>182</div></div><div><span>}*/</span></div></div><div><div><div>183</div></div><div>
</div></div><div><div><div>184</div></div><div>
</div></div><div><div><div>185</div></div><div><span>/*========排版设置===========*/</span></div></div><div><div><div>186</div></div><div>
</div></div><div><div><div>187</div></div><div><span>/*左侧栏层级置于上层*/</span></div></div><div><div><div>188</div></div><div><span>#leftbar_part1</span><span> {</span></div></div><div><div><div>189</div></div><div><span><span>    </span></span><span>z-index: </span><span>1</span><span>;</span></div></div><div><div><div>190</div></div><div><span>}</span></div></div><div><div><div>191</div></div><div>
</div></div><div><div><div>192</div></div><div><span>/*分类卡片文本居中*/</span></div></div><div><div><div>193</div></div><div><span>#content</span><span> </span><span>&gt;</span><span> </span><span>div</span><span>.page-information-card-container</span><span> </span><span>&gt;</span><span> </span><span>div</span><span> </span><span>&gt;</span><span> </span><span>div</span><span>{</span></div></div><div><div><div>194</div></div><div><span><span>    </span></span><span>text-align:</span><span>center</span><span>;</span></div></div><div><div><div>195</div></div><div><span>}</span></div></div><div><div><div>196</div></div><div>
</div></div><div><div><div>197</div></div><div><span>/*子菜单对齐及样式调整*/</span></div></div><div><div><div>198</div></div><div><span>.dropdown-menu</span><span> </span><span>.dropdown-item</span><span>&gt;</span><span>i</span><span>{</span></div></div><div><div><div>199</div></div><div><span><span>    </span></span><span>width: </span><span><span>10</span><span>px</span></span><span>;</span></div></div><div><div><div>200</div></div><div><span>}</span></div></div><div><div><div>201</div></div><div><span>.dropdown-menu</span><span>&gt;</span><span>a</span><span> {</span></div></div><div><div><div>202</div></div><div><span><span>    </span></span><span>color:</span><span>var</span><span>(</span><span>--themecolor</span><span>);</span></div></div><div><div><div>203</div></div><div><span>}</span></div></div><div><div><div>204</div></div><div><span>.dropdown-menu</span><span>{</span></div></div><div><div><div>205</div></div><div><span><span>    </span></span><span>min-width:</span><span>max-content</span><span>;</span></div></div><div><div><div>206</div></div><div><span>}</span></div></div><div><div><div>207</div></div><div><span>.dropdown-menu</span><span> </span><span>.dropdown-item</span><span> {</span></div></div><div><div><div>208</div></div><div><span><span>    </span></span><span>padding: </span><span><span>.5</span><span>rem</span></span><span> </span><span><span>1.5</span><span>rem</span></span><span> </span><span><span>0.5</span><span>rem</span></span><span> </span><span><span>1</span><span>rem</span></span><span>;</span></div></div><div><div><div>209</div></div><div><span>}</span></div></div><div><div><div>210</div></div><div><span>.leftbar-menu-subitem</span><span>{</span></div></div><div><div><div>211</div></div><div><span><span>    </span></span><span>min-width:</span><span>max-content</span><span>;</span></div></div><div><div><div>212</div></div><div><span>}</span></div></div><div><div><div>213</div></div><div><span>.leftbar-menu-subitem</span><span> </span><span>.leftbar-menu-item</span><span>&gt;</span><span>a</span><span>{</span></div></div><div><div><div>214</div></div><div><span><span>    </span></span><span>padding: </span><span><span>0</span><span>rem</span></span><span> </span><span><span>1.5</span><span>rem</span></span><span> </span><span><span>0</span><span>rem</span></span><span> </span><span><span>1</span><span>rem</span></span><span>;</span></div></div><div><div><div>215</div></div><div><span>}</span></div></div><div><div><div>216</div></div><div>
</div></div><div><div><div>217</div></div><div><span>/*左侧栏边距修改*/</span></div></div><div><div><div>218</div></div><div><span>.tab-content</span><span>{</span></div></div><div><div><div>219</div></div><div><span><span>    </span></span><span>padding:</span><span><span>10</span><span>px</span></span><span> </span><span><span>0</span><span>px</span></span><span> </span><span><span>0</span><span>px</span></span><span> </span><span><span>0</span><span>px</span></span><span> </span><span>!important</span><span>;</span></div></div><div><div><div>220</div></div><div><span>}</span></div></div><div><div><div>221</div></div><div><span>.site-author-links</span><span>{</span></div></div><div><div><div>222</div></div><div><span><span>    </span></span><span>padding:</span><span><span>0</span><span>px</span></span><span> </span><span><span>0</span><span>px</span></span><span> </span><span><span>0</span><span>px</span></span><span> </span><span><span>10</span><span>px</span></span><span> ;</span></div></div><div><div><div>223</div></div><div><span>}</span></div></div><div><div><div>224</div></div><div><span>/*目录位置偏移修改*/</span></div></div><div><div><div>225</div></div><div><span>#leftbar_catalog</span><span>{</span></div></div><div><div><div>226</div></div><div><span><span>    </span></span><span>margin-left: </span><span><span>0</span><span>px</span></span><span>;</span></div></div><div><div><div>227</div></div><div><span>}</span></div></div><div><div><div>228</div></div><div><span>/*目录条目边距修改*/</span></div></div><div><div><div>229</div></div><div><span>#leftbar_catalog</span><span> </span><span>.index-link</span><span>{</span></div></div><div><div><div>230</div></div><div><span><span>    </span></span><span>padding: </span><span><span>4</span><span>px</span></span><span> </span><span><span>4</span><span>px</span></span><span> </span><span><span>4</span><span>px</span></span><span> </span><span><span>4</span><span>px</span></span><span>;</span></div></div><div><div><div>231</div></div><div><span>}</span></div></div><div><div><div>232</div></div><div><span>/*左侧栏小工具栏字体缩小*/</span></div></div><div><div><div>233</div></div><div><span>#leftbar_tab_tools</span><span>{</span></div></div><div><div><div>234</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>14</span><span>px</span></span><span>;</span></div></div><div><div><div>235</div></div><div><span>}</span></div></div><div><div><div>236</div></div><div>
</div></div><div><div><div>237</div></div><div><span>/*正文图片边距修改*/</span></div></div><div><div><div>238</div></div><div><span>article</span><span> </span><span>figure</span><span> {margin:</span><span>0</span><span>;}</span></div></div><div><div><div>239</div></div><div><span>/*正文图片居中显示*/</span></div></div><div><div><div>240</div></div><div><span>.fancybox-wrapper</span><span> {</span></div></div><div><div><div>241</div></div><div><span><span>    </span></span><span>margin: </span><span>auto</span><span>;</span></div></div><div><div><div>242</div></div><div><span>}</span></div></div><div><div><div>243</div></div><div><span>/*正文表格样式修改*/</span></div></div><div><div><div>244</div></div><div><span>article</span><span> </span><span>table</span><span> </span><span>&gt;</span><span> </span><span>tbody</span><span> </span><span>&gt;</span><span> </span><span>tr</span><span> </span><span>&gt;</span><span> </span><span>td</span><span>,</span></div></div><div><div><div>245</div></div><div><span>article</span><span> </span><span>table</span><span> </span><span>&gt;</span><span> </span><span>tbody</span><span> </span><span>&gt;</span><span> </span><span>tr</span><span> </span><span>&gt;</span><span> </span><span>th</span><span>,</span></div></div><div><div><div>246</div></div><div><span>article</span><span> </span><span>table</span><span> </span><span>&gt;</span><span> </span><span>tfoot</span><span> </span><span>&gt;</span><span> </span><span>tr</span><span> </span><span>&gt;</span><span> </span><span>td</span><span>,</span></div></div><div><div><div>247</div></div><div><span>article</span><span> </span><span>table</span><span> </span><span>&gt;</span><span> </span><span>tfoot</span><span> </span><span>&gt;</span><span> </span><span>tr</span><span> </span><span>&gt;</span><span> </span><span>th</span><span>,</span></div></div><div><div><div>248</div></div><div><span>article</span><span> </span><span>table</span><span> </span><span>&gt;</span><span> </span><span>thead</span><span> </span><span>&gt;</span><span> </span><span>tr</span><span> </span><span>&gt;</span><span> </span><span>td</span><span>,</span></div></div><div><div><div>249</div></div><div><span>article</span><span> </span><span>table</span><span> </span><span>&gt;</span><span> </span><span>thead</span><span> </span><span>&gt;</span><span> </span><span>tr</span><span> </span><span>&gt;</span><span> </span><span>th</span><span>{</span></div></div><div><div><div>250</div></div><div><span><span>    </span></span><span>padding: </span><span><span>8</span><span>px</span></span><span> </span><span><span>10</span><span>px</span></span><span>;</span></div></div><div><div><div>251</div></div><div><span><span>    </span></span><span>border: </span><span><span>1</span><span>px</span></span><span><span> </span><span>solid</span><span>;</span></span></div></div><div><div><div>252</div></div><div><span>}</span></div></div><div><div><div>253</div></div><div><span>/*表格居中样式*/</span></div></div><div><div><div>254</div></div><div><span>.wp-block-table.aligncenter</span><span>{margin:</span><span><span>10</span><span>px</span></span><span><span> </span><span>auto</span><span>;}</span></span></div></div><div><div><div>255</div></div><div>
</div></div><div><div><div>256</div></div><div><span>/*回顶图标放大*/</span></div></div><div><div><div>257</div></div><div><span>button</span><span>#fabtn_back_to_top</span><span><span>,</span><span> </span></span><span>button</span><span>#fabtn_go_to_comment</span><span><span>,</span><span> </span></span><span>button</span><span>#fabtn_toggle_blog_settings_popup</span><span><span>,</span><span> </span></span><span>button</span><span>#fabtn_toggle_sides</span><span><span>,</span><span> </span></span><span>button</span><span>#fabtn_open_sidebar</span><span>{</span></div></div><div><div><div>258</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>1.2</span><span>rem</span></span><span>;</span></div></div><div><div><div>259</div></div><div><span>}</span></div></div><div><div><div>260</div></div><div>
</div></div><div><div><div>261</div></div><div><span>/*顶栏菜单放大*/</span></div></div><div><div><div>262</div></div><div>
</div></div><div><div><div>263</div></div><div>
</div></div><div><div><div>264</div></div><div><span>.navbar-nav</span><span> </span><span>.nav-link</span><span> {</span></div></div><div><div><div>265</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>1</span><span>rem</span></span><span>;</span></div></div><div><div><div>266</div></div><div><span><span>    </span></span><span>font-family: </span><span>'echo'</span><span>;</span></div></div><div><div><div>267</div></div><div>
</div></div><div><div><div>268</div></div><div><span>}</span></div></div><div><div><div>269</div></div><div><span>.navbar-brand</span><span> {</span></div></div><div><div><div>270</div></div><div><span><span>  </span></span><span>color: </span><span>white</span><span>!important</span><span>;</span></div></div><div><div><div>271</div></div><div><span><span>  </span></span><span>font-family: </span><span>'echo'</span><span>;</span></div></div><div><div><div>272</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>1.4</span><span>rem</span></span><span>;</span></div></div><div><div><div>273</div></div><div><span><span>    </span></span><span>margin-right: </span><span><span>1</span><span>rem</span></span><span>;</span></div></div><div><div><div>274</div></div><div><span><span>    </span></span><span>padding-bottom: </span><span><span>.2</span><span>rem</span></span><span>;</span></div></div><div><div><div>275</div></div><div><span>}</span></div></div><div><div><div>276</div></div><div><span>/*菜单大小*/</span></div></div><div><div><div>277</div></div><div><span>.nav-link-inner--text</span><span> {</span></div></div><div><div><div>278</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>1.2</span><span>em</span></span><span>;</span></div></div><div><div><div>279</div></div><div><span>}</span></div></div><div><div><div>280</div></div><div><span>.navbar-nav</span><span> </span><span>.nav-item</span><span> {</span></div></div><div><div><div>281</div></div><div><span><span>    </span></span><span>margin-right:</span><span>0</span><span>;</span></div></div><div><div><div>282</div></div><div><span>}</span></div></div><div><div><div>283</div></div><div><span>.mr-lg-5</span><span><span>,</span><span> </span></span><span>.mx-lg-5</span><span> {</span></div></div><div><div><div>284</div></div><div><span><span>    </span></span><span>margin-right:</span><span><span>1</span><span>rem</span></span><span> </span><span>!important</span><span>;</span></div></div><div><div><div>285</div></div><div><span>}</span></div></div><div><div><div>286</div></div><div><span>.navbar-toggler-icon</span><span> {</span></div></div><div><div><div>287</div></div><div><span><span>    </span></span><span>width: </span><span><span>1.8</span><span>rem</span></span><span>;</span></div></div><div><div><div>288</div></div><div><span><span>    </span></span><span>height: </span><span><span>1.8</span><span>rem</span></span><span>;</span></div></div><div><div><div>289</div></div><div><span>}</span></div></div><div><div><div>290</div></div><div><span>/*菜单间距*/</span></div></div><div><div><div>291</div></div><div><span>.navbar-expand-lg</span><span> </span><span>.navbar-nav</span><span> </span><span>.nav-link</span><span> {</span></div></div><div><div><div>292</div></div><div><span><span>    </span></span><span>padding-right: </span><span><span>2.1</span><span>em</span></span><span>;</span></div></div><div><div><div>293</div></div><div><span><span>    </span></span><span>padding-left: </span><span>1</span><span>.em;</span></div></div><div><div><div>294</div></div><div><span>}</span></div></div><div><div><div>295</div></div><div>
</div></div><div><div><div>296</div></div><div><span>/*隐藏wp-SEO插件带来的线条阴影（不一定要装）*/</span></div></div><div><div><div>297</div></div><div><span>*</span><span>[</span><span>style</span><span>=</span><span>'position: relative; z-index: 99998;'</span><span>]</span><span> {</span></div></div><div><div><div>298</div></div><div><span><span>    </span></span><span>display: </span><span>none</span><span>;</span></div></div><div><div><div>299</div></div><div><span>}</span></div></div><div><div><div>300</div></div><div>
</div></div><div><div><div>301</div></div><div><span>/* Github卡片样式*/</span></div></div><div><div><div>302</div></div><div><span>.github-info-card-header</span><span> </span><span>a</span><span> {</span></div></div><div><div><div>303</div></div><div><span>    </span><span>/*Github卡片抬头颜色*/</span></div></div><div><div><div>304</div></div><div><span><span>    </span></span><span>color: </span><span>black</span><span> </span><span>!important</span><span>;</span></div></div><div><div><div>305</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>1.5</span><span>rem</span></span><span>;</span></div></div><div><div><div>306</div></div><div><span>}</span></div></div><div><div><div>307</div></div><div><span>.github-info-card</span><span> {</span></div></div><div><div><div>308</div></div><div><span>    </span><span>/*Github卡片文字（非链接）*/</span></div></div><div><div><div>309</div></div><div><span><span>    </span></span><span>font-size: </span><span><span>1</span><span>rem</span></span><span>;</span></div></div><div><div><div>310</div></div><div><span><span>    </span></span><span>color: </span><span>black</span><span> </span><span>!important</span><span>;</span></div></div><div><div><div>311</div></div><div><span>}</span></div></div><div><div><div>312</div></div><div><span>.github-info-card.github-info-card-full.card.shadow-sm</span><span> {</span></div></div><div><div><div>313</div></div><div><span>    </span><span>/*Github卡片背景色*/</span></div></div><div><div><div>314</div></div><div><span><span>    </span></span><span>background-color: </span><span>rgba</span><span>(</span><span>var</span><span>(</span><span>--themecolor-rgbstr</span><span>), </span><span>0.1</span><span>) </span><span>!important</span><span>;</span></div></div><div><div><div>315</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h2>美化JSON<a href="#美化json"><span>#</span></a></h2><p>懒得自己配置的，也可以直接导入美化配置JSON一键配置。</p></section></section>
<section><h1>相关链接<a href="#相关链接"><span>#</span></a></h1><p><a href="https://www.liveout.cn/25/" target="_blank">Argon主题博客美化 – Echo小窝 (liveout.cn)</a></p><p><a href="https://ace520.github.io/blog/post/2020/05/26/aplayer/" target="_blank">APlayer HTML5 音乐播放器 | ACE-BLOG (ace520.github.io)</a></p><p><a href="https://github.com/stevenjoezhang/live2d-widget" target="_blank">stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦) ノ | Live2D widget for web platform (github.com)</a></p><p><a href="https://blognas.hwb0307.com/linux/docker/744#comment-918" target="_blank">Docker 系列 WordPress 系列 特效 – Bensz (hwb0307.com)</a></p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/147/</id>
      <title type="text">nginx将域名反代到端口后css、js、图片等样式不加载的问题</title>
      <published>2023-05-07T12:14:52.000Z</published>
      <updated>2024-06-13T06:14:11.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/147/"/>
      <summary type="text">2024.06.13 更新WordPress反代后CSS、JS和PNG报mixed content错误 当遇到WordPress反代后CSS、JS和PNG等资源无法加载，报mixed content错误时，这通常意味着网站中同时存在HTTP</summary>
      <content type="html"><![CDATA[<ul>
<li>2024.06.13 更新WordPress反代后CSS、JS和PNG报mixed content错误
当遇到WordPress反代后CSS、JS和PNG等资源无法加载，报mixed content错误时，这通常意味着网站中同时存在HTTP和HTTPS两种协议的请求。这种情况在博客主题内容使用CDN进行分发时尤为常见。</li>
</ul>
<section><h1>CDN的基本概念<a href="#cdn的基本概念"><span>#</span></a></h1><p>CDN的作用：CDN（内容分发网络）是一种分布式的网络服务，它通过在多个地理位置分布的服务器上存储网站的静态文件（如CSS、JS、图片等），来加快网站的访问速度。
CDN与HTTPS：当网站启用HTTPS加密协议后，如果CDN没有正确配置支持HTTPS，就会导致资源加载时的mixed content问题。</p></section>
<section><h1>强制HTTPS的重要性<a href="#强制https的重要性"><span>#</span></a></h1><p>数据安全：强制HTTPS可以确保用户与网站之间传输的数据不被截获和篡改，提高数据传输的安全性。
搜索引擎优化：搜索引擎，如Google和百度，更倾向于对启用HTTPS的网站给予更好的排名。</p></section>
<section><h1>CDN配置的关键点<a href="#cdn配置的关键点"><span>#</span></a></h1><p>HTTP回源问题：如果CDN配置为HTTP回源，而网站的其他部分已经使用了HTTPS，就会导致协议不一致的问题。解决这个问题需要在CDN设置中选择HTTPS回源。
缓存问题：CDN可能会缓存301重定向响应，导致即使设置了HTTP到HTTPS的跳转，用户仍可能访问到HTTP版本的页面。这需要通过在页面中加入JavaScript代码来实现客户端的自动跳转。</p></section>
<section><h1>具体解决方案<a href="#具体解决方案"><span>#</span></a></h1><p>选择支持HTTPS的CDN：选择一个支持HTTPS的CDN服务商，如腾讯云CDN或VeryCloud，并确保正确配置SSL证书。
配置Nginx规则：对于不支持HTTPS的请求，可以通过配置Nginx规则来实现重定向。例如，对于非POST请求，可以强制重定向到HTTPS版本。</p><p>下面将详细解释这个问题的原因及解决方案，可以尝试配置Nginx规则在反向代理配置中加入以下代码：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>proxy_set_header X-Forwarded-Proto https;</span></div></div><div><div><div>2</div></div><div><span>proxy_redirect http:// https://;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>这两行代码的作用是：</p><p><code>proxy_set_header X-Forwarded-Proto https;</code>：这行代码告诉后端服务器，客户端使用的真实协议是HTTPS。这样，后端服务器就可以根据这个信息来生成正确的URL，确保资源请求也是通过HTTPS协议发送的。</p><p><code>proxy_redirect http:// https://;</code>：这行代码的作用是在反向代理收到后端服务器发回的HTTP响应内容时，直接将其中的HTTP URL重定向为HTTPS URL，然后再发回给用户。这样可以确保用户最终获取到的资源也是通过HTTPS协议加载的，避免了mixed content错误。</p><p>这两种方法可以单独使用，也可以结合使用。如果使用了CDN，可以直接强制HTTPS，或者启用HSTS（HTTP Strict Transport Security），或者对资源URL进行重写，都可以解决mixed content问题。这种问题通常是因为没有使用CDN直接反代服务器导致的。</p><h1>nginx将域名反代到端口后css、js、图片等样式不加载的问题</h1>
<p>宝塔创建网页后，将域名(<a href="http://chevereto.leiting2020.top/)反代到4000端口，通过在配置文件中添加一下代码实现">http://chevereto.leiting2020.top/)反代到4000端口，通过在配置文件中添加一下代码实现</a></p>
<pre><code>    location / {
      proxy_pass http://blog.leihub.cn:4000/;
    }</code></pre>
<p>使用nginx的反向代理后，发现页面能正常跳转，可是css、js和相关的图片就是不出来,如下图</p>
<p><img src="http://imgbed.leihub.cn/img/202305072013635.png" alt="202305071823320" /></p>
<p>打开F12开发者模式，发现反代报错</p>
<p><img src="http://imgbed.leihub.cn/img/202305072003522.png" alt="image-20230507152221523" /></p>
<p>在配置中加上以下代码</p>
<pre><code>    location ~ .*\.(js|css)?\$
    {
        expires      12h;
        proxy_set_header Host \$http_host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_pass http://blog.leihub.cn:4000;#4000可改为你自己起服务器本地服务的端口
        error_log /dev/null;
        access_log /dev/null;
    }<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>location / {</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>proxy_set_header Host \$http_host;</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>proxy_set_header X-Real-IP \$remote_addr;</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;</span></div></div><div><div><div>5</div></div><div><span><span>  </span></span><span>proxy_pass http://blog.leihub.cn:4000/;#4000可改为你自己起服务器本地服务的端口</span></div></div><div><div><div>6</div></div><div><span>}&lt;/code&gt;&lt;/pre&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>重启nginx服务，页面正常了。</p></code></pre></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/759/</id>
      <title type="text">机器人运动轨迹转换</title>
      <published>2023-04-23T13:11:30.000Z</published>
      <updated>2024-06-06T15:56:58.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/759/"/>
      <summary type="text">机器人铣削运动链 如图所示为机器人铣削系统，由机器人本体、变位器、工件以及电主轴组成，机器人通过底座本体固定于地面，而电主轴通过刚性连接固定于末端法兰。机器人铣削系统包括了多个参考坐标系，机器人基坐标系 定义于机器人底座中心，机器人工具坐标</summary>
      <content type="html"><![CDATA[<section><h1>机器人铣削运动链<a href="#机器人铣削运动链"><span>#</span></a></h1><p>如图所示为机器人铣削系统，由机器人本体、变位器、工件以及电主轴组成，机器人通过底座本体固定于地面，而电主轴通过刚性连接固定于末端法兰。机器人铣削系统包括了多个参考坐标系，机器人基坐标系*<code>XB-YB-ZB</code><em>定义于机器人底座中心，机器人工具坐标系</em><code>XT-YT-ZT</code><em>可通过电主轴标定确定，变位器坐标系</em>XZ-YZ-<code>ZZ</code><em>定义在变位器的中心位置，会根据变位器的旋转运动而发生变化，工件坐标系</em><code>XW-YW-ZW</code>*会根据工件的装夹位置和姿态进行确定，要对机器人铣削系统进行运动链分析，需要对各个坐标系进行标定。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306062034470.png" alt="image-20230606203420846" /><figcaption>image-20230606203420846</figcaption></figure><p></p><section><h2>工具坐标系标定<a href="#工具坐标系标定"><span>#</span></a></h2><p>机器人末端工具坐标系*<code>XT-YT-ZT</code>*的标定分为电主轴刀尖原点和姿态的确定。电主轴刀尖原点可以使用<code>XYZ 4点法</code>和<code>XYZ参照法</code>进行测量，电主轴刀尖姿态可以使用<code>ABC世界坐标法</code>和<code>ABC两点法</code>进行测量。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306062045684.png" alt="image-20230606204541414" /><figcaption>image-20230606204541414</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306062045902.png" alt="image-20230606204555740" /><figcaption>image-20230606204555740</figcaption></figure><p></p></section><section><h2>工件坐标系标定<a href="#工件坐标系标定"><span>#</span></a></h2><p>要实现工件坐标系*<code>XW-YW-ZW</code><em>的标定，需要对工件变位器坐标系</em><code>XZ-YZ-ZZ</code>*进行标定。首先，在变位器上确定一个参照点，并在机器人系统中输入其距离变位器中心的距离。将已标定的工具坐标系移动至参考点，并对工具坐标系位置进行测量保存，重复上述步骤3次，每次重复前都需要转动变位器，以便工具坐标系从不同的出发位置移动到参考点，如图所示。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306062056418.png" alt="image-20230606205615187" /><figcaption>image-20230606205615187</figcaption></figure><p></p><p>使用已标定好的电主轴确定工件坐标系的原点，机器人控制系统会计算工件坐标系原点与变位器坐标系之间的相对位置，通过<code>ABC 2点法</code>确定工件坐标系相对于变位器的姿态，得到了工件坐标系相对于变位器的相对位姿。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202306062133135.png" alt="image-20230606213300894" /><figcaption>image-20230606213300894</figcaption></figure><p></p><p>在完成工件坐标系的标定后，还需要确定变位器的运行模式，变位器有两种运行模式，一种是同步运行模式，通过在KUKA KRL程序中将机器人基坐标系与变位器相关联，这样机器人与变位器会同步运行；另一种是非同步模式，在KUKA KRL程序中将变位器与基坐标系解除关联，机器人与变位器会按一定顺序先后运行。为了提高机器人加工系统的稳定性，铣削加工中通常使用非同步模式。</p></section><section><h2>运动链分析<a href="#运动链分析"><span>#</span></a></h2><p>如图2-5所示为机器人铣削系统，机器人铣削系统中各个坐标系形成一个闭环，构成了一个完整的运动链，机器人末端坐标系<em>XT-YT-ZT</em>的姿态在基坐标系中可以定义为：</p><span><span><span>toolBT=ZBT⋅Troz(β)⋅WZT⋅toolWT{}_{tool}^BT={_Z^B}T\cdot T_{roz}(\beta)\cdot{_W^Z}T\cdot {_{tool}^W}T</span><span><span><span></span><span><span></span><span><span><span><span><span><span></span><span><span><span>t</span><span>oo</span><span>l</span></span></span></span><span><span></span><span><span>B</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>T</span><span></span><span>=</span><span></span></span><span><span></span><span><span><span></span><span><span><span><span><span><span></span><span><span>Z</span></span></span><span><span></span><span><span>B</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span><span>T</span><span></span><span>⋅</span><span></span></span><span><span></span><span><span>T</span><span><span><span><span><span><span></span><span><span><span>r</span><span>oz</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>β</span><span>)</span><span></span><span>⋅</span><span></span></span><span><span></span><span><span><span></span><span><span><span><span><span><span></span><span><span>W</span></span></span><span><span></span><span><span>Z</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span><span>T</span><span></span><span>⋅</span><span></span></span><span><span></span><span><span><span></span><span><span><span><span><span><span></span><span><span><span>t</span><span>oo</span><span>l</span></span></span></span><span><span></span><span><span>W</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span><span>T</span></span></span></span></span><p>其中，<span><span>ZBT{}_Z^B{T}</span><span><span><span></span><span><span></span><span><span><span><span><span><span></span><span><span>Z</span></span></span><span><span></span><span><span>B</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span>T</span></span></span></span></span>为基坐标系下变位器的位姿矩阵，<span><span>Troz(β)T_{roz}(\beta)</span><span><span><span></span><span><span>T</span><span><span><span><span><span><span></span><span><span><span>r</span><span>oz</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>β</span><span>)</span></span></span></span>为变位器绕自身<em>Z</em>轴旋转<em>β</em>后的变换矩阵，<span><span>WZT{}_W^Z{T}</span><span><span><span></span><span><span></span><span><span><span><span><span><span></span><span><span>W</span></span></span><span><span></span><span><span>Z</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span>T</span></span></span></span></span>为工件坐标系相对于变位器的位姿矩阵，与工件装夹位置有关，<span><span>toolWT{}_{tool}^W{T}</span><span><span><span></span><span><span></span><span><span><span><span><span><span></span><span><span><span>t</span><span>oo</span><span>l</span></span></span></span><span><span></span><span><span>W</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span>T</span></span></span></span></span>为给定的加工任务。</p><p>UG软件生成的加工轨迹通常适用于数控加工，轨迹信息包括加工位置<span><span>PtoolZ\boldsymbol{P}_{\mathrm{tool}}^{\mathrm{Z}}</span><span><span><span></span><span><span><span><span>P</span></span></span><span><span><span><span><span><span></span><span><span><span><span>tool</span></span></span></span></span><span><span></span><span><span><span>Z</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>和刀轴方向矢量<em><strong>V*</strong>tool。要确定机器人末端工具的加工轨迹，需要将五轴加工任务转换为机器人末端的六自由度运动轨迹，即机器人末端的位置(<em>X</em>,<em>Y</em>,<em>Z</em>)和姿态(<em>A</em>,<em>B</em>,<em>C</em>)。与机器人运动轨迹相比，五轴加工的位置和刀轴方向是确定的，但缺少一个绕刀轴旋转方向的冗余自由度</em>α*，如图2-11所示。</p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/757/</id>
      <title type="text">使用UG曲面加工轨迹</title>
      <published>2023-04-23T13:08:37.000Z</published>
      <updated>2025-11-14T15:22:19.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/757/"/>
      <summary type="text">一、加工前处理 1.选择模板 使用软件打开模型，进入到加工界面，选择多轴加工模板 2.设置机床坐标系以及安全平面。 右键点击工序导航器空白处切换到几何视图，双击MCSMILL结点 点击确定，再定义安全平面，选择自动平面，安全距离为10. 3</summary>
      <content type="html"><![CDATA[<section><h1>一、加工前处理<a href="#一加工前处理"><span>#</span></a></h1><section><h2>1.选择模板<a href="#1选择模板"><span>#</span></a></h2><p>使用软件打开模型，进入到加工界面，选择<strong>多轴加工模板</strong></p><p></p><figure><img src="http://imgbed.leihub.cn/img/15352741749409.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p></section><section><h2><strong>2.设置机床坐标系以及安全平面。</strong><a href="#2设置机床坐标系以及安全平面"><span>#</span></a></h2><p>右键点击工序导航器空白处切换到几何视图，双击MCS_MILL结点</p><p></p><figure><img src="http://imgbed.leihub.cn/img/15342071663647.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/15342072167570.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p><p>点击确定，再定义安全平面，<strong>选择自动平面，安全距离为10.</strong></p><p></p><figure><img src="http://imgbed.leihub.cn/img/15352744533127.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p></section><section><h2><strong>3.设置几何体</strong><a href="#3设置几何体"><span>#</span></a></h2><p>双击如下所示<strong>WORKPIECE</strong>结点，选择部件几何体</p><p></p><figure><img src="http://imgbed.leihub.cn/img/15342075332981.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220315113735427.png" alt="image-20220315113735427" /><figcaption>image-20220315113735427</figcaption></figure><p></p><p>点击确定后弹出如下对话框，点击如下<strong>指定毛坯</strong>按钮</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220315113818697.png" alt="image-20220315113818697" /><figcaption>image-20220315113818697</figcaption></figure><p></p><p>系统弹出选择毛坯对话框，选择<strong>包容块</strong>， 参数设置如下：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220315113808133.png" alt="image-20220315113808133" /><figcaption>image-20220315113808133</figcaption></figure><p></p><p>点击确定后退回到工件对话框，观察到如图所示图案高亮，就可以点击确定按钮完成几何体的设置。</p></section><section><h2>4.设置铣削区域几何体<a href="#4设置铣削区域几何体"><span>#</span></a></h2><p>右键点击WORKPIECE结点，在弹出的选项中选择插入子选项下的几何体按钮。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/15342081781160.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p><p>弹出对话框，<strong>设置几何体为WORKPIECE</strong>，点击<strong>铣削几何体</strong>按钮，名称为<strong>MILL_AREA_1</strong>如下所示：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/15352747908537.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p><p>弹出铣削边界对话框，点击<strong>指定切削区域按钮</strong>按钮</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220315114124484.png" alt="image-20220315114124484" /><figcaption>image-20220315114124484</figcaption></figure><p></p><p>观察工序导航器可以发现多了<strong>铣削几何体1</strong>节点做为WORKPIECE结点的<strong>子节点</strong>出现：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220315114201859.png" alt="image-20220315114201859" /><figcaption>image-20220315114201859</figcaption></figure><p></p></section><section><h2>5.设置刀具<a href="#5设置刀具"><span>#</span></a></h2><p>右键点击工序导航器切换至机床视图，右键单击未用项下的刀具按钮</p><p></p><figure><img src="http://imgbed.leihub.cn/img/15352759483932.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/15342093646955.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p><p>添加两把刀具，一把用于粗加工的平头铣刀，一把球头铣刀。</p></section></section>
<section><h1>二、添加粗加工工序<a href="#二添加粗加工工序"><span>#</span></a></h1><p>1.添加平面铣加工工序</p><p>将工序导航器切换至程序视图，右键点击插入工序：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/15342098144760.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/15342098387492.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p><p>弹出对话框，选择平面铣（planar Mill）参数设置如下：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220315114652207.png" alt="image-20220315114652207" /><figcaption>image-20220315114652207</figcaption></figure><p></p><p>弹出平面铣对话框，设置切削层参数，可以修改相应的切削参数</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220315114725330.png" alt="image-20220315114725330" /><figcaption>image-20220315114725330</figcaption></figure><p></p><p>点击生成，出现刀轨效果如下：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220315114841403.png" alt="image-20220315114841403" /><figcaption>image-20220315114841403</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220315110346007.png" alt="image-20220315110346007" /><figcaption>image-20220315110346007</figcaption></figure><p></p></section>
<section><h1>三、精加工工序<a href="#三精加工工序"><span>#</span></a></h1><p>将工序导航器切换至程序视图，右键点击插入工序：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/15342098387492-164731619499113.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p><p>弹出对话框，选择<strong>可变轴轮廓铣（VARIABLE_CONTOUR）</strong>，选择之前创建的<strong>铣削几何体（MILL_AREA）</strong>，参数设置如下</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220315115034297.png" alt="image-20220315115034297" /><figcaption>image-20220315115034297</figcaption></figure><p></p><p>弹出<strong>可变****轮廓铣</strong>对话框，设置驱动方法为曲面，</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220315115140634.png" alt="image-20220315115140634" /><figcaption>image-20220315115140634</figcaption></figure><p></p><p>弹出对话框，点击指定驱动几何体按钮，如下：</p><p>通过修改驱动设置可以改变铣削参数</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220315115320124.png" alt="image-20220315115320124" /><figcaption>image-20220315115320124</figcaption></figure><p></p><p>点击确定，系统回退至曲面区域驱动方法对话框，选择切削方向如下:</p><p></p><figure><img src="http://imgbed.leihub.cn/img/15352768746542.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p><p>选择完成后系统有回退至之前对话框，设置材料侧方向，点击如下按钮，</p><p></p><figure><img src="http://imgbed.leihub.cn/img/15352770378816.png" alt="undefined" /><figcaption>undefined</figcaption></figure><p></p><p>点击生成刀轨</p><p>刀轨生成后可以在3d动态中查看铣削状态。</p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/746/</id>
      <title type="text">ADAMS机械动力学（一）：机电联合仿真</title>
      <published>2023-04-10T11:52:45.000Z</published>
      <updated>2024-06-06T15:59:17.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/746/"/>
      <summary type="text">1.创建控制系统 单击界面菜单中的工具 Tools ，然后单击工具下的插件管理器（ Plugin Manager ，系统弹加载模块。在模块中选择Adams Controls和Adams Mechatronics两项，如图8-35所示，然后单</summary>
      <content type="html"><![CDATA[<section><h1>1.创建控制系统<a href="#1创建控制系统"><span>#</span></a></h1><p>单击界面菜单中的工具(Tools )，然后单击工具下的插件管理器（ Plugin Manager )，系统弹加载模块。在模块中选择Adams Controls和Adams Mechatronics两项，如图8-35所示，然后单击确定（OK）按钮加载。
单击界面菜单Mechatronics(机械电子学),然后依次单击控制系统( Control System） →新建(New）系统弹出创建控制系统对话框。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/@FY8O8RY9AN8Y4%7B1%25$@0Y7P-1680400372310-5.png" alt="@FY8O8RY9AN8Y4{1%$@0Y7P" /><figcaption>@FY8O8RY9AN8Y4{1%$@0Y7P</figcaption></figure><p></p><p>在名称（Name )中输入robot_control，在系统类型(System Type栏中选择外部系统库(External System Library )，在静态搁置(Static Hold)栏中选择开（On )在输入的个数( Number of Inputs )栏中输入12，在输出的个数( Number of Outputs )栏中输入3,如图所示。然后单击图标，系统弹出创建单变量对话框。</p><p>在创建单变量对话框中按照如图所示的参数进行设置。然后单击OK(确定）按钮完成设置。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/%E5%8F%98%E9%87%8F.jpg" alt="变量" /><figcaption>变量</figcaption></figure><figure><img src="http://imgbed.leihub.cn/img/%E8%BE%93%E5%85%A5%E5%8F%98%E9%87%8F.png" alt="输入变量" /><figcaption>输入变量</figcaption></figure><p></p></section>
<section><h1>2.创建传感器信号<a href="#2创建传感器信号"><span>#</span></a></h1><ol>
<li>
<p>分别在两个连杆之间建立12个测量参考点，用于建立关节角测量传感器</p>
</li>
<li>
<p>在界面上依次单击机械电子学(Mechatronics)→机械系统(Mechanical System )→传感器信号( Transducer Signal)→新建(New )，系统弹出创建传感器信号对话框。在信号名称 （Signal Name)栏中输入axis_angle_1，在函数(Function)栏中输入( <code>AZ( ref_2, ref_1)</code>)，在单位类型栏中选择角度，在单位字符串栏中选择rad，在请求有效栏后的选项中选中开，如图所示，然后单击确定按钮,通过上述步骤建立6个关节角的传感器信号。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/%E5%85%B3%E8%8A%82%E4%BC%A0%E6%84%9F%E5%99%A8%E4%BF%A1%E5%8F%B7.png" alt="关节传感器信号" /><figcaption>关节传感器信号</figcaption></figure><p></p>
</li>
<li>
<p>在界面上依次单击机械电子学(Mechatronics )→机械系统(Mechanical System )→传感器信号( Transducer Signal )→新建（New)，系统弹出创建输入信号对话框，添加末端位姿测量传感器，以基座标为基准。</p>
</li>
<li>
<p>在信号名称( Signal Name)栏中输入<code>tool_position_x</code>，在函数(Function )栏中输入<code>DX( .KUKA.Tool.MARKER_tool , .KUKA.base.jizuobiao , .KUKA.base.jizuobiao )</code>。</p>
</li>
<li>
<p>在单位类型(Unit Type )栏中选择长度( length )，在单位字符串 ( Unit String )栏中选择模型单位 ( model units )，在请求有效(Request Active）栏中选中开（On )，如图所示，然后单击确定（OK）按钮，同理添加姿态传感器信号。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/%E6%9C%AB%E7%AB%AF%E4%BD%8D%E7%BD%AE%E4%BC%A0%E6%84%9F%E5%99%A8.png" alt="末端位置传感器" /><figcaption>末端位置传感器</figcaption></figure><p></p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/%E6%9C%AB%E7%AB%AF%E5%A7%BF%E6%80%81%E4%BC%A0%E6%84%9F%E5%99%A8.png" alt="末端姿态传感器" /><figcaption>末端姿态传感器</figcaption></figure><p></p>
</li>
</ol></section>
<section><h1>3.创建激励信号<a href="#3创建激励信号"><span>#</span></a></h1><ol>
<li>在界面上依次单击机械电子学( Mechatronics )→机械系统( Mechanical System )→激励信号( Actuator Signal )→新建( New)，系统弹出创建激励信号对话框。</li>
<li>在信号名称( Signal Name)栏中输入controller_torque，在单位类型( Unit Type)栏中选择扭矩( torque )，在单位字符串(Unit String )栏中选择模型单位( model units )，在请求有效(RequestActive)栏中选中开( On )，如图8-43所示，然后单击确定（OK）按钮。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/%E6%BF%80%E5%8A%B1%E4%BF%A1%E5%8F%B7.png" alt="激励信号" /><figcaption>激励信号</figcaption></figure><p></p></section>
<section><h1>4.编辑控制系统<a href="#4编辑控制系统"><span>#</span></a></h1><ol>
<li>
<p>在界面上单击编辑(Edit)菜单，然后单击修改( Modify )选项，双击ball_beam，从中选择SFORCE_x，单击确定（OK)按钮，系统弹出控制系统。</p>
</li>
<li>
<p>单击函数( Function ),在其中输入<code>VARVAL(.KUKA.ues_csa_force_z_control.signal_variable)</code>,其余采用默认设置，然后单击确定（OK)按钮完成创建，如图所示。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/%E7%BC%96%E8%BE%91%E6%8E%A7%E5%88%B6%E7%B3%BB%E7%BB%9F.png" alt="编辑控制系统" /><figcaption>编辑控制系统</figcaption></figure><p></p>
<h1>5.用信号管理器连接信号<a href="#5用信号管理器连接信号"><span>#</span></a></h1>
<ol>
<li>
<p>在界面上依次单击机械电子学(Mechatronics )→信号管理(Signal Manager )→显示( Display ) ,如图所示，单击应用（ Apply)按钮，系统弹出信号管理器。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/%E4%BF%A1%E5%8F%B7%E7%AE%A1%E7%90%86%E5%99%A8.png" alt="信号管理器" /><figcaption>信号管理器</figcaption></figure><p></p>
</li>
<li>
<p>双击信号管理器中的任意一个表格，系统弹出信号管理，单击Inputs(输入）中的第一栏，系统弹出如图所示的对话框。单击Connector Signal Name(连接信号名称）下的第一行，然后单击Select(选择）按钮，再单击Apply(应用)按钮，将输入输出与信号进行连接。</p>
<p></p><figure><img src="http://imgbed.leihub.cn/img/%E8%BE%93%E5%85%A5%E4%BF%A1%E5%8F%B7.png" alt="输入信号" /><figcaption>输入信号</figcaption></figure><figure><img src="http://imgbed.leihub.cn/img/%E8%BE%93%E5%87%BA%E4%BF%A1%E5%8F%B7.png" alt="输出信号" /><figcaption>输出信号</figcaption></figure><p></p>
</li>
</ol>
</li>
</ol></section>
<section><h1>6.输出面板<a href="#6输出面板"><span>#</span></a></h1><p>在界面菜单中依次单击机械电子学(Mechatronics )→工具(Tools )→输出面板(Export Plant）系统弹出输出面板控制系统，在系统名称(System Name ）中输入<code>ues_robot_control</code>，在文件前辍( File Prefix )栏中输入<code>robot_control</code>，在目标软件（Target Software)栏中选择MATLAB，如图所示。单击确定（OK）按钮，系统弹出信息提示，单击确定（OK）按钮关闭信息。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/%E8%BE%93%E5%87%BA%E9%9D%A2%E6%9D%BF.png" alt="输出面板" /><figcaption>输出面板</figcaption></figure><p></p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/114/</id>
      <title type="text">粒子群算法</title>
      <published>2023-03-27T08:49:09.000Z</published>
      <updated>2024-06-06T04:29:39.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/114/"/>
      <summary type="text">粒子群算法（Particle Swarm Optimization，PSO）是20世纪90年代兴起的一门学科，因其概念简明、实现方便、收敛速度快而为人所知。粒子群算法的基本思想是模拟鸟群随机搜寻食物的捕食行为，鸟群通过自身经验和种群之间的交</summary>
      <content type="html"><![CDATA[<p>粒子群算法（Particle Swarm Optimization，PSO）是20世纪90年代兴起的一门学科，因其概念简明、实现方便、收敛速度快而为人所知。粒子群算法的基本思想是模拟鸟群随机搜寻食物的捕食行为，鸟群通过自身经验和种群之间的交流调整自己的搜寻路径，从而找到食物最多的地点。其中每只鸟的位置/路径则为自变量组合，每次到达的地点的食物密度即函数值。每次搜寻都会根据自身经验（自身历史搜寻的最优地点）和种群交流（种群历史搜寻的最优地点）调整自身搜寻方向和速度，这个称为跟踪极值，从而找到最优解。</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>粒子群算法是一门新兴算法，此算法与遗传算法有很多相似之处，其收敛于全局最优解的概率很大。</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
<p>①相较于传统算法计算速度非常快，全局搜索能力也很强；
②PSO对于种群大小不十分敏感，所以初始种群设为500-1000，速度影响也不大；
③粒子群算法适用于连续函数极值问题，对于非线性、多峰问题均有较强的全局搜索能力。</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>其流程图如下：</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
<p>Step1&lt;确定一个粒子的运动状态是利用位置和速度两个参数描述的&gt;，因此初始化的也是这两个参数；
Step2: 每次搜寻的结果（函数值）即为粒子适应度，然后记录每个粒子的个体历史最优位置和群体的历史最优位置；
Step3: 个体历史最优位置和群体的历史最优位置相当于产生了两个力，结合粒子本身的惯性共同影响粒子的运动状态，由此来更新粒子的位置和速度。</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>粒子群算法中所涉及到的参数有：</span></div></div><div><div><div>2</div></div><div><span><span>   </span></span><span>种群数量：粒子群算法的最大特点就是速度快，因此初始种群取50-1000都是可以的，虽然初始种群越大收敛性会更好，不过太大了也会影响速度；</span></div></div><div><div><div>3</div></div><div><span><span>   </span></span><span>迭代次数：一般取100~4000，太少解不稳定，太多浪费时间。对于复杂问题，进化代数可以相应地提高；</span></div></div><div><div><div>4</div></div><div><span><span>   </span></span><span>惯性权重：该参数反映了个体历史成绩对现在的影响，一般取0.5~1；</span></div></div><div><div><div>5</div></div><div><span><span>   </span></span><span>学习因子：一般取0~4，此处要根据自变量的取值范围来定，并且学习因子分为个体和群体两种；</span></div></div><div><div><div>6</div></div><div><span><span>   </span></span><span>空间维数：粒子搜索的空间维数即为自变量的个数。</span></div></div><div><div><div>7</div></div><div><span><span>   </span></span><span>位置限制：限制粒子搜索的空间，即自变量的取值范围，对于无约束问题此处可以省略。</span></div></div><div><div><div>8</div></div><div><span><span>   </span></span><span>速度限制：如果粒子飞行速度过快，很可能直接飞过最优解位置，但是如果飞行速度过慢，会使得收敛速度变慢，因此设置合理的速度限制就很有必要了。</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span><span>  </span></span><span>不同于遗传算法，粒子群算法不需要编码，直接利用粒子的位置来表示自变量，每个粒子的位置都由自变量的个数和取值范围决定，而速度由自变量的个数和速度限制决定，形式如下，其中d代表空间维数(自变量数）：</span></div></div><div><div><div>11</div></div><div>
</div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>下面我们用一个例子来帮助理解，对于函数 f=x*sin(x)*cos(2*x)-2*x*sin(3*x) ，求其在区间[0,20]上该函数的最大值。首先我们需要画出函数的图像，如下图：</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span><span>   </span></span><span>多峰问题对于算法的检验效果最佳，而上图显然是一个简单的非等距、非等高的多峰一元函数。</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
<p>初始化种群
已知位置限制[0,20],由于一维问题较为简单，因此可以取初始种群N 为50，迭代次数为100,当然空间维数d 也就是1。
位置和速度的初始化即在位置和速度限制内随机生成一个N x d 的矩阵，对于此题，位置初始化也就是在020内随机生成一个50x1的数据矩阵，而对于速度则不用考虑约束，一般直接在01内随机生成一个50x1的数据矩阵。
此处的位置约束也可以理解为位置限制，而速度限制是保证粒子步长不超限制的，一般设置速度限制为[-1,1]。
粒子群的另一个特点就是记录每个个体的历史最优和种群的历史最优，因此而二者对应的最优位置和最优值也需要初始化。其中每个个体的历史最优位置可以先初始化为当前位置,而种群的历史最优位置则可初始化为原点。对于最优值，如果求最大值则初始化为负无穷，相反地初始化为正无穷。
每次搜寻都需要将当前的适应度和最优解同历史的记录值进行对比，如果超过历史最优值，则更新个体和种群的历史最优位置和最优解。
通过之前的参数设定可以得到如下的初始分布图：</p>
<p>速度与位置的更新
速度和位置更新是粒子群算法的核心，其原理表达式和更新方式如下:</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>   </span></span><span>每次更新完速度和位置都需要考虑速度和位置的限制，需要将其限制在规定范围内，此处仅举出一个常规方法，即将超约束的数据约束到边界（当位置或者速度超出初始化限制时，将其拉回靠近的边界处）。当然，你不用担心他会停住不动，因为每个粒子还有惯性和其他两个参数的影响。</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
<blockquote><p>代码如下:</p><p>clc;clear;close all;</p><p>%% 初始化种群</p><p>f= @(x)x .* sin(x) .* cos(2 * x) - 2 * x .* sin(3 * x); % 函数表达式</p><p>figure(1);ezplot(f,[0,0.01,20]);</p><p>N = 50; % 初始种群个数</p><p>d = 1; % 空间维数</p><p>ger = 100; % 最大迭代次数</p><p>limit = [0, 20]; % 设置位置参数限制</p><p>vlimit = [-1, 1]; % 设置速度限制</p><p>w = 0.8; % 惯性权重</p><p>c1 = 0.5; % 自我学习因子</p><p>c2 = 0.5; % 群体学习因子</p><p>for i = 1</p><p>x = limit(i, 1) + (limit(i, 2) - limit(i, 1)) * rand(N, d);%初始种群的位置</p><p>end</p><p>v = rand(N, d); % 初始种群的速度</p><p>xm = x; % 每个个体的历史最佳位置</p><p>ym = zeros(1, d); % 种群的历史最佳位置</p><p>fxm = zeros(N, 1); % 每个个体的历史最佳适应度</p><p>fym = -inf; % 种群历史最佳适应度</p><p>hold on</p><p>plot(xm, f(xm), ‘ro’);title(‘初始状态图’);</p><p>figure(2)</p><p>%% 群体更新</p><p>iter = 1;</p><p>record = zeros(ger, 1); % 记录器</p><p>while iter &lt;= ger fx = f(x) ; % 个体当前适应度 for i = 1 if fxm(i) &lt; fx(i) fxm(i) = fx(i); % 更新个体历史最佳适应度 xm(i,:) = x(i,:); % 更新个体历史最佳位置 end end if fym &lt; max(fxm) = max(fxm); % 更新群体历史最佳适应度 ym = xm(nmax, :); % 更新群体历史最佳位置 end v = v * w + c1 * rand * (xm - x) + c2 * rand * (repmat(ym, N, 1) - x);% 速度更新 % 边界速度处理 v(v &gt; vlimit(2)) = vlimit(2);</p><p>v(v &lt; vlimit(1)) = vlimit(1); x = x + v;% 位置更新 % 边界位置处理 x(x &gt; limit(2)) = limit(2);</p><p>x(x &lt; limit(1)) = limit(1);</p><p>record(iter) = fym;%最大值记录</p><p>% x0 = 0 : 0.01 : 20;</p><p>% plot(x0, f(x0), ‘b-’, x, f(x), ‘ro’);title(‘状态位置变化’)</p><p>% pause(0.1)</p><p>iter = iter+1;</p><p>end</p><p>figure(3);plot(record);title(‘收敛过程’)</p><p>x0 = 0 : 0.01 : 20;</p><p>figure(4);plot(x0, f(x0), ‘b-’, x, f(x), ‘ro’);title(‘最终状态位置’)</p><p>disp([‘最大值：‘,num2str(fym)]);</p><p>disp([‘变量取值：‘,num2str(ym)]);</p></blockquote>
<p>结果如下：</p>
<div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>由上图可以看出算法已成功找出了最优解，其最优解为18.3014，而其最大值为32.1462。</span></div></div><div><div><div>2</div></div><div><span>如果想看粒子群算法中粒子的搜索过程的可以将代码中注释掉的三行代码放上去。效果是这样的：</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
<p>原文链接：<a href="https://blog.csdn.net/nightmare_dimple/article/details/74331679" target="_blank">https://blog.csdn.net/nightmare_dimple/article/details/74331679</a></p>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/755/</id>
      <title type="text">typora公式记录</title>
      <published>2023-01-16T13:04:58.000Z</published>
      <updated>2024-06-06T15:59:27.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/755/"/>
      <summary type="text">Markdown公式 1.公式块 创建独立的一块公式区域。 方法一：左上角点击“段落”，再点击“公式块” 方法二：在文中输入 ，再按下回车 2.行内公式 将公式嵌入文字内。 方法一： 在 的中间加入需要的公式 简便的方法一：先按 ，再按 “</summary>
      <content type="html"><![CDATA[<section><h1>Markdown公式<a href="#markdown公式"><span>#</span></a></h1><section><h2>1.公式块<a href="#1公式块"><span>#</span></a></h2><ul>
<li><strong>创建独立的一块公式区域</strong>。</li>
</ul><p><strong>方法一</strong>：左上角点击“段落”，再点击“公式块”</p><p><strong>方法二</strong>：在文中输入$$，再按下回车</p><section><h3>2.行内公式<a href="#2行内公式"><span>#</span></a></h3><ul>
<li><strong>将公式嵌入文字内</strong>。</li>
</ul><p><strong>方法一</strong>： 在$$的中间加入需要的公式</p><p><strong>简便的方法一</strong>：先按 $ ，再按 “esc”（键盘左上角）</p><p>（行内公式是需要先设置一下）</p><hr /></section></section><section><h2>基本格式<a href="#基本格式"><span>#</span></a></h2><section><h3><strong>1.上下标</strong><a href="#1上下标"><span>#</span></a></h3><blockquote><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span>A_1^2</span></div></div><div><div><div>3</div></div><div><span>\\</span></div></div><div><div><div>4</div></div><div><span>B_{12}</span></div></div><div><div><div>5</div></div><div><span>\\</span></div></div><div><div><div>6</div></div><div><span>2^{x^2+y}</span></div></div><div><div><div>7</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></blockquote><span><span><span>A12B122x2+y\begin{gathered}
A_1^2
\\
B_{12}
\\
2^{x^2+y}
\end{gathered}</span><span><span><span></span><span><span><span><span><span><span><span><span></span><span><span><span>A</span><span><span><span><span><span><span></span><span><span>1</span></span></span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span><span><span>B</span><span><span><span><span><span><span></span><span><span><span>12</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span><span><span>2</span><span><span><span><span><span><span></span><span><span><span><span>x</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span><span>+</span><span>y</span></span></span></span></span></span></span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span></span></section><section><h3><strong>2.分数</strong><a href="#2分数"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span>\frac{x}{1+x^2}</span></div></div><div><div><div>3</div></div><div><span>\\</span></div></div><div><div><div>4</div></div><div><span>\frac{\frac{1}{2}+x}{y}</span></div></div><div><div><div>5</div></div><div><span>\\</span></div></div><div><div><div>6</div></div><div><span>\tfrac{a}{b}</span></div></div><div><div><div>7</div></div><div><span>\frac{a}{b}</span></div></div><div><div><div>8</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><span><span><span>x1+x212+xyabab\begin{gathered}
\frac{x}{1+x^2}
\\
\frac{\frac{1}{2}+x}{y}
\\
\tfrac{a}{b}
\frac{a}{b}
\end{gathered}</span><span><span><span></span><span><span><span><span><span><span><span><span></span><span><span><span></span><span><span><span><span><span><span></span><span><span>1</span><span></span><span>+</span><span></span><span><span>x</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span></span></span><span><span></span><span></span></span><span><span></span><span><span>x</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span></span></span><span><span></span><span><span><span></span><span><span><span><span><span><span></span><span><span>y</span></span></span><span><span></span><span></span></span><span><span></span><span><span><span></span><span><span><span><span><span><span></span><span><span><span>2</span></span></span></span><span><span></span><span></span></span><span><span></span><span><span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span><span></span><span>+</span><span></span><span>x</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span></span></span><span><span></span><span><span><span></span><span><span><span><span><span><span></span><span><span><span>b</span></span></span></span><span><span></span><span></span></span><span><span></span><span><span><span>a</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span><span><span></span><span><span><span><span><span><span></span><span><span>b</span></span></span><span><span></span><span></span></span><span><span></span><span><span>a</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span></span></section><section><h3>3.开根号，取模<a href="#3开根号取模"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span>\sqrt{x}</span></div></div><div><div><div>3</div></div><div><span>\sqrt</span><span>[</span><span>3</span><span>]</span><span>{x}</span></div></div><div><div><div>4</div></div><div><span>\\</span></div></div><div><div><div>5</div></div><div><span>x \pmod a</span></div></div><div><div><div>6</div></div><div><span>\\</span></div></div><div><div><div>7</div></div><div><span>2\mod{x}</span></div></div><div><div><div>8</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><span><span><span>xx3x(moda)2mod  x\begin{gathered}
\sqrt{x}
\sqrt[3]{x}
\\
x \pmod a
\\
2\mod{x}
\end{gathered}</span><span><span><span></span><span><span><span><span><span><span><span><span></span><span><span><span><span><span><span><span></span><span><span>x</span></span></span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span><span><span><span><span><span><span></span><span><span><span>3</span></span></span></span></span></span></span></span><span><span><span><span><span></span><span><span>x</span></span></span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span><span><span></span><span><span>x</span><span></span><span></span><span>(</span><span><span><span>mod</span></span></span><span></span><span>a</span><span>)</span></span></span><span><span></span><span><span>2</span><span></span><span></span><span><span><span>mod</span></span></span><span></span><span></span><span>x</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span></span></section><section><h3>4**.组合数**<a href="#4组合数"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span>\binom{n}{k}</span></div></div><div><div><div>3</div></div><div><span>\tbinom{n}{k}</span></div></div><div><div><div>4</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><span><span><span>(nk)(nk)\binom{n}{k}
\tbinom{n}{k}</span><span><span><span></span><span><span><span>(</span></span><span><span><span><span><span><span></span><span><span>k</span></span></span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span><span>)</span></span></span><span><span><span>(</span></span><span><span><span><span><span><span></span><span><span><span>k</span></span></span></span><span><span></span><span><span><span>n</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span><span>)</span></span></span></span></span></span></span></section><section><h3><strong>5.导数、偏微分、积分</strong>、累加/累乘/极限<a href="#5导数偏微分积分累加累乘极限"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code></code></pre><div><div></div><div></div></div></figure></div><span><span><span>a′a′′a′∇∫12∫21∮∫∬∯∭∰\begin{gathered}
a'
a''
a^{\prime}
\\
\nabla
\\

\\
\int_{1}^{2}
\intop_{2}^{1}
\oint
\smallint
\\
\iint
\oiint
\iiint
\oiiint
\end{gathered}</span><span><span><span></span><span><span><span><span><span><span><span><span></span><span><span><span>a</span><span><span><span><span><span><span></span><span><span><span>′</span></span></span></span></span></span></span></span></span><span><span>a</span><span><span><span><span><span><span></span><span><span><span>′′</span></span></span></span></span></span></span></span></span><span><span>a</span><span><span><span><span><span><span></span><span><span><span>′</span></span></span></span></span></span></span></span></span></span></span><span><span></span><span><span>∇</span></span></span><span><span></span><span></span></span><span><span></span><span><span><span>∫</span><span><span><span><span><span><span></span><span><span><span>1</span></span></span></span><span><span></span><span><span><span>2</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span><span><span><span><span><span></span><span><span><span>2</span></span></span></span><span><span></span><span><span>∫</span></span></span><span><span></span><span><span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span><span>∮</span><span></span><span>∫</span></span></span><span><span></span><span><span>∬</span><span></span><span><span><span><span><span></span><span>∬</span></span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span><span></span><span>∭</span><span></span><span><span><span><span><span></span><span>∭</span></span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span></span></section><section><h3>7.积分<a href="#7积分"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$ \int_0^1 {x^2} \,{\rm d}x $$</span></div></div></code></pre><div><div></div><div></div></div></figure></div><span><span><span>∫01x2 dx\int_0^1 {x^2} \,{\rm d}x</span><span><span><span></span><span><span>∫</span><span><span><span><span><span><span></span><span><span>0</span></span></span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span><span><span>x</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span></span><span></span><span><span><span>d</span></span></span><span>x</span></span></span></span></span></section><section><h3>8.求导<a href="#8求导"><span>#</span></a></h3><section><h4>(1）求导<a href="#1求导"><span>#</span></a></h4><span><span><span>df(θ)dθ\frac{df(\theta)}{d\theta}</span><span><span><span></span><span><span></span><span><span><span><span><span><span></span><span><span>d</span><span>θ</span></span></span><span><span></span><span></span></span><span><span></span><span><span>df</span><span>(</span><span>θ</span><span>)</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span></span></span></span></span><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span>\frac{df(\theta)}{d\theta}</span></div></div><div><div><div>3</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h4>(2) 求偏导<a href="#2-求偏导"><span>#</span></a></h4><span><span><span>∂Loss∂C\frac {\partial Loss } {\partial C }</span><span><span><span></span><span><span></span><span><span><span><span><span><span></span><span><span>∂</span><span>C</span></span></span><span><span></span><span></span></span><span><span></span><span><span>∂</span><span>L</span><span>oss</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span></span></span></span></span><hr /><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span>\frac {\partial Loss } {\partial C }</span></div></div><div><div><div>3</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section></section></section><section><h2><strong>矩阵</strong><a href="#矩阵"><span>#</span></a></h2><section><h3><strong>1.简单矩阵</strong><a href="#1简单矩阵"><span>#</span></a></h3><p>使用<code>\begin{matrix}…\end{matrix}</code>生成， 每一行以<code>\\</code>结尾表示换行，元素间以<code>&amp;</code>间隔，式子的表示序号<code>\tag{1}</code>（右边的序号）。</p><p></p><figure><img src="https://www.zhihu.com/equation?tex=%5Cbegin%7Bmatrix%7D++1+%26+2+%26+3+%5C++4+%26+5+%26+6+%5C++7+%26+8+%26+9++%5Cend%7Bmatrix%7D+%5Ctag%7B1%7D" alt="[公式]" /><figcaption>[公式]</figcaption></figure><p></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span> </span></span><span>$$</span></div></div><div><div><div>2</div></div><div><span>\begin{matrix}</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>1 &amp; 2 &amp; 3 \\</span></div></div><div><div><div>4</div></div><div><span><span> </span></span><span>4 &amp; 5 &amp; 6 \\</span></div></div><div><div><div>5</div></div><div><span><span> </span></span><span>7 &amp; 8 &amp; 9</span></div></div><div><div><div>6</div></div><div><span>\end{matrix} \tag{1}</span></div></div><div><div><div>7</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3><strong>2.带左右括号的矩阵(大中小括号)</strong><a href="#2带左右括号的矩阵大中小括号"><span>#</span></a></h3><p><strong>方法一</strong>：在<code>\begin{}</code>之前和<code>\end{}</code>之后添加左右括号的代码。</p><p>大括号：</p><p></p><figure><img src="https://www.zhihu.com/equation?tex=%5Cleft%7B++%5Cbegin%7Bmatrix%7D++++1+%26+2+%26+3+%5C++++4+%26+5+%26+6+%5C++++7+%26+8+%26+9+++%5Cend%7Bmatrix%7D+++%5Cright%7D+%5Ctag%7B2%7D" alt="[公式]" /><figcaption>[公式]</figcaption></figure><p></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>\left\{</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>\begin{matrix}</span></div></div><div><div><div>4</div></div><div><span><span>   </span></span><span>1 &amp; 2 &amp; 3 \\</span></div></div><div><div><div>5</div></div><div><span><span>   </span></span><span>4 &amp; 5 &amp; 6 \\</span></div></div><div><div><div>6</div></div><div><span><span>   </span></span><span>7 &amp; 8 &amp; 9</span></div></div><div><div><div>7</div></div><div><span><span>  </span></span><span>\end{matrix}</span></div></div><div><div><div>8</div></div><div><span><span>  </span></span><span>\right\} \tag{2}</span></div></div><div><div><div>9</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>中括号：</p><p></p><figure><img src="https://www.zhihu.com/equation?tex=%5Cleft%5B++%5Cbegin%7Bmatrix%7D++++1+%26+2+%26+3+%5C++++4+%26+5+%26+6+%5C++++7+%26+8+%26+9+++%5Cend%7Bmatrix%7D+++%5Cright%5D+%5Ctag%7B3%7D" alt="[公式]" /><figcaption>[公式]</figcaption></figure><p></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>\left[</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>\begin{matrix}</span></div></div><div><div><div>4</div></div><div><span><span>   </span></span><span>1 &amp; 2 &amp; 3 \\</span></div></div><div><div><div>5</div></div><div><span><span>   </span></span><span>4 &amp; 5 &amp; 6 \\</span></div></div><div><div><div>6</div></div><div><span><span>   </span></span><span>7 &amp; 8 &amp; 9</span></div></div><div><div><div>7</div></div><div><span><span>  </span></span><span>\end{matrix}</span></div></div><div><div><div>8</div></div><div><span><span>  </span></span><span>\right] \tag{3}</span></div></div><div><div><div>9</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>小括号：</p><p></p><figure><img src="https://www.zhihu.com/equation?tex=%5Cleft(++%5Cbegin%7Bmatrix%7D++++1+%26+2+%26+3+%5C++++4+%26+5+%26+6+%5C++++7+%26+8+%26+9+++%5Cend%7Bmatrix%7D+++%5Cright)+%5Ctag%7B4%7D" alt="[公式]" /><figcaption>[公式]</figcaption></figure><p></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>\left(</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>\begin{matrix}</span></div></div><div><div><div>4</div></div><div><span><span>   </span></span><span>1 &amp; 2 &amp; 3 \\</span></div></div><div><div><div>5</div></div><div><span><span>   </span></span><span>4 &amp; 5 &amp; 6 \\</span></div></div><div><div><div>6</div></div><div><span><span>   </span></span><span>7 &amp; 8 &amp; 9</span></div></div><div><div><div>7</div></div><div><span><span>  </span></span><span>\end{matrix}</span></div></div><div><div><div>8</div></div><div><span><span>  </span></span><span>\right) \tag{4}</span></div></div><div><div><div>9</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>方法二</strong>：改变<code>\begin{matrix}</code>和<code>\end{matrix}</code>中<code>{matrix}</code></p><p>大括号：</p><p></p><figure><img src="https://www.zhihu.com/equation?tex=%5Cbegin%7BBmatrix%7D++++1+%26+2+%26+3+%5C++++4+%26+5+%26+6+%5C++++7+%26+8+%26+9+++%5Cend%7BBmatrix%7D+%5Ctag%7B5%7D" alt="[公式]" /><figcaption>[公式]</figcaption></figure><p></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>\begin{Bmatrix}</span></div></div><div><div><div>3</div></div><div><span><span>   </span></span><span>1 &amp; 2 &amp; 3 \\</span></div></div><div><div><div>4</div></div><div><span><span>   </span></span><span>4 &amp; 5 &amp; 6 \\</span></div></div><div><div><div>5</div></div><div><span><span>   </span></span><span>7 &amp; 8 &amp; 9</span></div></div><div><div><div>6</div></div><div><span><span>  </span></span><span>\end{Bmatrix} \tag{6}</span></div></div><div><div><div>7</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>中括号：</p><p></p><figure><img src="https://www.zhihu.com/equation?tex=%5Cbegin%7Bbmatrix%7D++++1+%26+2+%26+3+%5C++++4+%26+5+%26+6+%5C++++7+%26+8+%26+9+++%5Cend%7Bbmatrix%7D+%5Ctag%7B6%7D" alt="[公式]" /><figcaption>[公式]</figcaption></figure><p></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>\begin{bmatrix}</span></div></div><div><div><div>3</div></div><div><span><span>   </span></span><span>1 &amp; 2 &amp; 3 \\</span></div></div><div><div><div>4</div></div><div><span><span>   </span></span><span>4 &amp; 5 &amp; 6 \\</span></div></div><div><div><div>5</div></div><div><span><span>   </span></span><span>7 &amp; 8 &amp; 9</span></div></div><div><div><div>6</div></div><div><span><span>  </span></span><span>\end{bmatrix} \tag{6}</span></div></div><div><div><div>7</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3><strong>3.包含希腊字母与省略号</strong><a href="#3包含希腊字母与省略号"><span>#</span></a></h3><p>行省略号<code>\cdots</code>，列省略号<code>\vdots</code>，斜向省略号（左上至右下）<code>\ddots</code>。</p><p></p><figure><img src="https://www.zhihu.com/equation?tex=%5Cleft%7B++%5Cbegin%7Bmatrix%7D++1++++++%26+2++++++++%26+%5Ccdots+%26+5++++++++%5C++6++++++%26+7++++++++%26+%5Ccdots+%26+10+++++++%5C++%5Cvdots+%26+%5Cvdots+++%26+%5Cddots+%26+%5Cvdots+++%5C++%5Calpha+%26+%5Calpha%2B1+%26+%5Ccdots+%26+%5Calpha%2B4+++%5Cend%7Bmatrix%7D++%5Cright%7D" alt="[公式]" /><figcaption>[公式]</figcaption></figure><p></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>\left\{</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>\begin{matrix}</span></div></div><div><div><div>4</div></div><div><span><span> </span></span><span>1      &amp; 2        &amp; \cdots &amp; 5        \\</span></div></div><div><div><div>5</div></div><div><span><span> </span></span><span>6      &amp; 7        &amp; \cdots &amp; 10       \\</span></div></div><div><div><div>6</div></div><div><span><span> </span></span><span>\vdots &amp; \vdots   &amp; \ddots &amp; \vdots   \\</span></div></div><div><div><div>7</div></div><div><span><span> </span></span><span>\alpha &amp; \alpha+1 &amp; \cdots &amp; \alpha+4</span></div></div><div><div><div>8</div></div><div><span><span> </span></span><span>\end{matrix}</span></div></div><div><div><div>9</div></div><div><span><span> </span></span><span>\right\}</span></div></div><div><div><div>10</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div><hr /></section></section><section><h2>公式序号<a href="#公式序号"><span>#</span></a></h2><p>见“矩阵”小节，代码最后的一行即表示右端序号</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>......</span></div></div><div><div><div>2</div></div><div><span>\tag{6}</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h2>行列式<a href="#行列式"><span>#</span></a></h2><p>行列式相关语法与矩阵类似</p><span><span><span>∣123456789∣(7)\begin{vmatrix}
   1 &amp; 2 &amp; 3 \\
   4 &amp; 5 &amp; 6 \\
   7 &amp; 8 &amp; 9
  \end{vmatrix}
\tag{7}</span><span><span><span></span><span><span><span><span><span><span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span><span><span><span><span><span><span></span><span><span>1</span></span></span><span><span></span><span><span>4</span></span></span><span><span></span><span><span>7</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span><span></span><span><span><span><span><span><span></span><span><span>2</span></span></span><span><span></span><span><span>5</span></span></span><span><span></span><span><span>8</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span><span></span><span><span><span><span><span><span></span><span><span>3</span></span></span><span><span></span><span><span>6</span></span></span><span><span></span><span><span>9</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span><span><span><span><span><span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span><span>(</span><span><span>7</span></span><span>)</span></span></span></span></span></span><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>\begin{vmatrix}</span></div></div><div><div><div>3</div></div><div><span><span>   </span></span><span>1 &amp; 2 &amp; 3 \\</span></div></div><div><div><div>4</div></div><div><span><span>   </span></span><span>4 &amp; 5 &amp; 6 \\</span></div></div><div><div><div>5</div></div><div><span><span>   </span></span><span>7 &amp; 8 &amp; 9</span></div></div><div><div><div>6</div></div><div><span><span>  </span></span><span>\end{vmatrix}</span></div></div><div><div><div>7</div></div><div><span>\tag{7}</span></div></div><div><div><div>8</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div><hr /></section><section><h2>表格<a href="#表格"><span>#</span></a></h2><section><h3><strong>1.简易表格</strong><a href="#1简易表格"><span>#</span></a></h3><p></p><figure><img src="https://www.zhihu.com/equation?tex=%5Cbegin%7Barray%7D%7B%7Cc%7Cc%7Cc%7C%7D+%09%5Chline+2%269%264%5C%5C+%09%5Chline+7%265%263%5C%5C+%09%5Chline+6%261%268%5C%5C+%09%5Chline+%5Cend%7Barray%7D" alt="[公式]" /><figcaption>[公式]</figcaption></figure><p></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span>\begin{array}{|c|c|c|}</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>\hline 2&amp;9&amp;4\\</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>\hline 7&amp;5&amp;3\\</span></div></div><div><div><div>5</div></div><div><span><span>  </span></span><span>\hline 6&amp;1&amp;8\\</span></div></div><div><div><div>6</div></div><div><span><span>  </span></span><span>\hline</span></div></div><div><div><div>7</div></div><div><span>\end{array}</span></div></div><div><div><div>8</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>开头结尾</strong>： <code>\begin{array}</code> ， <code>\end{array}</code></p><p><strong>定义式</strong>：例：<code>{|c|c|c|}</code>，其中<code>c</code> <code>l</code> <code>r</code> 分别代表居中、左对齐及右对齐。</p><p><strong>分割线</strong>：①<strong>竖直分割线</strong>：在定义式中插入 <code>|</code>， （<code>||</code>表示两条竖直分割线）。</p><p>②<strong>水平分割线</strong>：在下一行输入前插入 <code>\hline</code>，以下图真值表为例。</p><p>其他：每行元素间均须要插入 <code>&amp;</code> ，每行元素以 <code>\\</code> 结尾。</p></section><section><h3><strong>2..真值表</strong><a href="#2真值表"><span>#</span></a></h3><p></p><figure><img src="https://www.zhihu.com/equation?tex=%5Cbegin%7Barray%7D%7Bcc%7Cc%7D+%09+++++++A%26B%26F%5C%5C+%09%5Chline+0%260%260%5C%5C+%09+++++++0%261%261%5C%5C+%09+++++++1%260%261%5C%5C+%09+++++++1%261%261%5C%5C+%5Cend%7Barray%7D" alt="[公式]" /><figcaption>[公式]</figcaption></figure><p></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span>\begin{array}{cc|c}</span></div></div><div><div><div>3</div></div><div><span><span>         </span></span><span>A&amp;B&amp;F\\</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>\hline 0&amp;0&amp;0\\</span></div></div><div><div><div>5</div></div><div><span><span>         </span></span><span>0&amp;1&amp;1\\</span></div></div><div><div><div>6</div></div><div><span><span>         </span></span><span>1&amp;0&amp;1\\</span></div></div><div><div><div>7</div></div><div><span><span>         </span></span><span>1&amp;1&amp;1\\</span></div></div><div><div><div>8</div></div><div><span>\end{array}</span></div></div><div><div><div>9</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div><hr /></section></section><section><h2><strong>多行等式对齐</strong><a href="#多行等式对齐"><span>#</span></a></h2><p></p><figure><img src="https://www.zhihu.com/equation?tex=%5Cbegin%7Baligned%7D+a+%26%3D+b+%2B+c+%5C+++%26%3D+d+%2B+e+%2B+f+%5Cend%7Baligned%7D" alt="[公式]" /><figcaption>[公式]</figcaption></figure><p></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span>\begin{aligned}</span></div></div><div><div><div>3</div></div><div><span>a &amp;= b + c \\</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>&amp;= d + e + f</span></div></div><div><div><div>5</div></div><div><span>\end{aligned}</span></div></div><div><div><div>6</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h2><strong>方程组、条件表达式</strong><a href="#方程组条件表达式"><span>#</span></a></h2><p>方程组：</p><p></p><figure><img src="https://www.zhihu.com/equation?tex=%5Cbegin%7Bcases%7D+3x+%2B+5y+%2B++z+%5C+7x+-+2y+%2B+4z+%5C+-6x+%2B+3y+%2B+2z+%5Cend%7Bcases%7D" alt="[公式]" /><figcaption>[公式]</figcaption></figure><p></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span>\begin{cases}</span></div></div><div><div><div>3</div></div><div><span>3x + 5y +  z \\</span></div></div><div><div><div>4</div></div><div><span>7x - 2y + 4z \\</span></div></div><div><div><div>5</div></div><div><span>-6x + 3y + 2z</span></div></div><div><div><div>6</div></div><div><span>\end{cases}</span></div></div><div><div><div>7</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>同理，条件表达式：</p><p></p><figure><img src="https://www.zhihu.com/equation?tex=f(n)+%3D+%5Cbegin%7Bcases%7D++n%2F2%2C++%26+%5Ctext%7Bif+%7Dn%5Ctext%7B+is+even%7D+%5C+3n%2B1%2C+%26+%5Ctext%7Bif+%7Dn%5Ctext%7B+is+odd%7D+%5Cend%7Bcases%7D" alt="[公式]" /><figcaption>[公式]</figcaption></figure><p></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span>f(n) =</span></div></div><div><div><div>3</div></div><div><span>\begin{cases}</span></div></div><div><div><div>4</div></div><div><span>n/2,  &amp; \text{if }n\text{ is even} \\</span></div></div><div><div><div>5</div></div><div><span>3n+1, &amp; \text{if }n\text{ is odd}</span></div></div><div><div><div>6</div></div><div><span>\end{cases}</span></div></div><div><div><div>7</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div><hr /></section><section><h2><strong>间隔 (大小空格、紧贴)</strong><a href="#间隔-大小空格紧贴"><span>#</span></a></h2><p><strong>紧贴 + 无空格 + 小空格 + 中空格 + 大空格 + 真空格 + 双真空格</strong></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$$</span></div></div><div><div><div>2</div></div><div><span>a\!b + ab + a\,b + a\;b + a\ b + a\quad b + a\qquad b</span></div></div><div><div><div>3</div></div><div><span>$$</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>紧贴<code>\!</code></p><p>无空格 小空格<code>\,</code> 中空格<code>\;</code> 大空格<code>\</code></p><p>真空格<code>\quad</code> 双真空格<code>\qquad</code></p><hr /></section><section><h2>通过Python生成LaTeX表达式<a href="#通过python生成latex表达式"><span>#</span></a></h2><section><h3><strong>step1：安装latexify-py模块</strong><a href="#step1安装latexify-py模块"><span>#</span></a></h3></section><section><h3><strong>step2：编写代码</strong><a href="#step2编写代码"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>import</span><span><span> math        </span><span>//</span><span>引入数学模块</span><span>(有些运算的函数需要)</span></span></div></div><div><div><div>2</div></div><div><span>import</span><span><span> latexify      </span><span>//</span><span>引入latexify模块</span></span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span><span>@latexify</span><span>.</span><span>with_latex</span></span><span>  //特定语法，表示之后定义的函数可以转化为LaTeX代码</span></div></div><div><div><div>5</div></div><div><span>def</span><span> </span><span>f</span><span>(</span><span>x</span><span>,</span><span>y</span><span>,</span><span>z</span><span><span>):        </span><span>//</span><span>包含的参数</span></span></div></div><div><div><div>6</div></div><div><span>    </span><span>pass</span><span><span>         </span><span>//</span><span>此处填写可能需要的数学表达式</span></span></div></div><div><div><div>7</div></div><div><span>    </span><span>return</span><span><span> result    </span><span>//</span><span>也可以直接体现数学关系</span></span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>print</span><span><span>(f)         </span><span>//</span><span>直接print</span><span>(函数名)</span></span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section><section><h3><strong>step3：在输出区得到需要的LaTeX数学表达式</strong><a href="#step3在输出区得到需要的latex数学表达式"><span>#</span></a></h3><p><strong>特别说明</strong>，生成的表达式为<strong>定义式</strong>，即 ，如果只需要等式 ，可以把生成表达式中的<code>\triangleq</code>改成<code>=</code> ！</p></section></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/752/</id>
      <title type="text">kuka编程（二）：Ethernet KRL</title>
      <published>2022-06-15T12:29:29.000Z</published>
      <updated>2024-06-06T15:58:42.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/752/"/>
      <summary type="text">Ethernet KRL 1.配置以太网连接 通过 XML 文件配置以太网连接。针对每个连接，必须在机器人控制系统的目录 C: KRC ROBOTER Config User Common EthernetKRL 中定义一个配置文件。在连接</summary>
      <content type="html"><![CDATA[<section><h1>Ethernet KRL<a href="#ethernet-krl"><span>#</span></a></h1><section><h2>1.配置以太网连接<a href="#1配置以太网连接"><span>#</span></a></h2><p>通过 <strong>XML</strong> 文件配置以太网连接。针对每个连接，必须在机器人控制系统的目录 <strong>C:\KRC\ROBOTER\Config\User\Common\EthernetKRL</strong> 中定义一个配置文件。在连接初始化时将读入该配置。</p></section><section><h2>2.数据交换<a href="#2数据交换"><span>#</span></a></h2><p>数据接收 基本流程 :</p><ol>
<li>外部系统发送数据，通过协议传输数据并由 <strong>EKI</strong> 接收。</li>
<li>数据以一定的结构储存在数据存储器中。</li>
<li>从 KRL 程序以一定的结构存取数据。利用 KRL 指令读取数据并复制到KRL 变量中。</li>
</ol><p>数据发送 基本流程 :</p><ol>
<li>利用 KRL 指令将数据以一定的结构写入数据存储器中。</li>
<li>用 KRL 指令从存储器中读取数据。</li>
<li><strong>EKI</strong> 通过协议将数据发送给外部系统</li>
</ol></section><section><h2>数据保存<a href="#数据保存"><span>#</span></a></h2></section><section><h2>3.客户端 - 服务器运行模式<a href="#3客户端---服务器运行模式"><span>#</span></a></h2><p>机器人控制系统和外部系统作为客户端和服务器相互连接。其中，外部系统可以是客户端或服务器。激活的连接数量限制在 16 个。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606203015336.png" alt="image-20240606203015336" /><figcaption>image-20240606203015336</figcaption></figure><p></p><p>将 <strong>EKI</strong> 配置为服务器时，只能有一个单独的客户端与服务器连接。如果需要多个连接，则还要创建多台 EKI 服务器。可以同时在 EKI 内部运行多个客户端和服务器</p></section><section><h2>4.编程<a href="#4编程"><span>#</span></a></h2><p>在机器人控制系统的目录 <strong>C:\KRC\ROBOTER\Config\User\Common\EthernetKRL</strong> 中定义一个配置文件。XML 文件都是 “ 区分大小写 ” 的。必须注意区分大小写。</p><p>XML 文件的名称同时也是 KRL 的访问密钥。
示例：<strong>…\EXT.XML —&gt; EKI_INIT(“EXT”)</strong></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>ETHERNETKRL</span><span>&gt;</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>​  &lt;</span><span>CONFIGURATION</span><span>&gt;</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span>​    &lt;</span><span>EXTERNAL</span><span>&gt;&lt;/</span><span>EXTERNAL</span><span>&gt;</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>​    &lt;</span><span>INTERNAL</span><span>&gt;&lt;/</span><span>INTERNAL</span><span>&gt;</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>​  &lt;/</span><span>CONFIGURATION</span><span>&gt;</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>​  &lt;</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>​    &lt;</span><span>ELEMENTS</span><span>&gt;&lt;/</span><span>ELEMENTS</span><span>&gt;</span></div></div><div><div><div>14</div></div><div>
</div></div><div><div><div>15</div></div><div><span>​  &lt;/</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>16</div></div><div>
</div></div><div><div><div>17</div></div><div><span>​  &lt;</span><span>SEND</span><span>&gt;</span></div></div><div><div><div>18</div></div><div>
</div></div><div><div><div>19</div></div><div><span>​    &lt;</span><span>ELEMENTS</span><span>&gt;&lt;/</span><span>ELEMENTS</span><span>&gt;</span></div></div><div><div><div>20</div></div><div>
</div></div><div><div><div>21</div></div><div><span>​  &lt;/</span><span>SEND</span><span>&gt;</span></div></div><div><div><div>22</div></div><div>
</div></div><div><div><div>23</div></div><div><span>&lt;/</span><span>ETHERNETKRL</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div>

<table><thead><tr><th>阶段</th><th>说明</th></tr></thead><tbody><tr><td><code>&lt;CONFIGURATION&gt; … &lt;/CONFIGURATION&gt;</code></td><td>配置外部系统和 EKI 之间的连接参数**-&gt;4.1**</td></tr><tr><td><code>&lt;RECEIVE&gt; … &lt;/RECEIVE&gt;</code></td><td>配置机器人控制系统接收的接收结构**-&gt;4.2**</td></tr><tr><td><code>&lt;SEND&gt; … &lt;/SEND&gt;</code></td><td>配置机器人控制系统发送的发送结构**-&gt;4.3**</td></tr></tbody></table><section><h3>4.1连接属性的XML结构<a href="#41连接属性的xml结构"><span>#</span></a></h3><p>在段落 <code>&lt;EXTERNAL &gt; … &lt;/EXTERNAL &gt;</code> 中定义外部系统的设置：</p><ul>
<li>

<table><thead><tr><th>元素</th><th>说明</th></tr></thead><tbody><tr><td><strong>TYPE</strong></td><td><strong>Server</strong>：外部系统是服务器。<br /><strong>Client</strong>：外部系统是客户端。 <br />默认值： 服务器</td></tr><tr><td><strong>IP</strong></td><td><strong>外部系统定义为服务器</strong>时的 IP 地址。<br />如果 TYPE = 客户端，将忽略 IP 地址</td></tr><tr><td>PORT</td><td>外部系统定义为服务器时的端口号<br /><strong>1 … 65534</strong></td></tr></tbody></table>
</li>
</ul><p>在段落 <code>&lt;INTERNAL&gt; … &lt;/INTERNAL&gt;</code> 中定义 EKI 的设置：</p>

<table><thead><tr><th>元素</th><th>属性</th><th>说明</th></tr></thead><tbody><tr><td><strong>ENVIRONMENT</strong></td><td>---</td><td>将删除连接与操作相结合 （可选） <br /><strong>Program</strong>：在机器人解释器操作后删除 <br /><strong>Submit</strong>：在提交解释器操作后删除 <br /><strong>System</strong>：在系统操作后删除<br />默认值： <strong>Program</strong></td></tr><tr><td><strong>BUFFERING</strong></td><td>Mode</td><td>处理所有数据存储器的方法 （可选） <br /><strong>FIFO</strong>：先进先出 <br /><strong>LIFO</strong>：后进先出 <br />默认值： <strong>FIFO</strong></td></tr><tr><td></td><td>Limit</td><td>数据存储器能够容纳的数据元素最大数量 （可选） 1 … 512 默认值： <strong>16</strong></td></tr><tr><td><strong>BUFFSIZE</strong></td><td>Limit</td><td>能够接收而无需解释的字节最大数量 (可选) 1 … 65534 字节 默认值： <strong>16384</strong> 字节</td></tr><tr><td><strong>TIMEOUT</strong></td><td>Connect</td><td>尝试建立连接的时间，超过这段时间后将中止 尝试 （可选）<strong>0 … 65534 ms</strong>  默认值： 2000 ms</td></tr><tr><td><strong>ALIVE</strong></td><td>Set_Out/Set_Flag</td><td>连接成功时给输出端或旗标赋值 （可选）<br />输出端编号： <strong>1 … 4096</strong> <br />旗标编号：    <strong>1 … 1024</strong> <br />只要有与外部系统的连接处于激活状态，旗标 或输出端就处于已赋值状态。如果与外部系统的连接中止，则输出端或旗标将被删除。</td></tr><tr><td></td><td>Ping</td><td>发送监控与外部系统连接的 Ping 命令的周期 （可选）  <strong>1 … 65534</strong></td></tr><tr><td><strong>IP</strong></td><td>---</td><td><strong>EKI 定义为服务器</strong>时的 IP 地址 <br />（EXTERNAL/TYPE = 客户端）<br /> 如果 EXTERNAL/TYPE = 服务器，将忽略 IP 地 址。</td></tr><tr><td><strong>PORT</strong></td><td>---</td><td>EKI 定义为服务器时的端口号<br /><strong>54600-54615</strong></td></tr><tr><td><strong>PROTOCOL</strong></td><td>---</td><td>传输协议 （可选）<br /><strong>TCP</strong> <br /><strong>UPD</strong> <br />默认值： <strong>TCP</strong> 建议始终使用 <strong>TCP/IP</strong> 协议。</td></tr><tr><td><strong>MESSAGES</strong></td><td>Logging</td><td>禁用在 EKI 日志中写入信息 （可选）。<br /><strong>warning</strong>：记录警告信息和错误信息。<br /><strong>error</strong>：仅记录错误信息。<br /><strong>disabled</strong>：记录已禁用。<br />默认值： <strong>错误</strong></td></tr><tr><td></td><td>显示屏</td><td>禁用 smartHMI 上的输出信息。<br />默认值： 错误</td></tr></tbody></table><p><strong>实例</strong></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>CONFIGURATION</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>EXTERNAL</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>IP</span><span>&gt;172.1.10.5&lt;/</span><span>IP</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>&lt;</span><span>PORT</span><span>&gt;60000&lt;/</span><span>PORT</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>&lt;</span><span>TYPE</span><span>&gt;Server&lt;/</span><span>TYPE</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span><span>  </span></span><span>&lt;/</span><span>EXTERNAL</span><span>&gt;</span></div></div><div><div><div>7</div></div><div><span><span>  </span></span><span>&lt;</span><span>INTERNAL</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>&lt;</span><span>ENVIRONMENT</span><span>&gt;Program&lt;/</span><span>ENVIRONMENT</span><span>&gt;</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>&lt;</span><span>BUFFERING</span><span> </span><span>Mode</span><span>=</span><span>"FIFO"</span><span> </span><span>Limit</span><span>=</span><span>"10"</span><span>/&gt;</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>&lt;</span><span>BUFFSIZE</span><span> </span><span>Limit</span><span>=</span><span>"16384"</span><span>/&gt;</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>&lt;</span><span>TIMEOUT</span><span> </span><span>Connect</span><span>=</span><span>"60000"</span><span>/&gt;</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>&lt;</span><span>ALIVE</span><span> </span><span>Set_Out</span><span>=</span><span>"666"</span><span> </span><span>Ping</span><span>=</span><span>"200"</span><span>/&gt;</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>&lt;</span><span>IP</span><span>&gt;192.1.10.20&lt;/</span><span>IP</span><span>&gt;</span></div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>&lt;</span><span>PORT</span><span>&gt;54600&lt;/</span><span>PORT</span><span>&gt;</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>&lt;</span><span>PROTOCOL</span><span>&gt;TCP&lt;/</span><span>PROTOCOL</span><span>&gt;</span></div></div><div><div><div>16</div></div><div><span><span>    </span></span><span>&lt;</span><span>MESSAGES</span><span> </span><span>Logging</span><span>=</span><span>"error"</span><span> </span><span>Display</span><span>=</span><span>"disabled"</span><span>/&gt;</span></div></div><div><div><div>17</div></div><div><span><span>  </span></span><span>&lt;/</span><span>INTERNAL</span><span>&gt;</span></div></div><div><div><div>18</div></div><div><span>&lt;/</span><span>CONFIGURATION</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h3>4.2用于数据接收的 XML 结构<a href="#42用于数据接收的-xml-结构"><span>#</span></a></h3><p>配置取决于是接收 XML 数据还是二进制数据。</p><ul>
<li>
<p>如果是接收 XML 数据，必须定义 XML 结构：<code>&lt;XML&gt; … &lt;/XML&gt;</code></p>
</li>
<li>
<p>如果是接收二进制数据，必须定义原始数据：<code>&lt;RAW&gt; … &lt;/RAW&gt;</code></p>
<section><h4>XML 结构 <code>&lt;XML&gt; … &lt;/XML&gt;</code> 的元素中的属性：<a href="#xml-结构-xml--xml-的元素中的属性"><span>#</span></a></h4></section>
</li>
</ul>

<table><thead><tr><th>元素</th><th>属性</th><th></th></tr></thead><tbody><tr><td><strong>ELEMENT</strong></td><td></td><td><strong>元素名称 在此定义用于接收数据的 XML 结构 （XPath）-&gt;4.4</strong></td></tr><tr><td><strong>ELEMENT</strong></td><td><code>TYPE</code></td><td>元素的数据类型<br /><code>STRING</code><br /><code>REAL</code><br /><code>INT</code><br /><code>BOOL</code><br /><code>FRAME</code><br />提示：当标签仅用于事件信息时，可选。在这种情况下不为该元素预留存储空间。 事件旗标示例：<code>&lt;ELEMENT Tag="Ext" Set_Flag="56"/&gt;</code></td></tr><tr><td><strong>ELEMENT</strong></td><td><code>Set_Out/Set_Flag</code></td><td>接收到元素时给输出端或旗标赋值 （可选） <br />输出端编号:<br /><strong>1-4096</strong><br />旗标编号：<br /><strong>1-1024</strong></td></tr><tr><td><strong>ELEMENT</strong></td><td><code>Mode</code></td><td>处理数据存储器中的数据组的方法<br /><code>FIFO</code>：先进先出<br /><code>LIFO</code>：后进先出<br />只有当处理各个数据组的方法与 <strong>BUFFERING</strong> 下 为 EKI 配置的不同时才相关。</td></tr></tbody></table><p>原始数据 <code>&lt;RAW&gt; … &lt;/RAW&gt;</code> 中的元素的属性：</p>

<table><thead><tr><th>元素</th><th>属性</th><th>说明</th></tr></thead><tbody><tr><td><strong>ELEMENT</strong></td><td></td><td>元素名称</td></tr><tr><td><strong>ELEMENT</strong></td><td><strong>TYPE</strong></td><td>元素的数据类型<br /><code>BYTE</code>：有固定长度的二进制数据组。<br /><code>STREAM：</code>有可变末尾字符串和可变长度的二 进制数据组</td></tr><tr><td><strong>ELEMENT</strong></td><td><code>Set_Out/Set_Flag</code></td><td>接收到元素时给输出端或旗标赋值 （可选）<br />输出端编号：<br /><strong>1 … 4096</strong><br />旗标编号：<br /><strong>1 … 1024</strong></td></tr><tr><td><strong>ELEMENT</strong></td><td><strong>EOS</strong></td><td>基本信息的末尾字符串 （只有当 Type = “STREAM” 时，才相关)<br />ASCII 编码： <strong>1 … 32 个字符</strong><br />备选结尾通过符号 “|“隔开。<br />&lt;ELEMENT … EOS=“123,134,21”/&gt;<br />&lt;ELEMENT … EOS=“123,134,21Ι13,10”/&gt;</td></tr><tr><td><strong>ELEMENT</strong></td><td>Size</td><td>当 Type = “BYTE” 时，信息的固定大小<br /><strong>1 … 3600 字节</strong></td></tr></tbody></table><p><strong>实例</strong></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>XML</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Ext/Str"</span><span> </span><span>Type</span><span>=</span><span>"STRING"</span><span>/&gt;</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Ext/Pos/XPos"</span><span> </span><span>Type</span><span>=</span><span>"REAL"</span><span> </span><span>Mode</span><span>=</span><span>"LIFO"</span><span>/&gt;</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Ext/Pos/YPos"</span><span> </span><span>Type</span><span>=</span><span>"REAL"</span><span>/&gt;</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Ext/Pos/ZPos"</span><span> </span><span>Type</span><span>=</span><span>"REAL"</span><span>/&gt;</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Ext/Temp/Cpu"</span><span> </span><span>Type</span><span>=</span><span>"REAL"</span><span> </span><span>Set_Out</span><span>=</span><span>"1"</span><span>/&gt;</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Ext/Temp/Fan"</span><span> </span><span>Type</span><span>=</span><span>"REAL"</span><span> </span><span>Set_Flag</span><span>=</span><span>"14"</span><span>/&gt;</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Ext/Integer/AState"</span><span> </span><span>Type</span><span>=</span><span>"INT"</span><span>/&gt;</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Ext/Integer/BState"</span><span> </span><span>Type</span><span>=</span><span>"INT"</span><span>/&gt;</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Ext/Boolean/CState"</span><span> </span><span>Type</span><span>=</span><span>"BOOL"</span><span>/&gt;</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Ext/Frames/Frame1"</span><span> </span><span>Type</span><span>=</span><span>"FRAME"</span><span>/&gt;</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Ext/Attributes/@A1"</span><span> </span><span>Type</span><span>=</span><span>"STRING"</span><span>/&gt;</span></div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Ext/Attributes/@A2"</span><span> </span><span>Type</span><span>=</span><span>"INT"</span><span>/&gt;</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Ext"</span><span> </span><span>Set_Flag</span><span>=</span><span>"56"</span><span>/&gt;</span></div></div><div><div><div>16</div></div><div><span><span>  </span></span><span>&lt;/</span><span>XML</span><span>&gt;</span></div></div><div><div><div>17</div></div><div><span>&lt;/</span><span>RECEIVE</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>RAW</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"RawData"</span><span> </span><span>Type</span><span>=</span><span>"BYTE"</span><span> </span><span>Size</span><span>=</span><span>"1408"</span></div></div><div><div><div>4</div></div><div><span>    </span><span>Set_Flag</span><span>=</span><span>"14"</span><span>/&gt;</span></div></div><div><div><div>5</div></div><div><span><span>  </span></span><span>&lt;/</span><span>RAW</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span>&lt;/</span><span>RECEIVE</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>RAW</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"MyStream"</span><span> </span><span>Type</span><span>=</span><span>"STREAM"</span><span> </span><span>EOS</span><span>=</span><span>"123,134,21"</span><span> </span><span>Size</span><span>=</span><span>"836"</span><span>           </span><span>Set_Flag</span><span>=</span><span>"14"</span><span>/&gt;</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>&lt;/</span><span>RAW</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span>&lt;/</span><span>RECEIVE</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>4.3用于发送数据的 XML 结构<a href="#43用于发送数据的-xml-结构"><span>#</span></a></h3><p>配置取决于是发送 XML 数据还是二进制数据。</p><ul>
<li>
<p>如果是发送 XML 数据，必须定义 XML 结构：<code>&lt;XML&gt; … &lt;/XML&gt;</code></p>
</li>
<li>
<p>发送二进制数据直接在 KRL 编程中实现。无须指定配置。</p>
</li>
</ul>

<table><thead><tr><th>属性</th><th>说明</th></tr></thead><tbody><tr><td>ELEMENT</td><td>元素名称 在此定义用于发送数据的 XML 结构 （XPath）。</td></tr></tbody></table><p><strong>示例</strong></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>SEND</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>XML</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/ActPos/@X"</span><span>/&gt;</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/ActPos/@Y"</span><span>/&gt;</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/ActPos/@Z"</span><span>/&gt;</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/ActPos/@A"</span><span>/&gt;</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/ActPos/@B"</span><span>/&gt;</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/ActPos/@C"</span><span>/&gt;</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Status"</span><span>/&gt;</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Mode"</span><span>/&gt;</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Complex/Tickcount"</span><span>/&gt;</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/RobotType/Robot/Type"</span><span>/&gt;</span></div></div><div><div><div>13</div></div><div><span><span>  </span></span><span>&lt;/</span><span>XML</span><span>&gt;</span></div></div><div><div><div>14</div></div><div><span>&lt;/</span><span>SEND</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>4.4按照 XPath 框架配置<a href="#44按照-xpath-框架配置"><span>#</span></a></h3><p>使用 XML 进行数据交换时，交换的 XML 文件必须按照相同框架构建。 Ethernet KRL 使用 <strong>XPath</strong> 框架进行 XML 文件的描述和读取。</p><p>根据 XPath 需区分下列情况：</p><ul>
<li>描述和读取元素</li>
<li>描述和读取属性</li>
<li><strong>元素写法</strong></li>
<li><strong>保存的用于发送数据</strong>的 XML 文件：</li>
</ul><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>Robot</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>Mode</span><span>&gt;...&lt;/</span><span>Mode</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>&lt;</span><span>RobotLamp</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>&lt;</span><span>GrenLamp</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span><span>      </span></span><span>&lt;</span><span>LightOn</span><span>&gt;...&lt;/</span><span>LightOn</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>&lt;/</span><span>GrenLamp</span><span>&gt;</span></div></div><div><div><div>7</div></div><div><span><span>  </span></span><span>&lt;/</span><span>RobotLamp</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span>&lt;/</span><span>Robot</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><ul>
<li>为<strong>发送数据所配置</strong>的 XML <strong>结构</strong>：</li>
</ul><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>SEND</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>XML</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Mode"</span><span> /&gt;</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/RobotLamp/GrenLamp/LightOn"</span><span> /&gt;</span></div></div><div><div><div>5</div></div><div><span><span>  </span></span><span>&lt;/</span><span>XML</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span>&lt;</span><span>SEND</span><span> /&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><ul>
<li><strong>元素写法</strong></li>
<li><strong>保存的用于发送数据</strong>的 XML <strong>文件</strong>：</li>
</ul><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>Robot</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>Data</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>ActPos</span><span> </span><span>X</span><span>=</span><span>"..."</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>&lt;/</span><span>ActPos</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>&lt;</span><span>LastPos</span><span> </span><span>A</span><span>=</span><span>"..."</span><span> </span><span>B</span><span>=</span><span>"..."</span><span> </span><span>C</span><span>=</span><span>"..."</span><span> </span><span>X</span><span>=</span><span>"..."</span><span> </span><span>Y</span><span>=</span><span>"..."</span><span> </span><span>Z</span><span>=</span><span>"..."</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>&lt;/</span><span>LastPos</span><span>&gt;</span></div></div><div><div><div>7</div></div><div><span><span>  </span></span><span>&lt;/</span><span>Data</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span>&lt;/</span><span>Robot</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>SEND</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>XML</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@X"</span><span> /&gt;</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@Y"</span><span> /&gt;</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>...</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/ActPos/@X"</span><span> /&gt;</span></div></div><div><div><div>7</div></div><div><span><span>  </span></span><span>&lt;/</span><span>XML</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span>&lt;</span><span>SEND</span><span> /&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section></section><section><h2>5.用于数据交换的函数<a href="#5用于数据交换的函数"><span>#</span></a></h2><p>Ethernet KRL 将相应的函数提供给机器人控制系统和外部系统之间的数据交换。</p><p><strong>函数的详细说明可参见KST_Ethemet附录</strong>。</p>

<table><thead><tr><th>初始化、打开、关闭和删除连接</th></tr></thead><tbody><tr><td>EKI_STATUS = EKI_Init(CHAR[])</td></tr><tr><td>EKI_STATUS = EKI_Open(CHAR[])</td></tr><tr><td>EKI_STATUS = EKI_Close(CHAR[])</td></tr><tr><td>EKI_STATUS = EKI_Clear(CHAR[])</td></tr></tbody></table>

<table><thead><tr><th>发送数据</th></tr></thead><tbody><tr><td>EKI_STATUS = EKI_Send(CHAR[], CHAR[], INT)</td></tr></tbody></table>

<table><thead><tr><th>写入数据</th></tr></thead><tbody><tr><td>EKI_STATUS = EKI_SetReal(CHAR[], CHAR[], REAL)</td></tr><tr><td>EKI_STATUS = EKI_SetInt(CHAR[], CHAR[], INT)</td></tr><tr><td>EKI_STATUS = EKI_SetBool(CHAR[], CHAR[], BOOL)</td></tr><tr><td>EKI_STATUS = EKI_SetFrame(CHAR[], CHAR[], FRAME)</td></tr><tr><td>EKI_STATUS = EKI_SetString(CHAR[], CHAR[], CHAR[])</td></tr></tbody></table>

<table><thead><tr><th>读取数据</th></tr></thead><tbody><tr><td>EKI_STATUS = EKI_GetBool(CHAR[], CHAR[], BOOL)</td></tr><tr><td>EKI_STATUS = EKI_GetBoolArray(CHAR[], CHAR[], BOOL[])</td></tr><tr><td>EKI_STATUS = EKI_GetInt(CHAR[], CHAR[], INT)</td></tr><tr><td>EKI_STATUS = EKI_GetIntArray(CHAR[], CHAR[], INT[])</td></tr><tr><td>EKI_STATUS = EKI_GetReal(CHAR[], CHAR[], REAL)</td></tr><tr><td>EKI_STATUS = EKI_GetRealArray(CHAR[], CHAR[], REAL[])</td></tr><tr><td>EKI_STATUS = EKI_GetString(CHAR[], CHAR[], CHAR[])</td></tr><tr><td>EKI_STATUS = EKI_GetFrame(CHAR[], CHAR[], FRAME)</td></tr><tr><td>EKI_STATUS = EKI_GetFrameArray(CHAR[], CHAR[], FRAME[])</td></tr></tbody></table>

<table><thead><tr><th>检查函数是否出现错误</th></tr></thead><tbody><tr><td>EKI_CHECK(EKI_STATUS, EKrlMsgType, CHAR[])</td></tr></tbody></table>

<table><thead><tr><th>删除、禁用、解禁、检查数据存储器</th></tr></thead><tbody><tr><td>EKI_STATUS = EKI_Clear(CHAR[])</td></tr><tr><td>EKI_STATUS = EKI_ClearBuffer(CHAR[], CHAR[])</td></tr><tr><td>EKI_STATUS = EKI_Lock(CHAR[])</td></tr><tr><td>EKI_STATUS = EKI_Unlock(CHAR[])</td></tr><tr><td>EKI_STATUS = EKI_CheckBuffer(CHAR[], CHAR[])</td></tr></tbody></table><section><h3>5.1提示<a href="#51提示"><span>#</span></a></h3><ul>
<li>建议为每个发送和接收任务打开一个单独的通道。</li>
<li>使用 KUKA.MultiSubmitInterpreter 时，上述发送和接收特性同样适用。</li>
<li>在预进中执行 EKI 指令！</li>
</ul></section><section><h3>5.2初始化和删除连接<a href="#52初始化和删除连接"><span>#</span></a></h3><p>必须用函数 <code>EKI_Init()</code> 创建连接并初始化。此时将读入函数中给出的连接配置。既可在机器人解释器，也可在提交解释器中创建连接。可在机器人或提交解释器中通过函数 <code>EKI_Clear()</code> 重新删除连接。此外，删除连接可与机器人或提交解释器的操作或系统操作对接。（可通过连接配置中的 <code>&lt;ENVIRONMENT&gt;</code> 元素配置）</p></section><section><h3>5.3打开和关闭连接<a href="#53打开和关闭连接"><span>#</span></a></h3><p><strong>通过一个 KRL 程序建立与外部系统的连接</strong></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>1 DEF Connection()</span></div></div><div><div><div>2</div></div><div><span>2 ...</span></div></div><div><div><div>3</div></div><div><span>3 RET=EKI_Init("Connection") //将 EKI 与外部系统连接的通道初始化。</span></div></div><div><div><div>4</div></div><div><span>4 RET=EKI_Open("Connection") //打开通道。</span></div></div><div><div><div>5</div></div><div><span>5 ...                      //用于将数据写入存储器、发送数据或访问已接收的数据的 KRL指令</span></div></div><div><div><div>6</div></div><div><span>6 Write data, send data or get received data</span></div></div><div><div><div>7</div></div><div><span>7 ...</span></div></div><div><div><div>8</div></div><div><span>8 RET=EKI_Close("Connection") //关闭通道</span></div></div><div><div><div>9</div></div><div><span>9 RET=EKI_Clear("Connection") //删除通道</span></div></div><div><div><div>10</div></div><div><span>10 ...</span></div></div><div><div><div>11</div></div><div><span>11 END</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>编程时须注意 EKI 是配置为服务器还是客户端。</p><p><strong>服务器运行模式</strong></p><ul>
<li>当外部系统配置为客户端时，<code>EKI_Open()</code> 会将 EKI （= 服务器）置于监听状态。服务器等待客户端的连接问询，但不中断程序运行。如果配置文件中未描述元素 <code>&lt;TIMEOUT Connect="…"/&gt;</code>，服务器将一直等待，直至客户端请求连接为止。</li>
<li>客户端的连接问询通过访问 EKI 或通过事件信息表示，例如通过元素 <code>&lt;ALIVE</code>
<code>SET_OUT="…"/&gt;</code>。</li>
<li>如果在服务器期待连接问询的过程中要中断程序运行，必须编程设定一个事件
旗标或输出端，例如 <code>WAIT FOR $OUT[…]</code>。</li>
</ul><p><strong>建议在服务器运行模式下不要使用 <code>EKI_Close()</code>。在服务器运行模式下，将从外部客户端关闭通道。</strong></p></section><section><h3>5.4发送数据<a href="#54发送数据"><span>#</span></a></h3><p>根据配置和编程不同，可用 <code>EKI_Send()</code> 发送下列数据</p><p><strong>通过 XML 结构通讯时：</strong></p><ul>
<li>完整的 XML 结构</li>
<li>XML 结构的一部分</li>
<li>可变长度的任意字符串</li>
</ul><p><strong>通过原始数据通讯时：</strong></p><ul>
<li>对于有固定长度的二进制数据组 （属性 Type = “BYTE”）：有固定长度的任意字符串
<ul>
<li>用字节表示的字符串大小必须与配置的属性 Size （大小）完全相符。超出时将输出错误信息，低于时将输出警告信息。</li>
<li>必须在 KRL 程序中用 <code>CAST_TO()</code> 读入固定长度的二进制数据组。只可读取类型为 REAL （4 字节）的数据，非 Double （双精度）型</li>
</ul>
</li>
</ul><section><h4>5.4.1 发送 XML 数据：<a href="#541-发送-xml-数据"><span>#</span></a></h4><p>发送完整的 XML 结构</p><ul>
<li>保存的用于发送数据的 XML 结构：</li>
</ul><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>Robot</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>ActPos</span><span> </span><span>X</span><span>=</span><span>"1000.12"</span><span>&gt;&lt;/</span><span>ActPos</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>&lt;</span><span>Status</span><span>&gt;12345678&lt;/</span><span>Status</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span>&lt;/</span><span>Robot</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><ul>
<li>编程</li>
</ul><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DECL EKI_STATUS RET</span></div></div><div><div><div>2</div></div><div><span>RET=EKI_Send("Channel_1","Robot")</span></div></div></code></pre><div><div></div><div></div></div></figure></div><ul>
<li>发送的 XML 结构：</li>
</ul><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>Robot</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>ActPos</span><span> </span><span>X</span><span>=</span><span>"1000.12"</span><span>&gt;&lt;/</span><span>ActPos</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>&lt;</span><span>Status</span><span>&gt;12345678&lt;/</span><span>Status</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span>&lt;/</span><span>Robot</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>发送 XML <strong>结构的一部分</strong>：</p><ul>
<li>
<p>保存的用于发送数据的 XML 结构与之前相同</p>
</li>
<li>
<p>编程</p>
</li>
</ul><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DECL EKI_STATUS RET</span></div></div><div><div><div>2</div></div><div><span>RET=EKI_Send("Channel_1","Robot/ActPos")</span></div></div></code></pre><div><div></div><div></div></div></figure></div><ul>
<li>发送的 XML 结构</li>
</ul><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>Robot</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>ActPos</span><span> </span><span>X</span><span>=</span><span>"1000.12"</span><span>&gt;&lt;/</span><span>ActPos</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span>&lt;/</span><span>Robot</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h4>5.4.2直接发送字符串：<a href="#542直接发送字符串"><span>#</span></a></h4></section><section><h4>5.4.3发送二进制数据：<a href="#543发送二进制数据"><span>#</span></a></h4><p>发送固定长度 （10字节）的二进制数据组</p><p>发送有末尾字符串和可变长度的二进制数据组：</p><p>发送有末尾字符串和可变长度、限制为字符最大值的二进制数据组：</p></section></section><section><h3>5.5读取数据<a href="#55读取数据"><span>#</span></a></h3><p>​	读取数据时，必须通过数值赋值等方式，将相应的 KRL 变量初始化。</p><ul>
<li>
<p>​	如要读取 XML 数据，可使用所有存取函数 <code>EKI_Get…</code>()  。</p>
</li>
<li>
<p>​	如要从存储器中读取二进制数据组，必须使用存储函数<code>EKI_GetString()</code>。</p>
</li>
</ul><section><h4>读取 XML 数据：<a href="#读取-xml-数据"><span>#</span></a></h4><p><strong>用于数据接收的 XML 结构</strong></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>XML</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Message"</span><span> </span><span>Type</span><span>=</span><span>"STRING"</span><span> /&gt;</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Status/IsActive"</span><span> </span><span>Type</span><span>=</span><span>"BOOL"</span><span> /&gt;</span></div></div><div><div><div>5</div></div><div><span><span>  </span></span><span>&lt;/</span><span>XML</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span>&lt;/</span><span>RECEIVE</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>编程：</strong></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>; Declaration</span></div></div><div><div><div>2</div></div><div><span>INT i</span></div></div><div><div><div>3</div></div><div><span>DECL EKI_STATUS RET</span></div></div><div><div><div>4</div></div><div><span>CHAR valueChar[256]</span></div></div><div><div><div>5</div></div><div><span>BOOL valueBOOL</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>; Initialization</span></div></div><div><div><div>8</div></div><div><span>FOR i=(1) TO (256)</span></div></div><div><div><div>9</div></div><div><span><span>  </span></span><span>valueChar[i]=0</span></div></div><div><div><div>10</div></div><div><span>ENDFOR</span></div></div><div><div><div>11</div></div><div><span>valueBOOL=FALSE</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>RET=EKI_GetString("Channel_1", "Sensor/Message", valueChar[])</span></div></div><div><div><div>14</div></div><div><span>RET=EKI_GetBool("Channel_1", "Sensor/Status/IsActive", valueBOOL)</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>用传感器数据描述的 XML 文件 （已接收的数据）：</strong></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>Sensor</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>Message</span><span>&gt;Example message&lt;/</span><span>Message</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>&lt;</span><span>Status</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>&lt;</span><span>IsActive</span><span>&gt;1&lt;/</span><span>IsActive</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span><span>  </span></span><span>&lt;/</span><span>Status</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span>&lt;/</span><span>Sensor</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>读取二进制数据组</strong></p></section></section><section><h3>5.6删除数据存储器<a href="#56删除数据存储器"><span>#</span></a></h3><ul>
<li>
<p>通过 <code>EKI_Clear()</code> 删除：删除所有数据存储器，退出以太网连接</p>
</li>
<li>
<p>通过 <code>EKI_ClearBuffer()</code> 删除：删除特定数据存储器，不退出以太网连接</p>
</li>
</ul></section><section><h3>5.7EKI_STATUS – 函数特定返回值的结构<a href="#57eki_status--函数特定返回值的结构"><span>#</span></a></h3><p>EKI 的每项函数都会返回函数特定的数值。EKI_STATUS 是这些数值写入的全 局结构变量。</p></section><section><h3>5.8配置事件信息<a href="#58配置事件信息"><span>#</span></a></h3><p>通过给输出端或旗标赋值，可报告下列事件：</p><ul>
<li>连接已激活。</li>
<li>出现一个单独的 XML 元素。</li>
<li>出现一个完整的 XML 结构或一个完整的二进制数据组。</li>
</ul><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606203215197.png" alt="image-20240606203215197" /><figcaption>image-20240606203215197</figcaption></figure><p></p><p>只要与外部系统的连接处于激活状态，$OUT[23] 即被赋值。连接不再激活 时，将重置 $OUT[23]。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606203300420.png" alt="image-20240606203300420" /><figcaption>image-20240606203300420</figcaption></figure><p></p></section><section><h3>5.9 接收完整的 XML 数据组<a href="#59-接收完整的-xml-数据组"><span>#</span></a></h3><p>存取函数 EKI_Get…() 会一直保持禁用，直至一个 XML 数据组中的所有数据 都位于存储器中为止。</p><p>当配置为 LIFO，且有 2 个或多个 XML 数据组相继出现时，不再确保从存储器 中连续地取出一个数据组。例如可能出现这样的情况：尽管第一个数据组尚未 完全处理好，但是第二个数据组的数据已储存在存储器中。由于在 ILFO 运行 模式下，始终是先存取最后一次保存的数据，因此导致 KRL 中可用的数据组 不一致。</p><p>为防止在 ILFO 运行模式下数据组出现碎片化现象，必须禁止处理新接收的数 据，直至从存储器中取出所有关联的数据为止。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>...</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>RET=EKI_Lock("MyChannel")</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>RET=EKI_Get...()</span></div></div><div><div><div>4</div></div><div><span><span> </span></span><span>RET=EKI_Get...()</span></div></div><div><div><div>5</div></div><div><span><span> </span></span><span>...</span></div></div><div><div><div>6</div></div><div><span><span> </span></span><span>RET=EKI_Get...()</span></div></div><div><div><div>7</div></div><div><span><span> </span></span><span>RET=EKI_Unlock("MyChannel")</span></div></div><div><div><div>8</div></div><div><span><span> </span></span><span>...</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>5.10 处理不完整数据组<a href="#510-处理不完整数据组"><span>#</span></a></h3><p>可能会出现外部系统发送不完整数据组的情况。单个 XML 元素为空或完全缺 失，使得在一个班次的存储器中存在来自多个数据包的数据。</p><p>如果 KRL 中的数据组必须是连续的，则可使用变量 EKI_STATUS 的结构元素  Counter。使用 EKI_Get…Array 函数时，可从返回 Counter = 0 识别出时间 上不连续的数据</p></section><section><h3>5.11 EKI_CHECK() – 检查函数是否有错误<a href="#511-eki_check--检查函数是否有错误"><span>#</span></a></h3><p>Ethernet KRL 会在出现任何错误时在 smartHMI 上输出一条信息。可禁用信息 的自动输出。</p><p>接收时出错时将始终关闭连接。以太网连接中止时，作为错误策略，可编程设 定一个中断。</p><p>在配置文件 XmlTransmit.XML 中定义了在成功连接时 FLAG[1] 将赋值。 连接丢失时将重置 FLAG[1]。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;ALIVE Set_Flag="1"/&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>中断在 KRL 程序中声明并接通。重置 FLAG[1] 时，将执行中断程序。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>FOLD Define callback</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>INTERRUPT DECL 89 WHEN $FLAG[1]==FALSE DO CON_ERR()</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>INTERRUPT ON 89</span></div></div><div><div><div>4</div></div><div><span><span> </span></span><span>;ENDFOLD</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>在中断程序中，用 EKI_CHECK() 查询发生了什么错误，然后重新打开连 接。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DEF CON_ERR()</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>DECL EKI_STATUS RET</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>RET={Buff 0,Read 0, Msg_no 0, Connected false}</span></div></div><div><div><div>4</div></div><div><span><span> </span></span><span>EKI_CHECK(RET,#Quit,"XmlTransmit")</span></div></div><div><div><div>5</div></div><div><span><span> </span></span><span>RET=EKI_OPEN("XmlTransmit")</span></div></div><div><div><div>6</div></div><div><span><span> </span></span><span>END</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section></section><section><h2>6.实例程序<a href="#6实例程序"><span>#</span></a></h2><p>Ethernet KRL 的供货范围包括一个服务器程序及多个示例配置和示例程序。 利用这些示例配置和示例程序，可以在服务器程序与机器人控制系统之间建立 通讯。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606203803679.png" alt="image-20240606203803679" /><figcaption>image-20240606203803679</figcaption></figure><p></p><section><h3>6.1接入服务器程序和示例<a href="#61接入服务器程序和示例"><span>#</span></a></h3><p>外部系统：</p><p>​	  已安装 .NET-Framework 3.5 或更高版本的 Windows 操作系统</p><p>机器人控制系统：</p><p>​	  专家用户组</p><p>​	 运行方式T1或者T2</p><p>操作步骤</p><ol>
<li>将服务器程序复制到外部系统上。</li>
<li>将 XML 示例配置粘贴到机器人控制系统的目录  C:\KRC\ROBOTER\Config\User\Common\EthernetKRL 中。</li>
<li>将 KRL 示例程序粘贴到机器人控制系统的目录 C:\KRC\ROBOTER\Program  中。</li>
<li>启动外部系统上的服务器程序。</li>
<li>按下菜单按钮。窗口通讯属性打开。</li>
<li>只有当外部系统有多个网络接口可用时：输入与机器人控制系统通讯时使 用的网络适配器编号（= 网卡索引）。</li>
<li>关闭窗口通讯属性并按下启动按钮。通讯时可用的 IP 地址会显示在信息 窗口中。</li>
<li>在所需的 XML 文件中设置显示的外部系统 IP 地址</li>
</ol></section><section><h3>6.2服务器程序操作界面<a href="#62服务器程序操作界面"><span>#</span></a></h3><p>服务器程序可通过与机器人控制系统建立稳定连接，测试外部系统和机器人控 制系统之间的通讯。</p><p>服务器程序包含以下功能：</p><ol>
<li>发送和接收数据（自动或手动）</li>
<li>显示接收的数据</li>
<li>显示发送的数据</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606204203589.png" alt="image-20240606204203589" /><figcaption>image-20240606204203589</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606204218687.png" alt="image-20240606204218687" /><figcaption>image-20240606204218687</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606204224341.png" alt="image-20240606204224341" /><figcaption>image-20240606204224341</figcaption></figure><p></p><p><strong>在服务器程序中设置通讯参数</strong></p><p>操作步骤</p><p>​	1.在服务器程序中点击菜单按钮。 窗口通讯属性打开。</p><p>​	2.设置通讯伙伴。</p><p>​	3.关闭窗口。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606204342905.png" alt="image-20240606204342905" /><figcaption>image-20240606204342905</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606204348458.png" alt="image-20240606204348458" /><figcaption>image-20240606204348458</figcaption></figure><p></p></section><section><h3>6.3 “BinaryFixed”示例<a href="#63-binaryfixed示例"><span>#</span></a></h3><p>与机器人控制系统通讯时，必须在服务器程序中设置合适的示例数 据，例如这里是“BinaryFixed”。</p><p>EKI 配置为客户端。通过连接仅能接收固定长度为 10 字节、元素名称为 “Buffer”的二进制数据组。服务器程序发送一个数据组。EKI 接收到外部 数据后，$FLAG[1] 将被赋值。</p><p><strong>XML文件</strong></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>ETHERNETKRL</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>CONFIGURATION</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>EXTERNAL</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span><span>      </span></span><span>&lt;</span><span>IP</span><span>&gt;x.x.x.x&lt;/</span><span>IP</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span><span>      </span></span><span>&lt;</span><span>PORT</span><span>&gt;59152&lt;/</span><span>PORT</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>&lt;/</span><span>EXTERNAL</span><span>&gt;</span></div></div><div><div><div>7</div></div><div><span><span>  </span></span><span>&lt;/</span><span>CONFIGURATION</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span><span>  </span></span><span>&lt;</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>&lt;</span><span>RAW</span><span>&gt;</span></div></div><div><div><div>10</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Buffer"</span><span> </span><span>Type</span><span>=</span><span>"BYTE"</span><span> </span><span>Set_Flag</span><span>=</span><span>"1"</span><span> </span><span>Size</span><span>=</span><span>"10"</span><span> /&gt;</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>&lt;/</span><span>RAW</span><span>&gt;</span></div></div><div><div><div>12</div></div><div><span><span>  </span></span><span>&lt;/</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>13</div></div><div><span><span>  </span></span><span>&lt;/</span><span>SEND</span><span>&gt;</span></div></div><div><div><div>14</div></div><div><span><span> </span></span><span>&lt;/</span><span>ETHERNETKRL</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>必须在 KRL 程序中用 CAST_TO() 和 CAST_FROM() 读入和读取固定长度的二进 制数据组。只可读取类型为 REAL（4 字节）的数据，非 Double（双精度） 型。</p><p><strong>程序</strong></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span> </span></span><span>1 DEF BinaryFixed( )</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>2 Declaration</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>3 INI</span></div></div><div><div><div>4</div></div><div><span><span> </span></span><span>4 Initialize sample data 通过数值赋值将 KRL 变量初始化</span></div></div><div><div><div>5</div></div><div><span><span> </span></span><span>5</span></div></div><div><div><div>6</div></div><div><span><span> </span></span><span>6 RET=EKI_Init("BinaryFixed")  EKI_Init() 将 EKI 与外部系统连接的通道初始化。</span></div></div><div><div><div>7</div></div><div><span><span> </span></span><span>7 RET=EKI_Open("BinaryFixed") EKI_Open() 打开通道并与服务器连接。</span></div></div><div><div><div>8</div></div><div><span><span> </span></span><span>8</span></div></div><div><div><div>9</div></div><div><span><span> </span></span><span>9 OFFSET=0   CAST_TO 将数值写入 CHAR 数组 Bytes[]。</span></div></div><div><div><div>10</div></div><div><span><span> </span></span><span>10 CAST_TO(Bytes[],OFFSET,34.425,674345,"R",TRUE)</span></div></div><div><div><div>11</div></div><div><span><span> </span></span><span>11</span></div></div><div><div><div>12</div></div><div><span><span> </span></span><span>12 RET=EKI_Send("BinaryFixed",Bytes[])</span></div></div><div><div><div>13</div></div><div><span><span> </span></span><span>13</span></div></div><div><div><div>14</div></div><div><span><span> </span></span><span>14 WAIT FOR $FLAG[1]</span></div></div><div><div><div>15</div></div><div><span><span> </span></span><span>15 RET=EKI_GetString("BinaryFixed","Buffer",Bytes[])</span></div></div><div><div><div>16</div></div><div><span><span> </span></span><span>16 $FLAG[1]=FALSE</span></div></div><div><div><div>17</div></div><div><span><span> </span></span><span>17  $FLAG[1] 表示接收配置的数据元素。</span></div></div><div><div><div>18</div></div><div><span><span>   </span></span><span>EKI_GetString 访问存储器并将数据复制到 CHAR 数组 Bytes[] 中。</span></div></div><div><div><div>19</div></div><div><span><span>   </span></span><span>$FLAG[1] 被重置。</span></div></div><div><div><div>20</div></div><div><span><span> </span></span><span>18 OFFSET=0</span></div></div><div><div><div>21</div></div><div><span><span> </span></span><span>19 CAST_FROM(Bytes[], OFFSET, valueReal, valueInt, valueChar[],</span></div></div><div><div><div>22</div></div><div><span><span>  </span></span><span>valueBool)</span></div></div><div><div><div>23</div></div><div><span><span> </span></span><span>20    CAST_FROM 读取 CHAR 数组 Bytes[] 包含的数值，并根据类型将其复制到给出的变量中。</span></div></div><div><div><div>24</div></div><div><span><span> </span></span><span>21 RET=EKI_Close("BinaryFixed")  关闭通道。</span></div></div><div><div><div>25</div></div><div><span><span> </span></span><span>22 RET=EKI_Clear("BinaryFixed") 删除通道。</span></div></div><div><div><div>26</div></div><div><span><span> </span></span><span>23 END</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h3>6.4 “BinaryStream”示例<a href="#64-binarystream示例"><span>#</span></a></h3><p>EKI 配置为客户端。通过连接仅能接收长度最大为 64 字节、元素名称为 “Buffer”的二进制数据组。二进制数据组的末尾必须用末尾字符串 CR、LF  标记。当 EKI 接收到该元素时，$FLAG[1] 将赋值。</p><p><strong>XML文件</strong></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>ETHERNETKRL&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>CONFIGURATION</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>EXTERNAL</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span><span>      </span></span><span>&lt;</span><span>IP</span><span>&gt;x.x.x.x&lt;/</span><span>IP</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span><span>      </span></span><span>&lt;</span><span>PORT</span><span>&gt;59152&lt;/</span><span>PORT</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>&lt;/</span><span>EXTERNAL</span><span>&gt;</span></div></div><div><div><div>7</div></div><div><span><span>  </span></span><span>&lt;/</span><span>CONFIGURATION</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span><span>  </span></span><span>&lt;</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>&lt;</span><span>RAW</span><span>&gt;</span></div></div><div><div><div>10</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Buffer"</span><span> </span><span>Type</span><span>=</span><span>"STREAM"</span><span> </span><span>Set_Flag</span><span>=</span><span>"1"</span></div></div><div><div><div>11</div></div><div><span>               </span><span>Size</span><span>=</span><span>"64"</span><span> </span><span>EOS</span><span>=</span><span>"13,10"</span><span> /&gt;</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>&lt;/</span><span>RAW</span><span>&gt;</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>&lt;/</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>14</div></div><div><span><span>  </span></span><span>&lt;/</span><span>SEND</span><span>&gt;</span></div></div><div><div><div>15</div></div><div><span><span> </span></span><span>&lt;/</span><span>ETHERNETKRL</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p><strong>程序</strong></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span> </span></span><span>1 DEF BinaryStream( )</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>2 Declaration</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>3 INI</span></div></div><div><div><div>4</div></div><div><span><span> </span></span><span>4 Initialize sample data</span></div></div><div><div><div>5</div></div><div><span><span> </span></span><span>5</span></div></div><div><div><div>6</div></div><div><span><span> </span></span><span>6 RET=EKI_Init("BinaryStream")</span></div></div><div><div><div>7</div></div><div><span><span> </span></span><span>7 RET=EKI_Open("BinaryStream")</span></div></div><div><div><div>8</div></div><div><span><span> </span></span><span>8</span></div></div><div><div><div>9</div></div><div><span><span> </span></span><span>9 Bytes[]="Stream ends with CR,LF"</span></div></div><div><div><div>10</div></div><div><span><span> </span></span><span>10</span></div></div><div><div><div>11</div></div><div><span><span> </span></span><span>11 RET=EKI_Send("BinaryStream",Bytes[])</span></div></div><div><div><div>12</div></div><div><span><span> </span></span><span>12</span></div></div><div><div><div>13</div></div><div><span><span> </span></span><span>13 WAIT FOR $FLAG[1]</span></div></div><div><div><div>14</div></div><div><span><span> </span></span><span>14 RET=EKI_GetString("BinaryStream","Buffer",Bytes[])</span></div></div><div><div><div>15</div></div><div><span><span> </span></span><span>15 $FLAG[1]=FALSE</span></div></div><div><div><div>16</div></div><div><span><span> </span></span><span>16</span></div></div><div><div><div>17</div></div><div><span><span> </span></span><span>17 RET=EKI_Close("BinaryStream")</span></div></div><div><div><div>18</div></div><div><span><span> </span></span><span>18 RET=EKI_Clear("BinaryStream")</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h3>6.5 “XmlTransmit”示例<a href="#65-xmltransmit示例"><span>#</span></a></h3><p>EKI 配置为客户端。将发送机器人数据，等待 1 秒后，从存储器读取接收的 传感器数据。</p><p><strong>XML文件</strong></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>ETHERNETKRL</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>CONFIGURATION</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>EXTERNAL</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span><span>      </span></span><span>&lt;</span><span>IP</span><span>&gt;x.x.x.x&lt;/</span><span>IP</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span><span>      </span></span><span>&lt;</span><span>PORT</span><span>&gt;59152&lt;/</span><span>PORT</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>&lt;/</span><span>EXTERNAL</span><span>&gt;</span></div></div><div><div><div>7</div></div><div><span><span>  </span></span><span>&lt;/</span><span>CONFIGURATION</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span><span>  </span></span><span>&lt;</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>&lt;</span><span>XML</span><span>&gt;</span></div></div><div><div><div>10</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Message"</span><span> </span><span>Type</span><span>=</span><span>"STRING"</span><span> /&gt;</span></div></div><div><div><div>11</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Positions/Current/@X"</span><span> </span><span>Type</span><span>=</span><span>"REAL"</span><span> /&gt;</span></div></div><div><div><div>12</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Positions/Before/X"</span><span> </span><span>Type</span><span>=</span><span>"REAL"</span><span> /&gt;</span></div></div><div><div><div>13</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Nmb"</span><span> </span><span>Type</span><span>=</span><span>"INT"</span><span> /&gt;</span></div></div><div><div><div>14</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Status/IsActive"</span><span> </span><span>Type</span><span>=</span><span>"BOOL"</span><span> /&gt;</span></div></div><div><div><div>15</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Read/xyzabc"</span><span> </span><span>Type</span><span>=</span><span>"FRAME"</span><span> /&gt;</span></div></div><div><div><div>16</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Show/@error"</span><span> </span><span>Type</span><span>=</span><span>"BOOL"</span><span> /&gt;</span></div></div><div><div><div>17</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Show/@temp"</span><span> </span><span>Type</span><span>=</span><span>"INT"</span><span> /&gt;</span></div></div><div><div><div>18</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Show"</span><span> </span><span>Type</span><span>=</span><span>"STRING"</span><span> /&gt;</span></div></div><div><div><div>19</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Free"</span><span> </span><span>Type</span><span>=</span><span>"INT"</span><span> /&gt;</span></div></div><div><div><div>20</div></div><div><span><span>    </span></span><span>&lt;/</span><span>XML</span><span>&gt;</span></div></div><div><div><div>21</div></div><div><span><span>  </span></span><span>&lt;/</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>22</div></div><div><span><span>  </span></span><span>&lt;</span><span>SEND</span><span>&gt;</span></div></div><div><div><div>23</div></div><div><span><span>    </span></span><span>&lt;</span><span>XML</span><span>&gt;</span></div></div><div><div><div>24</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@X"</span><span> /&gt;</span></div></div><div><div><div>25</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@Y"</span><span> /&gt;</span></div></div><div><div><div>26</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@Z"</span><span> /&gt;</span></div></div><div><div><div>27</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@A"</span><span> /&gt;</span></div></div><div><div><div>28</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@B"</span><span> /&gt;</span></div></div><div><div><div>29</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@C"</span><span> /&gt;</span></div></div><div><div><div>30</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/ActPos/@X"</span><span> /&gt;</span></div></div><div><div><div>31</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Status"</span><span> /&gt;</span></div></div><div><div><div>32</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Mode"</span><span> /&gt;</span></div></div><div><div><div>33</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/RobotLamp/GrenLamp/LightOn"</span><span> /&gt;</span></div></div><div><div><div>34</div></div><div><span><span>     </span></span><span>&lt;/</span><span>XML</span><span>&gt;</span></div></div><div><div><div>35</div></div><div><span><span>    </span></span><span>&lt;/</span><span>SEND</span><span>&gt;</span></div></div><div><div><div>36</div></div><div><span><span> </span></span><span>&lt;/</span><span>ETHERNETKRL</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p><strong>程序</strong></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span> </span></span><span>1 DEF XmlTransmit( )</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>2 Declaration</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>3 Communicated data</span></div></div><div><div><div>4</div></div><div><span><span> </span></span><span>4 INI</span></div></div><div><div><div>5</div></div><div><span><span> </span></span><span>5 Initialize sample data</span></div></div><div><div><div>6</div></div><div><span><span> </span></span><span>6</span></div></div><div><div><div>7</div></div><div><span><span> </span></span><span>7 RET=EKI_Init("XmlTransmit")</span></div></div><div><div><div>8</div></div><div><span><span> </span></span><span>8 RET=EKI_Open("XmlTransmit")</span></div></div><div><div><div>9</div></div><div><span><span> </span></span><span>9</span></div></div><div><div><div>10</div></div><div><span><span> </span></span><span>10 Write data to connection</span></div></div><div><div><div>11</div></div><div><span><span> </span></span><span>11 Send data to external program</span></div></div><div><div><div>12</div></div><div><span><span> </span></span><span>12 Get received sensor data</span></div></div><div><div><div>13</div></div><div><span><span> </span></span><span>13</span></div></div><div><div><div>14</div></div><div><span><span> </span></span><span>14 RET=EKI_Close("XmlTransmit")</span></div></div><div><div><div>15</div></div><div><span><span> </span></span><span>15 RET=EKI_Clear("XmlTransmit")</span></div></div><div><div><div>16</div></div><div><span><span> </span></span><span>16</span></div></div><div><div><div>17</div></div><div><span><span> </span></span><span>17 END</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h3>6.6 “XmlServer”示例<a href="#66-xmlserver示例"><span>#</span></a></h3><p>EKI 配置为服务器。只要与外部系统存在连接，$FLAG[1] 就处于赋值状态。</p><p><strong>XML文件</strong></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>ETHERNETKRL</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>CONFIGURATION</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>EXTERNAL</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span><span>      </span></span><span>&lt;</span><span>TYPE</span><span>&gt;Client&lt;/</span><span>TYPE</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>&lt;/</span><span>EXTERNAL</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>&lt;</span><span>INTERNAL</span><span>&gt;</span></div></div><div><div><div>7</div></div><div><span><span>      </span></span><span>&lt;</span><span>IP</span><span>&gt;x.x.x.x&lt;/</span><span>IP</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span><span>      </span></span><span>&lt;</span><span>PORT</span><span>&gt;54600&lt;/</span><span>PORT</span><span>&gt;</span></div></div><div><div><div>9</div></div><div><span><span>      </span></span><span>&lt;</span><span>ALIVE</span><span> </span><span>Set_Flag</span><span>=</span><span>"1"</span><span> /&gt;</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>&lt;/</span><span>INTERNAL</span><span>&gt;</span></div></div><div><div><div>11</div></div><div><span><span>  </span></span><span>&lt;/</span><span>CONFIGURATION</span><span>&gt;</span></div></div><div><div><div>12</div></div><div><span><span>  </span></span><span>&lt;</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>&lt;</span><span>XML</span><span>&gt;</span></div></div><div><div><div>14</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/A"</span><span> </span><span>Type</span><span>=</span><span>"BOOL"</span><span> /&gt;</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>&lt;/</span><span>XML</span><span>&gt;</span></div></div><div><div><div>16</div></div><div><span><span>  </span></span><span>&lt;/</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>17</div></div><div><span><span>  </span></span><span>&lt;</span><span>SEND</span><span>&gt;</span></div></div><div><div><div>18</div></div><div><span><span>     </span></span><span>&lt;</span><span>XML</span><span>&gt;</span></div></div><div><div><div>19</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/B"</span><span> /&gt;</span></div></div><div><div><div>20</div></div><div><span><span>    </span></span><span>&lt;/</span><span>XML</span><span>&gt;</span></div></div><div><div><div>21</div></div><div><span><span>  </span></span><span>&lt;/</span><span>SEND</span><span>&gt;</span></div></div><div><div><div>22</div></div><div><span><span> </span></span><span>&lt;/</span><span>ETHERNETKRL</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p><strong>程序</strong></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span> </span></span><span>1 DEF XmlServer( )</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>2 Declaration</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>3 INI</span></div></div><div><div><div>4</div></div><div><span><span> </span></span><span>4</span></div></div><div><div><div>5</div></div><div><span><span> </span></span><span>5 RET=EKI_Init("XmlServer")</span></div></div><div><div><div>6</div></div><div><span><span> </span></span><span>6 RET=EKI_Open("XmlServer")</span></div></div><div><div><div>7</div></div><div><span><span> </span></span><span>7</span></div></div><div><div><div>8</div></div><div><span><span> </span></span><span>8 ; wait until server is conntected</span></div></div><div><div><div>9</div></div><div><span><span> </span></span><span>9 wait for $FLAG[1</span></div></div><div><div><div>10</div></div><div><span><span> </span></span><span>10 ; wait until server is deconnected</span></div></div><div><div><div>11</div></div><div><span><span> </span></span><span>11 wait for $FLAG[1]==FALSE</span></div></div><div><div><div>12</div></div><div><span><span> </span></span><span>12</span></div></div><div><div><div>13</div></div><div><span><span> </span></span><span>13 RET=EKI_Clear("XmlServer")</span></div></div><div><div><div>14</div></div><div><span><span> </span></span><span>14 END</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>6.7“XmlCallback”示例<a href="#67xmlcallback示例"><span>#</span></a></h3><p>EKI 配置为客户端。将发送机器人数据，接收传感器数据，然后等待  $FLAG[1]。$FLAG[1] 表示已读取传感器数据。</p><p>XML 文件中配置了当 EKI 接收了所有传感器数据后，$FLAG[998] 将赋值。该 旗标将触发程序中断。通过将标签“Sensor”配置为事件标签，可确保当所 有数据都位于存储器中时，才取出传感器数据。</p><p>已读取传感器数据时，将重置 $FLAG[998] 并给 $FLAG[1] 赋值。</p><p><strong>XML文件</strong></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>ETHERNETKRL</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>CONFIGURATION</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>EXTERNAL</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span><span>      </span></span><span>&lt;</span><span>IP</span><span>&gt;x.x.x.x&lt;/</span><span>IP</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span><span>      </span></span><span>&lt;</span><span>PORT</span><span>&gt;59152&lt;/</span><span>PORT</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>&lt;/</span><span>EXTERNAL</span><span>&gt;</span></div></div><div><div><div>7</div></div><div><span><span>  </span></span><span>&lt;/</span><span>CONFIGURATION</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span><span>  </span></span><span>&lt;</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>&lt;</span><span>XML</span><span>&gt;</span></div></div><div><div><div>10</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Message"</span><span> </span><span>Type</span><span>=</span><span>"STRING"</span><span> /&gt;</span></div></div><div><div><div>11</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Positions/Current/@X"</span><span> </span><span>Type</span><span>=</span><span>"REAL"</span><span> /&gt;</span></div></div><div><div><div>12</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Positions/Before/X"</span><span> </span><span>Type</span><span>=</span><span>"REAL"</span><span> /&gt;</span></div></div><div><div><div>13</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Nmb"</span><span> </span><span>Type</span><span>=</span><span>"INT"</span><span> /&gt;</span></div></div><div><div><div>14</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Status/IsActive"</span><span> </span><span>Type</span><span>=</span><span>"BOOL"</span><span> /&gt;</span></div></div><div><div><div>15</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Read/xyzabc"</span><span> </span><span>Type</span><span>=</span><span>"FRAME"</span><span> /&gt;</span></div></div><div><div><div>16</div></div><div><span><span> </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Show/@error"</span><span> </span><span>Type</span><span>=</span><span>"BOOL"</span><span> /&gt;</span></div></div><div><div><div>17</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Show/@temp"</span><span> </span><span>Type</span><span>=</span><span>"INT"</span><span> /&gt;</span></div></div><div><div><div>18</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Show"</span><span> </span><span>Type</span><span>=</span><span>"STRING"</span><span> /&gt;</span></div></div><div><div><div>19</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor/Free"</span><span> </span><span>Type</span><span>=</span><span>"INT"</span><span> </span><span>Set_Out</span><span>=</span><span>"998"</span><span> /&gt;</span></div></div><div><div><div>20</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Sensor"</span><span> </span><span>Set_Flag</span><span>=</span><span>"998"</span><span> /&gt;</span></div></div><div><div><div>21</div></div><div><span><span>    </span></span><span>&lt;/</span><span>XML</span><span>&gt;</span></div></div><div><div><div>22</div></div><div><span><span>  </span></span><span>&lt;/</span><span>RECEIVE</span><span>&gt;</span></div></div><div><div><div>23</div></div><div><span><span>  </span></span><span>&lt;</span><span>SEND</span><span>&gt;</span></div></div><div><div><div>24</div></div><div><span><span>    </span></span><span>&lt;</span><span>XML</span><span>&gt;</span></div></div><div><div><div>25</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@X"</span><span> /&gt;</span></div></div><div><div><div>26</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@Y"</span><span> /&gt;</span></div></div><div><div><div>27</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@Z"</span><span> /&gt;</span></div></div><div><div><div>28</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@A"</span><span> /&gt;</span></div></div><div><div><div>29</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@B"</span><span> /&gt;</span></div></div><div><div><div>30</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/LastPos/@C"</span><span> /&gt;</span></div></div><div><div><div>31</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Data/ActPos/@X"</span><span> /&gt;</span></div></div><div><div><div>32</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Status"</span><span> /&gt;</span></div></div><div><div><div>33</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/Mode"</span><span> /&gt;</span></div></div><div><div><div>34</div></div><div><span><span>      </span></span><span>&lt;</span><span>ELEMENT</span><span> </span><span>Tag</span><span>=</span><span>"Robot/RobotLamp/GrenLamp/LightOn"</span><span> /&gt;</span></div></div><div><div><div>35</div></div><div><span><span>    </span></span><span>&lt;/</span><span>XML</span><span>&gt;</span></div></div><div><div><div>36</div></div><div><span><span>  </span></span><span>&lt;/</span><span>SEND</span><span>&gt;</span></div></div><div><div><div>37</div></div><div><span><span> </span></span><span>&lt;/</span><span>ETHERNETKRL</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p><strong>程序</strong></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span> </span></span><span>1 DEF XmlCallBack( )</span></div></div><div><div><div>2</div></div><div><span><span> </span></span><span>2 Declaration</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>3 Communicated data</span></div></div><div><div><div>4</div></div><div><span><span> </span></span><span>4 INI</span></div></div><div><div><div>5</div></div><div><span><span> </span></span><span>5 Define callback</span></div></div><div><div><div>6</div></div><div><span><span> </span></span><span>6</span></div></div><div><div><div>7</div></div><div><span><span> </span></span><span>7 RET=EKI_Init("XmlCallBack")</span></div></div><div><div><div>8</div></div><div><span><span> </span></span><span>8 RET=EKI_Open("XmlCallBack")</span></div></div><div><div><div>9</div></div><div><span><span> </span></span><span>9</span></div></div><div><div><div>10</div></div><div><span><span> </span></span><span>10 Write data to connection</span></div></div><div><div><div>11</div></div><div><span><span> </span></span><span>11 RET=EKI_Send("XmlCallBack","Robot")</span></div></div><div><div><div>12</div></div><div><span><span> </span></span><span>12</span></div></div><div><div><div>13</div></div><div><span><span> </span></span><span>13 ;wait until data read</span></div></div><div><div><div>14</div></div><div><span><span> </span></span><span>14 WAIT FOR $FLAG[1]</span></div></div><div><div><div>15</div></div><div><span><span> </span></span><span>15</span></div></div><div><div><div>16</div></div><div><span><span> </span></span><span>16 RET=EKI_Close("XmlCallBack")</span></div></div><div><div><div>17</div></div><div><span><span> </span></span><span>17 RET=EKI_Clear("XmlCallBack")</span></div></div><div><div><div>18</div></div><div><span><span> </span></span><span>18 END</span></div></div><div><div><div>19</div></div><div><span><span> </span></span><span>19</span></div></div><div><div><div>20</div></div><div><span><span> </span></span><span>20 DEF GET_DATA()</span></div></div><div><div><div>21</div></div><div><span><span> </span></span><span>21 Declaration</span></div></div><div><div><div>22</div></div><div><span><span> </span></span><span>22 Initialize sample data</span></div></div><div><div><div>23</div></div><div><span><span> </span></span><span>23 Get received sensor data</span></div></div><div><div><div>24</div></div><div><span><span> </span></span><span>24 Signal read</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p><strong>数据发送</strong></p><p>XML 文件由 KRL 程序用机器人数据来描述并通过 EKI 发送给外部系统。</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>Robot</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>Data</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>   </span></span><span>&lt;</span><span>LastPos</span><span> </span><span>X</span><span>=</span><span>"..."</span><span> </span><span>Y</span><span>=</span><span>"..."</span><span> </span><span>Z</span><span>=</span><span>"..."</span><span> </span><span>A</span><span>=</span><span>"..."</span><span> </span><span>B</span><span>=</span><span>"..."</span><span> </span><span>C</span><span>=</span><span>"..."</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span><span>   </span></span><span>&lt;/</span><span>LastPos</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span><span>   </span></span><span>&lt;</span><span>ActPos</span><span> </span><span>X</span><span>=</span><span>"1000.12"</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>&lt;/</span><span>ActPos</span><span>&gt;</span></div></div><div><div><div>7</div></div><div><span><span>  </span></span><span>&lt;/</span><span>Data</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span><span>  </span></span><span>&lt;</span><span>Status</span><span>&gt;12345678&lt;/</span><span>Status</span><span>&gt;</span></div></div><div><div><div>9</div></div><div><span><span>  </span></span><span>&lt;</span><span>Mode</span><span>&gt;ConnectSensor&lt;/</span><span>Mode</span><span>&gt;</span></div></div><div><div><div>10</div></div><div><span><span>  </span></span><span>&lt;</span><span>RobotLamp</span><span>&gt;</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>&lt;</span><span>GrenLamp</span><span>&gt;</span></div></div><div><div><div>12</div></div><div><span><span>     </span></span><span>&lt;</span><span>LightOn</span><span>&gt;1&lt;/</span><span>LightOn</span><span>&gt;</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>&lt;/</span><span>GrenLamp</span></div></div><div><div><div>14</div></div><div><span><span>  </span></span><span>&lt;/RobotLamp&gt;</span></div></div><div><div><div>15</div></div><div><span><span> </span></span><span>&lt;/</span><span>Robot</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p><strong>数据接收</strong></p><p>XML 文件由服务器程序用传感器数据来描述并由 EKI 接收。</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span> </span></span><span>&lt;</span><span>Sensor</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>Message</span><span>&gt;Example message&lt;/</span><span>Message</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>&lt;</span><span>Positions</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>&lt;</span><span>Current</span><span> </span><span>X</span><span>=</span><span>"4645.2"</span><span> /&gt;</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>&lt;</span><span>Before</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span><span>      </span></span><span>&lt;</span><span>X</span><span>&gt;0.9842&lt;/</span><span>X</span><span>&gt;</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>&lt;/</span><span>Before</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span><span>  </span></span><span>&lt;/</span><span>Positions</span><span>&gt;</span></div></div><div><div><div>9</div></div><div><span><span>  </span></span><span>&lt;</span><span>Nmb</span><span>&gt;8&lt;/</span><span>Nmb</span><span>&gt;</span></div></div><div><div><div>10</div></div><div><span><span>  </span></span><span>&lt;</span><span>Status</span><span>&gt;</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>&lt;</span><span>IsActive</span><span>&gt;1&lt;/</span><span>IsActive</span><span>&gt;</span></div></div><div><div><div>12</div></div><div><span><span>  </span></span><span>&lt;/</span><span>Status</span><span>&gt;</span></div></div><div><div><div>13</div></div><div><span><span>  </span></span><span>&lt;</span><span>Read</span><span>&gt;</span></div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>&lt;</span><span>xyzabc</span><span> </span><span>X</span><span>=</span><span>"210.3"</span><span> </span><span>Y</span><span>=</span><span>"825.3"</span><span> </span><span>Z</span><span>=</span><span>"234.3"</span><span> </span><span>A</span><span>=</span><span>"84.2"</span><span> </span><span>B</span><span>=</span><span>"12.3"</span></div></div><div><div><div>15</div></div><div><span>            </span><span>C</span><span>=</span><span>"43.5"</span><span> /&gt;</span></div></div><div><div><div>16</div></div><div><span><span>  </span></span><span>&lt;/</span><span>Read</span><span>&gt;</span></div></div><div><div><div>17</div></div><div><span><span>  </span></span><span>&lt;</span><span>Show</span><span> </span><span>error</span><span>=</span><span>"0"</span><span> </span><span>temp</span><span>=</span><span>"9929"</span><span>&gt;Taginfo in attributes&lt;/</span><span>Show</span><span>&gt;</span></div></div><div><div><div>18</div></div><div><span><span>  </span></span><span>&lt;</span><span>Free</span><span>&gt;2912&lt;/</span><span>Free</span><span>&gt;</span></div></div><div><div><div>19</div></div><div><span><span> </span></span><span>&lt;/</span><span>Sensor</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/749/</id>
      <title type="text">kuka编程(一)：KUKA系统软件(KSS)</title>
      <published>2022-06-08T04:27:17.000Z</published>
      <updated>2024-06-06T15:59:02.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/749/"/>
      <summary type="text">1、KRL程序 1.1程序的结构与建立 1.1.1程序接口 当KRC1软件被安装在目录 ：时，下列文件可作为标准。 File Meaning ------------ ------------------------------------</summary>
      <content type="html"><![CDATA[<section><h1>1、KRL程序<a href="#1krl程序"><span>#</span></a></h1><section><h2>1.1程序的结构与建立<a href="#11程序的结构与建立"><span>#</span></a></h2><section><h3>1.1.1程序接口<a href="#111程序接口"><span>#</span></a></h3><p>当KRC1软件被安装在目录<code>“KRC：\R1\MADA\”</code>：时，下列文件可作为标准。</p>

<table><thead><tr><th>File</th><th>Meaning</th></tr></thead><tbody><tr><td>$MACHINE.DAT</td><td>控制器和机器人的系统数据列表和系统变量</td></tr><tr><td>$ROBCOR.DAT</td><td>机器人动态模型的系统数据列表和数据</td></tr><tr><td>MACHINE.UPG</td><td>用于将来升级的系统文件</td></tr><tr><td>ROBCOR.UPG</td><td>用于将来升级的系统文件</td></tr></tbody></table><p>下列文件可在目录<code>“KRC：\R1\SYSTEM\”</code>：下找到</p>

<table><thead><tr><th>File</th><th>Meaning</th></tr></thead><tbody><tr><td>$CONFIG.DAT</td><td>系统数据列表和一般数据</td></tr><tr><td>BAS.SRC</td><td>运动控制的基本软件包</td></tr><tr><td>IR_STOPM.SRC</td><td>故障时服务功能所使用的程序</td></tr><tr><td>SPS.SUB</td><td>监视使用的提交文件</td></tr></tbody></table></section><section><h3>1.1.2 文件<a href="#112-文件"><span>#</span></a></h3><p>KRL程序由SRC和DAT文件组成。</p><p><strong>SRC</strong>文件包含实际的程序代码，有两个变量：<strong>DEF</strong>和<strong>DEFFCT</strong>(带返回值)。</p><p><strong>DAT</strong>文件包含特定的程序数据。它们的区别基于<strong>KRL</strong>文件概念：除处理顺序不同外，程序包含工业机器人完成的动作也不同。也可能是特殊的运动顺序，打开和关闭夹手，或复杂的顺序，例如有关焊枪限制的控制。</p></section><section><h3>1.1.3文件结构<a href="#113文件结构"><span>#</span></a></h3><p>KRL文件的内部结构由<strong>声明部分、指令部分和最多255个局部子程序和函数</strong>组成。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DEF NAME(x1：IN)</span></div></div><div><div><div>2</div></div><div><span>声明</span></div></div><div><div><div>3</div></div><div><span>指令</span></div></div><div><div><div>4</div></div><div><span>END</span></div></div></code></pre><div><div></div><div></div></div></figure></div><ul>
<li><strong>DEF</strong>&lt;有的文件不带扩展名&gt;，因此在声明中前缀**“DEF”<strong>。名称最多可包含24个字符，但不允许包含关键字(见[变量和声明]一节)。所有文件以</strong>“DEF”<strong>开头和</strong>“END”**结束。</li>
<li><strong>声明</strong> &lt;程序执行前已经检查过声明&gt;，即在编译期间检查声明。声明部分不可能有指令,第一个指令开始于指令部分。</li>
<li><strong>指令</strong> 与声明不同，指令是动态的，程序处理过程中执行指令。</li>
<li><strong>数据列表</strong> 一个机器人程序可能仅包含一个单个的程序文件或一个程序文件和相关的数据表。 数据表和文件具有相同的公共名，区别仅在于扩展名不同。</li>
</ul></section></section><section><h2>1.2建立和编辑程序<a href="#12建立和编辑程序"><span>#</span></a></h2><section><h3>1.2.1新建程序<a href="#121新建程序"><span>#</span></a></h3><p>**Module：**包含框架程序的一个SRC文件和DAT文件被创建。
**Expert：**仅包含标题DEF…和END的一个SRC文件和DAT文件被创建。
**Cell：**此时，仅创建一个包含SRC的框架程序。该程序用于通过中央PLC控制机器人。
**Function：**此时，一个包含标题DEF…和END的函数(SRC文件)被创建。
**Submit：**创建一个SUB文件的框架程序。Submit文件包含可以使用的指令，例如，用于循环监视(夹手等)。Submit文件工作类似于机器人，由控制器解释程序处理。
**Expert Submit：**使用Submit模板，创建一个SUB文件，这时仅包含标题DEF…和END。</p></section><section><h3>1.2.2 编辑、编译和链接程序<a href="#122-编辑编译和链接程序"><span>#</span></a></h3><p>通过菜单**“新建”<strong>建立一个文件后， 则可以使用编辑器编辑该文件， 可使用软键</strong>“编辑”<strong>完成该操作。关闭编辑器后，则整个程序代码被</strong>编译**，也就是说，原文的KRL代码被转换为能让控制器理解的语言。</p><p>**编译：<strong>该处理中，编译器检查代码和语法上的错误，如果检查到错误，则产生对应的消息和拓展名为</strong>“.ERR”.**的错误文件</p><p>**链接编辑器：<strong>当通过软件“选择”装入一个程序后，建立程序所需要的所有文件和数据表被链接到一起。链接期间，检查模型是否存在，是否已经被编译和存在错误。当传输参数时，编辑器检查所传输参数的类型兼容性。如果链接期间出现错误，则产生扩展名为</strong>“.ERR”**的错误文件。</p><p>您也可以使用一般文本编辑器写一个KRL程序，然后通过“装载”软键装入系统存储器中。这时，您必须<strong>确保完成所有的必要的初始化（例如：轴速度） 。</strong></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>下面的简单程序是一个定义轴速度和加速度的举例</span></div></div><div><div><div>2</div></div><div><span>DEF PROG1()</span></div></div><div><div><div>3</div></div><div><span>：-----声明部分----</span></div></div><div><div><div>4</div></div><div><span>INT J</span></div></div><div><div><div>5</div></div><div><span>：------指令部分-------</span></div></div><div><div><div>6</div></div><div><span>$VEL_AXIS[1]=100 ；定义轴速度</span></div></div><div><div><div>7</div></div><div><span>$VEL_AXIS[2]=100</span></div></div><div><div><div>8</div></div><div><span>$VEL_AXIS[3]=100</span></div></div><div><div><div>9</div></div><div><span>$VEL_AXIS[4]=100</span></div></div><div><div><div>10</div></div><div><span>$VEL_AXIS[5]=100</span></div></div><div><div><div>11</div></div><div><span>$VEL_AXIS[6]=100</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>$ACC_AXIS[1]=100 ；定义轴加速度</span></div></div><div><div><div>14</div></div><div><span>$ACC_AXIS[2]=100</span></div></div><div><div><div>15</div></div><div><span>$ACC_AXIS[3]=100</span></div></div><div><div><div>16</div></div><div><span>$ACC_AXIS[4]=100</span></div></div><div><div><div>17</div></div><div><span>$ACC_AXIS[5]=100</span></div></div><div><div><div>18</div></div><div><span>$ACC_AXIS[6]=100</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span>PTP{A1 0，A2 -90，A3 90，A4 0，A5 0，A6 0}</span></div></div><div><div><div>21</div></div><div>
</div></div><div><div><div>22</div></div><div><span>FOR J=1 TO 5</span></div></div><div><div><div>23</div></div><div><span>PTP {A1 4}</span></div></div><div><div><div>24</div></div><div><span>PTP {A2 -7，A3 5}</span></div></div><div><div><div>25</div></div><div><span>PTP {A1 0，A2 -9，A3 9}</span></div></div><div><div><div>26</div></div><div><span>ENDFOR</span></div></div><div><div><div>27</div></div><div>
</div></div><div><div><div>28</div></div><div><span>PTP {A1 0，A2 -90，A3 90，A4 0，A5 0，A6 0}</span></div></div><div><div><div>29</div></div><div>
</div></div><div><div><div>30</div></div><div><span>END</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section><section><h2>1.3改变程序<a href="#13改变程序"><span>#</span></a></h2><section><h3>1.3.1程序修改<a href="#131程序修改"><span>#</span></a></h3></section><section><h3>1.3.2编辑器<a href="#132编辑器"><span>#</span></a></h3></section><section><h3>1.4隐藏程序部分<a href="#14隐藏程序部分"><span>#</span></a></h3><p>缺省时“折合”是“关闭”的，且只能由专家级别用户“打开”，然后用户才可以在KUKA图形用户界面(KUKAGUI)上看见信息。专家级用户在指示范围内装入相关的声明或指令**“ FOLD”<strong>和</strong>“ ：ENDFOLD”**就可以使KRL块让一般用户看见。</p><p>通过按菜单键“程序”，然后选择“折合”和需要的命令，可以使程序中的折合显示或隐藏  。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606195955894.png" alt="image-20240606195955894" /><figcaption>image-20240606195955894</figcaption></figure><p></p><p> <strong>Current FOLD opn/cls</strong> 打开或关闭编辑光标定位行的折合
 <strong>All FOLDs opn</strong> 打开程序的所有折合
 <strong>All FOLDs cls</strong> 关闭程序的所有折合</p></section><section><h3>1.4.1 程序举例<a href="#141-程序举例"><span>#</span></a></h3><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DEF FOLDS( )</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>：FOLD DECLARATION；%附加信息</span></div></div><div><div><div>4</div></div><div><span>：---------声明部分--------</span></div></div><div><div><div>5</div></div><div><span>EXT BAS (BAS_COMMAND：IN，REAL：IN)</span></div></div><div><div><div>6</div></div><div><span>DECL AXIS HOME</span></div></div><div><div><div>7</div></div><div><span>INT I</span></div></div><div><div><div>8</div></div><div><span>：END FOLD</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span>：FOLD INITIALISATION</span></div></div><div><div><div>11</div></div><div><span>：----------初始化--------</span></div></div><div><div><div>12</div></div><div><span>INTERRUPT DECL 3 WHEN $STOPMESS==TRUE DO IR_STOPM( )</span></div></div><div><div><div>13</div></div><div><span>INTERRUPT ON 3</span></div></div><div><div><div>14</div></div><div><span>BAS(#INITMOV，0)初始化速度，</span></div></div><div><div><div>15</div></div><div><span>：加速度，$BASE，$TOOL，等</span></div></div><div><div><div>16</div></div><div><span>FOR I=1 TO 16</span></div></div><div><div><div>17</div></div><div><span>$OUT[I]=FALSE</span></div></div><div><div><div>18</div></div><div><span>ENDFOR</span></div></div><div><div><div>19</div></div><div><span>HOME={AXIS：A10，A2-90，A390，A40，A530，A60}</span></div></div><div><div><div>20</div></div><div><span>：END FOLD</span></div></div><div><div><div>21</div></div><div>
</div></div><div><div><div>22</div></div><div><span>：-------------主程序部分-----------</span></div></div><div><div><div>23</div></div><div><span>PTP HOME：BCO运行</span></div></div><div><div><div>24</div></div><div><span>LIN{X 540，Y 630，Z 1500，A 0，B 90，C 0}</span></div></div><div><div><div>25</div></div><div><span>PTP HOME</span></div></div><div><div><div>26</div></div><div>
</div></div><div><div><div>27</div></div><div><span>END</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>该举例程序在屏上幕显示如下</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200050234.png" alt="image-20240606200050234" /><figcaption>image-20240606200050234</figcaption></figure><p></p><p>打开折合时的显示：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200058178.png" alt="image-20240606200058178" /><figcaption>image-20240606200058178</figcaption></figure><p></p><p>对于编辑器来说“折回”仅仅是一个指令。因为其前面的分号，所以编译器把折合语句看作是一般注释。</p></section></section><section><h2>1.5程序运行模式<a href="#15程序运行模式"><span>#</span></a></h2><p>程序运行模式定义如何执行程序</p><ul>
<li>
<p>程序不停止</p>
</li>
<li>
<p>一步一步执行运动指令</p>
</li>
<li>
<p>单步执行。</p>
<p>所有的程序运行模式如下表说明</p>
</li>
</ul>

<table><thead><tr><th>运行模式</th><th>说明</th></tr></thead><tbody><tr><td><strong>GO</strong></td><td>执行程序中的所有指令，直到程序结束。</td></tr><tr><td><strong>MSTEP</strong></td><td>运动步(运动指令) 程序一次执行一个运动指令，也就是说，每个运动指令后插入一个 STOP。 执行的程序不作前置处理。</td></tr><tr><td><strong>ISTEP</strong></td><td>增量步进(单步) 程序一步一步执行， 也就是说， 每个指令后插入一个STOP（包括空行） 。 执行的程序不作前置处理。</td></tr><tr><td><strong>PSTEP</strong></td><td>程序单步(程序单步) 子程序被完整地执行。 执行的程序不作前置处理。</td></tr><tr><td><strong>CSTEP</strong></td><td>连续步进(运动指令) 程序一次执行一个运动指令，也就是说，每个运动指令后插入一个 STOP且精确定位。 执行的程序作前置处理。也就是说，定位为粗定位。</td></tr></tbody></table><p>可在<strong>KCP</strong>上使用状态键或通过变量“<strong>$PRO_MODE</strong>”选择程序运行模式<strong>GO，MSTEP和ISTEP</strong>。另一方面，程序运行模式<strong>PSTEP和CSTEP</strong>只能通过变量**“$PRO_MODE”<strong>来设置。要修改该状态，首先激活菜单函数</strong>“Monitor”—&gt;“Variable”—&gt;“Single”**，然后在“名称”的文本输入框中输入变量“$PRO_MODE”和“新值”文本输入框中输入期望的新值。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200115063.png" alt="image-20240606200115063" /><figcaption>image-20240606200115063</figcaption></figure><p></p></section><section><h2>1.6错误处理<a href="#16错误处理"><span>#</span></a></h2><section><h3>view ERR<a href="#view-err"><span>#</span></a></h3><p>使用菜单**“监视”→“变量”→“修改”<strong>，您可以在线显示错误号的含义。要这样做的话，在状态窗口的</strong>“Name”<strong>文本输入框中输入字符</strong>“$”<strong>后跟错误号。本例子中，输入</strong>“$2263”**,然后按回车键。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200152916.png" alt="image-20240606200152916" /><figcaption>image-20240606200152916</figcaption></figure><p></p></section><section><h3>jump to<a href="#jump-to"><span>#</span></a></h3><p>如果现在将SRC文件(“ERROR.SRC”存在的条件下)装入编辑器，您必须进行适当的修改。闪烁光标已经自动定位在包含错误的第一行，使得修改非常方便。确保关闭受限制的可见性和可以看见DEF—行。细节可见**[隐藏程序部分]**。</p></section><section><h3>Refresh<a href="#refresh"><span>#</span></a></h3><p>关闭编辑器，存储修改后的文件，按错误列表中的软键“刷新”；如果已经排除完了所有的错误，则错误列表消失。</p></section></section><section><h2>1.7注释<a href="#17注释"><span>#</span></a></h2><p>注释可在程序的任何位置插入。通常在其前面加<code>“：”</code></p></section></section>
<section><h1>2 变量和声明<a href="#2-变量和声明"><span>#</span></a></h1><section><h2>2.1变量和名称<a href="#21变量和名称"><span>#</span></a></h2><section><h4><strong>名称</strong><a href="#名称"><span>#</span></a></h4><p>KRL中的名称</p><ul>
<li>最大长度为24个字符。</li>
<li>可以包含字母（A-Z）、数字（0－9）和符号‘—’和‘$’。</li>
<li>必须以字母开始。</li>
<li>不要使用关键字。</li>
</ul><blockquote><p>因为所有的系统变量（见2.4节）以符号**‘$’**开头，所以该符号在自定义名称中不能作为第一个符号。</p></blockquote><p>变量被看作是一个固定的存储器区域，变量的内容可以通过变量名称来寻址。当执行程序时，变量通过存储器位置（地址）和存储器内容（值）来表示。</p></section><section><h4><strong>值分配</strong><a href="#值分配"><span>#</span></a></h4><p>使用等号(=)给变量分配值。</p><p>不同的数据对象(见节2.2)有不同的存储器需求，所以变量的数据类型在使用前<strong>必须声明</strong></p></section><section><h4><strong>变量周期</strong><a href="#变量周期"><span>#</span></a></h4><p>变量的周期即该时间段内变量在存储器内存在。 取决于变量是在SRC文件或数据表中声明：</p><p><strong>SRC文件中声明的变量</strong>
周期受程序运行时间的限制。执行完成后存储器区域再分配，则变量值丢失。
<strong>数据表中声明的变量 (见数据表一章)</strong>
周期与程序运行时间无关，只要该数据表存在，该变量就存在。因此这种变量是永久保持的（直到系统关机）</p></section></section><section><h2>2.2数据对象<a href="#22数据对象"><span>#</span></a></h2><section><h3>2.2.1数据对象的声明和初始化<a href="#221数据对象的声明和初始化"><span>#</span></a></h3><section><h4><strong>DECL：</strong><a href="#decl"><span>#</span></a></h4><p>给一个数据类型分配一个变量名称和保留存储器空间，在KRL中须使用DECL声明来完成。</p><p><code>DECL INT QUANTITY，NUMBER</code></p><p>两个变量<code>QUANTITY</code>和<code>NUMBER</code>为<code>INTEGER</code>数据类型。
这样编译器就知道这两个变量和相关的数据类型，当使用该变量时，可检查该数据类型是否允许操作。
声明变量，如例子所述，首先是<strong>关键字</strong><code>DECL</code>，其后跟的是<strong>数据类型</strong>和<strong>分配该数据类型的变量列表</strong></p><blockquote><p>当声明变量和阵列为预定数据类型时，关键字DECL可以省略。不包括简单数据类型<code>INT，REAL，CHAR和BOOL</code>(见2.2.2一节)，结构数据类型<code>POS，E6POS，FRAME，AXIS和E6AXIS</code>(见2.2.5一节)是预定的。</p><p>对于数据类型是POS的变量（非阵列），声明可以省略。POS数据类型是变量的标准数据类型。
自由可定义结构或列举类型的声明中关键字DECL是包括缺少的。(见节2.2.5和2.2.6)。</p></blockquote></section><section><h4><strong>初始化</strong><a href="#初始化"><span>#</span></a></h4><p>当变量声明完成后，它的值第一次是不可用的，因为根据存储器位置的不同该值可能不同。要使变量可以开始工作，必须预设定一个特定的值。第一次<strong>给变量分配值</strong>称为初始化。</p><p>分配给变量的值是一个指令，因此不要在声明部分出现。初始化，可在指令的任何部分发生。理想状态下，所有<strong>声明过的变量应该是在声明部分后的初始化部分直接初始化完成</strong>。</p><p><strong>仅数据表中允许直接在声明行中初始化变量。</strong></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200233746.png" alt="image-20240606200233746" /><figcaption>image-20240606200233746</figcaption></figure><p></p></section></section><section><h3>2.2.2简单数据类型<a href="#222简单数据类型"><span>#</span></a></h3>

<table><thead><tr><th>数据类型</th><th>整数</th><th>实数</th><th>布尔</th><th>字符</th></tr></thead><tbody><tr><td>关键字</td><td>INT</td><td>REAL</td><td>BOOL</td><td>CHAR</td></tr><tr><td>含义</td><td>整数</td><td>浮点数字</td><td>逻辑型</td><td>1个字符</td></tr><tr><td>值的范围</td><td>-2^31-2^31-1</td><td>+1.1E-38…  ±3.4E+38</td><td>TRUE，FALSE</td><td>ASCII字符</td></tr></tbody></table><section><h4>INT<a href="#int"><span>#</span></a></h4><p>如果将一个实数值分配给一个整数型变量，则该值一般被圆整(x.0到.49向下圆整，x.5到x.99向上圆整)。</p><blockquote><p>另外：整数相除的结果从小数点后被切掉，举例：7/4=1</p></blockquote></section><section><h4>二进制系统 十六进制系统<a href="#二进制系统-十六进制系统"><span>#</span></a></h4><p>KRL中可使用反逗号<code>（’）</code>和二进制前缀<strong>B</strong>或十六进制前缀<strong>H</strong>表示二进制或十六进制整数。</p></section><section><h4>实数<a href="#实数"><span>#</span></a></h4><p>以<strong>浮点形式</strong>表示，标准格式将一个数字分成<strong>固定点部分</strong>和一个<strong>指数</strong>。</p></section><section><h4>布尔<a href="#布尔"><span>#</span></a></h4><p>布尔变量用于逻辑状态的说明（例如，输入/输出）。值仅有真或假。</p></section><section><h4>字符型<a href="#字符型"><span>#</span></a></h4><p>字符型变量可以代表符合ASCII字符规定的一个准确的字符。给一个字符型变量分配的ASCII字符，必须位于括号**(”)**内。</p></section></section><section><h3>2.2.3阵列<a href="#223阵列"><span>#</span></a></h3><p>术语“阵列“指的是相同数据类型对象的组合产生的一个数据对象；通过下标可以寻址阵列中的独立的元素。声明如下
<code>DECL INT OTTO[7]</code></p><section><h4>阵列指针<a href="#阵列指针"><span>#</span></a></h4><p>●阵列可能是任何数据类型。单独的元素也可能有复杂的数据类型(例如，阵列组成的阵列)。
●仅整数型数据类型允许作为下标。
●除常量和变量外，算术表达式也允许作为下标（见节2.3.1）。
●下标起始值通常为1。</p></section><section><h4>2维阵列<a href="#2维阵列"><span>#</span></a></h4><p>除已经讨论过的一维阵列，也就是说仅有一个下标，在KRL中还可以使用两维或三维阵列。采用
<code>DECL REAL MATRIX[7，3]</code></p></section><section><h4>三维阵列<a href="#三维阵列"><span>#</span></a></h4><p>三维阵列可以看作是一个接一个的一些两维矩阵。第三维指示矩阵所处位置的级别（见图4）。一个三维阵列可简单地声明为一维或两维阵列，例如：
<code>DECL BOOL ARRAY_3D[5，3，4]</code></p></section></section><section><h3>2.2.4 字符串<a href="#224-字符串"><span>#</span></a></h3><p>使用字符型数据类型，您仅可以存储一个独立的字符。要使用一串字符，例如字，您只需简单地将一个一维阵列的数据类型定义为字符型：
<code>DECL CHAR NAME[8]</code></p><p>如同通常一样，您可以寻址阵列NAME[ ]中的单个的元素，例如：<code>NAME[3]=”G”</code></p><p>当然，您也可以直接输入全部字符串：<code>NAME[ ]=”ABCDEFG”</code></p></section><section><h3>2.2.5结构<a href="#225结构"><span>#</span></a></h3><p>使用声明语句<code>STRUC</code>，预先定义好的不同数据类型或预定数据类型的组合构成一个新的复合数据类型</p><section><h4>STRU<a href="#stru"><span>#</span></a></h4><p>复合使用的一个典型例子是标准数据类型POS。它由文件$OPERATE.SRC中声明的6个实数值和2个整数值组成：
<code>STRUC POS REAL X，，Y，Z，A，B，C，INT S，T</code></p></section><section><h4>点分离<a href="#点分离"><span>#</span></a></h4><p>如果，例如您现在使用结构数据类型的一个POSITION变量，您可以使用分离点给个别的元素分配值：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>POSITION.X=34.4</span></div></div><div><div><div>2</div></div><div><span>POSITION.Y=-23.2</span></div></div><div><div><div>3</div></div><div><span>POSITION.Z=100.0</span></div></div><div><div><div>4</div></div><div><span>POSITION.A=90</span></div></div><div><div><div>5</div></div><div><span>POSITION.B=29.5</span></div></div><div><div><div>6</div></div><div><span>POSITION.C=3.5</span></div></div><div><div><div>7</div></div><div><span>POSITION.S=2</span></div></div><div><div><div>8</div></div><div><span>POSITION.T=6</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h4>集合<a href="#集合"><span>#</span></a></h4><p>或使用所谓的集合共同分配值：
<code>POSITION={X34.4，Y-23.2，Z100.0，A90，B29.5，C3.5，S2，T6}</code></p><p>● 集合的值可以是简单的常量或它们自己的集合。
● 不是必须在集合中指定结构中的所有组成。
● 成分的指定顺序不必依照它们定义的顺序。
● 集合中每个成分可能只包含一次。
● 在由结构组成阵列的情况下，一个集合定义一个单独的阵列元素的值。
● 结构类型的名称可在一个集合的开头指定-以冒号分开。</p><blockquote><p>对于POS、E6POS、AXIS、E6AXIS和FRAME结构缺少的成分不能被改变。而对于其它集合，则不存在的成分被设置为无效的成分</p></blockquote><p>建立您自己的结构变量的步骤使用下列例子解释：</p><p>变量S_PARA必须由3个不同数据类型的元素组成。首先，必须建立一个满足这个要求的新的数据类型：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>STRUC WELDTYPE REAL V_WIRE，INT CHARAC，BOOL ARC</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>建立了一个名称为<code>WELDTYPE</code>的新的数据类型(<code>WELDTYPE</code>不是一个变量!)。<strong>WELDTYPE</strong>由
<code>V_WIRE、CHARAC和ARC</code>三个成分组成。您现在可以任何新数据类型的变量，例如：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DECL WELDTYPE S_PARA</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>这样您就建立了一个数据类型为WELDTYPE的变量S_PARA。可以通过点分开单独寻址各个成分和通过集合－如上说明来寻址。</p><blockquote><p>为了更容易区分自定义数据类型和变量，新数据类型的名称以…TYPE结束。</p></blockquote></section><section><h4>预定义结构<a href="#预定义结构"><span>#</span></a></h4><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200426476.png" alt="image-20240606200426476" /><figcaption>image-20240606200426476</figcaption></figure><p></p></section><section><h4>几何数据类型<a href="#几何数据类型"><span>#</span></a></h4><p><strong>AXIS，E6AXIS，POS，E6POS和FRAME</strong>的类型也称为几何数据类型，因为它们提供编程师一个简单的方法用来说明几何关系。</p></section></section><section><h3>2.2.6列举类型<a href="#226列举类型"><span>#</span></a></h3><p>ENUM</p><p>#符号</p></section></section><section><h2>2.3数据处理<a href="#23数据处理"><span>#</span></a></h2><section><h3>2.3.1操作<a href="#231操作"><span>#</span></a></h3><section><h4>2.3.1.1算术操作<a href="#2311算术操作"><span>#</span></a></h4>

<table><thead><tr><th>操作</th><th>说明</th></tr></thead><tbody><tr><td>+</td><td>加法或正号</td></tr><tr><td>-</td><td>减法或负号</td></tr><tr><td>*</td><td>乘法</td></tr><tr><td>/</td><td>除法</td></tr></tbody></table></section><section><h4>2.3.1.2几何操作<a href="#2312几何操作"><span>#</span></a></h4><p>KRL中几何操作以冒号 <code>：</code>表示。完成数据类型为<strong>FRAME</strong>和<strong>POS</strong>的操作数的框架联接（<strong>逻辑操作</strong>）。</p></section><section><h4>框架连接<a href="#框架连接"><span>#</span></a></h4><p>框架操作是求左和右的值。<strong>最右边的结果</strong>的数据类型往往是操作数的数据类型（见表5）。</p>

<table><thead><tr><th>左边操作数(参考CS)</th><th>操作</th><th>右边操作数(目标CS)</th><th>结果</th></tr></thead><tbody><tr><td>POS</td><td>：</td><td>POS</td><td>POS</td></tr><tr><td>POS</td><td>：</td><td>FRAME</td><td>FRAME</td></tr><tr><td>FRAME</td><td>：</td><td>POS</td><td>POS</td></tr><tr><td>FRAME</td><td>：</td><td>FRAME</td><td>FRAME</td></tr></tbody></table><blockquote><p>如果左边的操作数的数据类型是POS，进行类型匹配。POS结构指定的位置被转换为框架。意思是系统检查该位置的刀具框架。</p></blockquote><section><h5>举例<a href="#举例"><span>#</span></a></h5><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200448421.png" alt="image-20240606200448421" /><figcaption>image-20240606200448421</figcaption></figure><p></p><p>现在的任务就是定义工件坐标系和房间坐标系的相对关系。首先必须先定义下列框架变量：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>FRAME TABLE，WORKPIECE，BASE</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>房间坐标系已经由系统明确地指定。桌子坐标系和工件坐标系现在根据给定的约束初始化。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>TABLE={X450，Y600，Z800，A0，B0，C0}</span></div></div><div><div><div>2</div></div><div><span>WORKPIECE={X80，Y110，Z55，A-40，B180，C0}</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>使用几何操作得到工件坐标系和房间坐标系的相对关系</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>BASE=TABLE：WORKPIECE</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>在我们的案例中，BASE定义如下：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>BASE={X530，Y710，Z855，A140，B0，C-180}</span></div></div><div><div><div>2</div></div><div><span>另一个可能是：</span></div></div><div><div><div>3</div></div><div><span>BASE={X530，Y710，Z855，A-40，B180，C0}</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section></section><section><h4>2.3.1.3关系操作<a href="#2313关系操作"><span>#</span></a></h4>

<table><thead><tr><th>操作</th><th>说明</th><th>允许的数据类型</th></tr></thead><tbody><tr><td>==</td><td>等于</td><td>INT，REAL，CHAR，ENUM，BOOL</td></tr><tr><td>&lt;&gt;</td><td>不等于</td><td>INT，REAL，CHAR，ENUM，BOOL</td></tr><tr><td>&gt;</td><td>大于</td><td>INT，REAL，CHAR，ENUM</td></tr><tr><td>&lt;</td><td>小于</td><td>INT，REAL，CHAR，ENUM</td></tr><tr><td>&gt;=</td><td>大于或等于</td><td>INT，REAL，CHAR，ENUM</td></tr><tr><td>&lt;=</td><td>小于或等于</td><td>INT，REAL，CHAR，ENUM</td></tr></tbody></table></section><section><h4>2.3.1.4逻辑操作<a href="#2314逻辑操作"><span>#</span></a></h4>

<table><thead><tr><th>操作</th><th>操作数数量</th><th>说明</th></tr></thead><tbody><tr><td>NOT</td><td>1</td><td>非</td></tr><tr><td>AND</td><td>2</td><td>逻辑与</td></tr><tr><td>OR</td><td>2</td><td>逻辑或</td></tr><tr><td>EXOR</td><td>2</td><td>异或</td></tr></tbody></table>

<table><thead><tr><th>操作</th><th>NOT A</th><th>A AND B</th><th>A OR B</th><th>A EXOR B</th><th></th></tr></thead><tbody><tr><td>A=TRUE</td><td>B=TRUE</td><td>FALSE</td><td>TRUE</td><td>TRUE</td><td>FALSE</td></tr><tr><td>A=TRUE</td><td>B=FALSE</td><td>FALSE</td><td>FALSE</td><td>TRUE</td><td>TRUE</td></tr><tr><td>A=FALSE</td><td>B=TRUE</td><td>TRUE</td><td>FALSE</td><td>TRUE</td><td>TRUE</td></tr><tr><td>A=FALSE</td><td>B=FALSE</td><td>TRUE</td><td>FALSE</td><td>FALSE</td><td>FALSE</td></tr></tbody></table></section><section><h4>2.3.1.5位操作<a href="#2315位操作"><span>#</span></a></h4>

<table><thead><tr><th>操作</th><th>操作数数量</th><th>说明</th></tr></thead><tbody><tr><td>B_NOT</td><td>1</td><td>一位一位反</td></tr><tr><td>B_AND</td><td>2</td><td>一位一位与</td></tr><tr><td>B_OR</td><td>2</td><td>一位一位或</td></tr><tr><td>B_EXOR</td><td>2</td><td>一位一位异或</td></tr></tbody></table></section><section><h4>2.3.1.6操作优先级<a href="#2316操作优先级"><span>#</span></a></h4>

<table><thead><tr><th>优先级</th><th>操作</th></tr></thead><tbody><tr><td>1</td><td>NOT B_NOT</td></tr><tr><td>2</td><td>* /</td></tr><tr><td>3</td><td>+ -</td></tr><tr><td>4</td><td>AND B_AND</td></tr><tr><td>5</td><td>EXOR B_EXOR</td></tr><tr><td>6</td><td>OR B_OR</td></tr><tr><td>7</td><td>== &lt;&gt; &lt; &gt; &gt;= &lt;=</td></tr></tbody></table></section></section><section><h3>2.3.2标准函数<a href="#232标准函数"><span>#</span></a></h3>

<table><thead><tr><th>说明</th><th>函数</th><th>函数的数 据类型</th><th>函数值的范围</th><th>函数的数 据类型</th><th>结果的范围</th></tr></thead><tbody><tr><td><strong>绝对值</strong></td><td><strong>ABS(X)</strong></td><td><strong>REAL</strong></td><td><strong>—∞…+∞</strong></td><td><strong>REAL</strong></td><td><strong>0…+∞</strong></td></tr><tr><td><strong>平方根</strong></td><td><strong>SQRT(X)</strong></td><td><strong>REAL</strong></td><td><strong>0…+∞</strong></td><td><strong>REAL</strong></td><td><strong>0…+∞</strong></td></tr><tr><td><strong>正弦</strong></td><td><strong>SIN(X)</strong></td><td><strong>REAL</strong></td><td><strong>—∞…+∞</strong></td><td><strong>REAL</strong></td><td><strong>-1…+1</strong></td></tr><tr><td><strong>余弦</strong></td><td><strong>COS(X)</strong></td><td><strong>REAL</strong></td><td><strong>—∞…+∞</strong></td><td><strong>REAL</strong></td><td><strong>-1…+1</strong></td></tr><tr><td><strong>正切</strong></td><td><strong>TAN(X)</strong></td><td><strong>REAL</strong></td><td><strong>—∞…+∞</strong>*</td><td><strong>REAL</strong></td><td><strong>—∞…+∞</strong></td></tr><tr><td><strong>反余弦</strong></td><td><strong>ACOS(x)</strong></td><td><strong>REAL</strong></td><td><strong>-1…+1</strong></td><td><strong>REAL</strong></td><td><strong>00…180</strong></td></tr><tr><td><strong>反正切</strong></td><td><strong>ATAN2(Y，X)</strong></td><td><strong>REAL</strong></td><td><strong>—∞…+∞</strong></td><td><strong>REAL</strong></td><td><strong>-900…+900</strong></td></tr><tr><td>**<em>900的倍数，也就是说.X≠(2k-1)<em>90，K∈N</em></em></td><td></td><td></td><td></td><td></td><td></td></tr></tbody></table></section></section><section><h2>2.4系统变量和系统文件<a href="#24系统变量和系统文件"><span>#</span></a></h2><blockquote><p>所有预定变量的列表见单独资料[系统变量]</p></blockquote><section><h3>计时器<a href="#计时器"><span>#</span></a></h3><p>16个计时器变量**$TIMER[1]…$TIMER[16]<strong>可用于测量时间顺序，可用作“秒表”。开始和停止计时使用系统变量</strong>$TIMER_STOP[1]…$TIMER_STOP[16]：**</p><p><strong>开始计时器4</strong></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$TIMER_STOP[4]=FALSE</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>关闭计时器4</strong></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$TIMER_STOP[4]=TRUE</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>使用一般变量分配可在任何时候复位有关的计时器变量。举例来说：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$TIMER[4]=0</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>如果计时器变量值从负向正变化，对应的标记则设置为TRUE(暂停条件)，举例来说：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$TIMER_FLAG[4]=TRUE</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>当控制器启动时，所有的计时器变量预设置为0，标记
<strong>$TIMER_FLAG[1]……$TIMER_FLAG[16]</strong> 预设置为<strong>FALSE</strong></p><p>变量**$TIMER_STOP[1]……$TIMER_STOP[16]** 预设置为<strong>TRUE</strong>。
计时器变量的单位是毫秒(ms)。**$TIMER[1]……$TIMER[16]和$TIMER_FLAG[1]……$TIMER_FLAG[16]**以12ms循环更新。</p></section><section><h3>标记<a href="#标记"><span>#</span></a></h3><p>1024个标记**$FLAG[1]…$FLAG[1024]<strong>被用作全局标记。这些布尔变量预设置为</strong>FALSE**。您可以随时在用户界面上通过“监视”菜单看标记的当前值</p></section><section><h3>循环标记<a href="#循环标记"><span>#</span></a></h3><p>KRC…中可用32个循环标记**$CYCFLAG[1]…$CYCFLAG[32]**  ，控制器启动后预设为<strong>FALSE</strong>。</p></section><section><h3>$符号<a href="#符号"><span>#</span></a></h3><p>预定变量一般选择一个容易记忆的名称。以$符号开始和有意义的英文缩写组成。</p><p>有的预定变量针对整个KRC…控制器(例如**$ALARM_STOP<strong>用于定义输出到到PLC的急停信号PLC).其它，然而仅用于机器人(例如</strong>$BASE**用于基本坐标系)。</p><p>机器人驱动器中有关控制的数据存储在目录**“Steu”<strong>中，有关机器人的数据存储在目录</strong>“R1”**中，并可在KUKA GUI上显示。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200519949.png" alt="image-20240606200519949" /><figcaption>image-20240606200519949</figcaption></figure><p></p><p>在KRC…中还有KUKA定义的和控制软件一起的数据表。这些数据表被称为预定数据表，主要包含预定变量。</p><section><h4>$MACHINE.DAT<a href="#machinedat"><span>#</span></a></h4><p>是预定数据表，包含专有的系统变量。适配控制器和所连接机器人(运动信息，控制参数等)的机床数据。控制系统和机器人系统中都有一个$MACHINE.DAT，您不可以新建或删除现存的。
例如：</p>

<table><thead><tr><th><strong>$ALARM_STOP</strong></th><th><strong>急停信号  (控制器特有)</strong></th></tr></thead><tbody><tr><td><strong>$NUM_AX</strong></td><td><strong>机器人轴数 （机器人特有）</strong></td></tr></tbody></table></section><section><h4>$CUSTOM.DAT<a href="#customdat"><span>#</span></a></h4><p>仅在控制系统中存在的数据表。包含可以配置或参数化特定控制函数的数据。编程师仅可以改变预定变量的值。不可以新建或删除现存的。例如：</p>

<table><thead><tr><th><strong>$PSER_1</strong></th><th><strong>串行接口1的协议参数</strong></th></tr></thead><tbody><tr><td><strong>$IBUS_ON</strong></td><td><strong>激活可选的联络母线组</strong></td></tr></tbody></table></section><section><h4>$CONFIG.DAT<a href="#configdat"><span>#</span></a></h4><p>KUKA预定的数据表，不包含任何系统变量，然而，在控制级和机器人级都有一个**$CONFIG.DAT**可用。其中可定义长时间有效的变量、结构、通道和信号，对许多程序普通重要。
数据表分为以下几个程序块：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>-- BAS</span></div></div><div><div><div>2</div></div><div><span>-- AUTOEXT</span></div></div><div><div><div>3</div></div><div><span>-- GRIPPER</span></div></div><div><div><div>4</div></div><div><span>-- PERCEPT</span></div></div><div><div><div>5</div></div><div><span>-- SPOT</span></div></div><div><div><div>6</div></div><div><span>A10</span></div></div><div><div><div>7</div></div><div><span>A50</span></div></div><div><div><div>8</div></div><div><span>A20</span></div></div><div><div><div>9</div></div><div><span>-- TOUCHSENSE</span></div></div><div><div><div>10</div></div><div><span>-- USER</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>用户的全局声明应该输入USER程序块，因为仅该处的声明在以后的软件升级中被转移。</p></section><section><h4>$ROBCOR.DAT<a href="#robcordat"><span>#</span></a></h4><p>文件**$ROBCOR.DAT**包含特定机器人的机器人动态模型的数据。在轨迹计划编排中需要这些数据。在文件中您不可以新建一个新变量或删除现存的。</p></section></section></section></section>
<section><h1>3运动编程<a href="#3运动编程"><span>#</span></a></h1><section><h2>3.1不同坐标系的应用<a href="#31不同坐标系的应用"><span>#</span></a></h2><p>最基本的坐标系时<strong>连接（轴指定）坐标系和笛卡尔坐标系</strong></p><p>KRC…中定义的角度A、B和C是绕坐标轴Z、Y和X的旋转角度。旋转的顺序必须保留。</p><ol>
<li>绕Z轴的旋转角度为A</li>
<li>绕Y轴的旋转角度为B</li>
<li>绕X轴的旋转角度为C</li>
</ol><p>这个旋转顺序与众所周知的航空领域的roll—pitch—yaw角度一致。角度C对应于roll，角度B对应于pitch，角度A对应于yaw。</p><p>KRC…中预定了下列<strong>笛卡儿坐标系</strong></p>

<table><thead><tr><th>坐标系</th><th>系统变量</th><th>状态</th></tr></thead><tbody><tr><td>全局坐标系</td><td>$WORLD</td><td>写保护</td></tr><tr><td>机器人坐标系</td><td>$ROBROOT</td><td>写保护(可在 R1/MADA/$MA CHINE.DAT中改 变)</td></tr><tr><td>工具坐标系</td><td>$TOOL*</td><td>可写</td></tr><tr><td>基本(工件)坐标系</td><td>$BASE*</td><td>可写</td></tr></tbody></table><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200613659.png" alt="image-20240606200613659" /><figcaption>image-20240606200613659</figcaption></figure><p></p><section><h3>world坐标系<a href="#world坐标系"><span>#</span></a></h3><p>全局坐标系是固定的(=当机器人移动时坐标系不动)坐标系，用作机器人系统（机器人、支撑部分或工具）的根本坐标系。是机器人系统和单元外围装备的参考系统。</p></section><section><h3>机器人坐标系<a href="#机器人坐标系"><span>#</span></a></h3><p>机器人坐标系位于机器人底部，是机器人机械结构的参考坐标系。起源于全局坐标系且当机器人系统交货时机器人坐标系与全局坐标系一致。与$WORLD的偏置关系可使用$ROBROOT定义。</p></section><section><h3>工具坐标系<a href="#工具坐标系"><span>#</span></a></h3><p>工具坐标系的原点在刀尖上。可以以下列方法选择方位，坐标系的X轴与工具的工作方向一致，X轴的方向远离工具。工具坐标系随工具的移动而移动</p></section><section><h3>基坐标系<a href="#基坐标系"><span>#</span></a></h3><p>基坐标系是用来定义工件位置的参考坐标系。机器人在基坐标系中编程，全局坐标系作为它的参考坐标系。在交货时，<strong>$BASE=$WORLD</strong>。可以改变**$BASE**，例如当使用相同的程序加工不同位置的许多相同的工件时。</p></section></section><section><h2>3.2点到点运动PTP<a href="#32点到点运动ptp"><span>#</span></a></h2><p>PTP&lt;点到点运动是将刀尖&gt;（刀具中心点：TCP）从当前位置移动到编程终点位置的最快方法。控制器计算各轴必要的角度差别。</p><section><h3>3.2.1一般说明<a href="#321一般说明"><span>#</span></a></h3><p>使用下列系统变量：
●<strong>$VEL_AXIS[轴数]&lt;编程的最大轴速度&gt;</strong>
<strong>●$ACC_AXIS[轴数]&lt;编程的最大轴加速度&gt;</strong>
机床数据中所有的输入以最大值的百分比给定。对于所有轴来说，如果还没有编程这两个系统变量，执行程序则会产生相关的错误消息。</p><blockquote><p>由于在笛卡儿坐标系中的PTP运动通常不知道哪一个轴是主导轴，所以明智的做法是将所有轴设置同样的加速度和速度值。</p></blockquote></section><section><h3>3.2.2更高级的运动轮廓<a href="#322更高级的运动轮廓"><span>#</span></a></h3></section><section><h3>3.2.3运动命令<a href="#323运动命令"><span>#</span></a></h3><blockquote><p>程序中首先定义轴的速度和加速度，必须在执行点到点运动前分配这些值</p></blockquote><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DEFPTP_AXIS( ) ;程序名是PTP_AXIS</span></div></div><div><div><div>2</div></div><div><span>$VEL_AXIS[1]=100 ；定义轴速度</span></div></div><div><div><div>3</div></div><div><span>$VEL_AXIS[2]=100</span></div></div><div><div><div>4</div></div><div><span>$VEL_AXIS[3]=100</span></div></div><div><div><div>5</div></div><div><span>$VEL_AXIS[4]=100</span></div></div><div><div><div>6</div></div><div><span>$VEL_AXIS[5]=100</span></div></div><div><div><div>7</div></div><div><span>$VEL_AXIS[6]=100</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>$ACC_AXIS[1]=100 ；定义轴加速度</span></div></div><div><div><div>10</div></div><div><span>$ACC_AXIS[2]=100</span></div></div><div><div><div>11</div></div><div><span>$ACC_AXIS[3]=100</span></div></div><div><div><div>12</div></div><div><span>$ACC_AXIS[4]=100</span></div></div><div><div><div>13</div></div><div><span>$ACC_AXIS[5]=100</span></div></div><div><div><div>14</div></div><div><span>$ACC_AXIS[6]=100</span></div></div><div><div><div>15</div></div><div><span>PTP{AXIS：A1 0，A2 –90，A3 90，A4 0，A5 0，A6 0}</span></div></div><div><div><div>16</div></div><div><span>END</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><section><h4>PTP<a href="#ptp"><span>#</span></a></h4><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>PTP{A3 45}</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>PTP指令中定义的角度值是绝对值。因此机器人并不是旋转45度，而是旋转到45度。</p></section><section><h4>PTP_REL<a href="#ptp_rel"><span>#</span></a></h4><p>相对运动，使用指令PTP REL。例如要旋转轴1和4都是35度，简单编程如下：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>PTP REL PTP REL {A1 35，A4 35}</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>通过POS结构在笛卡儿坐标系中输入值，如同下面的举例：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DEF PTP_POS( )</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>$BASE=$WORLD ;设置基本坐标系</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span>$TOOL=$NULLFRAME  ；设置工具坐标系</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>$VEL_AXIS[1]=100 ；定义轴速度</span></div></div><div><div><div>8</div></div><div><span>$VEL_AXIS[2]=100</span></div></div><div><div><div>9</div></div><div><span>$VEL_AXIS[3]=100</span></div></div><div><div><div>10</div></div><div><span>$VEL_AXIS[4]=100</span></div></div><div><div><div>11</div></div><div><span>$VEL_AXIS[5]=100</span></div></div><div><div><div>12</div></div><div><span>$VEL_AXIS[6]=100</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span>$ACC_AXIS[1]=100 ；定义轴加速度</span></div></div><div><div><div>15</div></div><div><span>$ACC_AXIS[2]=100</span></div></div><div><div><div>16</div></div><div><span>$ACC_AXIS[3]=100</span></div></div><div><div><div>17</div></div><div><span>$ACC_AXIS[4]=100</span></div></div><div><div><div>18</div></div><div><span>$ACC_AXIS[5]=100</span></div></div><div><div><div>19</div></div><div><span>$ACC_AXIS[6]=100</span></div></div><div><div><div>20</div></div><div>
</div></div><div><div><div>21</div></div><div><span>PTP{POS：X 1025，Y 0，Z 1480，A 0，B 90，C 0，S ’B010’，T ’B000010’}</span></div></div><div><div><div>22</div></div><div><span>END</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h4>坐标系<a href="#坐标系"><span>#</span></a></h4><p>笛卡儿坐标系中使用<strong>几何操作</strong>可以直接在运动命令中进行框架联接，这种方法，例如可以不修改系统变量**$BASE**而初始化与基本坐标系的偏置。</p><blockquote><p>而且，通过冒号操作指定一个基本偏置比重新定义$BASE更有优势：运动指令中出现偏置操作，则必须在运动指令前设置$BASE。以该方法，即使停止了程序后选择后续的程序段，运动总是选择了正确的基本坐标系。</p><p>因此， $BASE 和$TOOL 仅可以被设置一次，例如，在程序的初始化部分。然后可以使用几何操作进行后续的偏置。</p></blockquote></section><section><h4>INI<a href="#ini"><span>#</span></a></h4><p>在这个例子中，速度和加速度及$BASE和$TOOL坐标系的分配不是“手动”进行，而时由标准基本软件包中的“BAS.SRC”来完成，要这样做，必须首先使用EXT指令使程序认识。
初始化命令</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>INI BAS(#INITMOV，0)</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>然后分配缺省值给所有重要的系统变量。</p></section><section><h4>BCO<a href="#bco"><span>#</span></a></h4><blockquote><p>明智的做法是编程一个“Home”作为第一个运动指令；移动机器人到一个明确定义的位置，这样就确立了程序段一致性。机器人在程序的结束应返回该位置。</p></blockquote></section><section><h4>S和T<a href="#s和t"><span>#</span></a></h4><p>POS定义中的“S”和“T”用于选择一个特定的， 明确定义的空间中需要许多轴定位的同一个点的机器人位置 。</p><p>程序的第一个运动指令必须总是一个定义了状态和转的完整的PTP指令(或一个完整的使用轴坐标系的PTP指令)。在后续的PTP指令中，只要不需要特定轴定位，例如要要避开障碍时可以省略“S”和“T”，机器人保持最短轴轨迹使用的S和T值，则在第一个PTP指令中编程 “S”和 “T”后，每次程序运行时，机器人的轨迹都相同  。</p></section><section><h4>Turn<a href="#turn"><span>#</span></a></h4><p>属性包含“Turn”属性的扩展笛卡儿位置，可以在不需要特殊移动策略（例如辅助点）时，轴的移动角度大于+1800或小于－1800。对于旋转轴，轴值前面的各位决定符号，如下：
位x=0：轴的角度 ≥00
位x=1：轴的角度＜00</p><p><strong>值T‘B10011’意思是指轴1、2、5的角度是负值，而轴3、4、6是正值(高位是0可以省略)。</strong></p></section><section><h4>Status<a href="#status"><span>#</span></a></h4><p>状态S当轴位置不明确时使用(见图18)。S根据当前机器人运动系统的不同而不同</p></section></section></section><section><h2>3.3连续轨迹运动(CP运动=连续轨迹)<a href="#33连续轨迹运动cp运动连续轨迹"><span>#</span></a></h2><section><h3>3.3.1速度和加速度<a href="#331速度和加速度"><span>#</span></a></h3><p>与PTP运动不同，在连续轨迹运动中不是只定义起点和终点，还需要定义这些点之间沿直线和圆弧轨迹的TCP运动。
输入的速度和加速率对于单独的轴或TCP的运动不再有关系，对于平移运动、旋转角和旋转的角度<strong>必须编程速度和加速度</strong>。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200643554.png" alt="image-20240606200643554" /><figcaption>image-20240606200643554</figcaption></figure><p></p><p>当调用基本软件包的初始化顺序时，CP运动的缺省设置速度和加速率也被预设为机床数据**$CONFIG.DAT<strong>定义的最大值。
CP运动的轴速度和加速度被监视，监视范围在系统变量</strong><span><span>ACCACTMA和ACC_ACT_MA\text{和}</span><span><span><span></span><span>A</span><span>C</span><span><span>C</span><span><span><span><span><span><span></span><span><span>A</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>C</span><span><span>T</span><span><span><span><span><span><span></span><span><span>M</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>A</span><span><span>和</span></span></span></span></span>VEL_ACT_MA<strong>定义，如果超过该范围，则触发制动反应，同时产生错误消息。标准范围是法向轴加速度的250%和法向轴速度的110%。这些监控范围对所有操作模式和手动移动都有效。要预防超过监控范围引起的反应（制动反应），可以使用系统变量</strong>$CP_VEL_TYPE<strong>降低轴进给速、加速度和速度。该变量的缺省设置是</strong>#CONSTANT**，I也就是说，在程序模式降速是不激活的。如果要在T1模式（T1模式使用更低的速度和加速度）使用该功能，必须设置值**#VAR_T1**，而对于所有操作模式则要设置值**#VAR_ALL**。在JOG模式总是激活降速。在测试模式如果降低轨迹速度，系统变量**$CPVELREDMELD**会产生错误消息，要这样做的话，必须分配该值为“1”。</p></section><section><h3>3.3.2方位控制<a href="#332方位控制"><span>#</span></a></h3><p>如果轨迹运动期间，要改变工具在空间中的方位，可以使用系统变量**$ORI_TYPE**设置为方位控制模式(见图21)：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$ORI_TYPE=#CONSTANT 轨迹运动期间方位保持不变；对于使用的起点和终点，编程的方位被忽略。</span></div></div><div><div><div>2</div></div><div><span>$ORI_TYPE=#VAR 轨迹运动期间从最初的方位到最终的方位，方位连续变化。 该值在初始化期间通过BAS(#INITMOV，0)来设置。</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200703318.png" alt="image-20240606200703318" /><figcaption>image-20240606200703318</figcaption></figure><p></p><p>对于圆弧运动，  固定的和变化的方位外，还需要选择空间相关的方位和轨迹相关的方位</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$CIRC_TYPE=#BASE 在圆弧运动期间执行空间相关的方位控制。该值也要在初始化期间通过BAS(#INITMOV，0)来设置。</span></div></div><div><div><div>2</div></div><div><span>$CIRC_TYPE=#PATH  在圆弧运动期间执行轨迹相关的方位控制。</span></div></div></code></pre><div><div></div><div></div></div></figure></div><section><h4>固定方位＋轨迹相关<a href="#固定方位轨迹相关"><span>#</span></a></h4><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200718732.png" alt="image-20240606200718732" /><figcaption>image-20240606200718732</figcaption></figure><p></p></section><section><h4>变化的方位+轨迹相关<a href="#变化的方位轨迹相关"><span>#</span></a></h4><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200730772.png" alt="image-20240606200730772" /><figcaption>image-20240606200730772</figcaption></figure><p></p></section><section><h4>固定方位＋空间相关<a href="#固定方位空间相关"><span>#</span></a></h4><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200740842.png" alt="image-20240606200740842" /><figcaption>image-20240606200740842</figcaption></figure><p></p></section><section><h4>变化的方位＋空间相关<a href="#变化的方位空间相关"><span>#</span></a></h4><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200751160.png" alt="image-20240606200751160" /><figcaption>image-20240606200751160</figcaption></figure><p></p></section></section><section><h3>3.3.3线性运动<a href="#333线性运动"><span>#</span></a></h3><section><h4>LINE<a href="#line"><span>#</span></a></h4><p>使用关键字LIN或LIN_REL及终点定义来编程一个线性运动，类似于PTP编程。线性运动的终点以笛卡儿坐标输入。仅允许使用数据类型<strong>FRAME或POS</strong>  .</p></section><section><h4>CIRCLE<a href="#circle"><span>#</span></a></h4><p>要明确地定义空间中的一个圆和圆弧运动，需要互相不在一条直线的三个不同点。圆弧运动的起点也是当前位置，同PTP中的LIN。</p></section><section><h4>CONTINUE<a href="#continue"><span>#</span></a></h4></section></section></section><section><h2>3.5使用逼近定位的运动<a href="#35使用逼近定位的运动"><span>#</span></a></h2></section></section>
<section><h1>5.程序执行控制<a href="#5程序执行控制"><span>#</span></a></h1><section><h2>5.1程序分支<a href="#51程序分支"><span>#</span></a></h2><section><h3>5.1.1跳跃分支<a href="#511跳跃分支"><span>#</span></a></h3><section><h4><strong>GOTO</strong><a href="#goto"><span>#</span></a></h4></section></section><section><h3>5.1.2条件分支<a href="#512条件分支"><span>#</span></a></h3><section><h4><strong>IF</strong><a href="#if"><span>#</span></a></h4><p>结构化的IF语句允许使用选择两个选项之一的公式化的指令。该指令的一般形式是：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200810080.png" alt="image-20240606200810080" /><figcaption>image-20240606200810080</figcaption></figure><p></p><p>执行条件是布尔表达式。如果满足执行条件则执行THEN程序段。如果不满足则可以执 行ELSE程序段或省缺。如果省缺，则立即离开分支。</p><p>可以使用一个不受次数限制的指令。特别是可以使用深一层的IF语句。IF程序段的嵌 套是允许的。但是每一层的IF语句必须以自己的ENDIF结束。</p><p>在下列程序中，如果输入10为FALSE，机器人将移动到HOME位置。如果输入10被设置 且变量A的值大于变量B的值，则输出10被设置，机器人移动到点1。与A和B无关，只 要输入1被设置，变量A的值就会增加1，机器人运动到HOME位置:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>…</span></div></div><div><div><div>2</div></div><div><span>INTA，B</span></div></div><div><div><div>3</div></div><div><span>…</span></div></div><div><div><div>4</div></div><div><span>IF $IN[10]==FALSE THEN</span></div></div><div><div><div>5</div></div><div><span>PTP HOME</span></div></div><div><div><div>6</div></div><div><span>ELSE</span></div></div><div><div><div>7</div></div><div><span>IF A&gt;B THEN</span></div></div><div><div><div>8</div></div><div><span>$OUT[1]=TRUE</span></div></div><div><div><div>9</div></div><div><span>LINPUNKT1</span></div></div><div><div><div>10</div></div><div><span>END IF</span></div></div><div><div><div>11</div></div><div><span>A=A+1</span></div></div><div><div><div>12</div></div><div><span>PTP HOME</span></div></div><div><div><div>13</div></div><div><span>END IF</span></div></div><div><div><div>14</div></div><div><span>…</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section></section><section><h3>5.1.3转换<a href="#513转换"><span>#</span></a></h3><section><h4>SWITCH<a href="#switch"><span>#</span></a></h4><p>SWITCH语句是用于不同程序分支的选择指令。选择的标准是SWITCH语句前分配的值。  如果该值与程序段标识符一致，则执行对应的分支，程序直接跳跃到ENDSWITCH语句 而不考虑后面程序段的标识符。</p><p>如果没有程序段标识符与选择标准一致，就执行 DEFAULT语句程序段，如果有一个。否则，程序从ENDSWITCH后的指令重新开始执行。  一个程序分支可以分配许多程序段标识符。另一方面，一个程序段标识符使用许多 次则是不明智的，因为仅考虑对应标识符的第一个分支。</p><p>选择标准允许的数据类型是INT，CHAR和ENUM。选择标准的数据类型必须与程序段标 识符一致。</p><p>可以省略DEFAULT语句，且在SWITCH语句内仅可以出现一次。  SWITCH语句可以用于，例如，通过程序号调用不同的子程序。程序号也可以，例如 用于KRC..中PLC的数字输入（见节6.3有关SIGNAL语句的信息）。以该方法，作为整 数值用作选择标准。</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DEF MAIN（）</span></div></div><div><div><div>2</div></div><div><span>…</span></div></div><div><div><div>3</div></div><div><span>SIGNAL PROG_NR $IN[1] TO $IN[4]；期望的程序号现在通过PLC存储在INT变量PROG_NO中</span></div></div><div><div><div>4</div></div><div><span>…</span></div></div><div><div><div>5</div></div><div><span>SWITCH PROG_NO</span></div></div><div><div><div>6</div></div><div><span><span>  </span></span><span>CASE 1 ；如果PROG_NO=1</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>PART_1（）</span></div></div><div><div><div>8</div></div><div><span><span>  </span></span><span>CASE 2 ；如果PROG_NO=2</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>PART_2（）</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>PART_2A（）</span></div></div><div><div><div>11</div></div><div><span><span>  </span></span><span>CASE3，4，5 ；如果PROG_NO=3，4或5</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>$OUT[3]=TRUE</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>PART_345（）</span></div></div><div><div><div>14</div></div><div><span><span>  </span></span><span>DEFAULT ；如果PROG_NO&lt;&gt;1，2，3，4或5</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>ERROR_UP（）</span></div></div><div><div><div>16</div></div><div><span>ENDSWITCH</span></div></div><div><div><div>17</div></div><div><span>…</span></div></div><div><div><div>18</div></div><div><span>END</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section></section><section><h2>5.2循环<a href="#52循环"><span>#</span></a></h2><section><h3>5.2.1计数循环<a href="#521计数循环"><span>#</span></a></h3><section><h4>FOR<a href="#for"><span>#</span></a></h4><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606200836178.png" alt="image-20240606200836178" /><figcaption>image-20240606200836178</figcaption></figure><p></p><p>计数器中输入整数类型的表达式作为<strong>Start和End</strong>的值。 循环开始时对该表达式求值。</p><p>以起始值预先定义整数型变量<strong>Counter</strong>(必须提前声明) ，然后该值在每次循环执行后增加或减少编程的增量。</p><p><strong>Increment</strong>既不能是一个变量，也不能是零。如果没有指定增量，则使用缺省值1。允许使用负的增量值。</p><p>每个FOR语句必须以一个<strong>ENDFOR</strong>语句结束。</p><p>在下面的例子中，首先设置轴速度$VEL_AXIS[1]…$VEL_AXIS[6]为100%。然后使用 计算出的值初始化二维阵列的组件。</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DEF</span></div></div><div><div><div>2</div></div><div><span>FOR_PROG( )</span></div></div><div><div><div>3</div></div><div><span>...</span></div></div><div><div><div>4</div></div><div><span>INT I,J</span></div></div><div><div><div>5</div></div><div><span>INT ARRAY[10,6]</span></div></div><div><div><div>6</div></div><div><span>...</span></div></div><div><div><div>7</div></div><div><span>FOR I=1 TO 6</span></div></div><div><div><div>8</div></div><div><span>$VEL_AXIS[I]=100  ;所有轴速设置到100%</span></div></div><div><div><div>9</div></div><div><span>ENDFOR</span></div></div><div><div><div>10</div></div><div><span>...</span></div></div><div><div><div>11</div></div><div><span>FOR</span></div></div><div><div><div>12</div></div><div><span>I=1TO 9 STEP2</span></div></div><div><div><div>13</div></div><div><span>FOR J=6 TO 1 STEP –1</span></div></div><div><div><div>14</div></div><div><span>ARRAY[I,J]=I*2+J*J</span></div></div><div><div><div>15</div></div><div><span>ARRAY[I+1,J]=I*2+I*J</span></div></div><div><div><div>16</div></div><div><span>ENDFOR</span></div></div><div><div><div>17</div></div><div><span>ENDFOR    ;现在I的值为11,J的值为0</span></div></div><div><div><div>18</div></div><div><span>...</span></div></div><div><div><div>19</div></div><div><span>END</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section><section><h3>5.2.2跳出循环<a href="#522跳出循环"><span>#</span></a></h3><section><h4>WHILE<a href="#while"><span>#</span></a></h4><p>WHILE循环在重复开始时请求一个执行条件。它是一个跳出循环，它不是单次运行，直到开始设置的执行条件满足时才跳出。WHILE循环语法如下:</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201154892.png" alt="image-20240606201154892" /><figcaption>image-20240606201154892</figcaption></figure><p></p><p>执行条件是一个逻辑表达式，可以是一个布尔变量、一个布尔函数调用或一个布尔结 果的逻辑操作。</p><p>逻辑操作的值为TRUE时执行指令程序段,也就是说满足执行条件。逻辑操作的值为 FALSE时程序从ENDWHILE后的下一个指令重新开始。因此每个WHILE语句必须以 ENDWHILE语句结束。</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DEF WHILE_PR()</span></div></div><div><div><div>2</div></div><div><span>...</span></div></div><div><div><div>3</div></div><div><span>INT X,W</span></div></div><div><div><div>4</div></div><div><span>...</span></div></div><div><div><div>5</div></div><div><span>WHILE $IN[4]==TRUE</span></div></div><div><div><div>6</div></div><div><span>PTP PALLET</span></div></div><div><div><div>7</div></div><div><span>$OUT[2]=TRUE</span></div></div><div><div><div>8</div></div><div><span>PTP POS_2</span></div></div><div><div><div>9</div></div><div><span>$OUT[2]=FALSE</span></div></div><div><div><div>10</div></div><div><span>PTP HOME</span></div></div><div><div><div>11</div></div><div><span>ENDWHILE</span></div></div><div><div><div>12</div></div><div><span>...</span></div></div><div><div><div>13</div></div><div><span>X=1</span></div></div><div><div><div>14</div></div><div><span>W=1</span></div></div><div><div><div>15</div></div><div><span>WHILE W&lt;5;</span></div></div><div><div><div>16</div></div><div><span>X=X*W</span></div></div><div><div><div>17</div></div><div><span>W=W+1</span></div></div><div><div><div>18</div></div><div><span>ENDWHILE</span></div></div><div><div><div>19</div></div><div><span>...</span></div></div><div><div><div>20</div></div><div><span>W=100</span></div></div><div><div><div>21</div></div><div><span>WHILE&lt;W100</span></div></div><div><div><div>22</div></div><div><span>$OUT[15]=TRUE</span></div></div><div><div><div>23</div></div><div><span>W=W+1</span></div></div><div><div><div>24</div></div><div><span>ENDWHILE</span></div></div><div><div><div>25</div></div><div><span>...</span></div></div><div><div><div>26</div></div><div><span>END</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section><section><h3>5.2.3非一跳出循环<a href="#523非一跳出循环"><span>#</span></a></h3><section><h4>REPEAT<a href="#repeat"><span>#</span></a></h4><p>与WHILE循环相对应的是REPEAT循环。 REPEAT,直到循环结束时才检查结束条件。因 此REPEAT循环总是运行一次，即使在循环开始前结束条件已经满足。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201248295.png" alt="image-20240606201248295" /><figcaption>image-20240606201248295</figcaption></figure><p></p></section></section><section><h3>5.2.4无穷循环<a href="#524无穷循环"><span>#</span></a></h3><p>只能使用EXIT语句结束指令程序段的重复执行</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201259768.png" alt="image-20240606201259768" /><figcaption>image-20240606201259768</figcaption></figure><p></p></section><section><h3>5.2.5循环的退出<a href="#525循环的退出"><span>#</span></a></h3><p>使用<strong>EXIT语句</strong>可以提前结束任何循环。通过在循环的指令程序段内调用EXIT，循环运行立即结束，程序在循环结束语句后重新开始。</p><p>在REPEAT和WHILEl循环中选择合理的结束和执行条件而不必主要依靠使用EXIT语句。但是对于无穷循环，仅可以使用EXIT结束循环的执行。</p></section></section><section><h2>5.3等待指令<a href="#53等待指令"><span>#</span></a></h2><section><h3>5.3.1等待一个事件<a href="#531等待一个事件"><span>#</span></a></h3><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201311768.png" alt="image-20240606201311768" /><figcaption>image-20240606201311768</figcaption></figure><p></p><p>如果在调用WAIT时逻辑表达式条件已经为TRUE，则不会停止程序的执行(但是触发提前运行停止)。
如果条件为FALSE，则停止执行程序直到表达式的值为TRUE才继续执行程序。</p><section><h4>数字值<a href="#数字值"><span>#</span></a></h4>

<table><thead><tr><th>WAIT FOR…</th><th>消息窗口中的消息</th><th>含义</th></tr></thead><tbody><tr><td><strong>$IN[5]</strong></td><td><strong>Waiting for input5</strong></td><td><strong>等待直到输入5为TRUE</strong></td></tr><tr><td><strong>$OUT[5]==FALSE</strong></td><td><strong>Waiting for not output5</strong></td><td><strong>等待直到输入5为FALSE</strong></td></tr><tr><td><strong>$TIMER[5]&gt;=300</strong></td><td><strong>Waiting until timer5&gt;=300</strong></td><td><strong>等待直到计时器5至少达到 300ms</strong></td></tr><tr><td><strong>$TIMER_FLAG[5]</strong></td><td><strong>Waiting for Timer_Flag5</strong></td><td><strong>等待直到计时器标志5为TRUE</strong></td></tr><tr><td><strong>$FLAG[5]==FALSE</strong></td><td><strong>Waiting for not flag5</strong></td><td><strong>等待直到标志5为FALSE</strong></td></tr><tr><td><strong>$CYCFLAG[5]</strong></td><td><strong>Waiting for cyclical flag5</strong></td><td><strong>等待直到循环标志5为TRUE</strong></td></tr><tr><td><strong>I[5]==9</strong></td><td><strong>Waiting for counter5==9</strong></td><td><strong>等待直到计时器5的值等于 “9</strong></td></tr></tbody></table></section><section><h4>变量值<a href="#变量值"><span>#</span></a></h4><p>一个变量被转换为一个数字。该变量必须在数据表(<em>.dat)中声明。在源文件(</em>.src)中的声明则是定义该变量的值。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>数据表：            源文件：</span></div></div><div><div><div>2</div></div><div><span>DEFDAT PROG1      DEF PROG1( )</span></div></div><div><div><div>3</div></div><div><span>…                 …</span></div></div><div><div><div>4</div></div><div><span>DECL INT          INT VAR INT VAR=7</span></div></div><div><div><div>5</div></div><div><span>…                 …</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>长文本</p><p>信号声明</p></section></section><section><h3>5.3.2 等待时间<a href="#532-等待时间"><span>#</span></a></h3><p><strong>WAIT SEC</strong>语句允许使用秒来编程等待时间：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201354778.png" alt="image-20240606201354778" /><figcaption>image-20240606201354778</figcaption></figure><p></p></section></section><section><h2>5.4停止程序<a href="#54停止程序"><span>#</span></a></h2><p><strong>HALT</strong> 如果要中断程序执行和停止处理，编程如下指令</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201403088.png" alt="image-20240606201403088" /><figcaption>image-20240606201403088</figcaption></figure><p></p></section><section><h2>5.5 确认消息<a href="#55-确认消息"><span>#</span></a></h2><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201410413.png" alt="image-20240606201410413" /><figcaption>image-20240606201410413</figcaption></figure><p></p></section></section>
<section><h1>6 输入输出指令<a href="#6-输入输出指令"><span>#</span></a></h1><section><h2>6.1一般说明<a href="#61一般说明"><span>#</span></a></h2><p>KRC…可以识别1026个输入和1024个输出。在标准的KUKA控制柜中，用户可以使用X11连接器的下列输入和输出（MFC模块）：
输入 1…16</p><p>其它输入/输出可以随意配置，例如使用区域总线。
可以读输入和写输出。它们通过系统变量**$IN[No]或$OUT[No]<strong>寻址。未使用的输出可以当作标记使用。
MFC模块可在文件</strong>“ IOSYS.INI”**重新分配输入/输出。</p></section></section>
<section><h1>7.子程序和函数<a href="#7子程序和函数"><span>#</span></a></h1><section><h2>7.1声明<a href="#71声明"><span>#</span></a></h2><section><h3>DEF<a href="#def"><span>#</span></a></h3><p>所有的子程序与主程序的声明方法一样，使用DEF声明加上名字，以END结束，举例说明：
</p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201453189.png" alt="image-20240606201453189" /><figcaption>image-20240606201453189</figcaption></figure><p></p></section><section><h3>DEFFCT<a href="#deffct"><span>#</span></a></h3><p>函数是子程序类型中的一种；不同的是，程序名同时也是一个指定数据类型的变量。函数的结果可以通过简单地给变量分配一个值来传递。因此，当使用关键字DEFFCT声明函数时，函数的数据类型和函数的名字都要指定。函数以ENDFCT指令结束。因为函数假设为传递一个值，所以必须在ENDFCT语句前使用RETURN语句指定该值。例子:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DEFFCT INT FUNCTION（）</span></div></div><div><div><div>2</div></div><div><span>…</span></div></div><div><div><div>3</div></div><div><span>RETURN（X）</span></div></div><div><div><div>4</div></div><div><span>ENDFCT</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>局部函数<a href="#局部函数"><span>#</span></a></h3><p>主程序和子程序或函数在同一个SRC文件中。该文件与主程序名相同。</p></section><section><h3>全局函数<a href="#全局函数"><span>#</span></a></h3><p>全局子程序和函数以单独的SRC文件存储。以该方法，则如果被其它程序调用，则每个调用的程序都变成了子程序</p><p>有在主程序的数据表中声明过的变量都可以在子程序和函数中被识别。主程序（SRC文件）中已经声明过的变量称为“ runtime变量”，仅可以在主程序中使用。试图在子程序中使用这些变量会产生相应的错误消息。
主程序中声明过的变量也不能在全局子程序和函数中被识别。
子程序或函数中声明过的变量在主程序中不能被识别。
主程序不能存储其它主程序的局部子程序和函数。
局部子程序/函数名的最大长度是24个字符。全局子程序/函数名的最大长度是20个字符（由于有文件扩展名）。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201509531.png" alt="image-20240606201509531" /><figcaption>image-20240606201509531</figcaption></figure><p></p></section></section><section><h2>7.2子程序和函数的调用和参数传递<a href="#72子程序和函数的调用和参数传递"><span>#</span></a></h2><p>通过输入子程序名加上圆括号调用子程序。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>SUBPROG1（）</span></div></div></code></pre><div><div></div><div></div></div></figure></div><section><h3>参数表<a href="#参数表"><span>#</span></a></h3><p><strong>值调用（IN）</strong></p><p><strong>参考调用(OUT)</strong></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201535954.png" alt="image-20240606201535954" /><figcaption>image-20240606201535954</figcaption></figure><p></p><p>在子程序或函数中通过在参数表的每个变量后输入关键字<strong>IN</strong>输入“通过值调用”。通过输入字<strong>OUT</strong>得到 “通过参考调用”，<strong>OUT</strong>也是缺省设置。例如：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DEF CALCULATE（X：OUT，Y：IN，Z：IN，B）</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>当传输一个阵列时，在子程序和函数中也必须声明该阵列，但是没有索引。</p></section></section></section>
<section><h1>8中断处理<a href="#8中断处理"><span>#</span></a></h1><section><h2>8.1声明<a href="#81声明"><span>#</span></a></h2><section><h3>INTERRUPT<a href="#interrupt"><span>#</span></a></h3><p>可能产生中断的原因和系统将对它们采取的措施，必须在中断可以被激活前定义好。
INTERRUPT 使用中断声明完成该操作，给每个中断分配一个优先级、事件和调用的中断程序。完整的语句是：
</p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201644281.png" alt="image-20240606201644281" /><figcaption>image-20240606201644281</figcaption></figure><p></p>

<table><thead><tr><th>自变量</th><th>数据类型</th><th>含义</th></tr></thead><tbody><tr><td>Priority</td><td>INT</td><td>指定中断优先级的算术表达式，可以使用的优先级为 1…39和81…128。 值40…80为机器人系统的自动优先级分配保留。</td></tr><tr><td>Event</td><td>BOOL</td><td>定义中断事件的逻辑表达式。下列是允许的： 一个布尔常数 一个布尔变量 一个信号名 一个比较</td></tr><tr><td>Subprogram</td><td></td><td>当事件发生时要执行的中断程序的名字</td></tr></tbody></table><blockquote><p>中断声明是一条指令，因此， 千万不要在声明部分中使用。</p></blockquote><ul>
<li>一个声明可能在任何时候被另一个声明重写。</li>
<li>GLOBAL中断不同于一般的中断，即使声明的子程序在左边仍然保持有效。</li>
<li>一次最多可以声明32个中断。</li>
<li>在中断条件下不能存储结构变量和成分。</li>
<li>除GLOBAL变量和数据表中声明的变量外，实时变量不能当作中断程序参数被传输。</li>
</ul><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201656258.png" alt="image-20240606201656258" /><figcaption>image-20240606201656258</figcaption></figure><p></p></section></section><section><h2>8.2中断的激活<a href="#82中断的激活"><span>#</span></a></h2><section><h3>打开中断<a href="#打开中断"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>INTERRUPT ON 4  开优先级为4的中断</span></div></div><div><div><div>2</div></div><div><span>INTERRUPT ON  开所有中断</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>边缘触发<a href="#边缘触发"><span>#</span></a></h3><p>检查是边缘触发型的，也就是说一个中断仅在逻辑条件从FALSE状态变化为TRUE状态时被 触发，反之如果当开中断时条件已经是TRUE则不触发。</p></section><section><h3>关闭中断<a href="#关闭中断"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>与开的方法相同，中断可以单独或所有一起被关：</span></div></div><div><div><div>2</div></div><div><span>INTERRUPT OFF 4</span></div></div><div><div><div>3</div></div><div><span>或</span></div></div><div><div><div>4</div></div><div><span>INTERRUPT OFF</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>禁止/使能<a href="#禁止使能"><span>#</span></a></h3><p>使用关键字<strong>ENABLE和DISABLE</strong>，已经打开的中断可以被单独或全部使能或禁止。
禁止命令可以在被中断前保护程序的某些部分。一个禁止的中断可以被识别和存储，但是不能被执行。仅当被使能后，已经发生的中断才以它们的优先级顺序被执行。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>DISABLE 4</span></div></div><div><div><div>2</div></div><div><span>或</span></div></div><div><div><div>3</div></div><div><span>DISABLE</span></div></div></code></pre><div><div></div><div></div></div></figure></div><blockquote><p>触发一个中断的前提条件是：
●中断必须是声明过的（ INTERRUPT DECL…）
●中断必须被打开（ INTERRUPT ON）
●中断必须是没有被禁止的
●对应的事件必须已经发生（边缘触发）</p></blockquote></section><section><h3>优先级<a href="#优先级"><span>#</span></a></h3></section></section><section><h2>8.3停止现在的运动<a href="#83停止现在的运动"><span>#</span></a></h2><p>如果必要的话， 在中断程序中使用BRAKE语句，则可以在中断事件中停止已经正在执行的机器人的运动</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>BRAKE</span></div></div></code></pre><div><div></div><div></div></div></figure></div><blockquote><p>BRAKE 指令仅可以在中断程序中使用， 在其它程序中使用则会导致一个错误引起的停止。</p></blockquote></section><section><h2>8.4取消中断事务<a href="#84取消中断事务"><span>#</span></a></h2><p>KRC…中机器人运动的取消是可能的，使用语句：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>RESUME</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>RESUME可以取消当前中断被声明的级别和以下级别的所有运行的中断程序和子程序。</p><blockquote><p>同 BRAKE 语句，RESUME 仅允许在中断程序中使用。当激活 RESUME 语句时，提前运行指针千万不要在中断被声明的级别，至少应低一个级别。</p></blockquote></section><section><h2>8.5循环标记的使用<a href="#85循环标记的使用"><span>#</span></a></h2><p>在中断声明指令中不允许使用逻辑操作因此，要定义复杂的事件，您必须使用使用程序如下;</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>$CYCFLAG[3]=$IN[1] AND（[$IN[2] OR $IN[3]）</span></div></div><div><div><div>2</div></div><div><span>INTERRUPT DECL 10 WHEN $CYCFLAG[3] DO IR_PROG（）</span></div></div><div><div><div>3</div></div><div><span>INTERRUPT ON 10</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>您可以同时监视和逻辑组合3个输入。</p></section></section>
<section><h1>9 触发轨迹相关的开关动作<a href="#9-触发轨迹相关的开关动作"><span>#</span></a></h1><section><h2>9.1在轨迹的起点或终点开关动作<a href="#91在轨迹的起点或终点开关动作"><span>#</span></a></h2><section><h3>TRIGGER<a href="#trigger"><span>#</span></a></h3><p>如果需要一个与运动轨迹起点或终点相关的开关动作，在相关的运动指令（PTP，LIN 或CIRC）前，以下列语法编程一个TRIGGER语句：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201727429.png" alt="image-20240606201727429" /><figcaption>image-20240606201727429</figcaption></figure><p></p>

<table><thead><tr><th>自变量</th><th>数据类型</th><th>含义</th></tr></thead><tbody><tr><td>Switching point</td><td>INT</td><td>对于单独的程序段， DISTANCE=0指明为下一个运动 的起点，属性DISTANCE=1则为终点。 对于逼近程序段， DISTANCE=1表示后续逼近定位圆 弧的中点。如果前一个程序段也 是一个逼近程序段， DISTANCE=0表示前述逼近定位 圆弧的终点。</td></tr><tr><td>Time</td><td>INT</td><td>使用属性DELAY，可以延迟或提前开关动作某些时 间。 开关点仅可以在有关程序段保持有效时被延迟 或提前。 单位是毫秒。</td></tr><tr><td>Instruction</td><td></td><td>指令可以是 一个子程序调用 变量值的分配 一个输出指令（也可以是脉冲）。</td></tr><tr><td>Priority</td><td>INT</td><td>使用子程序调用的每个TRIGGER语句必须定义一个 优先级。允许值为1…39和81…128。 优先级的使用与中断中的一样。（见章8）。 值40…80为机器人自动优先级分配保留。如果要 使用，编程PRIO=－1。</td></tr></tbody></table></section></section><section><h2>9.2在轨迹的任何点开关动作<a href="#92在轨迹的任何点开关动作"><span>#</span></a></h2><section><h3>TRIGGER<a href="#trigger-1"><span>#</span></a></h3><p>如果您正在使用轨迹相关的TRIGGER语句，则可以通过指定一个距离在沿轨迹的任何 位置触发开关动作，与在起点和终点的开关动作一样，也可以被延迟或提前。</p><p>轨迹相关的开关动作仅允许在连续轨迹运动（PTP，LIN或CIRC）中使用。这儿的触发 语句指的是下一个编程运动，语法如下：</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201758383.png" alt="image-20240606201758383" /><figcaption>image-20240606201758383</figcaption></figure><p></p>

<table><thead><tr><th>自变量</th><th>数据类型</th><th>含义</th></tr></thead><tbody><tr><td>Distance</td><td>INT</td><td>触发后， 您可以在从编程的终点起指定一个期望的 距离。 如果该终点是一个被逼近的点， 指定开关动作的期 望距离从逼近定位范围中紧靠终点位置算起。 通过指定一个负的距离， 开关点可以最远被移回到 起点。如果该起点是一个逼近定位点，开关点可以 最远被移到逼近定位范围的起点。 通过指定一个正的距离， 则最远移到编程的下一个 精确定位点 单位是毫米。</td></tr><tr><td>Time</td><td>INT</td><td>使用属性DELAY，可以延迟(+)或提前(-)轨迹中开 关点某些时间。 开关点仅可以在上述给定（最远到下一个精确定位 点）开关范围内被延迟或提前。逼近定位运动中。 开关点至多可以被提前到开始逼近定位的起点。 单位是毫秒。</td></tr><tr><td>Instruction</td><td></td><td>指令可以是 一个子程序调用 变量值的分配 一个输出指令（也可以是脉冲）。</td></tr><tr><td>Priority</td><td>INT</td><td>使用子程序调用的每个TRIGGER语句必须定义一个 优先级。允许值为1…39和81…128。 优先级的使用与中断中的一样。（见章8）。 值40…80为机器人自动优先级分配保留。如果要 使用，编程PRIO=－1。</td></tr></tbody></table></section></section><section><h2>9.3触发语句重叠<a href="#93触发语句重叠"><span>#</span></a></h2><ul>
<li>手动给两个触发语句分配各自的优先级；</li>
<li>分配两个触发语句的优先级都为“—1”，然后由系统自动分配正确的优先级。</li>
</ul></section></section>
<section><h1>10 数据表<a href="#10-数据表"><span>#</span></a></h1><section><h2>10.1局部数据表<a href="#101局部数据表"><span>#</span></a></h2><p>数据表用于特殊编程准备和更高级别声明。包含点的消息，例如坐标：
●一个数据表可能为每个SRC文件草拟。数据表与SRC文件具有相同的文件名并以“.DAT”作为扩展名。
●数据表仅可能由声明和初始化组成。
● 一行由声明和初始化组成。
●不接受系统变量。</p><section><h3>DEFDAT<a href="#defdat"><span>#</span></a></h3><p>数据表的声明类似于SRC文件的声明：声明以关键字DEFDAT和文件名开始，以关 键字ENDDAT结束。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201811945.png" alt="image-20240606201811945" /><figcaption>image-20240606201811945</figcaption></figure><p></p><p>在数据表中允许使用下列声明：
● SRC文件中使用子程序和函数的外部声明。
● 导入变量的导入声明。
● SRC文件中使用变量的声明和初始化。
● SRC文件中使用信号和通道名的声明。
● 数据表或SRC文件中使用数据的声明和列举类型（ Struc，Enum）。</p></section></section><section><h2>10.2全局数据表<a href="#102全局数据表"><span>#</span></a></h2><p>数据表中定义的变量可被“别的”主程序接受  。</p><section><h3>PUBLIC<a href="#public"><span>#</span></a></h3><p>数据表必须在开头行以关键字PUBLIC定义为“公共可接受”。</p><p>如果要使用变量OTTO，从以上数据表PROG_1中导入到PROG_2（），可以在PROG_2（）中编程下列导入声明，与数据表中的关键字PUBLIC一样：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>IMPORT INT OTTO_2 IS /R1/PROG_1..OTTO</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>目录/R1下的数据表PROG_1.DAT中的变量OTTO现在是程序PROG_2（）中的OTTO_2</p></section><section><h3>GLOBAL<a href="#global"><span>#</span></a></h3><p>变量被声明为“全局变量”，例如<code>DECL GLOBAL INTOTTO=0</code>，可不使用导入命令而被所有别的主程序接受。
如果一个全局变量已经被声明，就不能在别的主程序中改变该全局变量名。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606201919436.png" alt="image-20240606201919436" /><figcaption>image-20240606201919436</figcaption></figure><p></p><blockquote><p>仅允许在数据表中声明全局变量。 如果要在SRC或SUB文件中声明， 则会产生错误消息。</p><p>对许多程序有用的长时间有效的、一般意义的变量、结构、通道和信号可以提前定义在$CONFIG.DAT中</p></blockquote></section></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/743/</id>
      <title type="text">谱聚类算法</title>
      <published>2022-03-06T07:37:44.000Z</published>
      <updated>2024-06-06T15:54:24.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/743/"/>
      <summary type="text">-- title: &quot;谱聚类算法&quot; date: 2023-04-23 categories: 学习记录,机器学习 tags: 机器学习 聚类算法 -- 谱聚类算法：谱指的是某个矩阵的特征值。 谱聚类的思想来源于图论，它把待聚类的数据集中的每</summary>
      <content type="html"><![CDATA[<hr />
<p>title: “谱聚类算法”
date: 2023-04-23
categories:</p>
<ul>
<li>[学习记录,机器学习]
tags:</li>
<li>机器学习</li>
<li>聚类算法</li>
</ul>
<hr />
<p><strong>谱聚类算法</strong>：谱指的是某个矩阵的<strong>特征值</strong>。</p>
<p>谱聚类的思想来源于图论，它把待聚类的数据集中的每一个样本看做是图中一个<strong>顶点</strong>，这些顶点连接在一起，连接的这些<strong>边上有权重</strong>，<strong>权重的大小</strong>表示这些样本之间的<strong>相似程度</strong>。<strong>同一类</strong>的顶点它们的<strong>相似程度很高</strong>，在图论中体现为同一类的顶点中连接它们的边的<strong>权重很大</strong>；<strong>不在同一类</strong>的顶点连接它们的边的<strong>权重很小</strong>。于是谱聚类的<strong>最终目标</strong>就是找到一种<strong>切割图的方法</strong>，使得切割之后的各个子<strong>图内的权重很大</strong>，<strong>子图之间的权重很小</strong>。</p>
<p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/202203111026750.jpg" alt="img" /><figcaption>img</figcaption></figure><p></p>
<section><h1>一、预备知识<a href="#一预备知识"><span>#</span></a></h1><ul>
<li>
<p>假设给定一个数据集<span><span>X={x1,x2,...,xn}X=\{ x_1,x_2,...,x_n \}</span><span><span><span></span><span>X</span><span></span><span>=</span><span></span></span><span><span></span><span>{</span><span><span>x</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>x</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>...</span><span>,</span><span></span><span><span>x</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>}</span></span></span></span>，我们将这个n个数据向量当做m维空间中某一幅无向图上的一个个点，目的是衡量这些点的相似性。</p>
</li>
<li>
<p>把图叫做相似图，记为<span><span>G=(V,E)G=(V,E)</span><span><span><span></span><span>G</span><span></span><span>=</span><span></span></span><span><span></span><span>(</span><span>V</span><span>,</span><span></span><span>E</span><span>)</span></span></span></span>，其中<span><span>V={v1,v2...,vn}V=\{ v_1,v_2...,v_n \}</span><span><span><span></span><span>V</span><span></span><span>=</span><span></span></span><span><span></span><span>{</span><span><span>v</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>v</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>...</span><span>,</span><span></span><span><span>v</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>}</span></span></span></span>表示顶点，<span><span>EE</span><span><span><span></span><span>E</span></span></span></span>表示边的集合。两个顶点<span><span>vi,vjv_i,v_j</span><span><span><span></span><span><span>v</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>v</span><span><span><span><span><span><span></span><span><span>j</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>的边的权重记为<span><span>ωij\omega_{ij}</span><span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span><span>ij</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></p>
</li>
<li>
<p>相似性用<span><span>sijs_{ij}</span><span><span><span></span><span><span>s</span><span><span><span><span><span><span></span><span><span><span>ij</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>表示，越大表示越相似</p>
</li>
<li>
<p>n个权重点构成一个矩阵<span><span>W=(ωij)W=(\omega_{ij})</span><span><span><span></span><span>W</span><span></span><span>=</span><span></span></span><span><span></span><span>(</span><span><span>ω</span><span><span><span><span><span><span></span><span><span><span>ij</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>)</span></span></span></span></p>
</li>
</ul><section><h2>1.1<strong>邻接矩阵、度和度矩阵、连通子图</strong><a href="#11邻接矩阵度和度矩阵连通子图"><span>#</span></a></h2><section><h3>（1）邻接矩阵<a href="#1邻接矩阵"><span>#</span></a></h3><p>所有顶点之间的权重构成一个矩阵，叫<strong>邻接矩阵</strong>，也叫<strong>权重矩阵</strong>。两个顶点互相之间的权重是一样的，因此<span><span>WW</span><span><span><span></span><span>W</span></span></span></span>是对称矩阵。</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220311114622575.png" alt="image-20220311114622575" /><figcaption>image-20220311114622575</figcaption></figure><p></p></section><section><h3>（2）度矩阵<a href="#2度矩阵"><span>#</span></a></h3><p>对于某个顶点的<strong>度</strong><span><span>di,i=1,2,...,nd_i,i=1,2,...,n</span><span><span><span></span><span><span>d</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>i</span><span></span><span>=</span><span></span></span><span><span></span><span>1</span><span>,</span><span></span><span>2</span><span>,</span><span></span><span>...</span><span>,</span><span></span><span>n</span></span></span></span>，定义为</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220311115316683.png" alt="image-20220311115316683" /><figcaption>image-20220311115316683</figcaption></figure><p></p><p>度其实就是邻接矩阵的第<span><span>ii</span><span><span><span></span><span>i</span></span></span></span>行的和。（因为邻接矩阵是对称矩阵，所以第<span><span>jj</span><span><span><span></span><span>j</span></span></span></span>列的和也可以）</p><p><strong>度矩阵</strong>定义为<span><span>nn</span><span><span><span></span><span>n</span></span></span></span>个度构成的<strong>对角矩阵</strong>：</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220311115709665.png" alt="image-20220311115709665" /><figcaption>image-20220311115709665</figcaption></figure><p></p><p>对于给定顶点<span><span>VV</span><span><span><span></span><span>V</span></span></span></span>的一个子集<span><span>A⊂VA\subset V</span><span><span><span></span><span>A</span><span></span><span>⊂</span><span></span></span><span><span></span><span>V</span></span></span></span>，定义它的补为<span><span>Aˉ\bar{A}</span><span><span><span></span><span><span><span><span><span><span></span><span>A</span></span><span><span></span><span><span>ˉ</span></span></span></span></span></span></span></span></span></span>。对于某个顶点<span><span>vi∈Av_i \in A</span><span><span><span></span><span><span>v</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>∈</span><span></span></span><span><span></span><span>A</span></span></span></span>，定义对应的指示向量为<span><span>1A=[f1,f2...,fn]T∈Rn1_A = [f_1,f_2...,f_n]^T \in R^n</span><span><span><span></span><span><span>1</span><span><span><span><span><span><span></span><span><span>A</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>[</span><span><span>f</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>f</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>...</span><span>,</span><span></span><span><span>f</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span>]</span><span><span><span><span><span><span></span><span><span>T</span></span></span></span></span></span></span></span><span></span><span>∈</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span></span></span></span></span></span></span></span>，若<span><span>vi∈Av_i \in A</span><span><span><span></span><span><span>v</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>∈</span><span></span></span><span><span></span><span>A</span></span></span></span>，则<strong>指示向量</strong>第i个位置为1，即<span><span>fi=1f_i = 1</span><span><span><span></span><span><span>f</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>1</span></span></span></span>，否则为0；对于两个子集A和B，我们定义：</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220311132125530.png" alt="image-20220311132125530" /><figcaption>image-20220311132125530</figcaption></figure><p></p><p>公式(4)表示两个子集中顶点之间的权重之和，<strong>注意这里不包含子集内顶点之间的权重</strong>。</p><p><strong>子集大小</strong>有两种定义</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220311132240644.png" alt="image-20220311132240644" /><figcaption>image-20220311132240644</figcaption></figure><p></p></section><section><h3>（3）连通子图<a href="#3连通子图"><span>#</span></a></h3><p>如果<span><span>AA</span><span><span><span></span><span>A</span></span></span></span>中的任意两个顶点都至少存在一条路径将他们连接起来，并且<span><span>AA</span><span><span><span></span><span>A</span></span></span></span>中其他顶点也在这条路径上，则<span><span>AA</span><span><span><span></span><span>A</span></span></span></span>是<strong>连接</strong>的。如果子集<span><span>AA</span><span><span><span></span><span>A</span></span></span></span>是连接的，并且与他的补<span><span>Aˉ\bar{A}</span><span><span><span></span><span><span><span><span><span><span></span><span>A</span></span><span><span></span><span><span>ˉ</span></span></span></span></span></span></span></span></span></span>不存在任何的连接，则称为<strong>连通子图</strong>。非空子集<span><span>A1,A2,...,AkA_1,A_2,...,A_k</span><span><span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>...</span><span>,</span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>k</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>构成<span><span>VV</span><span><span><span></span><span>V</span></span></span></span>的一个<strong>分割</strong>，即<span><span>A1∪A2∪...∪Ak=VA_1\cup A_2 \cup... \cup A_k=V</span><span><span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>∪</span><span></span></span><span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>∪</span><span></span></span><span><span></span><span>...</span><span></span><span>∪</span><span></span></span><span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>k</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>V</span></span></span></span></p></section></section><section><h2>1.2 相似图的衡量方法<a href="#12-相似图的衡量方法"><span>#</span></a></h2><p>如果度量空间具有距离越远越不相似，越近越相似的特性，通常作为<strong>相似度</strong>的衡量标准。</p><section><h3>（1）<span><span>ϵ−近邻法\epsilon - \text{近邻法}</span><span><span><span></span><span>ϵ</span><span></span><span>−</span><span></span></span><span><span></span><span><span>近邻法</span></span></span></span></span><a href="#1ϵ近邻法epsilon---text近邻法ϵ近邻法"><span>#</span></a></h3><p>采用欧式距离计算两个顶点的距离<span><span>sijs_{ij}</span><span><span><span></span><span><span>s</span><span><span><span><span><span><span></span><span><span><span>ij</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>，然后设定一个阈值<span><span>ϵ\epsilon</span><span><span><span></span><span>ϵ</span></span></span></span></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312185718753.png" alt="image-20220312185718753" /><figcaption>image-20220312185718753</figcaption></figure><p></p></section><section><h3>（2）k-邻近法<a href="#2k-邻近法"><span>#</span></a></h3><p>利用<strong>KNN算法</strong>遍历所有的样本点，取每个样本最近的k个点作为近邻，取与顶点最近的<span><span>kk</span><span><span><span></span><span>k</span></span></span></span>个顶点，该顶点与<span><span>kk</span><span><span><span></span><span>k</span></span></span></span>个顶点的权重都大于0。但是这种方法不能保证相似矩阵是对称的，因为两个顶点可能不是在互相的近邻中。一般使用两种方法保证相似矩阵的对称。</p><ul>
<li>两个顶点只要其中一个点在另一个顶点的近邻中，则令<span><span>ωij=ωji\omega_{ij}=\omega_{ji}</span><span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span><span>ij</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span><span>j</span><span>i</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></li>
</ul><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312190301385.png" alt="image-20220312190301385" /><figcaption>image-20220312190301385</figcaption></figure><p></p><ul>
<li>两个顶点同时在双方的近邻中，则令<span><span>ωij=ωji\omega_{ij}=\omega_{ji}</span><span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span><span>ij</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span><span>j</span><span>i</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>​，否则<span><span>ωij=ωji=0\omega_{ij}=\omega_{ji}=0</span><span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span><span>ij</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span><span>j</span><span>i</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>0</span></span></span></span></li>
</ul><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312190424470.png" alt="image-20220312190424470" /><figcaption>image-20220312190424470</figcaption></figure><p></p></section><section><h3>（3）全连接法<a href="#3全连接法"><span>#</span></a></h3><p>该方法将所有的顶点都连接起来。然后通过度量空间中某种对称度量算子来计算顶点之间的相似度。常用的有<strong>多项式核函数，高斯核函数和Sigmoid核函数</strong>。最常用的是高斯核函数RBF，此时相似矩阵和邻接矩阵相同，比如使用<strong>高斯核函数</strong>计算两个顶点之间的相似度：</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312190629703.png" alt="image-20220312190629703" /><figcaption>image-20220312190629703</figcaption></figure><p></p><p>实际应用中，使用<strong>全连接法</strong>是最普遍的，而在全连接法中使用<strong>高斯径向核RBF</strong>是最普遍的。</p></section></section><section><h2>1.3 图拉普拉斯矩阵<a href="#13-图拉普拉斯矩阵"><span>#</span></a></h2><section><h3>1.3.1 非规范化的图拉普拉斯矩阵<a href="#131-非规范化的图拉普拉斯矩阵"><span>#</span></a></h3><p>图拉普拉斯矩阵的定义如下：</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312200714522.png" alt="image-20220312200714522" /><figcaption>image-20220312200714522</figcaption></figure><p></p><p>其中<span><span>DD</span><span><span><span></span><span>D</span></span></span></span>为度矩阵，W为权重（近似）矩阵，所以L也是对称矩阵</p><p><strong>性质：</strong></p><ul>
<li>对于任意向量<span><span>f∈Rnf \in R^n</span><span><span><span></span><span>f</span><span></span><span>∈</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span></span></span></span></span></span></span></span></li>
</ul><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312201051146.png" alt="image-20220312201051146" /><figcaption>image-20220312201051146</figcaption></figure><p></p><ul>
<li>
<p><span><span>LL</span><span><span><span></span><span>L</span></span></span></span>是一个<strong>对称半正定矩阵</strong>。</p>
<p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312201216584.png" alt="image-20220312201216584" /><figcaption>image-20220312201216584</figcaption></figure><p></p>
</li>
<li>
<p><span><span>LL</span><span><span><span></span><span>L</span></span></span></span>的最小特征值为0，对应的特征向量是全为1的向量<span><span>11</span><span><span><span></span><span>1</span></span></span></span>。<span><span>0≤λ1≤λ2...≤λn0 \le \lambda_1 \le \lambda_2 ...\le \lambda_n</span><span><span><span></span><span>0</span><span></span><span>≤</span><span></span></span><span><span></span><span><span>λ</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>≤</span><span></span></span><span><span></span><span><span>λ</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>...</span><span></span><span>≤</span><span></span></span><span><span></span><span><span>λ</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></p>
</li>
<li>
<p>对于一个对角分块矩阵<span><span>AA</span><span><span><span></span><span>A</span></span></span></span></p>
<p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312201648665.png" alt="image-20220312201648665" /><figcaption>image-20220312201648665</figcaption></figure><p></p>
<p>他的特征值等于各个分块矩阵的特征值。</p>
</li>
<li>
<p>若<span><span>GG</span><span><span><span></span><span>G</span></span></span></span>是一个具有非负权重的无向图，则它对应的图拉普拉斯矩阵L的0<strong>特征值的代数重数</strong>k等于G中<strong>连通子图的个数</strong>，假设k个连通子图记为<span><span>A1,A2,...AkA_1,A_2,...A_k</span><span><span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>...</span><span><span>A</span><span><span><span><span><span><span></span><span><span>k</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>，并且0特征值对应的特征值空间由各个连通子图的指示向量<span><span>1Ai∈Rn1_{A_i} \in R_n</span><span><span><span></span><span><span>1</span><span><span><span><span><span><span></span><span><span><span><span>A</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>∈</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>。</p>
</li>
</ul></section><section><h3>1.3.2规范化的图拉普拉斯矩阵<a href="#132规范化的图拉普拉斯矩阵"><span>#</span></a></h3><p>有两种规范化的图拉普拉斯矩阵，他们互相联系。这两种规划化的图拉普拉斯矩阵定义为：</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312205724786.png" alt="image-20220312205724786" /><figcaption>image-20220312205724786</figcaption></figure><p></p><p>公式(19)中的<span><span>LsymL_{sym}</span><span><span><span></span><span><span>L</span><span><span><span><span><span><span></span><span><span><span>sy</span><span>m</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>是一个对称矩阵，下标sym是单词symmetric的简写，<span><span>LrwL_{rw}</span><span><span><span></span><span><span>L</span><span><span><span><span><span><span></span><span><span><span>r</span><span>w</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>不是对称矩阵，该矩阵和随机游走(random walk)相关，下标rw就是random walk 的首字母组合。</p><p><span><span>LsymL_{sym}</span><span><span><span></span><span><span>L</span><span><span><span><span><span><span></span><span><span><span>sy</span><span>m</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>的性质:</p><ul>
<li>对于任意向量<span><span>f∈Rnf \in R^n</span><span><span><span></span><span>f</span><span></span><span>∈</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span></span></span></span></span></span></span></span></li>
</ul><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312205922264.png" alt="image-20220312205922264" /><figcaption>image-20220312205922264</figcaption></figure><p></p><ul>
<li><span><span>LsymL_{sym}</span><span><span><span></span><span><span>L</span><span><span><span><span><span><span></span><span><span><span>sy</span><span>m</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>和<span><span>LrwL_{rw}</span><span><span><span></span><span><span>L</span><span><span><span><span><span><span></span><span><span><span>r</span><span>w</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>具有相同的特征值，对应的特征值向量关系为</li>
</ul><span><span><span>ω=D1/2u\omega = D^{1/2} u</span><span><span><span></span><span>ω</span><span></span><span>=</span><span></span></span><span><span></span><span><span>D</span><span><span><span><span><span><span></span><span><span><span>1/2</span></span></span></span></span></span></span></span></span><span>u</span></span></span></span></span><ul>
<li></li>
</ul></section></section></section>
<section><h1>二、切割方法<a href="#二切割方法"><span>#</span></a></h1><p>优化的目标函数为：</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312210846810.png" alt="image-20220312210846810" /><figcaption>image-20220312210846810</figcaption></figure><p></p><section><h2>2.1 RatioCut切图<a href="#21-ratiocut切图"><span>#</span></a></h2><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312211959073.png" alt="image-20220312211959073" /><figcaption>image-20220312211959073</figcaption></figure><p></p><p>引入指示向量<span><span>hj∈h1,h2,..hk,j=1,2,...k,h_j\in {h_1,h_2,..h_k},j=1,2,...k,</span><span><span><span></span><span><span>h</span><span><span><span><span><span><span></span><span><span>j</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>∈</span><span></span></span><span><span></span><span><span><span>h</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>h</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>..</span><span><span>h</span><span><span><span><span><span><span></span><span><span>k</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span><span>,</span><span></span><span>j</span><span></span><span>=</span><span></span></span><span><span></span><span>1</span><span>,</span><span></span><span>2</span><span>,</span><span></span><span>...</span><span>k</span><span>,</span></span></span></span>对于任意一个向量<span><span>hjh_j</span><span><span><span></span><span><span>h</span><span><span><span><span><span><span></span><span><span>j</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>, 它是一个n维向量（n为样本数），我们定义</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312212210088.png" alt="image-20220312212210088" /><figcaption>image-20220312212210088</figcaption></figure><p></p><p>对应的<strong>RatioCut函数表达式</strong>为：</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312212238622.png" alt="image-20220312212238622" /><figcaption>image-20220312212238622</figcaption></figure><p></p><p>松弛化的目标函数：</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312213754655.png" alt="image-20220312213754655" /><figcaption>image-20220312213754655</figcaption></figure><p></p><p>将图切割为k个分组的问题转换成了求图拉普拉斯矩阵L的**前k个最小特征值对应的特征向量<span><span>hj∈h1,h2,..hk,j=1,2,...k,h_j\in {h_1,h_2,..h_k},j=1,2,...k,</span><span><span><span></span><span><span>h</span><span><span><span><span><span><span></span><span><span>j</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>∈</span><span></span></span><span><span></span><span><span><span>h</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>h</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>..</span><span><span>h</span><span><span><span><span><span><span></span><span><span>k</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span><span>,</span><span></span><span>j</span><span></span><span>=</span><span></span></span><span><span></span><span>1</span><span>,</span><span></span><span>2</span><span>,</span><span></span><span>...</span><span>k</span><span>,</span></span></span></span>**和L二次型之和。</p><p>求出来的<span><span>hih_i</span><span><span><span></span><span><span>h</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>并不能准确指示顶点所属类别，将矩阵<span><span>H=[h1,h2,..hk]H= [h_1,h_2,..h_k]</span><span><span><span></span><span>H</span><span></span><span>=</span><span></span></span><span><span></span><span>[</span><span><span>h</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>h</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>..</span><span><span>h</span><span><span><span><span><span><span></span><span><span>k</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>]</span></span></span></span>当作一个新的具有k个维度特征n个样本的数据集进行<span><span>k−meansk-means</span><span><span><span></span><span>k</span><span></span><span>−</span><span></span></span><span><span></span><span>m</span><span>e</span><span>an</span><span>s</span></span></span></span>聚类。是对每一个样本聚类，聚类的类别数是k,也就是对H的每一行进行聚类。</p></section><section><h2>2.2 Ncut切图<a href="#22-ncut切图"><span>#</span></a></h2><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312213256066.png" alt="image-20220312213256066" /><figcaption>image-20220312213256066</figcaption></figure><p></p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312213419592.png" alt="image-20220312213419592" /><figcaption>image-20220312213419592</figcaption></figure><p></p><p>优化目标任然是</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312213433072.png" alt="image-20220312213433072" /><figcaption>image-20220312213433072</figcaption></figure><p></p><p>松弛化的目标函数：</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312213820132.png" alt="image-20220312213820132" /><figcaption>image-20220312213820132</figcaption></figure><p></p><p>令<span><span>B=D1/2HB= D^{1/2}H</span><span><span><span></span><span>B</span><span></span><span>=</span><span></span></span><span><span></span><span><span>D</span><span><span><span><span><span><span></span><span><span><span>1/2</span></span></span></span></span></span></span></span></span><span>H</span></span></span></span>:</p><p></p><figure><img src="https://imgbed-1258546214.cos.ap-shanghai.myqcloud.com/img/image-20220312213915761.png" alt="image-20220312213915761" /><figcaption>image-20220312213915761</figcaption></figure><p></p><p>上式的解<span><span>B∗B^*</span><span><span><span></span><span><span>B</span><span><span><span><span><span><span></span><span><span>∗</span></span></span></span></span></span></span></span></span></span></span>也就是矩阵<span><span>LsymL_{sym}</span><span><span><span></span><span><span>L</span><span><span><span><span><span><span></span><span><span><span>sy</span><span>m</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>的前k个最小特征值对应的特征向量按列排列成<span><span>B∗={b1,b2,...,bk}B^* = \{ b_1,b_2,...,b_k \}</span><span><span><span></span><span><span>B</span><span><span><span><span><span><span></span><span><span>∗</span></span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>{</span><span><span>b</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>b</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>...</span><span>,</span><span></span><span><span>b</span><span><span><span><span><span><span></span><span><span>k</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>}</span></span></span></span>。反带入可得<span><span>LrwL_{rw}</span><span><span><span></span><span><span>L</span><span><span><span><span><span><span></span><span><span><span>r</span><span>w</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>前k个最小特征值对应的特征向量<span><span>H={h1,h2,..hk}H=\{h_1,h_2,..h_k\}</span><span><span><span></span><span>H</span><span></span><span>=</span><span></span></span><span><span></span><span>{</span><span><span>h</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>h</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>..</span><span><span>h</span><span><span><span><span><span><span></span><span><span>k</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>}</span></span></span></span></p><p>或者矩阵<span><span>LL</span><span><span><span></span><span>L</span></span></span></span>的前<span><span>kk</span><span><span><span></span><span>k</span></span></span></span>个最小的广义特征值对应的特征向量。</p></section></section>
<section><h1>三、算法实现步骤<a href="#三算法实现步骤"><span>#</span></a></h1><p>最常用的相似矩阵的生成方式是基于<strong>高斯核距离</strong>的全连接方式，最常用的<strong>切图方式是Ncut</strong>。而到最后常用的<strong>聚类方法为K-Means</strong>。</p><p>假设聚成<span><span>kk</span><span><span><span></span><span>k</span></span></span></span>个分组</p><p>（1）计算相似度矩阵<span><span>WW</span><span><span><span></span><span>W</span></span></span></span></p><p>（2）计算度矩阵<span><span>DD</span><span><span><span></span><span>D</span></span></span></span></p><p>（3）计算图拉普拉斯矩阵<span><span>LL</span><span><span><span></span><span>L</span></span></span></span>，构建标准化后的图拉普拉斯矩阵<span><span>D−1/2LD−1/2D^{-1/2}LD^{-1/2}</span><span><span><span></span><span><span>D</span><span><span><span><span><span><span></span><span><span><span>−</span><span>1/2</span></span></span></span></span></span></span></span></span><span>L</span><span><span>D</span><span><span><span><span><span><span></span><span><span><span>−</span><span>1/2</span></span></span></span></span></span></span></span></span></span></span></span></p><p>（4）直接对<span><span>D−1/2LD−1/2D^{-1/2}LD^{-1/2}</span><span><span><span></span><span><span>D</span><span><span><span><span><span><span></span><span><span><span>−</span><span>1/2</span></span></span></span></span></span></span></span></span><span>L</span><span><span>D</span><span><span><span><span><span><span></span><span><span><span>−</span><span>1/2</span></span></span></span></span></span></span></span></span></span></span></span>进行特征值分解，获取其前<span><span>kk</span><span><span><span></span><span>k</span></span></span></span>个特征值对应的特征向量按照列排成矩阵<span><span>Q=[q1,q2,...,qk]Q=[q_1,q_2,...,q_k]</span><span><span><span></span><span>Q</span><span></span><span>=</span><span></span></span><span><span></span><span>[</span><span><span>q</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>q</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>...</span><span>,</span><span></span><span><span>q</span><span><span><span><span><span><span></span><span><span>k</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>]</span></span></span></span></p><p>（5）对矩阵<span><span>QQ</span><span><span><span></span><span>Q</span></span></span></span>的 所有行<span><span>r1,r2,...rnr_1,r_2,...r_n</span><span><span><span></span><span><span>r</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>r</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>...</span><span><span>r</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>标准化，组成<span><span>n∗kn*k</span><span><span><span></span><span>n</span><span></span><span>∗</span><span></span></span><span><span></span><span>k</span></span></span></span>进行聚类，如使用<span><span>k−meansk-means</span><span><span><span></span><span>k</span><span></span><span>−</span><span></span></span><span><span></span><span>m</span><span>e</span><span>an</span><span>s</span></span></span></span>方法或者别的方法进行聚类得到<span><span>C1,C2,...,CkC_1,C_2,...,C_k</span><span><span><span></span><span><span>C</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>C</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>...</span><span>,</span><span></span><span><span>C</span><span><span><span><span><span><span></span><span><span>k</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></p><p>（6）输出原始数据的分组<span><span>A1,A2,...,AkA_1,A_2,...,A_k</span><span><span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span>...</span><span>,</span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>k</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>，其中<span><span>Ai={vj∣rj∈Ci}A_i=\{v_j|r_j \in C_i \}</span><span><span><span></span><span><span>A</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>{</span><span><span>v</span><span><span><span><span><span><span></span><span><span>j</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>∣</span><span><span>r</span><span><span><span><span><span><span></span><span><span>j</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>∈</span><span></span></span><span><span></span><span><span>C</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>}</span></span></span></span></p><p>注意：在第(4)步也可以再计算规范化的矩阵<span><span>LsymL_{sym}</span><span><span><span></span><span><span>L</span><span><span><span><span><span><span></span><span><span><span>sy</span><span>m</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>，在对这个矩阵做特征分解或者做广义特征值分解，后面步骤相同。</p></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/761/</id>
      <title type="text">机器人运动学笔记</title>
      <published>2022-01-26T15:48:42.000Z</published>
      <updated>2024-06-06T15:57:27.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/761/"/>
      <summary type="text">一、机器人学 1.POE （1）绪论 （2）形位空间 （3）刚体运动 3.1旋转与角速度 1.旋转矩阵 R=Rot hat omega , theta 满足以下条件 正则条件 正交条件 坐标系三个坐标轴遵循右手定则 33旋转矩阵组成的集合被</summary>
      <content type="html"><![CDATA[<section><h1>一、机器人学<a href="#一机器人学"><span>#</span></a></h1><section><h2>1.POE<a href="#1poe"><span>#</span></a></h2><section><h3>（1）绪论<a href="#1绪论"><span>#</span></a></h3></section><section><h3>（2）形位空间<a href="#2形位空间"><span>#</span></a></h3></section><section><h3>（3）刚体运动<a href="#3刚体运动"><span>#</span></a></h3><section><h4>3.1旋转与角速度<a href="#31旋转与角速度"><span>#</span></a></h4><section><h5>1.旋转矩阵<a href="#1旋转矩阵"><span>#</span></a></h5><span><span><span>R=Rot(ω^,θ)R=Rot(\hat{\omega},\theta)</span><span><span><span></span><span>R</span><span></span><span>=</span><span></span></span><span><span></span><span>R</span><span>o</span><span>t</span><span>(</span><span><span><span><span><span><span></span><span>ω</span></span><span><span></span><span><span>^</span></span></span></span></span></span></span><span>,</span><span></span><span>θ</span><span>)</span></span></span></span></span><p>满足以下条件</p><ul>
<li>正则条件</li>
<li>正交条件</li>
<li>坐标系三个坐标轴遵循右手定则</li>
</ul><p>3*3旋转矩阵组成的集合被称为<strong>特殊正交群SO(3)</strong></p><p><strong>特性</strong></p><ul>
<li>封闭性</li>
<li>结合律</li>
<li>幺元性</li>
<li>可逆性</li>
</ul><p><strong>用途</strong></p><ol>
<li>表示姿态</li>
<li>进行坐标系转换</li>
<li>对向量和坐标系进行旋转变换</li>
</ol><p><strong>左乘</strong>旋转矩阵会得到绕固定坐标系中的转轴转动，<strong>右乘</strong>会得到绕<strong>物体坐标系</strong>中转轴的转动。</p></section><section><h5>2.角速度<a href="#2角速度"><span>#</span></a></h5><span><span><span>ω=ω^θ˙\omega=\hat{\omega}\dot{\theta}</span><span><span><span></span><span>ω</span><span></span><span>=</span><span></span></span><span><span></span><span><span><span><span><span><span></span><span>ω</span></span><span><span></span><span><span>^</span></span></span></span></span></span></span><span><span><span><span><span><span></span><span>θ</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span></span></span></span></span><p><strong>反对称矩阵</strong></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606212625821.png" alt="image-20240606212625821" /><figcaption>image-20240606212625821</figcaption></figure><p></p><p>在<strong>空间坐标系中的角速度</strong></p><span><span><span>[ωs]=R˙R−1[\omega_s]=\dot{R}R^{-1}</span><span><span><span></span><span>[</span><span><span>ω</span><span><span><span><span><span><span></span><span><span>s</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>]</span><span></span><span>=</span><span></span></span><span><span></span><span><span><span><span><span><span></span><span>R</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span><span><span>R</span><span><span><span><span><span><span></span><span><span><span>−</span><span>1</span></span></span></span></span></span></span></span></span></span></span></span></span><p><strong>物体坐标系下的角速度</strong></p><span><span><span>[ωb]=R−1R˙[\omega_b]=R^{-1}\dot{R}</span><span><span><span></span><span>[</span><span><span>ω</span><span><span><span><span><span><span></span><span><span>b</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>]</span><span></span><span>=</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span><span>−</span><span>1</span></span></span></span></span></span></span></span></span><span><span><span><span><span><span></span><span>R</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span></span></span></span></span><p><span><span>ω∈R3\omega \in R^3</span><span><span><span></span><span>ω</span><span></span><span>∈</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>3</span></span></span></span></span></span></span></span></span></span></span>是角速度的向量表达形式，<span><span>[ω]∈so(3)[\omega]\in so(3)</span><span><span><span></span><span>[</span><span>ω</span><span>]</span><span></span><span>∈</span><span></span></span><span><span></span><span>so</span><span>(</span><span>3</span><span>)</span></span></span></span>是3*3矩阵表示形式。</p></section><section><h5>3.转动的指数坐标表示<a href="#3转动的指数坐标表示"><span>#</span></a></h5><p><strong>转动的三参数指数坐标</strong></p><p>向量<span><span>ω˙θ∈R3\dot\omega \theta \in R^3</span><span><span><span></span><span><span><span><span><span><span></span><span>ω</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span><span>θ</span><span></span><span>∈</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>3</span></span></span></span></span></span></span></span></span></span></span>就是转动的三参数指数坐标形式，单独写就是<strong>转动的轴-角表示法</strong></p><p><strong>刚体转动的指数坐标</strong></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606213017880.png" alt="image-20240606213017880" /><figcaption>image-20240606213017880</figcaption></figure><p></p><p><strong>刚体转动的矩阵对数</strong></p><p>若<span><span>ω˙θ∈R3\dot\omega \theta \in R^3</span><span><span><span></span><span><span><span><span><span><span></span><span>ω</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span><span>θ</span><span></span><span>∈</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>3</span></span></span></span></span></span></span></span></span></span></span>表示旋转矩阵R的指数坐标，那么反对称矩阵<span><span>[ω^θ]=[ω^]θ∈so(3)[\hat{\omega }\theta]=[\hat{\omega }]\theta \in so(3)</span><span><span><span></span><span>[</span><span><span><span><span><span><span></span><span>ω</span></span><span><span></span><span><span>^</span></span></span></span></span></span></span><span>θ</span><span>]</span><span></span><span>=</span><span></span></span><span><span></span><span>[</span><span><span><span><span><span><span></span><span>ω</span></span><span><span></span><span><span>^</span></span></span></span></span></span></span><span>]</span><span>θ</span><span></span><span>∈</span><span></span></span><span><span></span><span>so</span><span>(</span><span>3</span><span>)</span></span></span></span>就是矩阵R的矩阵对数。矩阵对数是矩阵指数的可逆形式。正像矩阵指数是矩阵形式的角速度<span><span>[ω^]θ∈so(3)[\hat{\omega }]\theta \in so(3)</span><span><span><span></span><span>[</span><span><span><span><span><span><span></span><span>ω</span></span><span><span></span><span><span>^</span></span></span></span></span></span></span><span>]</span><span>θ</span><span></span><span>∈</span><span></span></span><span><span></span><span>so</span><span>(</span><span>3</span><span>)</span></span></span></span>在单位时间（ 1秒）内的定积分，使刚体运动到给定姿态<span><span>R∈SO(3)R\in SO(3)</span><span><span><span></span><span>R</span><span></span><span>∈</span><span></span></span><span><span></span><span>S</span><span>O</span><span>(</span><span>3</span><span>)</span></span></span></span>—样，矩阵对数则是对R进行微分，以找到一个常值角速度<span><span>[ω^]θ∈so(3)[\hat{\omega }]\theta \in so(3)</span><span><span><span></span><span>[</span><span><span><span><span><span><span></span><span>ω</span></span><span><span></span><span><span>^</span></span></span></span></span></span></span><span>]</span><span>θ</span><span></span><span>∈</span><span></span></span><span><span></span><span>so</span><span>(</span><span>3</span><span>)</span></span></span></span>的矩阵表示形式。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606213047531.png" alt="image-20240606213047531" /><figcaption>image-20240606213047531</figcaption></figure><p></p></section></section><section><h4>3.2刚体运动与运动旋量<a href="#32刚体运动与运动旋量"><span>#</span></a></h4><p><strong>齐次变换矩阵T</strong>与旋转矩阵R相对应，螺旋轴S与旋转轴<span><span>ω^\hat\omega</span><span><span><span></span><span><span><span><span><span><span></span><span>ω</span></span><span><span></span><span><span>^</span></span></span></span></span></span></span></span></span></span>相对应，运动旋量V(可表示成<span><span>Sθ˙S\dot\theta</span><span><span><span></span><span>S</span><span><span><span><span><span><span></span><span>θ</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span></span></span></span>）与角速度<span><span>[ω^θ]=[ω^]θ∈so(3)[\hat{\omega }\theta]=[\hat{\omega }]\theta \in so(3)</span><span><span><span></span><span>[</span><span><span><span><span><span><span></span><span>ω</span></span><span><span></span><span><span>^</span></span></span></span></span></span></span><span>θ</span><span>]</span><span></span><span>=</span><span></span></span><span><span></span><span>[</span><span><span><span><span><span><span></span><span>ω</span></span><span><span></span><span><span>^</span></span></span></span></span></span></span><span>]</span><span>θ</span><span></span><span>∈</span><span></span></span><span><span></span><span>so</span><span>(</span><span>3</span><span>)</span></span></span></span>相对应，而用于描述刚体位移的指数坐标<span><span>Sθ∈R6S\theta \in R^6</span><span><span><span></span><span>S</span><span>θ</span><span></span><span>∈</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>6</span></span></span></span></span></span></span></span></span></span></span>与刚体转动的指数坐标<span><span>ω^θ∈R3\hat \omega \theta \in R^3</span><span><span><span></span><span><span><span><span><span><span></span><span>ω</span></span><span><span></span><span><span>^</span></span></span></span></span></span></span><span>θ</span><span></span><span>∈</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>3</span></span></span></span></span></span></span></span></span></span></span>相对应。</p><p>**特殊欧氏群SE(3)**亦称刚体运动群或齐次变换矩阵群，是所有4×4实矩阵T的集合 。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606213148038.png" alt="image-20240606213148038" /><figcaption>image-20240606213148038</figcaption></figure><p></p><section><h5>运动旋量<a href="#运动旋量"><span>#</span></a></h5><p>将<span><span>ωb,vb\omega_b,v_b</span><span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span>b</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>v</span><span><span><span><span><span><span></span><span><span>b</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>合在一起组成一个六维向量形式。为此定义为物体坐标系中的速度，简称为物体运动旋量。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606213346042.png" alt="image-20240606213346042" /><figcaption>image-20240606213346042</figcaption></figure><p></p><p>如前所述，角速度可以很方便的写成反对称矩阵形式，同样，运动旋量也能写成矩阵形式。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606213406815.png" alt="image-20240606213406815" /><figcaption>image-20240606213406815</figcaption></figure><p></p><p>同样，基于空间坐标系，写出<strong>空间运动旋量</strong></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606213553143.png" alt="image-20240606213553143" /><figcaption>image-20240606213553143</figcaption></figure><p></p><p><strong>物体运动旋量和空间运动旋量的关系</strong></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606213633133.png" alt="image-20240606213633133" /><figcaption>image-20240606213633133</figcaption></figure><p></p></section><section><h5>运动旋量的螺旋释义<a href="#运动旋量的螺旋释义"><span>#</span></a></h5><p>运动旋量<span><span>VV</span><span><span><span></span><span>V</span></span></span></span>也可以写成螺旋轴<span><span>SS</span><span><span><span></span><span>S</span></span></span></span>与绕该轴转动的速度<span><span>θ˙\dot\theta</span><span><span><span></span><span><span><span><span><span><span></span><span>θ</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span></span></span></span>组合形式</p><p><span><span>S=(ω,v)S=(\omega,v)</span><span><span><span></span><span>S</span><span></span><span>=</span><span></span></span><span><span></span><span>(</span><span>ω</span><span>,</span><span></span><span>v</span><span>)</span></span></span></span>的矩阵表达式为</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606213844939.png" alt="image-20240606213844939" /><figcaption>image-20240606213844939</figcaption></figure><p></p></section></section><section><h4>3.3刚体运动的指数坐标表达<a href="#33刚体运动的指数坐标表达"><span>#</span></a></h4><p>Chasles_Mozzi定理&lt;任何刚体运动都可通过绕空间某&gt;—固定螺旋轴S的运动来实现 。</p><p>类似转动情况，定义矩阵指数和矩阵对数</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606213908052.png" alt="image-20240606213908052" /><figcaption>image-20240606213908052</figcaption></figure><p></p><p>将<strong>矩阵指数</strong>进行级数展开</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606214005244.png" alt="image-20240606214005244" /><figcaption>image-20240606214005244</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606214020157.png" alt="image-20240606214020157" /><figcaption>image-20240606214020157</figcaption></figure><p></p><p><strong>矩阵对数</strong></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606214110402.png" alt="image-20240606214110402" /><figcaption>image-20240606214110402</figcaption></figure><p></p></section><section><h4>3.4力旋量<a href="#34力旋量"><span>#</span></a></h4><p>将力矩与力合成为—个六维的空间力（spatial lOrce）,称为力旋量（wrench）。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606214143504.png" alt="image-20240606214143504" /><figcaption>image-20240606214143504</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606214301209.png" alt="image-20240606214301209" /><figcaption>image-20240606214301209</figcaption></figure><p></p><p>回顾力与速度的点积即为功率，而功率为坐标系无关量，因此有</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606214232471.png" alt="image-20240606214232471" /><figcaption>image-20240606214232471</figcaption></figure><p></p></section><section><h4>3.5函数<a href="#35函数"><span>#</span></a></h4><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>1.计算旋转矩阵的逆</span></div></div><div><div><div>2</div></div><div><span>invR = RotInv(R)</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span>2.将三维向量转换为3*3反对称矩阵</span></div></div><div><div><div>5</div></div><div><span>so3mat = VecToso3(omg)</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>3.将3*3反对称矩阵转换为三维向量</span></div></div><div><div><div>8</div></div><div><span>omg = so3ToVec(so3mat)</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span>4.从旋转的三维指数坐标中提取出轴线和角度</span></div></div><div><div><div>11</div></div><div><span>[omghat,theta] = AxisAng3(expc3)</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>5.计算矩阵指数对应的旋转矩阵</span></div></div><div><div><div>14</div></div><div><span>R = MatrixExp3(so3mat)</span></div></div><div><div><div>15</div></div><div>
</div></div><div><div><div>16</div></div><div><span>6.计算旋转矩阵对应的矩阵对数</span></div></div><div><div><div>17</div></div><div><span>so3mat = MatrixLog3(R)</span></div></div><div><div><div>18</div></div><div>
</div></div><div><div><div>19</div></div><div><span>7.M到SO（3）旋转矩阵的空间距离的度量</span></div></div><div><div><div>20</div></div><div><span>d = DistanceToSO3(mat)</span></div></div><div><div><div>21</div></div><div>
</div></div><div><div><div>22</div></div><div><span>8.判断M是否为旋转矩阵</span></div></div><div><div><div>23</div></div><div><span>judge = TestIfSO3(mat)</span></div></div><div><div><div>24</div></div><div>
</div></div><div><div><div>25</div></div><div><span>9.返回与M最近的旋转矩阵</span></div></div><div><div><div>26</div></div><div><span>R = ProjectToSO3(mat)</span></div></div><div><div><div>27</div></div><div>
</div></div><div><div><div>28</div></div><div><span>10.将旋转矩阵和位置向量转换wei</span></div></div><div><div><div>29</div></div><div><span>T = RpToTrans(R,p)</span></div></div><div><div><div>30</div></div><div>
</div></div><div><div><div>31</div></div><div><span>11.从变换矩阵中分离出旋转矩阵和位置向量</span></div></div><div><div><div>32</div></div><div><span>[R,p] = TransToRp(T)</span></div></div><div><div><div>33</div></div><div>
</div></div><div><div><div>34</div></div><div><span>12.变换矩阵求逆</span></div></div><div><div><div>35</div></div><div><span>invT = TransInv(T)</span></div></div><div><div><div>36</div></div><div>
</div></div><div><div><div>37</div></div><div><span>13.构造与六维向量形式的运动旋量V对应的</span></div></div><div><div><div>38</div></div><div><span>se3mat = VecTose3(V)</span></div></div><div><div><div>39</div></div><div>
</div></div><div><div><div>40</div></div><div><span>14.构造与se(3)矩阵对应的六维向量形式的运动旋量V</span></div></div><div><div><div>41</div></div><div><span>V = se3ToVec(se3mat)</span></div></div><div><div><div>42</div></div><div>
</div></div><div><div><div>43</div></div><div><span>15.计算变换矩阵T的6*6的伴随矩阵</span></div></div><div><div><div>44</div></div><div><span>AdT = Adjoint(T)</span></div></div><div><div><div>45</div></div><div>
</div></div><div><div><div>46</div></div><div><span>16.返回正则化的螺旋轴表达式</span></div></div><div><div><div>47</div></div><div><span>S = ScrewToAxis(q,s,h)</span></div></div><div><div><div>48</div></div><div>
</div></div><div><div><div>49</div></div><div><span>17.从六位向量形式的指数坐标中提取出螺旋轴和沿轴线移动的距离</span></div></div><div><div><div>50</div></div><div><span>[S,theta] = AxisAng6(expc6)</span></div></div><div><div><div>51</div></div><div>
</div></div><div><div><div>52</div></div><div><span>18.计算矩阵指数对应的变换矩阵</span></div></div><div><div><div>53</div></div><div><span>T = MatrixExp6(se3mat)</span></div></div><div><div><div>54</div></div><div>
</div></div><div><div><div>55</div></div><div><span>19.计算变换矩阵对应的矩阵对数</span></div></div><div><div><div>56</div></div><div><span>se3mat = MatrixLog6(T)</span></div></div><div><div><div>57</div></div><div>
</div></div><div><div><div>58</div></div><div><span>20.M到变换矩阵的空间距离</span></div></div><div><div><div>59</div></div><div><span>d = DistanceToSE3(mat)</span></div></div><div><div><div>60</div></div><div>
</div></div><div><div><div>61</div></div><div><span>21.判断是否为SE3变换矩阵</span></div></div><div><div><div>62</div></div><div><span>judge = TestIfSE3(mat)</span></div></div><div><div><div>63</div></div><div>
</div></div><div><div><div>64</div></div><div><span>22.离M最近的变换矩阵</span></div></div><div><div><div>65</div></div><div><span>T = ProjectToSE3(mat)</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section><section><h3>（4）正向运动学<a href="#4正向运动学"><span>#</span></a></h3><section><h4>4.1指数积公式<a href="#41指数积公式"><span>#</span></a></h4><p>现在假定关节<span><span>nn</span><span><span><span></span><span>n</span></span></span></span>对应的关节变量为<span><span>θ\theta</span><span><span><span></span><span>θ</span></span></span></span>末端坐标系<span><span>MM</span><span><span><span></span><span>M</span></span></span></span>的位移可写成</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606221346291.png" alt="image-20240606221346291" /><figcaption>image-20240606221346291</figcaption></figure><p></p><p>式中，<span><span>T∈SO(3)T \in SO(3)</span><span><span><span></span><span>T</span><span></span><span>∈</span><span></span></span><span><span></span><span>S</span><span>O</span><span>(</span><span>3</span><span>)</span></span></span></span>为末端的新位形’，<span><span>S=(ωn,vn)S=(\omega_n,v_n)</span><span><span><span></span><span>S</span><span></span><span>=</span><span></span></span><span><span></span><span>(</span><span><span>ω</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span>v</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>)</span></span></span></span>为表示在基坐标系中的关节<span><span>nn</span><span><span><span></span><span>n</span></span></span></span>的旋量坐标。若关节<span><span>nn</span><span><span><span></span><span>n</span></span></span></span>是转动副（对应的是零节距的螺旋运动），则叫<span><span>ωn∈R3\omega_n \in R^3</span><span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>∈</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>3</span></span></span></span></span></span></span></span></span></span></span>是沿关节轴正向的单位向量，<span><span>vn=−ωn×qnv_n=-\omega_n\times q_n</span><span><span><span></span><span><span>v</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>−</span><span><span>ω</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>×</span><span></span></span><span><span></span><span><span>q</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>，<span><span>qnq_n</span><span><span><span></span><span><span>q</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>为关节轴上任一点，坐标值在基坐标系中进行度量。若关节<span><span>nn</span><span><span><span></span><span>n</span></span></span></span>
是移动副，则叫<span><span>ωn=0,vn∈R3\omega_n=0 ,v_n\in R^3</span><span><span><span></span><span><span>ω</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>0</span><span>,</span><span></span><span><span>v</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>∈</span><span></span></span><span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>3</span></span></span></span></span></span></span></span></span></span></span>是沿关节轴正向的单位向量，<span><span>θn\theta_n</span><span><span><span></span><span><span>θ</span><span><span><span><span><span><span></span><span><span>n</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>表示移动的距离。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606221455614.png" alt="image-20240606221455614" /><figcaption>image-20240606221455614</figcaption></figure><p></p><p>上述方程就是指数积公式的<strong>空间坐标表达形式</strong></p><p>同样也可以导出<strong>物体坐标系的指数积公式</strong></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606221811929.png" alt="image-20240606221811929" /><figcaption>image-20240606221811929</figcaption></figure><p></p></section><section><h4>4.2函数<a href="#42函数"><span>#</span></a></h4><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>末端坐标系下。给定初始形位，关节旋量以及关节值，计算末端坐标系</span></div></div><div><div><div>2</div></div><div><span>T = FKinBody(M,Blist,thetalist)</span></div></div><div><div><div>3</div></div><div><span>空间坐标系下。给定初始形位，关节旋量以及关节值，计算末端坐标系</span></div></div><div><div><div>4</div></div><div><span>T = FKinSpace(M,Slist,thetalist)</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h4>4.3库卡KR60-3运动学建模<a href="#43库卡kr60-3运动学建模"><span>#</span></a></h4><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>import</span><span> modern_robotics </span><span>as</span><span> mr</span></div></div><div><div><div>2</div></div><div><span>import</span><span> numpy </span><span>as</span><span> np</span></div></div><div><div><div>3</div></div><div><span>from</span><span> math </span><span>import</span><span> pi</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span><span>omega_1 </span><span>=</span><span> np.</span><span>array</span><span>([</span></span><span>0</span><span>,</span><span>0</span><span><span>,</span><span>-</span></span><span>1</span><span>])</span></div></div><div><div><div>7</div></div><div><span><span>omega_2</span><span>=</span><span>np.</span><span>array</span><span>([</span></span><span>0</span><span>,</span><span>1</span><span>,</span><span>0</span><span>])</span></div></div><div><div><div>8</div></div><div><span><span>omega_3</span><span>=</span><span>np.</span><span>array</span><span>([</span></span><span>0</span><span>,</span><span>1</span><span>,</span><span>0</span><span>])</span></div></div><div><div><div>9</div></div><div><span><span>omega_4</span><span>=</span><span>np.</span><span>array</span><span>([</span><span>-</span></span><span>1</span><span>,</span><span>0</span><span>,</span><span>0</span><span>])</span></div></div><div><div><div>10</div></div><div><span><span>omega_5</span><span>=</span><span>np.</span><span>array</span><span>([</span></span><span>0</span><span>,</span><span>1</span><span>,</span><span>0</span><span>])</span></div></div><div><div><div>11</div></div><div><span><span>omega_6</span><span>=</span><span>np.</span><span>array</span><span>([</span><span>-</span></span><span>1</span><span>,</span><span>0</span><span>,</span><span>0</span><span>])</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span><span>q1</span><span>=</span><span>np.</span><span>array</span><span>([</span></span><span>0</span><span>,</span><span>0</span><span>,</span><span>0</span><span>])</span></div></div><div><div><div>14</div></div><div><span><span>q2</span><span>=</span><span>np.</span><span>array</span><span>([</span></span><span>350</span><span>,</span><span>0</span><span>,</span><span>815</span><span>])</span></div></div><div><div><div>15</div></div><div><span><span>q3</span><span>=</span><span>np.</span><span>array</span><span>([</span></span><span>1200</span><span>,</span><span>0</span><span>,</span><span>815</span><span>])</span></div></div><div><div><div>16</div></div><div><span><span>q4</span><span>=</span><span>np.</span><span>array</span><span>([</span></span><span>2020</span><span>,</span><span>0</span><span>,</span><span>960</span><span>])</span></div></div><div><div><div>17</div></div><div><span><span>q5</span><span>=</span><span>np.</span><span>array</span><span>([</span></span><span>2020</span><span>,</span><span>0</span><span>,</span><span>960</span><span>])</span></div></div><div><div><div>18</div></div><div><span><span>q6</span><span>=</span><span>np.</span><span>array</span><span>([</span></span><span>2020</span><span>,</span><span>0</span><span>,</span><span>960</span><span>])</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span><span>M</span><span>=</span><span>np.</span><span>array</span><span>([[ </span></span><span>0</span><span>,    </span><span>0</span><span>,    </span><span>1</span><span>,  </span><span>2190</span><span>],</span></div></div><div><div><div>21</div></div><div><span><span>            </span></span><span>[ </span><span>0</span><span>,    </span><span>1</span><span>,    </span><span>0</span><span>,     </span><span>0</span><span>],</span></div></div><div><div><div>22</div></div><div><span><span>            </span></span><span>[</span><span>-</span><span>1</span><span>,    </span><span>0</span><span>,    </span><span>0</span><span>,   </span><span>960</span><span>],</span></div></div><div><div><div>23</div></div><div><span><span>            </span></span><span>[ </span><span>0</span><span>,    </span><span>0</span><span>,    </span><span>0</span><span>,     </span><span>1</span><span>]])</span></div></div><div><div><div>24</div></div><div>
</div></div><div><div><div>25</div></div><div><span># thetalist = np.array([0,-pi/2,pi/2,0,0,0])</span></div></div><div><div><div>26</div></div><div><span><span>thetalist </span><span>=</span><span> np.</span><span>array</span><span>([</span><span>-</span></span><span>2.410000</span><span><span> </span><span>/</span><span> </span></span><span>180</span><span><span> </span><span>*</span><span> pi, </span><span>-</span></span><span>57.230000</span><span><span> </span><span>/</span><span> </span></span><span>180</span><span><span> </span><span>*</span><span> pi, </span></span><span>112.080000</span><span><span> </span><span>/</span><span> </span></span><span>180</span><span><span> </span><span>*</span><span> pi, </span><span>-</span></span><span>0.780000</span><span><span> </span><span>/</span><span> </span></span><span>180</span><span><span> </span><span>*</span><span> pi, </span><span>-</span></span><span>54.890000</span><span><span> </span><span>/</span><span> </span></span><span>180</span><span><span> </span><span>*</span><span> pi,</span></span></div></div><div><div><div>27</div></div><div><span>     </span><span>1.440000</span><span><span> </span><span>/</span><span> </span></span><span>180</span><span><span> </span><span>*</span><span> pi])</span></span></div></div><div><div><div>28</div></div><div>
</div></div><div><div><div>29</div></div><div>
</div></div><div><div><div>30</div></div><div><span>def</span><span> </span><span>vcaculate</span><span>(</span><span>omega</span><span>,</span><span>q</span><span>):</span></div></div><div><div><div>31</div></div><div><span><span>    </span></span><span>v</span><span>=</span><span>np.</span><span>cross</span><span>(</span><span>-</span><span>omega,q)</span></div></div><div><div><div>32</div></div><div><span>    </span><span>return</span><span> v</span></div></div><div><div><div>33</div></div><div><span><span>v1</span><span>=</span><span>vcaculate</span><span>(omega_1,q1)</span></span></div></div><div><div><div>34</div></div><div><span><span>v2</span><span>=</span><span>vcaculate</span><span>(omega_2,q2)</span></span></div></div><div><div><div>35</div></div><div><span><span>v3</span><span>=</span><span>vcaculate</span><span>(omega_3,q3)</span></span></div></div><div><div><div>36</div></div><div><span><span>v4</span><span>=</span><span>vcaculate</span><span>(omega_4,q4)</span></span></div></div><div><div><div>37</div></div><div><span><span>v5</span><span>=</span><span>vcaculate</span><span>(omega_5,q5)</span></span></div></div><div><div><div>38</div></div><div><span><span>v6</span><span>=</span><span>vcaculate</span><span>(omega_6,q6)</span></span></div></div><div><div><div>39</div></div><div>
</div></div><div><div><div>40</div></div><div><span><span>s1</span><span>=</span><span>np.</span><span>append</span><span>(omega_1,v1)</span></span></div></div><div><div><div>41</div></div><div><span><span>s2</span><span>=</span><span>np.</span><span>append</span><span>(omega_2,v2)</span></span></div></div><div><div><div>42</div></div><div><span><span>s3</span><span>=</span><span>np.</span><span>append</span><span>(omega_3,v3)</span></span></div></div><div><div><div>43</div></div><div><span><span>s4</span><span>=</span><span>np.</span><span>append</span><span>(omega_4,v4)</span></span></div></div><div><div><div>44</div></div><div><span><span>s5</span><span>=</span><span>np.</span><span>append</span><span>(omega_5,v5)</span></span></div></div><div><div><div>45</div></div><div><span><span>s6</span><span>=</span><span>np.</span><span>append</span><span>(omega_6,v6)</span></span></div></div><div><div><div>46</div></div><div>
</div></div><div><div><div>47</div></div><div><span><span>Slist</span><span>=</span><span>np.</span><span>array</span><span>([s1,s2,s3,s4,s5,s6]).T</span></span></div></div><div><div><div>48</div></div><div><span># print(M)</span></div></div><div><div><div>49</div></div><div><span># print(v)</span></div></div><div><div><div>50</div></div><div><span># print(thetalist)</span></div></div><div><div><div>51</div></div><div>
</div></div><div><div><div>52</div></div><div>
</div></div><div><div><div>53</div></div><div><span><span>T </span><span>=</span><span> mr.</span><span>FKinSpace</span><span>(M,Slist,thetalist)</span></span></div></div><div><div><div>54</div></div><div><span>print</span><span>(T)</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section><section><h3>（5）一阶运动学和静力学<a href="#5一阶运动学和静力学"><span>#</span></a></h3><p>机器人正运动学可以写成</p><span><span><span>x(t)=f(θ(t))x(t)=f(\theta(t))</span><span><span><span></span><span>x</span><span>(</span><span>t</span><span>)</span><span></span><span>=</span><span></span></span><span><span></span><span>f</span><span>(</span><span>θ</span><span>(</span><span>t</span><span>))</span></span></span></span></span><p>对上式关于时间t求导</p><span><span><span>x˙=∂f(θ)∂θd(θ(t))dt=∂f(θ)∂θ=J(θ)θ˙\dot{x}=\frac {\partial f(\theta) } {\partial \theta }\frac {d(\theta(t)) } {dt }=\frac{\partial f(\theta)} {\partial \theta} = J(\theta)\dot{\theta}</span><span><span><span></span><span><span><span><span><span><span></span><span>x</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span><span></span><span><span><span><span><span><span></span><span><span>∂</span><span>θ</span></span></span><span><span></span><span></span></span><span><span></span><span><span>∂</span><span>f</span><span>(</span><span>θ</span><span>)</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span><span><span></span><span><span><span><span><span><span></span><span><span>d</span><span>t</span></span></span><span><span></span><span></span></span><span><span></span><span><span>d</span><span>(</span><span>θ</span><span>(</span><span>t</span><span>))</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span><span></span><span>=</span><span></span></span><span><span></span><span><span></span><span><span><span><span><span><span></span><span><span>∂</span><span>θ</span></span></span><span><span></span><span></span></span><span><span></span><span><span>∂</span><span>f</span><span>(</span><span>θ</span><span>)</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>J</span><span>(</span><span>θ</span><span>)</span><span><span><span><span><span><span></span><span>θ</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span></span></span></span></span><p>式中，<span><span>J(θ)J(\theta)</span><span><span><span></span><span>J</span><span>(</span><span>θ</span><span>)</span></span></span></span>被称为雅可比，表示末端执行器速度相对关节速度的线性敏感度，时关于关节变量<span><span>θ\theta</span><span><span><span></span><span>θ</span></span></span></span>的函数。在某些形位上，雅可比矩阵会变成奇异阵，相应的形位被称为奇异形位，特征主要表现在机器人在末端的某些方向上的速度不能实现。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606222952728.png" alt="image-20240606222952728" /><figcaption>image-20240606222952728</figcaption></figure><p></p><p>雅可比矩阵可以用来将关节转速的边界映射到<span><span>vtipv_{tip}</span><span><span><span></span><span><span>v</span><span><span><span><span><span><span></span><span><span><span>t</span><span>i</span><span>p</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>的边界中，如图5.2所示。不是如图那样将关节速度通过雅可比矩阵映射成多边形，而是在<span><span>θ˙1−θ˙2\dot{\theta}_1-\dot{\theta}_2</span><span><span><span></span><span><span><span><span><span><span><span></span><span>θ</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>−</span><span></span></span><span><span></span><span><span><span><span><span><span><span></span><span>θ</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>平面内将关节速度映射成—个单位圆。这个圆表示关节速度空间的等廓线，其中驱动器的共同作用可考虑为关节速度的平方和。通过映射，单位圆映射成末端速度的—个椭球，这个椭球称为<strong>可操作度椭球</strong>。当操作手的位形接近奇异位形时，椭球将退化成一个线段，末端沿某方向运动的能力将会丧失。</p><p>假设用于机器人运动的功忽略不计，机器人末端施加的功应与关节处产生的功相等，末端力向量记作<span><span>ftipf_{tip}</span><span><span><span></span><span><span>f</span><span><span><span><span><span><span></span><span><span><span>t</span><span>i</span><span>p</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>关节力矩向量记作<span><span>τ\tau</span><span><span><span></span><span>τ</span></span></span></span>
根据能量守恒定律可得</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606223656956.png" alt="image-20240606223656956" /><figcaption>image-20240606223656956</figcaption></figure><p></p><p>由于<span><span>vtip=J(θ)θ˙v_{tip}=J(\theta)\dot{\theta}</span><span><span><span></span><span><span>v</span><span><span><span><span><span><span></span><span><span><span>t</span><span>i</span><span>p</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>J</span><span>(</span><span>θ</span><span>)</span><span><span><span><span><span><span></span><span>θ</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span></span></span></span>，因此等式改写为</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606223710706.png" alt="image-20240606223710706" /><figcaption>image-20240606223710706</figcaption></figure><p></p><p>用于生成末端力<span><span>ftipf_{tip}</span><span><span><span></span><span><span>f</span><span><span><span><span><span><span></span><span><span><span>t</span><span>i</span><span>p</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>的关节力矩<span><span>τ\tau</span><span><span><span></span><span>τ</span></span></span></span>可以通过上式计算得到。如果机器人处于非奇异形位，雅可比矩阵及其转置矩阵可逆，可以写成</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606230328369.png" alt="image-20240606230328369" /><figcaption>image-20240606230328369</figcaption></figure><p></p><p>同样，类似于可操作度椭球，可以通过雅可比矩阵的逆转置，将<span><span>τ1−τ2\tau_{1}-\tau_{2}</span><span><span><span></span><span><span>τ</span><span><span><span><span><span><span></span><span><span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>−</span><span></span></span><span><span></span><span><span>τ</span><span><span><span><span><span><span></span><span><span><span>2</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>平面内的一个等廓单位圆映射成<span><span>f1−f2f_{1}-f_{2}</span><span><span><span></span><span><span>f</span><span><span><span><span><span><span></span><span><span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>−</span><span></span></span><span><span></span><span><span>f</span><span><span><span><span><span><span></span><span><span><span>2</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>末端力平面的一个椭球，这个椭球被称为<strong>力椭球</strong>。表示生成不同方向力的难易程度。</p><p>由可操作度椭球和力椭球明显可以看出，若在某—方向上比较容易地产生末端速度，该方向产生力就变得比较困难，反之亦然，具体如图5.6所示。事实上，对于给定的机器人位形，可操作度椭球与力椭球的主轴方问完全重合，但力椭球的主轴长度与可操作度椭球的主轴长度正好相反</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606230427541.png" alt="image-20240606230427541" /><figcaption>image-20240606230427541</figcaption></figure><p></p><section><h4>5.1机器人雅可比<a href="#51机器人雅可比"><span>#</span></a></h4><section><h5>5.1.1空间雅可比<a href="#511空间雅可比"><span>#</span></a></h5><p>考虑一个n杆的开链机器人，其正向运动学的指数积公式为</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606230709663.png" alt="image-20240606230709663" /><figcaption>image-20240606230709663</figcaption></figure><p></p><p>空间速度<span><span>VSV_S</span><span><span><span></span><span><span>V</span><span><span><span><span><span><span></span><span><span>S</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>可以写成<span><span>[VS]=T˙T−1[V_S]=\dot{T}T^{-1}</span><span><span><span></span><span>[</span><span><span>V</span><span><span><span><span><span><span></span><span><span>S</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>]</span><span></span><span>=</span><span></span></span><span><span></span><span><span><span><span><span><span></span><span>T</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span><span><span>T</span><span><span><span><span><span><span></span><span><span><span>−</span><span>1</span></span></span></span></span></span></span></span></span></span></span></span>，其中</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606230739831.png" alt="image-20240606230739831" /><figcaption>image-20240606230739831</figcaption></figure><p></p><p>可计算得</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606230811284.png" alt="image-20240606230811284" /><figcaption>image-20240606230811284</figcaption></figure><p></p><p>可通过伴随映射写成向量形式</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606230826440.png" alt="image-20240606230826440" /><figcaption>image-20240606230826440</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606230846952.png" alt="image-20240606230846952" /><figcaption>image-20240606230846952</figcaption></figure><p></p><p>矩阵<span><span>JS(θ)J_S(\theta)</span><span><span><span></span><span><span>J</span><span><span><span><span><span><span></span><span><span>S</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>θ</span><span>)</span></span></span></span>即为空间固定坐标形式下得雅可比矩阵，简称为<strong>空间雅可比</strong>。</p><p><span><span>Jsi(θ)J_{si}(\theta)</span><span><span><span></span><span><span>J</span><span><span><span><span><span><span></span><span><span><span>s</span><span>i</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>θ</span><span>)</span></span></span></span>得第i列为</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606230950755.png" alt="image-20240606230950755" /><figcaption>image-20240606230950755</figcaption></figure><p></p><p>第<span><span>ii</span><span><span><span></span><span>i</span></span></span></span>列的结构形式为<span><span>Jsi(θ)=AdTi−1(Si)J_{si}(\theta)=Ad_{T_{i-1}}(S_{i})</span><span><span><span></span><span><span>J</span><span><span><span><span><span><span></span><span><span><span>s</span><span>i</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>θ</span><span>)</span><span></span><span>=</span><span></span></span><span><span></span><span>A</span><span><span>d</span><span><span><span><span><span><span></span><span><span><span><span>T</span><span><span><span><span><span><span></span><span><span><span>i</span><span>−</span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span><span>S</span><span><span><span><span><span><span></span><span><span><span>i</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>)</span></span></span></span>其中<span><span>Ti−1=e[S1θ1]⋯e[Si−1θi−1]T_{i-1}=e^{[S_1\theta_1]}\cdots e^{[S_{i-1}\theta_{i-1}]}</span><span><span><span></span><span><span>T</span><span><span><span><span><span><span></span><span><span><span>i</span><span>−</span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span><span>e</span><span><span><span><span><span><span></span><span><span><span>[</span><span><span>S</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span>θ</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>]</span></span></span></span></span></span></span></span></span><span></span><span>⋯</span><span></span><span><span>e</span><span><span><span><span><span><span></span><span><span><span>[</span><span><span>S</span><span><span><span><span><span><span></span><span><span><span>i</span><span>−</span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span>θ</span><span><span><span><span><span><span></span><span><span><span>i</span><span>−</span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>]</span></span></span></span></span></span></span></span></span></span></span></span>。回顾<span><span>SiS_i</span><span><span><span></span><span><span>S</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>为机器人处于零位时第i个关节相对固定坐标系的旋量坐标，因此<span><span>AdTi−1(Si)Ad_{T_{i-1}}(S_{i})</span><span><span><span></span><span>A</span><span><span>d</span><span><span><span><span><span><span></span><span><span><span><span>T</span><span><span><span><span><span><span></span><span><span><span>i</span><span>−</span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span><span>S</span><span><span><span><span><span><span></span><span><span><span>i</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>)</span></span></span></span>为该机器人经历刚体位移<span><span>Ti−1T_{i-1}</span><span><span><span></span><span><span>T</span><span><span><span><span><span><span></span><span><span><span>i</span><span>−</span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>之后的第i个关节相对固定坐标系的旋量坐标。物理上，这与前面的i-l个关节从零位到当前值theta1…theta_i-1时的旋量坐标是等效的。因此,<span><span>Js(θ)J_{s}(\theta)</span><span><span><span></span><span><span>J</span><span><span><span><span><span><span></span><span><span><span>s</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>θ</span><span>)</span></span></span></span>的第i列<span><span>Jsi(θ)J_{si}(\theta)</span><span><span><span></span><span><span>J</span><span><span><span><span><span><span></span><span><span><span>s</span><span>i</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>θ</span><span>)</span></span></span></span>只是描述第i个关节轴相对固定坐标系的旋量，同时也是关节变量theta1…theta_i-1的函数。不过是取任意的<span><span>θ\theta</span><span><span><span></span><span>θ</span></span></span></span>值而不是<span><span>θ\theta</span><span><span><span></span><span>θ</span></span></span></span>＝0。</p></section><section><h5>5.1.2物体雅可比<a href="#512物体雅可比"><span>#</span></a></h5><p>物体坐标系下，<span><span>[Vb]=T−1T˙[V_b]=T^{-1}\dot{T}</span><span><span><span></span><span>[</span><span><span>V</span><span><span><span><span><span><span></span><span><span>b</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>]</span><span></span><span>=</span><span></span></span><span><span></span><span><span>T</span><span><span><span><span><span><span></span><span><span><span>−</span><span>1</span></span></span></span></span></span></span></span></span><span><span><span><span><span><span></span><span>T</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span></span></span></span>，正运动学公式为</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606231212845.png" alt="image-20240606231212845" /><figcaption>image-20240606231212845</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606231225601.png" alt="image-20240606231225601" /><figcaption>image-20240606231225601</figcaption></figure><p></p><p>由此计算可得</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606231330183.png" alt="image-20240606231330183" /><figcaption>image-20240606231330183</figcaption></figure><p></p><p>以矩阵形式表示</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606231351271.png" alt="image-20240606231351271" /><figcaption>image-20240606231351271</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606231357762.png" alt="image-20240606231357762" /><figcaption>image-20240606231357762</figcaption></figure><p></p><p>矩阵<span><span>Jb(θ)J_{b}(\theta)</span><span><span><span></span><span><span>J</span><span><span><span><span><span><span></span><span><span><span>b</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>θ</span><span>)</span></span></span></span>即为物体坐标系下得雅可比行列式，简称<strong>物体雅可比</strong></p></section><section><h5>5.1.3几何解释<a href="#513几何解释"><span>#</span></a></h5></section><section><h5>5.1.4空间雅可比和物体雅可比的关系<a href="#514空间雅可比和物体雅可比的关系"><span>#</span></a></h5><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606232143067.png" alt="image-20240606232143067" /><figcaption>image-20240606232143067</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606232159752.png" alt="image-20240606232159752" /><figcaption>image-20240606232159752</figcaption></figure><p></p></section><section><h5>5.1.5几何雅可比和解析雅可比的关系<a href="#515几何雅可比和解析雅可比的关系"><span>#</span></a></h5></section></section><section><h4>5.2开链机器人静力学<a href="#52开链机器人静力学"><span>#</span></a></h4></section><section><h4>5.3奇异性分析<a href="#53奇异性分析"><span>#</span></a></h4><p>​		如在某个或者多个方向同时失去运动能力的位姿，我们称之为运动学奇异（kinematicsingularjty），或者简称为奇
异（singularity）。数学上,奇异位姿意味着雅可比矩阵<span><span>J(θ)J(\theta)</span><span><span><span></span><span>J</span><span>(</span><span>θ</span><span>)</span></span></span></span>不再满秩  。</p><p>​		当<span><span>J(θ)J(\theta)</span><span><span><span></span><span>J</span><span>(</span><span>θ</span><span>)</span></span></span></span>的阶数降到最大值以下，奇异位姿对应此时的<span><span>θ\theta</span><span><span><span></span><span>θ</span></span></span></span>。奇异位姿下末端坐标系丧失掉在某—维或多维方向的瞬时空间速度，这种奇异下损失的自由度同时伴随产生了与之对应方向上的约束力旋量 。</p><ul>
<li>2个旋转轴共轴</li>
<li>3各平面转动副轴线平行</li>
<li>4各转动副轴线共点</li>
<li>4个转动副轴线共面</li>
<li>6个转动副都与一条线相交</li>
</ul></section><section><h4>5.4 可操作度<a href="#54-可操作度"><span>#</span></a></h4><p>对于一个通用的″关节开链机器人，任务空间的坐标为q，可操作度椭球对应的是当关节速率满足<span><span>∣θ˙∣=1|\dot{\theta}|=1</span><span><span><span></span><span>∣</span><span><span><span><span><span><span></span><span>θ</span></span><span><span></span><span><span>˙</span></span></span></span></span></span></span><span>∣</span><span></span><span>=</span><span></span></span><span><span></span><span>1</span></span></span></span>时末端执行器的速度。在n维关节速度空间内的一个单元球。假设<span><span>JJ</span><span><span><span></span><span>J</span></span></span></span>可逆,单位关节速度条件数可以写成</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606232708214.png" alt="image-20240606232708214" /><figcaption>image-20240606232708214</figcaption></figure><p></p><p>由线性代数可知，上式定义m维空间椭球。椭球主轴方向为<span><span>viv_i</span><span><span><span></span><span><span>v</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>，主轴半径长为<span><span>λi\sqrt{\lambda_i}</span><span><span><span></span><span><span><span><span><span><span></span><span><span><span>λ</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span>。<strong>椭球的体积</strong>V与主轴半径长的乘积成正比。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606232833847.png" alt="image-20240606232833847" /><figcaption>image-20240606232833847</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606232845072.png" alt="image-20240606232845072" /><figcaption>image-20240606232845072</figcaption></figure><p></p><p>角速度与线速度的量纲不同，于是将雅可比矩阵分开。由此可以得到两个三维可操作度椭球&lt;一个表示角速度&gt;,另—个表示线速度。这两个可操作度椭球都有与A的特征向量相对应的主轴，长度为其特征值的平方根。其中，对于角速度可操作度椭球<span><span>J=JωJωTJ=J_\omega J_\omega^T</span><span><span><span></span><span>J</span><span></span><span>=</span><span></span></span><span><span></span><span><span>J</span><span><span><span><span><span><span></span><span><span>ω</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span>J</span><span><span><span><span><span><span></span><span><span>ω</span></span></span><span><span></span><span><span>T</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>，对于线速度可操作度椭球,<span><span>J=JvJvTJ=J_v J_v^T</span><span><span><span></span><span>J</span><span></span><span>=</span><span></span></span><span><span></span><span><span>J</span><span><span><span><span><span><span></span><span><span>v</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span>J</span><span><span><span><span><span><span></span><span><span>v</span></span></span><span><span></span><span><span>T</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></p><p>当在计算线速度可操作度椭球时’使用<strong>物体雅可比<span><span>JbJ_b</span><span><span><span></span><span><span>J</span><span><span><span><span><span><span></span><span><span>b</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span><strong>更合适些,因为我们</strong>通常对末端坐标系原点的速度更感兴趣</strong>而非固定坐标系原点的速度。</p><p>除了可操作度椭球的几何特征之外,还有一种方法是定义可操作度椭球的<strong>最长轴半径与最短轴半径的比值</strong></p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606232859933.png" alt="image-20240606232859933" /><figcaption>image-20240606232859933</figcaption></figure><p></p><p>当<span><span>μ1(A)\mu_1(A)</span><span><span><span></span><span><span>μ</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>A</span><span>)</span></span></span></span>接近1时,可操作度椭球接近球形或者各向同性。意味着该机器人沿任何方向都同样容易，这是理想情况。相反,当机器人接近奇异时<span><span>μ1(A)\mu_1(A)</span><span><span><span></span><span><span>μ</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>A</span><span>)</span></span></span></span>趋于无穷大 。</p><p>类似的，可以定义<span><span>μ2(A)\mu_2(A)</span><span><span><span></span><span><span>μ</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>A</span><span>)</span></span></span></span>为<span><span>μ1(A)\mu_1(A)</span><span><span><span></span><span><span>μ</span><span><span><span><span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>A</span><span>)</span></span></span></span>的平方，又称为矩阵A的<strong>条件数</strong> ，该值越小越理想。矩阵的条件数普遍用于衡量矩阵与向量相乘后的敏感度误差减少的程度 。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606232917608.png" alt="image-20240606232917608" /><figcaption>image-20240606232917608</figcaption></figure><p></p><p>最后一种度量方法是简单利用<strong>可操作度椭球的体积</strong>，这种情况是越大越好。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606232932258.png" alt="image-20240606232932258" /><figcaption>image-20240606232932258</figcaption></figure><p></p><p>与可操作度椭球类似，可以定义<strong>力椭球</strong>。 由单位关节力矩满足<span><span>∣∣τ∣∣=1||{\tau} ||=1</span><span><span><span></span><span>∣∣</span><span><span>τ</span></span><span>∣∣</span><span></span><span>=</span><span></span></span><span><span></span><span>1</span></span></span></span>，得到与上述类似的结果</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606233127435.png" alt="image-20240606233127435" /><figcaption>image-20240606233127435</figcaption></figure><p></p><p>因此，力椭球的主轴长度为可操作椭球长度的倒数。</p></section><section><h4>5.5软件函数<a href="#55软件函数"><span>#</span></a></h4><p>给定物体坐标系下描述的各关节旋量<span><span>BiB_i</span><span><span><span></span><span><span>B</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>及关节角，计算物体雅可比<span><span>JB(θ)J_B(\theta)</span><span><span><span></span><span><span>J</span><span><span><span><span><span><span></span><span><span>B</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>θ</span><span>)</span></span></span></span></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>Jb=JacobianBody(Blist,thetalist)</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>给定物体坐标系下描述的各关节旋量<span><span>SiS_i</span><span><span><span></span><span><span>S</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>及关节角，计算物体雅可比<span><span>JS(θ)J_S(\theta)</span><span><span><span></span><span><span>J</span><span><span><span><span><span><span></span><span><span>S</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>θ</span><span>)</span></span></span></span></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>J</span><span>=</span><span>JacobianBody</span><span>(Slist,thetalist)</span></span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section></section></section><section><h2>2.改进D-H建模<a href="#2改进d-h建模"><span>#</span></a></h2><section><h3>（1）D-H参数<a href="#1d-h参数"><span>#</span></a></h3><p>机器人工具箱中中定义改进DH连杆时一定要注意DH[theta d a alpha]中<strong>前两个参数下表为i</strong>，即当前关节的DH值，后<strong>两个参数</strong>下表为i-1，及前一个关节的DH值参数值！</p><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20240606234453822.png" alt="image-20240606234453822" /><figcaption>image-20240606234453822</figcaption></figure><p></p><p>此时对比代码中的DH参数和图中画的坐标系，得到DH定义为</p><blockquote><p>theta(i)：绕Zi轴，从Xi-1旋转到Xi的角度</p><p>d(i)：沿Zi轴，从Xi-1移动到Xi的距离</p><p>a(i)：沿Xi轴，从Zi移动到Zi+1的距离</p><p>alpha(i)：绕Xi轴，从Zi旋转到Zi+1的角度</p></blockquote>

<table><thead><tr><th>杆件</th><th>theta</th><th>d</th><th>a</th><th>alpha</th></tr></thead><tbody><tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr><tr><td>1</td><td>0</td><td>815</td><td>350</td><td>-90</td></tr><tr><td>2</td><td>-90</td><td>0</td><td>850</td><td>0</td></tr><tr><td>3</td><td>0</td><td>0</td><td>145</td><td>-90</td></tr><tr><td>4</td><td>0</td><td>820</td><td>0</td><td>90</td></tr><tr><td>5</td><td>0</td><td>0</td><td>0</td><td>-90</td></tr><tr><td>6</td><td>180</td><td>180</td><td>0</td><td>0</td></tr></tbody></table><p>所以在程序中定义DH参数：</p>

<table><thead><tr><th>杆件</th><th>theta</th><th>d</th><th>a</th><th>alpha</th></tr></thead><tbody><tr><td>1</td><td>0</td><td>815</td><td>0</td><td>0</td></tr><tr><td>2</td><td>-90</td><td>0</td><td>350</td><td>-90</td></tr><tr><td>3</td><td>0</td><td>0</td><td>850</td><td>0</td></tr><tr><td>4</td><td>0</td><td>820</td><td>145</td><td>-90</td></tr><tr><td>5</td><td>0</td><td>0</td><td>0</td><td>90</td></tr><tr><td>6</td><td>180</td><td>180</td><td>0</td><td>-90</td></tr></tbody></table><p>上图所示为机器人处于位姿原点位置，在D-H模型中关节转角theta为[0,-90,0,0,0,180]，而实际的机器人处于原点位姿的关节转角theta’为[0,-90,90,0,0,0]，这是由于机器人关节零位和旋转方向定义与D-H模型不同造成的，实际机器人与D-H模型第一，四，六轴的旋转方向相反，第三、六轴分别差-90°和180°，需要对理论模型和实际模型的关节转角转换关系进行明确的定义：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>theta1=-theta1';</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>theta2=-theta2';</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span>theta3=theta3'-90;</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>theta4=-theta4';</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>theta5=-theta5'</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>theta6=180-theta6'</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>（2）建模程序<a href="#2建模程序"><span>#</span></a></h3><p>使用python中的机器人工具箱进行D-H建模,程序命名为KR60.py</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>import</span><span> roboticstoolbox </span><span>as</span><span> rtb</span></div></div><div><div><div>2</div></div><div><span>from</span><span> spatialmath </span><span>import</span><span><span> </span><span>SE3</span></span></div></div><div><div><div>3</div></div><div><span>from</span><span> roboticstoolbox </span><span>import</span><span> DHRobot, RevoluteDH, RevoluteMDH</span></div></div><div><div><div>4</div></div><div><span>from</span><span> math </span><span>import</span><span> pi</span></div></div><div><div><div>5</div></div><div><span>import</span><span> numpy</span></div></div><div><div><div>6</div></div><div><span>from</span><span> numpy </span><span>import</span><span><span> </span><span>*</span></span></div></div><div><div><div>7</div></div><div><span>import</span><span> numpy </span><span>as</span><span> np</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>class</span><span><span> </span><span>KR60</span><span>(</span><span>DHRobot</span><span>)</span></span><span>:</span></div></div><div><div><div>10</div></div><div><span>    </span><span>def</span><span> </span><span>__init__</span><span>(</span><span>self</span><span>):</span></div></div><div><div><div>11</div></div><div><span><span>        </span></span><span>deg </span><span>=</span><span> pi </span><span>/</span><span> </span><span>180</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>        </span><span># Updated values form ARTE git. Old values left as comments</span></div></div><div><div><div>14</div></div><div>
</div></div><div><div><div>15</div></div><div><span><span>        </span></span><span>L1 </span><span>=</span><span> </span><span>RevoluteMDH</span><span>(</span><span>a</span><span>=</span><span>0</span><span>,</span></div></div><div><div><div>16</div></div><div><span>                         </span><span>d</span><span>=</span><span>0.815</span><span>,</span></div></div><div><div><div>17</div></div><div><span>                         </span><span>alpha</span><span>=</span><span>0</span><span>,  </span><span># alpha=pi / 2,</span></div></div><div><div><div>18</div></div><div><span>                         </span><span># theta=0,</span></div></div><div><div><div>19</div></div><div><span>                         </span><span>qlim</span><span><span>=</span><span>[</span><span>-</span></span><span>185</span><span><span> </span><span>*</span><span> deg, </span></span><span>185</span><span><span> </span><span>*</span><span> deg]</span></span></div></div><div><div><div>20</div></div><div><span><span>                        </span></span><span>)</span></div></div><div><div><div>21</div></div><div><span><span>        </span></span><span>L2 </span><span>=</span><span> </span><span>RevoluteMDH</span><span>(</span><span>a</span><span>=</span><span>0.35</span><span>,</span></div></div><div><div><div>22</div></div><div><span>                         </span><span>d</span><span>=</span><span>0</span><span>,  </span><span># d=0.135,</span></div></div><div><div><div>23</div></div><div><span>                         </span><span>alpha</span><span><span>=-</span><span>pi</span><span>/</span></span><span>2</span><span>,  </span><span># alpha=pi,</span></div></div><div><div><div>24</div></div><div><span>                         </span><span># theta=0,</span></div></div><div><div><div>25</div></div><div><span>                         </span><span>qlim</span><span><span>=</span><span>[</span><span>-</span></span><span>135</span><span><span> </span><span>*</span><span> deg, </span></span><span>35</span><span><span> </span><span>*</span><span> deg]</span></span></div></div><div><div><div>26</div></div><div><span><span>                        </span></span><span>)</span></div></div><div><div><div>27</div></div><div><span><span>        </span></span><span>L3 </span><span>=</span><span> </span><span>RevoluteMDH</span><span>(</span><span>a</span><span>=</span><span>0.85</span><span>,</span></div></div><div><div><div>28</div></div><div><span>                        </span><span>d</span><span>=</span><span>0</span><span>,  </span><span># d=0.135,</span></div></div><div><div><div>29</div></div><div><span>                        </span><span>alpha</span><span>=</span><span>0</span><span>,  </span><span># alpha=-pi / 2,</span></div></div><div><div><div>30</div></div><div><span>                        </span><span># theta=-pi/2,</span></div></div><div><div><div>31</div></div><div><span>                        </span><span>qlim</span><span><span>=</span><span>[</span><span>-</span></span><span>120</span><span><span> </span><span>*</span><span> deg, </span></span><span>158</span><span><span> </span><span>*</span><span> deg]</span></span></div></div><div><div><div>32</div></div><div><span><span>                        </span></span><span>)</span></div></div><div><div><div>33</div></div><div><span><span>        </span></span><span>L4 </span><span>=</span><span> </span><span>RevoluteMDH</span><span>(</span><span>a</span><span>=</span><span>0.145</span><span>,</span></div></div><div><div><div>34</div></div><div><span>                        </span><span>d</span><span>=</span><span>0.82</span><span>,  </span><span># d=0.62,</span></div></div><div><div><div>35</div></div><div><span>                        </span><span>alpha</span><span><span>=-</span><span>pi</span><span>/</span></span><span>2</span><span>,  </span><span># alpha=pi / 2,</span></div></div><div><div><div>36</div></div><div><span>                        </span><span># theta=0,</span></div></div><div><div><div>37</div></div><div><span>                        </span><span>qlim</span><span><span>=</span><span>[</span><span>-</span></span><span>350</span><span><span> </span><span>*</span><span> deg, </span></span><span>350</span><span><span> </span><span>*</span><span> deg]</span></span></div></div><div><div><div>38</div></div><div><span><span>                        </span></span><span>)</span></div></div><div><div><div>39</div></div><div><span><span>        </span></span><span>L5 </span><span>=</span><span> </span><span>RevoluteMDH</span><span>(</span><span>a</span><span>=</span><span>0.0</span><span>,</span></div></div><div><div><div>40</div></div><div><span>                        </span><span>d</span><span>=</span><span>0.0</span><span>,</span></div></div><div><div><div>41</div></div><div><span>                        </span><span>alpha</span><span><span>=</span><span>pi</span><span>/</span></span><span>2</span><span>,  </span><span># alpha=-pi / 2,</span></div></div><div><div><div>42</div></div><div><span>                        </span><span># theta=0,</span></div></div><div><div><div>43</div></div><div><span>                        </span><span>qlim</span><span><span>=</span><span>[</span><span>-</span></span><span>119</span><span><span> </span><span>*</span><span> deg, </span></span><span>119</span><span><span> </span><span>*</span><span> deg]</span></span></div></div><div><div><div>44</div></div><div><span><span>                        </span></span><span>)</span></div></div><div><div><div>45</div></div><div><span><span>        </span></span><span>L6 </span><span>=</span><span> </span><span>RevoluteMDH</span><span>(</span><span>a</span><span>=</span><span>0</span><span>,</span></div></div><div><div><div>46</div></div><div><span>                        </span><span>d</span><span>=</span><span>0.17</span><span>,</span></div></div><div><div><div>47</div></div><div><span>                        </span><span>alpha</span><span><span>=-</span><span>pi</span><span>/</span></span><span>2</span><span>,</span></div></div><div><div><div>48</div></div><div><span>                        </span><span># theta=-pi,</span></div></div><div><div><div>49</div></div><div><span>                        </span><span>qlim</span><span><span>=</span><span>[</span><span>-</span></span><span>350</span><span><span> </span><span>*</span><span> deg, </span></span><span>350</span><span><span> </span><span>*</span><span> deg]</span></span></div></div><div><div><div>50</div></div><div><span><span>                        </span></span><span>)</span></div></div><div><div><div>51</div></div><div>
</div></div><div><div><div>52</div></div><div><span><span>        </span></span><span>L </span><span>=</span><span> [L1, L2, L3, L4, L5, L6]</span></div></div><div><div><div>53</div></div><div>
</div></div><div><div><div>54</div></div><div><span>        </span><span># Create SerialLink object</span></div></div><div><div><div>55</div></div><div><span>        </span><span>super</span><span>().</span><span>__init__</span><span>(</span></div></div><div><div><div>56</div></div><div><span><span>            </span></span><span>L,</span></div></div><div><div><div>57</div></div><div><span>            </span><span># meshdir="KUKA/KR5_arc",</span></div></div><div><div><div>58</div></div><div><span>            </span><span>name</span><span>=</span><span>'KR60'</span><span>,</span></div></div><div><div><div>59</div></div><div><span>            </span><span>manufacturer</span><span>=</span><span>'KUKA'</span><span>)</span></div></div><div><div><div>60</div></div><div><span>            </span><span># meshdir="meshes/KUKA/KR60_arc")</span></div></div><div><div><div>61</div></div><div>
</div></div><div><div><div>62</div></div><div><span>        </span><span>self</span><span><span>.</span><span>addconfiguration</span><span>(</span></span><span>"qz"</span><span>, [</span><span>0</span><span><span>, </span><span>-</span><span>pi</span><span>/</span></span><span>2</span><span>, </span><span>0</span><span>, </span><span>0</span><span>, </span><span>0</span><span>, pi])</span></div></div><div><div><div>63</div></div><div><span>        </span><span>self</span><span><span>.</span><span>addconfiguration</span><span>(</span></span></div></div><div><div><div>64</div></div><div><span>          </span><span>"qk1"</span><span>, [</span><span>0</span><span><span>, </span><span>-</span><span>pi</span><span>/</span></span><span>2</span><span>, </span><span>0</span><span>, </span><span>0</span><span>, </span><span>0</span><span>, </span><span>0</span><span>])</span></div></div><div><div><div>65</div></div><div><span>        </span><span>self</span><span><span>.</span><span>addconfiguration</span><span>(</span></span></div></div><div><div><div>66</div></div><div><span>          </span><span>"qk2"</span><span><span>, [pi </span><span>/</span><span> </span></span><span>4</span><span><span>, pi </span><span>/</span><span> </span></span><span>3</span><span><span>, pi </span><span>/</span><span> </span></span><span>6</span><span><span>, pi </span><span>/</span><span> </span></span><span>3</span><span><span>, pi </span><span>/</span><span> </span></span><span>4</span><span><span>, pi </span><span>/</span><span> </span></span><span>6</span><span>])</span></div></div><div><div><div>67</div></div><div><span>        </span><span>self</span><span><span>.</span><span>addconfiguration</span><span>(</span></span></div></div><div><div><div>68</div></div><div><span>          </span><span>"qk3"</span><span><span>, [pi </span><span>/</span><span> </span></span><span>6</span><span><span>, pi </span><span>/</span><span> </span></span><span>3</span><span><span>, pi </span><span>/</span><span> </span></span><span>6</span><span><span>, pi </span><span>/</span><span> </span></span><span>3</span><span><span>, pi </span><span>/</span><span> </span></span><span>6</span><span><span>, pi </span><span>/</span><span> </span></span><span>3</span><span>])</span></div></div><div><div><div>69</div></div><div>
</div></div><div><div><div>70</div></div><div>
</div></div><div><div><div>71</div></div><div><span>if</span><span> </span><span>__name__</span><span><span> </span><span>==</span><span> </span></span><span>'__main__'</span><span>:   </span><span># pragma nocover</span></div></div><div><div><div>72</div></div><div><span><span>    </span></span><span>robot </span><span>=</span><span> </span><span>KR60</span><span>()</span></div></div><div><div><div>73</div></div><div><span>    </span><span>print</span><span>(robot)</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>在主程序中调用建模程序，同时对实际角度进行相应的转换，转换为D-H模型中对应的关节角进行运算。</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>import</span><span> roboticstoolbox </span><span>as</span><span> rtb</span></div></div><div><div><div>2</div></div><div><span>from</span><span> spatialmath </span><span>import</span><span><span> </span><span>SE3</span></span></div></div><div><div><div>3</div></div><div><span>from</span><span> spatialmath.base </span><span>import</span><span><span> </span><span>*</span></span></div></div><div><div><div>4</div></div><div><span>import</span><span><span> </span><span>KR60</span></span></div></div><div><div><div>5</div></div><div><span>from</span><span> math </span><span>import</span><span> pi</span></div></div><div><div><div>6</div></div><div><span>import</span><span> math</span></div></div><div><div><div>7</div></div><div><span>import</span><span> numpy</span></div></div><div><div><div>8</div></div><div><span>from</span><span> numpy </span><span>import</span><span><span> </span><span>*</span></span></div></div><div><div><div>9</div></div><div><span>import</span><span> numpy </span><span>as</span><span> np</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>def</span><span> </span><span>thetaTrans</span><span>(</span><span>q</span><span>):</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>q[</span><span>0</span><span><span>] </span><span>=</span><span> </span><span>-</span><span>q[</span></span><span>0</span><span>]</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>q[</span><span>1</span><span><span>] </span><span>=</span><span> q[</span></span><span>1</span><span>]</span></div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>q[</span><span>2</span><span><span>] </span><span>=</span><span> q[</span></span><span>2</span><span><span>] </span><span>-</span><span> pi </span><span>/</span><span> </span></span><span>2</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>q[</span><span>3</span><span><span>] </span><span>=</span><span> </span><span>-</span><span>q[</span></span><span>3</span><span>]</span></div></div><div><div><div>16</div></div><div><span><span>    </span></span><span>q[</span><span>4</span><span><span>] </span><span>=</span><span> q[</span></span><span>4</span><span>]</span></div></div><div><div><div>17</div></div><div><span><span>    </span></span><span>q[</span><span>5</span><span><span>] </span><span>=</span><span> pi </span><span>-</span><span> q[</span></span><span>5</span><span>]</span></div></div><div><div><div>18</div></div><div><span>    </span><span>return</span><span> q</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span><span>q </span><span>=</span><span> [</span><span>-</span></span><span>2.410000</span><span><span> </span><span>/</span><span> </span></span><span>180</span><span><span> </span><span>*</span><span> pi, </span><span>-</span></span><span>57.230000</span><span><span> </span><span>/</span><span> </span></span><span>180</span><span><span> </span><span>*</span><span> pi, </span></span><span>112.080000</span><span><span> </span><span>/</span><span> </span></span><span>180</span><span><span> </span><span>*</span><span> pi, </span><span>-</span></span><span>0.780000</span><span><span> </span><span>/</span><span> </span></span><span>180</span><span><span> </span><span>*</span><span> pi, </span><span>-</span></span><span>54.890000</span><span><span> </span><span>/</span><span> </span></span><span>180</span><span><span> </span><span>*</span><span> pi,</span></span></div></div><div><div><div>21</div></div><div><span>     </span><span>1.440000</span><span><span> </span><span>/</span><span> </span></span><span>180</span><span><span> </span><span>*</span><span> pi]</span></span></div></div><div><div><div>22</div></div><div><span><span>q </span><span>=</span><span> </span><span>thetaTrans</span><span>(q)</span></span></div></div><div><div><div>23</div></div><div><span>print</span><span>(q)</span></div></div><div><div><div>24</div></div><div>
</div></div><div><div><div>25</div></div><div><span><span>robot </span><span>=</span><span> </span><span>KR60</span><span>.</span><span>KR60</span><span>()</span></span></div></div><div><div><div>26</div></div><div><span><span>T </span><span>=</span><span> robot.</span><span>fkine</span><span>(q)</span></span></div></div><div><div><div>27</div></div><div><span>print</span><span>(T)</span></div></div><div><div><div>28</div></div><div><span><span>T.</span><span>printline</span><span>()</span></span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>得到的结果为</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>[0.04206243497306334, -0.9988519309163547, 0.38536869884034797, 0.01361356816555577, -0.9580112264196875, 3.1164599123610746]</span></div></div><div><div><div>2</div></div><div><span><span>   </span></span><span>0.001189 -0.03091   0.9995    1.569</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>-0.01727   0.9994    0.03092   0.06416</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>-0.9999   -0.01729   0.0006545  0.9428</span></div></div><div><div><div>5</div></div><div><span><span>   </span></span><span>0         0         0         1</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>t = 1.57, 0.0642, 0.943; rpy/zyx = -87.8°, 89°, -86.1°</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>（3）**<a href="https://github.com/petercorke/spatialmath-python" target="_blank"> spatialmath-python</a>**库<a href="#3-spatialmath-python库"><span>#</span></a></h3><section><h4>1.函数说明<a href="#1函数说明"><span>#</span></a></h4><p>spatialmath-python库提供了旋转角度，旋转矩阵，四元素，变换矩阵之间的转换函数。</p><p>例如，我们可以创建一个刚体变换，它是围绕 x 轴旋转 30 度：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>&gt;&gt;&gt;</span><span> </span></span><span>from</span><span> spatialmath.base </span><span>import</span><span><span> </span><span>*</span></span></div></div><div><div><div>2</div></div><div><span><span>&gt;&gt;&gt;</span><span> </span><span>rotx</span><span>(</span></span><span>30</span><span>, </span><span>'deg'</span><span>)</span></div></div><div><div><div>3</div></div><div><span><span>array</span><span>([[ </span></span><span>1</span><span>.   ,  </span><span>0</span><span>.   ,  </span><span>0</span><span>.   ],</span></div></div><div><div><div>4</div></div><div><span><span>       </span></span><span>[ </span><span>0</span><span>.   ,  </span><span>0.866</span><span><span>, </span><span>-</span></span><span>0.5</span><span>  ],</span></div></div><div><div><div>5</div></div><div><span><span>       </span></span><span>[ </span><span>0</span><span>.   ,  </span><span>0.5</span><span>  ,  </span><span>0.866</span><span>]])</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>这将导致一个 NumPy（4x4）数组，该数组属于组（SE3）。我们还可以创建一个类实例：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&gt;&gt;&gt; from spatialmath import *</span></div></div><div><div><div>2</div></div><div><span>&gt;&gt;&gt; T = SE3.Rx(30, 'deg')</span></div></div><div><div><div>3</div></div><div><span>&gt;&gt;&gt; type(T)</span></div></div><div><div><div>4</div></div><div><span>&lt;class 'spatialmath.pose3d.SE3'&gt;</span></div></div><div><div><div>5</div></div><div><span>&gt;&gt;&gt; print(T)</span></div></div><div><div><div>6</div></div><div><span><span>   </span></span><span>1         0         0         0</span></div></div><div><div><div>7</div></div><div><span><span>   </span></span><span>0         0.866    -0.5       0</span></div></div><div><div><div>8</div></div><div><span><span>   </span></span><span>0         0.5       0.866     0</span></div></div><div><div><div>9</div></div><div><span><span>   </span></span><span>0         0         0         1</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>它在内部表示为4*4 NumPy 数组。</p><p>虽然函数和类可以提供类似的功能，但该类具有以下优点：</p><ul>
<li>类型安全，不可能将3D旋转矩阵与2D刚体运动混合，即使两者都由3*3矩阵表示</li>
<li>运算符重载允许方便和可读的算法表达</li>
<li>表示的不仅仅是单个值，而是一系列值，这些值由运算符通过隐式广播值进行处理</li>
</ul></section><section><h4>2.Spatial math 类<a href="#2spatial-math-类"><span>#</span></a></h4><p>如上述所表示的SO3类R,可以计算出相应的欧拉角</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>&gt;&gt;</span><span> R.</span><span>eul</span><span>()</span></span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>在机器人技术中，我们经常需要一个序列，一个轨迹，旋转矩阵或姿势。这些姿势类从类继承功能<code>list</code></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>&gt;&gt;&gt;</span><span> R </span><span>=</span><span> </span><span>SO3</span><span>()   </span></span><span># the identity</span></div></div><div><div><div>2</div></div><div><span><span>&gt;&gt;&gt;</span><span> R.</span><span>append</span><span>(R1)</span></span></div></div><div><div><div>3</div></div><div><span><span>&gt;&gt;&gt;</span><span> R.</span><span>append</span><span>(R2)</span></span></div></div><div><div><div>4</div></div><div><span><span>&gt;&gt;&gt;</span><span> </span></span><span>len</span><span>(R)</span></div></div><div><div><div>5</div></div><div><span> </span><span>3</span></div></div><div><div><div>6</div></div><div><span><span>&gt;&gt;&gt;</span><span> R[</span></span><span>1</span><span>]</span></div></div><div><div><div>7</div></div><div><span>   </span><span>1</span><span>         </span><span>0</span><span>         </span><span>0</span></div></div><div><div><div>8</div></div><div><span>   </span><span>0</span><span>         </span><span>0.955336</span><span><span> </span><span>-</span></span><span>0.29552</span></div></div><div><div><div>9</div></div><div><span>   </span><span>0</span><span>         </span><span>0.29552</span><span>   </span><span>0.955336</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>这可以在循环和列表理解中使用<code>for</code></p><p>构造它的另一种方法是（在上面定义的<code>R1 R2</code>）</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>&gt;&gt;&gt;</span><span> R </span><span>=</span><span> </span><span>SO3</span><span>( [ </span><span>SO3</span><span>(), R1, R2 ] )</span></span></div></div><div><div><div>2</div></div><div><span><span>&gt;&gt;&gt;</span><span> </span></span><span>len</span><span>(R)</span></div></div><div><div><div>3</div></div><div><span> </span><span>3</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>许多构造函数支持矢量化，例如 <code>.Rx</code>, <code>.Ry</code> and <code>.Rz</code></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>&gt;&gt;&gt;</span><span> R </span><span>=</span><span> </span><span>SO3</span><span>.</span><span>Rx</span><span>( np.</span><span>arange</span><span>(</span></span><span>0</span><span>, </span><span>2</span><span><span>*</span><span>np.pi, </span></span><span>0.2</span><span>))</span></div></div><div><div><div>2</div></div><div><span><span>&gt;&gt;&gt;</span><span> </span></span><span>len</span><span>(R)</span></div></div><div><div><div>3</div></div><div><span> </span><span>32</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>它在一行中创建了旋转矩阵列表。</p><p>矢量化也适用于运算符，例如</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&gt;&gt;&gt; A = R * SO3.Ry(0.5)</span></div></div><div><div><div>2</div></div><div><span>&gt;&gt;&gt; len(R)</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>32</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>将产生一个结果，其中每个元素都是左侧与右侧的每个元素的乘积，即。 <code>R[i] * SO3.Ry(0.5)</code>.</p><p>同样地</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&gt;&gt;&gt; A = SO3.Ry(0.5) * R</span></div></div><div><div><div>2</div></div><div><span>&gt;&gt;&gt; len(R)</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>32</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>将产生一个结果，其中每个元素都是左侧的乘积，即右侧的每个元素。.<code>SO3.Ry(0.5) * R[i]</code></p><p>最后</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&gt;&gt;&gt; A = R * R</span></div></div><div><div><div>2</div></div><div><span>&gt;&gt;&gt; len(R)</span></div></div><div><div><div>3</div></div><div><span><span> </span></span><span>32</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>将产生一个结果，其中每个元素是左侧每个元素与右侧每个元素的乘积，即。.<code>R[i] * R[i]</code></p><p>这些类的基础表示是一个 numpy 矩阵，但该类确保该矩阵的结构对于所表示的特定类有效：SO（2）、SE（2）、SO（3）、SE（3）。任何对类无效的操作都将返回矩阵而不是 pose 类，例如</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&gt;&gt;&gt; SO3.Rx(0.3) * 2</span></div></div><div><div><div>2</div></div><div><span>array([[ 2.        ,  0.        ,  0.        ],</span></div></div><div><div><div>3</div></div><div><span><span>       </span></span><span>[ 0.        ,  1.91067298, -0.59104041],</span></div></div><div><div><div>4</div></div><div><span><span>       </span></span><span>[ 0.        ,  0.59104041,  1.91067298]])</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span>&gt;&gt;&gt; SO3.Rx(0.3) - 1</span></div></div><div><div><div>7</div></div><div><span>array([[ 0.        , -1.        , -1.        ],</span></div></div><div><div><div>8</div></div><div><span><span>       </span></span><span>[-1.        , -0.04466351, -1.29552021],</span></div></div><div><div><div>9</div></div><div><span><span>       </span></span><span>[-1.        , -0.70447979, -0.04466351]])</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>我们也可以打印和打印这些对象</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&gt;&gt;&gt; T = SE3(1,2,3) * SE3.Rx(30, 'deg')</span></div></div><div><div><div>2</div></div><div><span>&gt;&gt;&gt; T.print()</span></div></div><div><div><div>3</div></div><div><span><span>   </span></span><span>1         0         0         1</span></div></div><div><div><div>4</div></div><div><span><span>   </span></span><span>0         0.866025 -0.5       2</span></div></div><div><div><div>5</div></div><div><span><span>   </span></span><span>0         0.5       0.866025  3</span></div></div><div><div><div>6</div></div><div><span><span>   </span></span><span>0         0         0         1</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span>&gt;&gt;&gt; T.printline()</span></div></div><div><div><div>9</div></div><div><span>t =        1,        2,        3; rpy/zyx =       30,        0,        0 deg</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>&gt;&gt;&gt; T.plot()</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section></section></section></section>
<section><h1>二、VREP与PYTHON<a href="#二vrep与python"><span>#</span></a></h1><section><h2>1.建立URDF模型<a href="#1建立urdf模型"><span>#</span></a></h2><p>准备工作：下载solidworks导出urdf文件的插件：<a href="http://wiki.ros.org/sw_urdf_exporter" target="_blank">http://wiki.ros.org/sw_urdf_exporter</a> ，下载直接安装即可。</p><ol>
<li>
<p>去库卡官网下载KR60-3的STL模型</p>
</li>
<li>
<p>按照面重合-轴线重合的方式，装配好机器人模型。</p>
</li>
<li>
<p>在装配体中编辑零件，提取关节基准轴，以第六轴为例，命名为axis_6</p>
</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/20201128145008144.png" alt="img" /><figcaption>img</figcaption></figure><p></p><p></p><figure><img src="http://imgbed.leihub.cn/img/20201128142831325.png" alt="img" /><figcaption>img</figcaption></figure><p></p><ol>
<li>对各关节建立起相应的轴线之后，退出零件编辑，返回装配体设置，对基座、关节以及刀具建立坐标系，注意所建立的坐标系不能在零件的内部，必须在装配体的树形目录下，坐标系的Z轴指向关节旋转方向。</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/20201129062407480.png" alt="img" /><figcaption>img</figcaption></figure><p></p><ol>
<li>
<p>点击工具-tool-export as URDF,轴和坐标系之前建立的关节轴线和坐标轴，零件选择相应的杆件，轴的类型都选择旋转副。</p>
</li>
<li>
<p></p><figure><img src="http://imgbed.leihub.cn/img/20201128145539590.png" alt="img" /><figcaption>img</figcaption></figure>导出URDF文件，在最后的配置文件中可以调整杆件的颜色<p></p>
</li>
</ol></section><section><h2>2.导入VREP<a href="#2导入vrep"><span>#</span></a></h2><ol>
<li>
<p>在Vrep中，Plugins-URDF export导入模型文件，注意导入路径不能有中文，否则导入会失败。</p>
</li>
<li>
<p>将基座设置为固定，调整相应的杆件关节极限,运动模式修改为Torque/force mode。进一步修改杆件的动力学信息，使能电动机，将电动机的最大力矩调整为合适的大小，打开control position enable，修改关节速度极限，这样就可以在脚本中修改关节数据，使机器人按我们设定的轨迹运动。</p>
</li>
<li>
<p>添加运动脚本，ADD-Associated child scripts-no thread scripts。</p>
<p>API解释见：<a href="https://coppeliarobotics.com/helpFiles/en/apiFunctions.htm" target="_blank">regular API reference (coppeliarobotics.com)</a></p>
<p>Lua脚本分为4部分，包含由系统适当调用的回调函数集合。除了初始化回调之外，所有其他回调都是可选的。默认主脚本通常分为4个回调函数：</p>
<p>初始化函数：sysCall_init（）。此回调函数不是可选的。它将在模拟开始时执行一次。代码负责准备模拟等。通过sim.getObjectHandle函数初始化各关节的句柄</p>
<p>驱动函数：sysCall_actuation()。此回调函数将在每次模拟过程中执行。代码负责处理模拟的所有驱动功能。有一个函数特别有趣：sim.HandleChildScript，它调用子脚本的系统调用回调函数。如果没有这些命令，子脚本将无法执行或无法执行其驱动功能，特定的模型功能或行为也无法按预期运行。</p>
<p>传感函数：sysCall_sensing()。此回调函数将在每次模拟过程中执行。代码负责以通用方式处理模拟的所有传感功能（接近传感器等）。同样也有sim.HandleChildScript，它调用子脚本的系统调用回调函数。</p>
<p>恢复函数：sysCall_cleanup()。此函数将在模拟结束前执行一次。该代码负责恢复对象的初始配置、清除传感器状态等。</p>
<div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>function</span><span> </span><span>sysCall_init</span><span>()</span></div></div><div><div><div>2</div></div><div><span>    </span><span>-- do some initialization here</span></div></div><div><div><div>3</div></div><div><span>    </span><span>axis_1_handle</span><span> = </span><span>sim</span><span>.</span><span>getObjectHandle</span><span>(</span><span>'axis_1'</span><span>)</span></div></div><div><div><div>4</div></div><div><span>    </span><span>axis_2_handle</span><span> = </span><span>sim</span><span>.</span><span>getObjectHandle</span><span>(</span><span>'axis_2'</span><span>)</span></div></div><div><div><div>5</div></div><div><span>    </span><span>axis_3_handle</span><span> = </span><span>sim</span><span>.</span><span>getObjectHandle</span><span>(</span><span>'axis_3'</span><span>)</span></div></div><div><div><div>6</div></div><div><span>    </span><span>axis_4_handle</span><span> = </span><span>sim</span><span>.</span><span>getObjectHandle</span><span>(</span><span>'axis_4'</span><span>)</span></div></div><div><div><div>7</div></div><div><span>    </span><span>axis_5_handle</span><span> = </span><span>sim</span><span>.</span><span>getObjectHandle</span><span>(</span><span>'axis_5'</span><span>)</span></div></div><div><div><div>8</div></div><div><span>    </span><span>axis_6_handle</span><span> = </span><span>sim</span><span>.</span><span>getObjectHandle</span><span>(</span><span>'axis_6'</span><span>)</span></div></div><div><div><div>9</div></div><div><span>    </span><span>t</span><span> = </span><span>0</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>    </span><span>--graph</span></div></div><div><div><div>12</div></div><div><span>    </span><span>graph</span><span>=</span><span>sim</span><span>.</span><span>getObjectHandle</span><span>(</span><span>'Graph'</span><span>)</span></div></div><div><div><div>13</div></div><div><span>    </span><span>JointPos</span><span>=</span><span>sim</span><span>.</span><span>getObjectHandle</span><span>(</span><span>'JointPos'</span><span>)</span></div></div><div><div><div>14</div></div><div>
</div></div><div><div><div>15</div></div><div><span>    </span><span>objectPosX</span><span>=</span><span>sim</span><span>.</span><span>addGraphStream</span><span>(</span><span>graph</span><span>,</span><span>'object pos x'</span><span>,</span><span>'m'</span><span>,</span><span>1</span><span>)</span></div></div><div><div><div>16</div></div><div><span>    </span><span>objectPosY</span><span>=</span><span>sim</span><span>.</span><span>addGraphStream</span><span>(</span><span>graph</span><span>,</span><span>'object pos y'</span><span>,</span><span>'m'</span><span>,</span><span>1</span><span>)</span></div></div><div><div><div>17</div></div><div><span>    </span><span>objectPosZ</span><span>=</span><span>sim</span><span>.</span><span>addGraphStream</span><span>(</span><span>graph</span><span>,</span><span>'object pos Z'</span><span>,</span><span>'m'</span><span>,</span><span>1</span><span>)</span></div></div><div><div><div>18</div></div><div>
</div></div><div><div><div>19</div></div><div><span>    </span><span>objectJoint1</span><span>=</span><span>sim</span><span>.</span><span>addGraphStream</span><span>(</span><span>JointPos</span><span>,</span><span>'Joint1'</span><span>,</span><span>'deg/s'</span><span>,</span><span>0</span><span>,{</span><span>1</span><span>,</span><span>0</span><span>,</span><span>0</span><span>})</span></div></div><div><div><div>20</div></div><div><span>    </span><span>objectJoint2</span><span>=</span><span>sim</span><span>.</span><span>addGraphStream</span><span>(</span><span>JointPos</span><span>,</span><span>'Joint2'</span><span>,</span><span>'deg/s'</span><span>,</span><span>0</span><span>,{</span><span>1</span><span>,</span><span>0.5</span><span>,</span><span>0</span><span>})</span></div></div><div><div><div>21</div></div><div><span>    </span><span>objectJoint3</span><span>=</span><span>sim</span><span>.</span><span>addGraphStream</span><span>(</span><span>JointPos</span><span>,</span><span>'Joint3'</span><span>,</span><span>'deg/s'</span><span>,</span><span>0</span><span>,{</span><span>1</span><span>,</span><span>1</span><span>,</span><span>0</span><span>})</span></div></div><div><div><div>22</div></div><div><span>    </span><span>objectJoint4</span><span>=</span><span>sim</span><span>.</span><span>addGraphStream</span><span>(</span><span>JointPos</span><span>,</span><span>'Joint4'</span><span>,</span><span>'deg/s'</span><span>,</span><span>0</span><span>,{</span><span>1</span><span>,</span><span>0</span><span>,</span><span>0.5</span><span>})</span></div></div><div><div><div>23</div></div><div><span>    </span><span>objectJoint5</span><span>=</span><span>sim</span><span>.</span><span>addGraphStream</span><span>(</span><span>JointPos</span><span>,</span><span>'Joint5'</span><span>,</span><span>'deg/s'</span><span>,</span><span>0</span><span>,{</span><span>1</span><span>,</span><span>0</span><span>,</span><span>1</span><span>})</span></div></div><div><div><div>24</div></div><div><span>    </span><span>objectJoint6</span><span>=</span><span>sim</span><span>.</span><span>addGraphStream</span><span>(</span><span>JointPos</span><span>,</span><span>'Joint6'</span><span>,</span><span>'deg/s'</span><span>,</span><span>0</span><span>,{</span><span>1</span><span>,</span><span>1</span><span>,</span><span>1</span><span>})</span></div></div><div><div><div>25</div></div><div>
</div></div><div><div><div>26</div></div><div><span>    </span><span>objectTime</span><span>=</span><span>sim</span><span>.</span><span>addGraphStream</span><span>(</span><span>JointPos</span><span>,</span><span>'Time'</span><span>,</span><span>'m'</span><span>,</span><span>1</span><span>)</span></div></div><div><div><div>27</div></div><div>
</div></div><div><div><div>28</div></div><div><span>    </span><span>sim</span><span>.</span><span>addGraphCurve</span><span>(</span><span>graph</span><span>,</span><span>'object pos x/y/z'</span><span>,</span><span>3</span><span>,{</span><span>objectPosX</span><span>,</span><span>objectPosY</span><span>,</span><span>objectPosZ</span><span>},{</span><span>0</span><span>,</span><span>0</span><span>,</span><span>0</span><span>},</span><span>'m by m'</span><span>)</span></div></div><div><div><div>29</div></div><div><span>    </span><span>sim</span><span>.</span><span>addGraphCurve</span><span>(</span><span>JointPos</span><span>,</span><span>'Joint1'</span><span>,</span><span>2</span><span>,{</span><span>objectJoint1</span><span>,</span><span>objectTime</span><span>},{</span><span>0</span><span>,</span><span>0</span><span>,</span><span>0</span><span>},</span><span>'m by m'</span><span>)</span></div></div><div><div><div>30</div></div><div>
</div></div><div><div><div>31</div></div><div><span>    </span><span>--base frame</span></div></div><div><div><div>32</div></div><div><span>    </span><span>base_frame</span><span> = </span><span>sim</span><span>.</span><span>getObjectHandle</span><span>(</span><span>'baseframe'</span><span>)</span></div></div><div><div><div>33</div></div><div><span>end</span></div></div><div><div><div>34</div></div><div>
</div></div><div><div><div>35</div></div><div><span>function</span><span> </span><span>sysCall_actuation</span><span>()</span></div></div><div><div><div>36</div></div><div><span>    </span><span>-- put your actuation code here</span></div></div><div><div><div>37</div></div><div>
</div></div><div><div><div>38</div></div><div><span>    </span><span>t</span><span> = </span><span>t</span><span> + </span><span>0.01</span></div></div><div><div><div>39</div></div><div><span>    </span><span>--print(t)</span></div></div><div><div><div>40</div></div><div>
</div></div><div><div><div>41</div></div><div><span>    </span><span>axis_1_angle</span><span> = </span><span>sim</span><span>.</span><span>getJointPosition</span><span>(</span><span>axis_1_handle</span><span>)</span></div></div><div><div><div>42</div></div><div><span>    </span><span>axis_2_angle</span><span> = </span><span>sim</span><span>.</span><span>getJointPosition</span><span>(</span><span>axis_2_handle</span><span>)</span></div></div><div><div><div>43</div></div><div><span>    </span><span>axis_3_angle</span><span> = </span><span>sim</span><span>.</span><span>getJointPosition</span><span>(</span><span>axis_3_handle</span><span>)</span></div></div><div><div><div>44</div></div><div><span>    </span><span>axis_4_angle</span><span> = </span><span>sim</span><span>.</span><span>getJointPosition</span><span>(</span><span>axis_4_handle</span><span>)</span></div></div><div><div><div>45</div></div><div><span>    </span><span>axis_5_angle</span><span> = </span><span>sim</span><span>.</span><span>getJointPosition</span><span>(</span><span>axis_5_handle</span><span>)</span></div></div><div><div><div>46</div></div><div><span>    </span><span>axis_6_angle</span><span> = </span><span>sim</span><span>.</span><span>getJointPosition</span><span>(</span><span>axis_6_handle</span><span>)</span></div></div><div><div><div>47</div></div><div>
</div></div><div><div><div>48</div></div><div><span>    </span><span>axis_1_targetAngle</span><span> = </span><span>math.pi</span><span> / </span><span>3</span><span> * </span><span>math.sin</span><span>(</span><span>t</span><span>)</span></div></div><div><div><div>49</div></div><div><span>    </span><span>axis_2_targetAngle</span><span> = -</span><span>math.pi</span><span>/</span><span>2</span><span> * </span><span>math.sin</span><span>(</span><span>t</span><span>)</span></div></div><div><div><div>50</div></div><div><span>    </span><span>axis_3_targetAngle</span><span> = </span><span>math.pi</span><span>/</span><span>2</span><span> * </span><span>math.sin</span><span>(</span><span>t</span><span>)</span></div></div><div><div><div>51</div></div><div><span>    </span><span>axis_4_targetAngle</span><span> = </span><span>math.pi</span><span>/</span><span>4</span><span> * </span><span>math.sin</span><span>(</span><span>t</span><span>)</span></div></div><div><div><div>52</div></div><div><span>    </span><span>axis_5_targetAngle</span><span> = </span><span>math.pi</span><span>/</span><span>6</span><span> * </span><span>math.sin</span><span>(</span><span>t</span><span>)</span></div></div><div><div><div>53</div></div><div><span>    </span><span>axis_6_targetAngle</span><span> = </span><span>math.pi</span><span>/</span><span>5</span><span> * </span><span>math.sin</span><span>(</span><span>t</span><span>)</span></div></div><div><div><div>54</div></div><div>
</div></div><div><div><div>55</div></div><div><span>    </span><span>--print(180*sim.getJointPosition(axis_6_handle)/math.pi)</span></div></div><div><div><div>56</div></div><div>
</div></div><div><div><div>57</div></div><div><span>    </span><span>--print(180*sim.getJointPosition(axis_1_handle)/math.pi)</span></div></div><div><div><div>58</div></div><div><span>    </span><span>--print(axis_1_targetAngle)</span></div></div><div><div><div>59</div></div><div><span>    </span><span>sim</span><span>.</span><span>setJointTargetPosition</span><span>(</span><span>axis_1_handle</span><span>,</span><span>axis_1_targetAngle</span><span>)</span></div></div><div><div><div>60</div></div><div><span>    </span><span>sim</span><span>.</span><span>setJointTargetPosition</span><span>(</span><span>axis_2_handle</span><span>,</span><span>axis_2_targetAngle</span><span>)</span></div></div><div><div><div>61</div></div><div><span>    </span><span>sim</span><span>.</span><span>setJointTargetPosition</span><span>(</span><span>axis_3_handle</span><span>,</span><span>axis_3_targetAngle</span><span>)</span></div></div><div><div><div>62</div></div><div><span>    </span><span>sim</span><span>.</span><span>setJointTargetPosition</span><span>(</span><span>axis_4_handle</span><span>,</span><span>axis_4_targetAngle</span><span>)</span></div></div><div><div><div>63</div></div><div><span>    </span><span>sim</span><span>.</span><span>setJointTargetPosition</span><span>(</span><span>axis_5_handle</span><span>,</span><span>axis_5_targetAngle</span><span>)</span></div></div><div><div><div>64</div></div><div><span>    </span><span>sim</span><span>.</span><span>setJointTargetPosition</span><span>(</span><span>axis_6_handle</span><span>,</span><span>axis_6_targetAngle</span><span>)</span></div></div><div><div><div>65</div></div><div><span>    </span><span>--print(axis_1_angle)</span></div></div><div><div><div>66</div></div><div><span>    </span><span>--print(axis_2_angle)</span></div></div><div><div><div>67</div></div><div><span>    </span><span>--print(axis_2_targetAngle)</span></div></div><div><div><div>68</div></div><div>
</div></div><div><div><div>69</div></div><div>
</div></div><div><div><div>70</div></div><div><span>end</span></div></div><div><div><div>71</div></div><div>
</div></div><div><div><div>72</div></div><div><span>function</span><span> </span><span>sysCall_sensing</span><span>()</span></div></div><div><div><div>73</div></div><div><span>    </span><span>-- put your sensing code here</span></div></div><div><div><div>74</div></div><div><span>    </span><span>local</span><span> </span><span>pos</span><span>=</span><span>sim</span><span>.</span><span>getObjectPosition</span><span>(</span><span>graph</span><span>,-</span><span>1</span><span>)</span></div></div><div><div><div>75</div></div><div><span>    </span><span>--print(pos)</span></div></div><div><div><div>76</div></div><div>
</div></div><div><div><div>77</div></div><div><span>    </span><span>sim</span><span>.</span><span>setGraphStreamValue</span><span>(</span><span>graph</span><span>,</span><span>objectPosX</span><span>,</span><span>pos</span><span>[</span><span>1</span><span>])</span></div></div><div><div><div>78</div></div><div><span>    </span><span>sim</span><span>.</span><span>setGraphStreamValue</span><span>(</span><span>graph</span><span>,</span><span>objectPosY</span><span>,</span><span>pos</span><span>[</span><span>2</span><span>])</span></div></div><div><div><div>79</div></div><div><span>    </span><span>sim</span><span>.</span><span>setGraphStreamValue</span><span>(</span><span>graph</span><span>,</span><span>objectPosZ</span><span>,</span><span>pos</span><span>[</span><span>3</span><span>])</span></div></div><div><div><div>80</div></div><div>
</div></div><div><div><div>81</div></div><div><span>    </span><span>sim</span><span>.</span><span>setGraphStreamValue</span><span>(</span><span>JointPos</span><span>,</span><span>objectJoint1</span><span>,</span><span>180</span><span>*</span><span>sim</span><span>.</span><span>getJointPosition</span><span>(</span><span>axis_1_handle</span><span>)/</span><span>math.pi</span><span>)</span></div></div><div><div><div>82</div></div><div><span>    </span><span>sim</span><span>.</span><span>setGraphStreamValue</span><span>(</span><span>JointPos</span><span>,</span><span>objectJoint2</span><span>,</span><span>180</span><span>*</span><span>sim</span><span>.</span><span>getJointPosition</span><span>(</span><span>axis_2_handle</span><span>)/</span><span>math.pi</span><span>)</span></div></div><div><div><div>83</div></div><div><span>    </span><span>sim</span><span>.</span><span>setGraphStreamValue</span><span>(</span><span>JointPos</span><span>,</span><span>objectJoint3</span><span>,</span><span>180</span><span>*</span><span>sim</span><span>.</span><span>getJointPosition</span><span>(</span><span>axis_3_handle</span><span>)/</span><span>math.pi</span><span>)</span></div></div><div><div><div>84</div></div><div><span>    </span><span>sim</span><span>.</span><span>setGraphStreamValue</span><span>(</span><span>JointPos</span><span>,</span><span>objectJoint4</span><span>,</span><span>180</span><span>*</span><span>sim</span><span>.</span><span>getJointPosition</span><span>(</span><span>axis_4_handle</span><span>)/</span><span>math.pi</span><span>)</span></div></div><div><div><div>85</div></div><div><span>    </span><span>sim</span><span>.</span><span>setGraphStreamValue</span><span>(</span><span>JointPos</span><span>,</span><span>objectJoint5</span><span>,</span><span>180</span><span>*</span><span>sim</span><span>.</span><span>getJointPosition</span><span>(</span><span>axis_5_handle</span><span>)/</span><span>math.pi</span><span>)</span></div></div><div><div><div>86</div></div><div><span>    </span><span>sim</span><span>.</span><span>setGraphStreamValue</span><span>(</span><span>JointPos</span><span>,</span><span>objectJoint6</span><span>,</span><span>180</span><span>*</span><span>sim</span><span>.</span><span>getJointPosition</span><span>(</span><span>axis_6_handle</span><span>)/</span><span>math.pi</span><span>)</span></div></div><div><div><div>87</div></div><div>
</div></div><div><div><div>88</div></div><div><span>    </span><span>--Joint1={}</span></div></div><div><div><div>89</div></div><div><span>    </span><span>--table.insert(Joint1,axis_1_angle)</span></div></div><div><div><div>90</div></div><div><span>    </span><span>--sim.setGraphStreamValue(JointPos,objectJoint1,Joint1)</span></div></div><div><div><div>91</div></div><div><span>end</span></div></div><div><div><div>92</div></div><div>
</div></div><div><div><div>93</div></div><div><span>function</span><span> </span><span>sysCall_cleanup</span><span>()</span></div></div><div><div><div>94</div></div><div><span>    </span><span>-- do some clean-up here</span></div></div><div><div><div>95</div></div><div><span>end</span></div></div><div><div><div>96</div></div><div>
</div></div><div><div><div>97</div></div><div><span>-- See the user manual or the available code snippets for additional callback functions and details</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div>
<ol>
<li>点击仿真进行按钮，机器人就按着脚本中关节设置的轨迹进行移动，同时在空间中绘制出末端的运行轨迹，在弹出的框中也可以看到末端在XY平面的轨迹。</li>
</ol>
</li>
</ol></section><section><h2>3.联合仿真<a href="#3联合仿真"><span>#</span></a></h2><p>Vrep提供了三种远程api，远程API是应用程序与CoppeliaSim连接的几种方式之一。它允许CoppeliaSim和外部应用程序（即在不同进程或不同机器上运行的应用程序）之间的通信，是跨平台的，支持服务调用（即阻塞调用），还支持双向数据流。它有三种不同的版本/框架：</p><p><a href="https://coppeliarobotics.com/helpFiles/en/zmqRemoteApiOverview.htm" target="_blank">The ZeroMQ-based remote API</a>：它轻量级且易于使用，提供了通过CoppeliaSim脚本也可用的所有API函数，目前支持Python客户端。</p><p><a href="https://coppeliarobotics.com/helpFiles/en/legacyRemoteApiOverview.htm" target="_blank">The legacy remote API</a> (or simply <em>remote API</em>)：它相对轻量级，并且比基于B0的远程API具有更少的依赖性。它提供了API函数的子集，并支持以下客户端：C/C++、Java、Python、Matlab、Octave和Lua。</p><p><a href="https://coppeliarobotics.com/helpFiles/en/b0RemoteApiOverview.htm" target="_blank">The B0-based remote API</a>：它基于BlueZero中间件及其与CoppeliaSim的接口插件。它提供了API函数的子集，可以很容易地扩展和支持以下客户端：C++、java、python、Matlab和Lua。</p><section><h3>1.Vrep与matlab联合仿真<a href="#1vrep与matlab联合仿真"><span>#</span></a></h3><section><h4><a href="https://coppeliarobotics.com/helpFiles/en/legacyRemoteApiOverview.htm" target="_blank">Legacy remote API</a><a href="#legacy-remote-api"><span>#</span></a></h4><p>要在Matlab程序中使用远程API功能，需要以下3项：</p><ul>
<li>
<p>remoteApiProto.m</p>
</li>
<li>
<p>remApi.m</p>
</li>
<li>
<p>remoteApi.dll</p>
<ul>
<li>
<p>新建一个matlab项目文件夹</p>
</li>
<li>
<p>将C:\Program Files\CoppeliaRobotics\CoppeliaSimEdu\programming\remoteApiBindings\matlab\matlab中所有的文件拷贝到相应的matlab项目文件夹中。</p>
</li>
<li>
<p>转到C:\Program Files\CoppeliaRobotics\CoppeliaSimEdu文件夹，调整类型只显示应用程序拓展，全选所有的DLL文件，拷贝到matlab文件夹。</p>
</li>
<li>
<p>remoteapi.dll在C:\Program Files\CoppeliaRobotics\CoppeliaSimEdu\programming\remoteApiBindings\lib\lib\Windows文件夹中，同样拷贝到项目文件夹</p>
</li>
<li>
<p>打开matlab，将项目文件夹包含到预定路径中，使程序在运行中能调用相应的函数和dll文件。</p>
</li>
</ul>
</li>
</ul><p>在Matlab的当前文件夹中包含上述文件后，调用sim=remApi（‘remoteApi’）来构建对象并加载库。要在客户端（即您的应用程序）启用远程API，请调用sim.simxStart。请参阅simpleTest。以编程/remoteApiBindings/matlab目录中的m程序为例。本页列出并描述所有支持的Matlab远程API函数。CoppeliaSim远程API函数可以很容易地从它们的“simx”前缀中识别出来。
确保您的Matlab使用与remoteApi库相同的位体系结构：64位Matlab和32位remoteApi库将无法工作，反之亦然！</p><p>关键的语句</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>V</span><span>-REP端：</span></div></div><div><div><div>2</div></div><div><span>simExtRemoteApiStart</span><span>(</span><span>19999</span><span>)</span></div></div></code></pre><div><div></div><div></div></div></figure></div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>MATLAB端：</span></div></div><div><div><div>2</div></div><div><span>vrep=remApi(</span><span>'remoteApi'</span><span>); </span><span>% using the prototype file (remoteApiProto.m)</span></div></div><div><div><div>3</div></div><div><span>vrep.simxFinish(-</span><span>1</span><span>); </span><span>% just in case, close all opened connections</span></div></div><div><div><div>4</div></div><div><span>clientID=vrep.simxStart(</span><span>'blog.leihub.cn'</span><span>,</span><span>19999</span><span>,</span><span>true</span><span>,</span><span>true</span><span>,</span><span>5000</span><span>,</span><span>5</span><span>);</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h4><a href="https://coppeliarobotics.com/helpFiles/en/b0RemoteApiOverview.htm" target="_blank">B0-based remote API</a><a href="#b0-based-remote-api"><span>#</span></a></h4><section><h5>python<a href="#python"><span>#</span></a></h5><ol>
<li>
<section><h6>要在Python脚本中使用基于B0的远程API功能，您需要以下内容：<a href="#要在python脚本中使用基于b0的远程api功能您需要以下内容"><span>#</span></a></h6></section>
</li>
</ol><ul>
<li>安装用于Python的MessagePack:<code>pip install msgpack</code></li>
<li><em>C:\Program Files\CoppeliaRobotics\CoppeliaSimEdu\programming\b0RemoteApiBindings\python\b0RemoteApi.py</em></li>
<li>C:\Program Files\CoppeliaRobotics\CoppeliaSimEdu\programming\b0RemoteApiBindings\python\b0.py。</li>
<li>blueZero库（例如b0.dll），不要忘记blueZero库本身有依赖项（例如<em>libzmq</em>, <em>boost_chrono</em>, <em>boost_system</em>, <em>boost_thread</em>等）。</li>
</ul><ol>
<li>
<section><h6>创建anaconda虚拟环境<a href="#创建anaconda虚拟环境"><span>#</span></a></h6><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>1、用conda创建Python虚拟环境（在conda prompt环境下完成）</span></div></div><div><div><div>2</div></div><div><span>conda create -n Vrep python=3.7</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span>2、激活虚拟环境（在conda prompt环境下完成）</span></div></div><div><div><div>5</div></div><div><span>activate Vrep</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>3、给虚拟环境安装外部包</span></div></div><div><div><div>8</div></div><div><span>conda install -n Vrep [package]</span></div></div><div><div><div>9</div></div><div><span>例如: conda install -n tensorflow pandas</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>4、查看已有的环境(当前已激活的环境会显示一个星号)</span></div></div><div><div><div>12</div></div><div><span>conda info -e</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span>5、删除一个已有的虚拟环境</span></div></div><div><div><div>15</div></div><div><span>conda remove --name your_env_name --all</span></div></div><div><div><div>16</div></div><div>
</div></div><div><div><div>17</div></div><div><span>6、查看pip的安装目录</span></div></div><div><div><div>18</div></div><div><span>pip list</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span>7、删除已经安装的模块</span></div></div><div><div><div>21</div></div><div><span>pip uninstall **</span></div></div><div><div><div>22</div></div><div><span>(例如：pip uninstall numpy)</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>创建anaconda的虚拟环境后，会生成E:\Anaconda\envs\Vrep的文件夹，在Pycharm中选择创建的虚拟环境。</p><ol>
<li>
<p>和matlab操作一样，打开C:\Program Files\CoppeliaRobotics\CoppeliaSimEdu文件夹，调整类型只显示应用程序拓展，全选所有的DLL文件，拷贝到anaconda创建的虚拟环境的文件夹中。b0RemoteApi.py，b0.py拷贝到项目文件夹中，在pycharm控制台中使用，<code>conda install msgpack</code>下载msgpack包</p>
</li>
<li>
<p>打开Vrep端的服务器，直接在model browser中打开tools文件夹，将B0 Remote API Server拖动到场景中，就打开了Vrep端的服务器</p>
</li>
<li>
<p>打开python端的服务器</p>
</li>
</ol></section>
</li>
</ol><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>import</span><span> b0RemoteApi</span></div></div><div><div><div>2</div></div><div><span>import</span><span> time</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span>with</span><span><span> b0RemoteApi.</span><span>RemoteApiClient</span><span>(</span></span><span>'b0RemoteApi_pythonClient'</span><span>,</span><span>'b0RemoteApi'</span><span>) </span><span>as</span><span> client:</span></div></div><div><div><div>5</div></div><div><span>    </span><span>def</span><span> </span><span>getJointPos</span><span>(</span><span>num</span><span>):</span></div></div><div><div><div>6</div></div><div><span><span>        </span></span><span>jointname </span><span>=</span><span> </span><span>"axis_"</span><span><span> </span><span>+</span><span> </span></span><span>str</span><span>(num)</span></div></div><div><div><div>7</div></div><div><span><span>        </span></span><span>[</span><span>bool</span><span><span>, jointhandle] </span><span>=</span><span> client.</span><span>simxGetObjectHandle</span><span>(jointname, client.</span><span>simxServiceCall</span><span>())</span></span></div></div><div><div><div>8</div></div><div><span><span>        </span></span><span>[</span><span>bool</span><span><span>, joint] </span><span>=</span><span> client.</span><span>simxGetJointPosition</span><span>(jointhandle, client.</span><span>simxServiceCall</span><span>())</span></span></div></div><div><div><div>9</div></div><div><span>        </span><span>print</span><span>(joint)</span></div></div><div><div><div>10</div></div><div><span>        </span><span>return</span><span> joint</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>client.</span><span>simxStartSimulation</span><span>(client.</span><span>simxServiceCall</span><span>()) </span><span>#开始仿真</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>startTime </span><span>=</span><span> time.</span><span>time</span><span>()</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>getJointPos</span><span>(</span><span>1</span><span>)</span></div></div><div><div><div>14</div></div><div><span>    </span><span>while</span><span><span> time.</span><span>time</span><span>() </span><span>&lt;</span><span> startTime </span><span>+</span><span> </span></span><span>5</span><span>:</span></div></div><div><div><div>15</div></div><div><span>        </span><span>continue</span></div></div><div><div><div>16</div></div><div><span><span>    </span></span><span>client.</span><span>simxStopSimulation</span><span>(client.</span><span>simxServiceCall</span><span>()) </span><span>#停止仿真</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h5>基于B0的远程API操作方法<a href="#基于b0的远程api操作方法"><span>#</span></a></h5><p>大多数基于B0的远程API函数需要一个附加参数：用于执行函数调用的主题或通信通道。</p><p>主题可以是以下5个函数之一的返回值：
<strong>simxServiceCall：<strong>本主题允许在阻塞模式下执行功能，即命令将传输到服务器（即CoppeLisim），在那里执行，并向客户端返回响应。仅当</strong>作为一次性操作</strong>从服务器获取命令响应时（例如，simxGetObjectHandle通常使用服务调用来执行）才使用此主题。
<strong>simxDefaultPublisher</strong>：本主题允许在非阻塞模式下执行函数，即函数被发送到服务器（即CoppeliaSim），控制权立即返回到客户端（即客户端不会等待服务器的回复）。<strong>仅在向服务器发送命令时使用此主题，您不希望/不需要服务器响应</strong>（例如，simxSetJointPosition通常使用默认发布服务器执行）。
<strong>simxDefaultSubscriber</strong>：本主题通知服务器<strong>持续执行该函数，并持续将响应流式传输到客户端</strong>。客户端将在回调函数中接收响应。仅当您希望从服务器端连续执行的同一命令接收响应时，才使用此主题。（例如，simxGetJointForce通常使用默认订阅服务器执行）。定义的回调函数通过simxSpinOnce函数调用（当输入缓冲区中有响应可用时）。
<strong>simxCreatePublisher</strong>：这与simxDefaultPublisher非常相似，不同之处在于创建了一个<strong>专用的发布者主题</strong>，即创建了一个专用的发布频道。将特定功能/命令分配给专用发布服务器非常有用，特别是在数据量大的情况下（例如，simxSetVisionSensorImage通常使用专用发布服务器执行）。
<strong>simxCreateSubscriber</strong>：这与simxDefaultSubscriber非常相似，不同之处在于创建了专用订户主题，即创建了<strong>专用订户频道</strong>。将特定功能/命令分配给专用订阅者可能很有用，特别是在数据量大的情况下（例如，simxGetVisionSensorImage通常使用专用订阅者来执行）。
默认情况下，基于B0的远程API客户端和服务器（即CoppeliaSim）将异步运行。但是，为了实现同步操作，可以让客户端单独触发每个模拟步骤。以下是同步模式的Python示例：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>import</span><span> b0RemoteApi</span></div></div><div><div><div>2</div></div><div><span>import</span><span> time</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span>with</span><span><span> b0RemoteApi.</span><span>RemoteApiClient</span><span>(</span></span><span>'b0RemoteApi_pythonClient'</span><span>,</span><span>'b0RemoteApi'</span><span>) </span><span>as</span><span> client:</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>doNextStep</span><span>=</span><span>True</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>    </span><span>def</span><span> </span><span>simulationStepStarted</span><span>(</span><span>msg</span><span>):</span></div></div><div><div><div>8</div></div><div><span><span>        </span></span><span>simTime</span><span>=</span><span>msg[</span><span>1</span><span>][</span><span>b</span><span>'simulationTime'</span><span>]</span><span>;</span></div></div><div><div><div>9</div></div><div><span>        </span><span>print</span><span>(</span><span>'Simulation step started. Simulation time: '</span><span>,simTime)</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>    </span><span>def</span><span> </span><span>simulationStepDone</span><span>(</span><span>msg</span><span>):</span></div></div><div><div><div>12</div></div><div><span><span>        </span></span><span>simTime</span><span>=</span><span>msg[</span><span>1</span><span>][</span><span>b</span><span>'simulationTime'</span><span>]</span><span>;</span></div></div><div><div><div>13</div></div><div><span>        </span><span>print</span><span>(</span><span>'Simulation step done. Simulation time: '</span><span>,simTime)</span><span>;</span></div></div><div><div><div>14</div></div><div><span>        </span><span>global</span><span> doNextStep</span></div></div><div><div><div>15</div></div><div><span><span>        </span></span><span>doNextStep</span><span>=</span><span>True</span></div></div><div><div><div>16</div></div><div>
</div></div><div><div><div>17</div></div><div><span><span>    </span></span><span>client.</span><span>simxSynchronous</span><span>(</span><span>True</span><span>)</span></div></div><div><div><div>18</div></div><div><span><span>    </span></span><span>client.</span><span>simxGetSimulationStepStarted</span><span>(client.</span><span>simxDefaultSubscriber</span><span>(simulationStepStarted))</span><span>;</span></div></div><div><div><div>19</div></div><div><span><span>    </span></span><span>client.</span><span>simxGetSimulationStepDone</span><span>(client.</span><span>simxDefaultSubscriber</span><span>(simulationStepDone))</span><span>;</span></div></div><div><div><div>20</div></div><div><span><span>    </span></span><span>client.</span><span>simxStartSimulation</span><span>(client.</span><span>simxDefaultPublisher</span><span>())</span></div></div><div><div><div>21</div></div><div>
</div></div><div><div><div>22</div></div><div><span><span>    </span></span><span>startTime</span><span>=</span><span>time.</span><span>time</span><span>()</span></div></div><div><div><div>23</div></div><div><span>    </span><span>while</span><span><span> time.</span><span>time</span><span>()</span><span>&lt;</span><span>startTime</span><span>+</span></span><span>5</span><span>:</span></div></div><div><div><div>24</div></div><div><span>        </span><span>if</span><span> doNextStep:</span></div></div><div><div><div>25</div></div><div><span><span>            </span></span><span>doNextStep</span><span>=</span><span>False</span></div></div><div><div><div>26</div></div><div><span><span>            </span></span><span>client.</span><span>simxSynchronousTrigger</span><span>()</span></div></div><div><div><div>27</div></div><div><span><span>        </span></span><span>client.</span><span>simxSpinOnce</span><span>()</span></div></div><div><div><div>28</div></div><div><span><span>    </span></span><span>client.</span><span>simxStopSimulation</span><span>(client.</span><span>simxDefaultPublisher</span><span>())</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section></section></section></section>
<section><h1>三、仿真<a href="#三仿真"><span>#</span></a></h1></section>
<section><h1>四、python小知识<a href="#四python小知识"><span>#</span></a></h1><section><h2>1.创建anaconda虚拟环境<a href="#1创建anaconda虚拟环境"><span>#</span></a></h2><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>1、用conda创建Python虚拟环境（在conda prompt环境下完成）</span></div></div><div><div><div>2</div></div><div><span>conda create -n Vrep python=3.7</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span>2、激活虚拟环境（在conda prompt环境下完成）</span></div></div><div><div><div>5</div></div><div><span>activate Vrep</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>3、给虚拟环境安装外部包</span></div></div><div><div><div>8</div></div><div><span>conda install -n Vrep [package]</span></div></div><div><div><div>9</div></div><div><span>例如: conda install -n tensorflow pandas</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>4、查看已有的环境(当前已激活的环境会显示一个星号)</span></div></div><div><div><div>12</div></div><div><span>conda info -e</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span>5、删除一个已有的虚拟环境</span></div></div><div><div><div>15</div></div><div><span>conda remove --name your_env_name --all</span></div></div><div><div><div>16</div></div><div>
</div></div><div><div><div>17</div></div><div><span>6、查看pip的安装目录</span></div></div><div><div><div>18</div></div><div><span>pip list</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span>7、删除已经安装的模块</span></div></div><div><div><div>21</div></div><div><span>pip uninstall **</span></div></div><div><div><div>22</div></div><div><span>(例如：pip uninstall numpy)</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>创建anaconda的虚拟环境后，会生成E:\Anaconda\envs\Vrep的文件夹，在Pycharm中选择创建的虚拟环境。</p></section><section><h2>2.pip换镜像源<a href="#2pip换镜像源"><span>#</span></a></h2><p>在 python 里经常要安装各种这样的包，安装各种包时最常用的就是 pip，pip 默认从官网下载文件，官网位于国外，下载速度时快时慢，还经常断线，国内的体验并不太好。</p><p>解决办法是把 pip 源换成国内的，最常用的并且可信赖的源包括清华大学源、豆瓣源、阿里源：</p><blockquote><p>pypi 清华大学源：<a href="https://link.zhihu.com/?target=https%3A//pypi.tuna.tsinghua.edu.cn/simple" target="_blank">https://pypi.tuna.tsinghua.edu.cn/simple</a>
pypi 豆瓣源 ：<a href="https://link.zhihu.com/?target=http%3A//pypi.douban.com/simple/" target="_blank">http://pypi.douban.com/simple/</a>
pypi 腾讯源：<a href="https://link.zhihu.com/?target=http%3A//mirrors.cloud.tencent.com/pypi/simple" target="_blank">http://mirrors.cloud.tencent.com/pypi/simple</a>
pypi 阿里源：<a href="https://link.zhihu.com/?target=https%3A//mirrors.aliyun.com/pypi/simple/" target="_blank">https://mirrors.aliyun.com/pypi</a></p></blockquote><p>pip 源具体修改方式是，我们以安装 python 的robotics-toolbox-python模块为例，通常的方式是直接在命令行运行</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>pip</span><span> </span><span>install</span><span> </span><span>robotics-toolbox-python</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>这样会从国外官网下载robotics-toolbox-python模块并安装。</p><p>若要把 pip 源换成国内的，只需要把上面的代码改成下图这样（下图以清华大学源为例）：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>pip install robotics-toolbox-python -i https://pypi.tuna.tsinghua.edu.cn/simple</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>这样我们就从清华大学源成功安装了机器人工具箱，速度会比过pip默认的国外源快很多。</p><p>上述做法是临时改成国内源，如果不想每次用 pip 都加上 <code>-i https://pypi.tuna.tsinghua.edu.cn/simple</code>，那么可以把国内源设为默认，做法是：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 清华源</span></div></div><div><div><div>2</div></div><div><span>pip</span><span> </span><span>config</span><span> </span><span>set</span><span> </span><span>global.index-url</span><span> </span><span>https://pypi.tuna.tsinghua.edu.cn/simple</span></div></div><div><div><div>3</div></div><div><span># 阿里源</span></div></div><div><div><div>4</div></div><div><span>pip</span><span> </span><span>config</span><span> </span><span>set</span><span> </span><span>global.index-url</span><span> </span><span>https://mirrors.aliyun.com/pypi/simple/</span></div></div><div><div><div>5</div></div><div><span># 腾讯源</span></div></div><div><div><div>6</div></div><div><span>pip</span><span> </span><span>config</span><span> </span><span>set</span><span> </span><span>global.index-url</span><span> </span><span>http://mirrors.cloud.tencent.com/pypi/simple</span></div></div><div><div><div>7</div></div><div><span># 豆瓣源</span></div></div><div><div><div>8</div></div><div><span>pip</span><span> </span><span>config</span><span> </span><span>set</span><span> </span><span>global.index-url</span><span> </span><span>http://pypi.douban.com/simple/</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/763/</id>
      <title type="text">加工机器人冗余自由度</title>
      <published>2022-01-20T15:51:33.000Z</published>
      <updated>2024-06-06T15:52:33.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/763/"/>
      <summary type="text">一、冗余自由度 刀具路径由离散的CLS数据组成， CLS= x,y,z,i,j,k 其中x,y,z为刀具位置，i,j,k为刀轴方向的单位向量 1、CLS对应的末端姿态 方法一： 引用文献中的方法 Peng J, Ding Y, Zhang </summary>
      <content type="html"><![CDATA[<section><h1>一、冗余自由度<a href="#一冗余自由度"><span>#</span></a></h1><p>刀具路径由离散的CLS数据组成，</p><span><span><span>CLS=(x,y,z,i,j,k)CLS=(x,y,z,i,j,k)</span><span><span><span></span><span>C</span><span>L</span><span>S</span><span></span><span>=</span><span></span></span><span><span></span><span>(</span><span>x</span><span>,</span><span></span><span>y</span><span>,</span><span></span><span>z</span><span>,</span><span></span><span>i</span><span>,</span><span></span><span>j</span><span>,</span><span></span><span>k</span><span>)</span></span></span></span></span><p>其中<strong>x,y,z</strong>为刀具位置，<strong>i,j,k</strong>为刀轴方向的单位向量</p><section><h2>1、CLS对应的末端姿态<a href="#1cls对应的末端姿态"><span>#</span></a></h2><section><h3>方法一：<a href="#方法一"><span>#</span></a></h3><p>引用文献中的方法</p><blockquote><p>Peng J, Ding Y, Zhang G, 等. Smoothness-oriented path optimization for robotic milling processes[J]. Science China Technological Sciences, 2020, 63(9): 1751–1763.</p></blockquote><p>由cls可以生成刀具姿态，但是刀具姿态并不唯一，定义初始机器人任务姿态为：</p><p><span><span>oi=(x,y,z)o_i=(x,y,z)</span><span><span><span></span><span><span>o</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>(</span><span>x</span><span>,</span><span></span><span>y</span><span>,</span><span></span><span>z</span><span>)</span></span></span></span>为刀具姿态矩阵的位置，z轴向量为</p><span><span><span>zi=(i,j,k)z_i = (i,j,k)</span><span><span><span></span><span><span>z</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>(</span><span>i</span><span>,</span><span></span><span>j</span><span>,</span><span></span><span>k</span><span>)</span></span></span></span></span><p>x轴向量为</p><span><span><span>xi=yi×zix_i=y_i \times z_i</span><span><span><span></span><span><span>x</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span><span>y</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>×</span><span></span></span><span><span></span><span><span>z</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span><p>y轴向量可以有下式计算得来</p><span><span><span>yi=zi×oi+1oi‾∥zi×oi+1oi‾∥对于最后一个cls点yi=zi×oi−1oi‾∥zi×oi−1oi‾∥\begin{gathered}
y_i= \frac{z_i \times \overline{o_{i+1} o_{i}} } {\lVert {z_i \times \overline{o_{i+1} o_{i}}} \lVert}\\
\text{对于最后一个}cls\text{点}\\
y_i= \frac{z_i \times \overline{o_{i-1} o_{i}} } {\lVert {z_i \times \overline{o_{i-1} o_{i}}} \lVert}
\end{gathered}</span><span><span><span></span><span><span><span><span><span><span><span><span></span><span><span><span>y</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span><span><span></span><span><span><span><span><span><span></span><span><span>∥</span><span><span><span>z</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>×</span><span></span><span><span><span><span><span><span></span><span><span><span>o</span><span><span><span><span><span><span></span><span><span><span>i</span><span>+</span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span>o</span><span><span><span><span><span><span></span><span><span><span>i</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>∥</span></span></span><span><span></span><span></span></span><span><span></span><span><span><span>z</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>×</span><span></span><span><span><span><span><span><span></span><span><span><span>o</span><span><span><span><span><span><span></span><span><span><span>i</span><span>+</span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span>o</span><span><span><span><span><span><span></span><span><span><span>i</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span></span></span><span><span></span><span><span><span>对于最后一个</span></span><span>c</span><span>l</span><span>s</span><span><span>点</span></span></span></span><span><span></span><span><span><span>y</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span><span><span></span><span><span><span><span><span><span></span><span><span>∥</span><span><span><span>z</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>×</span><span></span><span><span><span><span><span><span></span><span><span><span>o</span><span><span><span><span><span><span></span><span><span><span>i</span><span>−</span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span>o</span><span><span><span><span><span><span></span><span><span><span>i</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>∥</span></span></span><span><span></span><span></span></span><span><span></span><span><span><span>z</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>×</span><span></span><span><span><span><span><span><span></span><span><span><span>o</span><span><span><span><span><span><span></span><span><span><span>i</span><span>−</span><span>1</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span>o</span><span><span><span><span><span><span></span><span><span><span>i</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span></span><p>由此可以得到机器人末端初始姿态矩阵，因为绕刀具轴的旋转对铣刀定位没有影响，因此对于一个CLS，存在无数的可行机器人姿态，可由绕刀轴旋转得到。</p><span><span><span>T(γi)=Ti⋅Rot(z^,γi)Ti=[xiyizioi0001]\begin{gathered}
T(\gamma_i) = T_i \cdot Rot(\hat{z},\gamma_i)\\
T_i = \begin{bmatrix}
x_i&amp;y_i&amp;z_i&amp;o_i\\
0&amp;0&amp;0&amp;1\end {bmatrix}
\end{gathered}</span><span><span><span></span><span><span><span><span><span><span><span><span></span><span><span>T</span><span>(</span><span><span>γ</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>)</span><span></span><span>=</span><span></span><span><span>T</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>⋅</span><span></span><span>R</span><span>o</span><span>t</span><span>(</span><span><span><span><span><span><span></span><span>z</span></span><span><span></span><span><span>^</span></span></span></span></span></span></span><span>,</span><span></span><span><span>γ</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>)</span></span></span><span><span></span><span><span><span>T</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span><span><span><span>[</span></span><span><span><span><span><span><span><span><span></span><span><span><span>x</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span><span>0</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span><span></span><span><span><span><span><span><span></span><span><span><span>y</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span><span>0</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span><span></span><span><span><span><span><span><span></span><span><span><span>z</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span><span>0</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span><span></span><span><span><span><span><span><span></span><span><span><span>o</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span><span>1</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span><span><span>]</span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span></span><p>其中<span><span>TiT_i</span><span><span><span></span><span><span>T</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>为cls对应的初始末端矩阵，<span><span>γ∈[−π,π]\gamma \in [-\pi,\pi]</span><span><span><span></span><span>γ</span><span></span><span>∈</span><span></span></span><span><span></span><span>[</span><span>−</span><span>π</span><span>,</span><span></span><span>π</span><span>]</span></span></span></span>为冗余自由度，这样就可以得到CLS任意冗余自由度对应的末端姿态矩阵。</p><blockquote><p>这种方法会导致刀具轨迹弯折时机器人姿态变化较大</p></blockquote></section><section><h3>方法二：<a href="#方法二"><span>#</span></a></h3><blockquote><p>[1]Zhu W, Qu W, Cao L, 等. An off-line programming system for robotic drilling in aerospace manufacturing[J]. The International Journal of Advanced Manufacturing Technology, 2013, 68(9–12): 2535–2545.</p></blockquote><p>定义与上一个的方法一样，<span><span>zi=[i,j,k]z_i = [i,j,k]</span><span><span><span></span><span><span>z</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span></span><span><span></span><span>[</span><span>i</span><span>,</span><span></span><span>j</span><span>,</span><span></span><span>k</span><span>]</span></span></span></span>，而<span><span>xix_i</span><span><span><span></span><span><span>x</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>是三个标准单位向量<span><span>[1,0,0],[0,1,0],[0,0,1][1,0,0],[0,1,0],[0,0,1]</span><span><span><span></span><span>[</span><span>1</span><span>,</span><span></span><span>0</span><span>,</span><span></span><span>0</span><span>]</span><span>,</span><span></span><span>[</span><span>0</span><span>,</span><span></span><span>1</span><span>,</span><span></span><span>0</span><span>]</span><span>,</span><span></span><span>[</span><span>0</span><span>,</span><span></span><span>0</span><span>,</span><span></span><span>1</span><span>]</span></span></span></span>在由<span><span>[x,y,z]和[i,j,k][x,y,z]\text{和}[i,j,k]</span><span><span><span></span><span>[</span><span>x</span><span>,</span><span></span><span>y</span><span>,</span><span></span><span>z</span><span>]</span><span><span>和</span></span><span>[</span><span>i</span><span>,</span><span></span><span>j</span><span>,</span><span></span><span>k</span><span>]</span></span></span></span>决定的平面上的最长投影的归一化向量，<span><span>yiy_i</span><span><span><span></span><span><span>y</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>是<span><span>ziz_i</span><span><span><span></span><span><span>z</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>和<span><span>xix_i</span><span><span><span></span><span><span>x</span><span><span><span><span><span><span></span><span><span>i</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span>的叉积。</p></section><section><h3>方法三:<a href="#方法三"><span>#</span></a></h3><blockquote><p>[1]熊刚. 机器人铣削加工的误差补偿和力控制方法研究[D]. 上海交通大学, 2019.</p></blockquote><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220513120231244.png" alt="image-20220513120231244" /><figcaption>image-20220513120231244</figcaption></figure><p></p></section><section><h3>方法四：<a href="#方法四"><span>#</span></a></h3><p>计算刀轴向量和 基座标系Z轴之间的变换矩阵</p><p>将两个向量之间的变换视为绕某一轴的旋转某一角度的螺旋运动，旋转角为两个向量之间的夹角，而旋转轴则是两个向量之间的叉积。</p><p>已知单位向量，将其绕某一轴<span><span>ω\omega</span><span><span><span></span><span>ω</span></span></span></span>旋转<span><span>θ\theta</span><span><span><span></span><span>θ</span></span></span></span>，通过使用<strong>罗德里格斯公式</strong>可以计算其旋转矩阵。</p><span><span><span>R(ω,θ)=I+sinθ[ω]+(1−cosθ)[ω]2R(\omega,\theta) =I +sin\theta[\omega]+(1-cos\theta)[\omega]^2</span><span><span><span></span><span>R</span><span>(</span><span>ω</span><span>,</span><span></span><span>θ</span><span>)</span><span></span><span>=</span><span></span></span><span><span></span><span>I</span><span></span><span>+</span><span></span></span><span><span></span><span>s</span><span>in</span><span>θ</span><span>[</span><span>ω</span><span>]</span><span></span><span>+</span><span></span></span><span><span></span><span>(</span><span>1</span><span></span><span>−</span><span></span></span><span><span></span><span>cos</span><span>θ</span><span>)</span><span>[</span><span>ω</span><span><span>]</span><span><span><span><span><span><span></span><span><span>2</span></span></span></span></span></span></span></span></span></span></span></span><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>方法一：</span></div></div><div><div><div>2</div></div><div><span>#使用轴角法求取向量之间的变换矩阵，和上一个函数是一样的方法</span></div></div><div><div><div>3</div></div><div><span>def</span><span> </span><span>rotation_matrix_from_vectors2</span><span>(</span><span>vec2</span><span>):</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>vec1 </span><span>=</span><span> [</span><span>0</span><span>, </span><span>0</span><span>, </span><span>1</span><span>]</span></div></div><div><div><div>5</div></div><div><span>    </span><span>#规范化两个向量</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>a, b </span><span>=</span><span> (vec1 </span><span>/</span><span> np.linalg.</span><span>norm</span><span>(vec1)).</span><span>reshape</span><span>(</span><span>3</span><span><span>), (vec2 </span><span>/</span><span> np.linalg.</span><span>norm</span><span>(vec2)).</span><span>reshape</span><span>(</span></span><span>3</span><span>)</span></div></div><div><div><div>7</div></div><div><span>    </span><span>#求两个向量变换的旋转轴</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>v </span><span>=</span><span> np.</span><span>cross</span><span>(a, b)</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>s </span><span>=</span><span> np.linalg.</span><span>norm</span><span>(v)</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>v </span><span>=</span><span> v </span><span>/</span><span> s</span></div></div><div><div><div>11</div></div><div><span>    </span><span>#求旋转角度</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>c </span><span>=</span><span> np.</span><span>dot</span><span>(a, b)</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>theta </span><span>=</span><span> math.</span><span>acos</span><span>(c)</span></div></div><div><div><div>14</div></div><div><span>    </span><span>#使用mr库求取轴角法的旋转矩阵，用的是罗德里格斯公式</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>omegaHat </span><span>=</span><span> mr.</span><span>VecToso3</span><span>(v)</span></div></div><div><div><div>16</div></div><div><span><span>    </span></span><span>so3mat </span><span>=</span><span> omegaHat </span><span>*</span><span> theta</span></div></div><div><div><div>17</div></div><div><span><span>    </span></span><span>matrix </span><span>=</span><span> mr.</span><span>MatrixExp3</span><span>(so3mat)</span></div></div><div><div><div>18</div></div><div><span>    </span><span>#求矩阵对应的欧拉角</span></div></div><div><div><div>19</div></div><div><span><span>    </span></span><span>r </span><span>=</span><span> R.</span><span>from_matrix</span><span>(matrix)</span></div></div><div><div><div>20</div></div><div><span><span>    </span></span><span>euler </span><span>=</span><span> r.</span><span>as_euler</span><span>(</span><span>'ZYX'</span><span>,</span><span>degrees</span><span>=</span><span>True</span><span>)</span></div></div><div><div><div>21</div></div><div><span><span>    </span></span><span>matrix </span><span>=</span><span> r.</span><span>as_matrix</span><span>()</span></div></div><div><div><div>22</div></div><div><span>    </span><span>return</span><span> matrix</span></div></div><div><div><div>23</div></div><div>
</div></div><div><div><div>24</div></div><div><span>方法二：本质上都是一样的</span></div></div><div><div><div>25</div></div><div><span>def</span><span> </span><span>rotation_matrix_from_vectors</span><span>(</span><span>vec1</span><span>,</span><span>vec2</span><span>):</span></div></div><div><div><div>26</div></div><div><span>    </span><span>""" Find the rotation matrix that aligns vec1 to vec2</span></div></div><div><div><div>27</div></div><div><span><span>    </span></span><span>:param vec1: A 3d "source" vector</span></div></div><div><div><div>28</div></div><div><span><span>    </span></span><span>:param vec2: A 3d "destination" vector</span></div></div><div><div><div>29</div></div><div><span><span>    </span></span><span>:return mat: A transform matrix (3x3) which when applied to vec1, aligns it with vec2.</span></div></div><div><div><div>30</div></div><div><span><span>    </span></span><span>"""</span></div></div><div><div><div>31</div></div><div><span><span>    </span></span><span>a, b </span><span>=</span><span> (vec1 </span><span>/</span><span> np.linalg.</span><span>norm</span><span>(vec1)).</span><span>reshape</span><span>(</span><span>3</span><span><span>), (vec2 </span><span>/</span><span> np.linalg.</span><span>norm</span><span>(vec2)).</span><span>reshape</span><span>(</span></span><span>3</span><span>)</span></div></div><div><div><div>32</div></div><div><span><span>    </span></span><span>v </span><span>=</span><span> np.</span><span>cross</span><span>(a, b)</span></div></div><div><div><div>33</div></div><div><span><span>    </span></span><span>c </span><span>=</span><span> np.</span><span>dot</span><span>(a, b)</span></div></div><div><div><div>34</div></div><div><span><span>    </span></span><span>s </span><span>=</span><span> np.linalg.</span><span>norm</span><span>(v)</span></div></div><div><div><div>35</div></div><div><span><span>    </span></span><span>kmat </span><span>=</span><span> np.</span><span>array</span><span>([[</span><span>0</span><span><span>, </span><span>-</span><span>v[</span></span><span>2</span><span>], v[</span><span>1</span><span>]], [v[</span><span>2</span><span>], </span><span>0</span><span><span>, </span><span>-</span><span>v[</span></span><span>0</span><span><span>]], [</span><span>-</span><span>v[</span></span><span>1</span><span>], v[</span><span>0</span><span>], </span><span>0</span><span>]])</span></div></div><div><div><div>36</div></div><div><span><span>    </span></span><span>rotation_matrix </span><span>=</span><span> np.</span><span>eye</span><span>(</span><span>3</span><span><span>) </span><span>+</span><span> kmat </span><span>+</span><span> kmat.</span><span>dot</span><span>(kmat) </span><span>*</span><span> ((</span></span><span>1</span><span><span> </span><span>-</span><span> c) </span><span>/</span><span> (s </span><span>**</span><span> </span></span><span>2</span><span>))</span></div></div><div><div><div>37</div></div><div><span>    </span><span>return</span><span> rotation_matrix</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section><section><h2>2、末端姿态对应的欧拉角<a href="#2末端姿态对应的欧拉角"><span>#</span></a></h2><p>末端到基座标的旋转角ABC，是绕动坐标系旋转的ZYX欧拉角，KRC中定义角度A、B和C是绕Z、Y和X的旋转角度，旋转顺序也必须遵从：</p><ol>
<li>绕Z轴旋转角度为A</li>
<li>绕Y轴旋转角度为B</li>
<li>绕X轴旋转角度为C</li>
</ol><p></p><figure><img src="http://imgbed.leihub.cn/img/image-20220504214148968-16516717171351.png" alt="image-20220504214148968" /><figcaption>image-20220504214148968</figcaption></figure><p></p><p>由机器人导论中的方法，对旋转矩阵求逆解</p><span><span><span>RZYX=RZ(α)RY(β)RX(γ)=[r11r12r13r21r22r23r31r32r33]β=Atan2(−r31,r112+r212)α=Atan2(r21cβ,r11cβ)γ=Atan2(r32cβ,r33cβ)\begin{gathered}
R_{ZYX}=R_Z(\alpha)R_Y(\beta)R_X(\gamma)=\begin {bmatrix} r11 &amp; r12 &amp;r13\\
r21&amp;r22&amp;r23\\
r31&amp;r32&amp;r33\end {bmatrix}\\
\beta=Atan2(-r_{31},\sqrt{r_{11}^2 + r_{21}^2})\\
\alpha=Atan2(\frac {r_{21}}{c\beta},\frac {r_{11}}{c\beta})\\
\gamma = Atan2(\frac{r_{32}}{c\beta},\frac {r_{33}}{c\beta})
\end{gathered}</span><span><span><span></span><span><span><span><span><span><span><span><span></span><span><span><span>R</span><span><span><span><span><span><span></span><span><span><span>Z</span><span>Y</span><span>X</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>=</span><span></span><span><span>R</span><span><span><span><span><span><span></span><span><span>Z</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>α</span><span>)</span><span><span>R</span><span><span><span><span><span><span></span><span><span>Y</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>β</span><span>)</span><span><span>R</span><span><span><span><span><span><span></span><span><span>X</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>(</span><span>γ</span><span>)</span><span></span><span>=</span><span></span><span><span><span><span><span><span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span><span><span><span><span><span><span><span></span><span><span>r</span><span>11</span></span></span><span><span></span><span><span>r</span><span>21</span></span></span><span><span></span><span><span>r</span><span>31</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span><span></span><span><span><span><span><span><span></span><span><span>r</span><span>12</span></span></span><span><span></span><span><span>r</span><span>22</span></span></span><span><span></span><span><span>r</span><span>32</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span><span></span><span><span><span><span><span><span></span><span><span>r</span><span>13</span></span></span><span><span></span><span><span>r</span><span>23</span></span></span><span><span></span><span><span>r</span><span>33</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span><span><span><span><span><span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span><span><span></span><span><span>β</span><span></span><span>=</span><span></span><span>A</span><span>t</span><span>an</span><span>2</span><span>(</span><span>−</span><span><span>r</span><span><span><span><span><span><span></span><span><span><span>31</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span>,</span><span></span><span><span><span><span><span><span></span><span><span><span>r</span><span><span><span><span><span><span></span><span><span><span>11</span></span></span></span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span><span></span><span>+</span><span></span><span><span>r</span><span><span><span><span><span><span></span><span><span><span>21</span></span></span></span><span><span></span><span><span>2</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span><span><span></span><span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span>)</span></span></span><span><span></span><span><span>α</span><span></span><span>=</span><span></span><span>A</span><span>t</span><span>an</span><span>2</span><span>(</span><span><span></span><span><span><span><span><span><span></span><span><span>c</span><span>β</span></span></span><span><span></span><span></span></span><span><span></span><span><span><span>r</span><span><span><span><span><span><span></span><span><span><span>21</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span><span>,</span><span></span><span><span></span><span><span><span><span><span><span></span><span><span>c</span><span>β</span></span></span><span><span></span><span></span></span><span><span></span><span><span><span>r</span><span><span><span><span><span><span></span><span><span><span>11</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span><span>)</span></span></span><span><span></span><span><span>γ</span><span></span><span>=</span><span></span><span>A</span><span>t</span><span>an</span><span>2</span><span>(</span><span><span></span><span><span><span><span><span><span></span><span><span>c</span><span>β</span></span></span><span><span></span><span></span></span><span><span></span><span><span><span>r</span><span><span><span><span><span><span></span><span><span><span>32</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span><span>,</span><span></span><span><span></span><span><span><span><span><span><span></span><span><span>c</span><span>β</span></span></span><span><span></span><span></span></span><span><span></span><span><span><span>r</span><span><span><span><span><span><span></span><span><span><span>33</span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span><span></span></span><span>)</span></span></span></span><span>​</span></span><span><span><span></span></span></span></span></span></span></span></span></span></span></span><p>虽然存在第二个解，但是在上式中取<span><span>β\beta</span><span><span><span></span><span>β</span></span></span></span>的正根以得到单解，满足<span><span>−90≤β≤90-90\le \beta \le 90</span><span><span><span></span><span>−</span><span>90</span><span></span><span>≤</span><span></span></span><span><span></span><span>β</span><span></span><span>≤</span><span></span></span><span><span></span><span>90</span></span></span></span>，以此获取各种姿态表示法之间一一对应的映射函数。如果等于+-90，解的结果就退化了，这个时候一般取<span><span>α=0\alpha = 0</span><span><span><span></span><span>α</span><span></span><span>=</span><span></span></span><span><span></span><span>0</span></span></span></span>。</p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/96/</id>
      <title type="text">MCSManager：创建Minecraft服务器</title>
      <published>2021-07-21T04:05:06.000Z</published>
      <updated>2024-06-06T04:29:45.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/96/"/>
      <summary type="text">Java版服务器创建 快速创建 对于新手，推荐通过Mcsmanager的预设实现一键部署，快速创建服务器。 在面板中的 点击 再选择 方案 McsManger提供了一些简单的开服方案，包括一些java、基岩版和整合包，对于纯净生存玩家可以直</summary>
      <content type="html"><![CDATA[<section><h2>Java版服务器创建<a href="#java版服务器创建"><span>#</span></a></h2><section><h4>快速创建<a href="#快速创建"><span>#</span></a></h4><p>对于新手，推荐通过Mcsmanager的预设实现一键部署，快速创建服务器。</p><p>在面板中的 <code>快速开始</code> 点击 <code>创建一个Minecraft服务</code> 再选择 <code>一键快速开服</code> 方案</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307120011796.png" alt="image-20230711212345026" /><figcaption>image-20230711212345026</figcaption></figure><p></p><p>McsManger提供了一些简单的开服方案，包括一些java、基岩版和整合包，对于纯净生存玩家可以直接选择相应的配置进行开服。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307120011694.png" alt="image-20230711212521734" /><figcaption>image-20230711212521734</figcaption></figure><p></p><p>选择相应的配置，点击安装，设置服务器名称后，McsManager就会下载相应的开服核心和模组，自动完成服务器的创建。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307120011079.png" alt="image-20230711212938990" /><figcaption>image-20230711212938990</figcaption></figure><p></p><p>创建实例</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307120011934.png" alt="image-20230711213058064" /><figcaption>image-20230711213058064</figcaption></figure><p></p><p>在未运行服务器之前，特定配置中只有<code>eula.txt</code>一个文件，点击开启实例后，会自动生成<code>server.properties</code>、 <code>spigot.yml</code>、<code>bukkit.yml</code>、 <code>paper.yml</code>等文件。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307120011108.png" alt="image-20230711213445402" /><figcaption>image-20230711213445402</figcaption></figure><p></p><p><code>server.properties</code>中存储着Minecraft 服务端极其重要的配置文件，如端口，种子、难度、人数，视距等配置，均可以此文件中进行编辑，我们主要是在这个配置文件中进行修改，点击浏览即可对文件进行编辑。</p><p>这里主要列出几个可能需要进行修改的配置</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>level-seed = #地图种子 默认留空</span></div></div><div><div><div>2</div></div><div><span>gamemode=survival #游戏模式（survival，creative，adventure，spectator）</span></div></div><div><div><div>3</div></div><div><span>query.port=25565 #设置监听服务器的端口号（参见 enable-rcon），多开时，需要修改端口，避免监听同一个端口产生冲突</span></div></div><div><div><div>4</div></div><div><span>level-name= #世界（地图）名称 不要使用中文</span></div></div><div><div><div>5</div></div><div><span>difficulty=easy#游戏难度（peaceful, easy, normal,hard）</span></div></div><div><div><div>6</div></div><div><span>max-players=20 #服务器最大玩家数限制</span></div></div><div><div><div>7</div></div><div><span>online-mode=true #在线（正版）验证，开启后盗版无法进入</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><code>spigot.yml</code>、<code>bukkit.yml</code>、 <code>paper.yml</code>为服务器核心的配置文件，能够进一步的控制服务器的行为和具体参数，一些更为高级的限制都在此配置文件中，如服务器最大的生命值上限、服务器最大的伤害上限、是否开启日志输出等。</p><p>在高级实例配置中，可以对服务配置进行查看，比如服务器的工作目录等</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307120011158.png" alt="image-20230711213152713" /><figcaption>image-20230711213152713</figcaption></figure><p></p></section><section><h4>自定义创建<a href="#自定义创建"><span>#</span></a></h4><p>点击左侧“快速开始”按钮，选择创建一个Minecraft服务器-普通流程创建服务器-Java 版 Minecraft 游戏服务端-上传单个服务端软件（推荐），选择“上传压缩包”或“上传单个服务端软件”，上传您下载的整合包或者jar文件。</p><section><h5><strong>单个服务端开服</strong><a href="#单个服务端开服"><span>#</span></a></h5><p>选择上传单个服务端软件，则需要去核心下载网站如<a href="https://papermc.io/downloads" target="_blank">paper</a>，选择你需要的版本下载</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307120011394.png" alt="image-20230712000216444" /><figcaption>image-20230712000216444</figcaption></figure><p></p><p>上传到面板中，就会自动进行创建。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307120012194.png" alt="image-20230711215017784" /><figcaption>image-20230711215017784</figcaption></figure><p></p><p>创建好服务器后，在服务器目录下创建了一个文件夹，文件夹里目前只有一个eula.txt文件</p><p>下载完成后，重启服务器，打开控制台查看运行情况，当输出timin reset时，服务器就启动完毕了。</p><p>可以在 服务端 server.properties 配置文件 中修改服务器配置，修改端口信息，难度，正版验证，这些参数按需修改。</p></section><section><h5><strong>整合包开服</strong><a href="#整合包开服"><span>#</span></a></h5><p>选择“上传压缩包”，可以去<a href="https://www.mcbbs.net/forum-serverpack-1.html" target="_blank">MCBBS论坛</a>下载别人准备好整合包，一般都会集成好服务器核心和模组，上传后会自动把zip文件解压。</p><p>在详细信息设置中可以对启动命令进行定义，如我下载的整合包中服务器核心文件为<code>[服务端核心]purpur.jar</code>，设置<code>最小内存为2G</code>，<code>最大内存为8G</code>，自动生成启动命令：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>java -Xmx8G -Xms2G -Dfile.encoding=UTF-8 -Duser.language=zh -Duser.country=CN -jar [服务端核心]purpur.jar nogui</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p></p><figure><img src="http://imgbed.leihub.cn/img/202307120012529.png" alt="image-20230711235135705" /><figcaption>image-20230711235135705</figcaption></figure><p></p><p>然后在<code>eula.txt</code>中，设置为<code>True</code>。</p><p>完成好配置后，即可在控制台界面点击开启实例，当控制台输入Timing Reset时说明服务器启动完毕，可以进去愉快的玩耍了，如图所示</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307120012520.png" alt="image-20230711235704239" /><figcaption>image-20230711235704239</figcaption></figure><p></p></section></section></section>
<section><h2>JAVA配置<a href="#java配置"><span>#</span></a></h2><p>在开始运行Java服务端之前 Java运行库是必不可少的. 以下是一些Minecraft版本所需的对应的Java版本运行库列表:</p><blockquote><ul>
<li>1.7.x / 1.8.x / 1.9.x - 使用<code>Java7(不推荐)</code>或<code>Java8</code>运行</li>
<li>1.10.x / 1.12.x - 使用<code>Java8</code>运行</li>
<li>1.12.x / 1.13.x / 1.15.x - 使用<code>Java8</code>,<code>Java9</code>或<code>Java12</code>运行</li>
<li>1.16.x - 使用<code>Java8</code>,<code>Java9</code>,<code>Java12</code>或<code>Java16</code>运行</li>
<li>1.17.x - 使用<code>Java16</code>或<code>Java17</code>运行</li>
<li>1.18.x - 使用Java17或Java18运行</li>
<li>1.18.x / 1.19.x - 使用Java17或<strong>更高版本</strong>运行.</li>
</ul></blockquote></section>
<section><h2>服务端核心<a href="#服务端核心"><span>#</span></a></h2><ul>
<li><a href="https://getbukkit.org/download/spigot" target="_blank">Spigot (opens new window)</a> [可以装插件]</li>
<li><a href="https://papermc.io/downloads" target="_blank">paper (opens new window)</a> [可以装插件]</li>
<li><a href="https://files.minecraftforge.net/" target="_blank">Forge (opens new window)</a> [可以装MOD]</li>
</ul></section>
<section><h2>服务器插件/MOD<a href="#服务器插件mod"><span>#</span></a></h2><ul>
<li><a href="https://dev.bukkit.org/" target="_blank">bukkit (opens new window)</a> [下载插件]</li>
<li><a href="https://www.spigotmc.org/" target="_blank">spigotmc (opens new window)</a> [下载插件]</li>
<li><a href="https://www.curseforge.com/minecraft/modpacks" target="_blank">curseforge (opens new window)</a> [下载MOD]</li>
</ul></section>
<section><h2>整合包下载<a href="#整合包下载"><span>#</span></a></h2><p>MCBBS 整合包: <a href="https://www.mcbbs.net/forum-serverpack-1.html" target="_blank">https://www.mcbbs.net/forum-serverpack-1.html</a></p></section>
<section><h2>基岩版服务器搭建<a href="#基岩版服务器搭建"><span>#</span></a></h2><blockquote><p>基岩版服务器推荐通过一键创建进行部署。如果需要手动部署，流程大致如下</p></blockquote><section><h3>大致操作流程<a href="#大致操作流程"><span>#</span></a></h3><p><strong>Windows：新建自定义命令实例 -&gt; 上传压缩包 -&gt; 写好启动命令 -&gt; 在线解压压缩包 -&gt; 开服</strong></p><p><strong>Linux：新建自定义命令实例 -&gt; 上传压缩包 -&gt; 写好启动脚本文件并上传 -&gt; 在线解压压缩包 -&gt; 开服</strong></p></section><section><h3>具体操作细节（Windows）<a href="#具体操作细节windows"><span>#</span></a></h3><ul>
<li>下载服务端后会有一个 <code>bedrock_server.exe</code> 文件，在面板中的<code>服务端管理</code> 点击 <code>创建新实例</code>再选择<code>自定义启动命令</code>方案。</li>
<li>取好名字，项目位置推荐默认，下一步。</li>
<li>使用 <code>选择文件上传</code> 上传你的服务端压缩包，下一步。</li>
<li>启动命令写成 <code>bedrock_server.exe</code> 即可，创建成功。</li>
<li>在<code>服务端管理</code>中的 <code>管理</code>界面，进入 <code>在线文件管理</code>，解压你刚刚上传的压缩包。</li>
<li>回到 <code>服务端管理</code> 中的 <code>终端</code>，点击 <code>开启</code> 即可启动服务器。</li>
</ul></section><section><h3>具体操作细节（Linux）<a href="#具体操作细节linux"><span>#</span></a></h3><p><strong>在 Linux 启动 bedrock 服务端就兼用用 sh 脚本启动的方法，否则很有可能启动失败。</strong></p><ul>
<li>首先下载Linux系统的服务端，其中会有一个叫做 <code>bedrock_server</code> 的文件。</li>
<li>在面板中的 <code>服务端管理</code> 点击 <code>创建新实例</code> 再选择 <code>自定义启动命令</code> 方案。</li>
<li>取好 <code>名字</code>，项目位置推荐默认，下一步。</li>
<li>使用 <code>选择文件上传</code> 上传你的压缩包（必须用zip格式，建议自己下载解压打包成zip），下一步。</li>
<li>启动命令写成 <code>sh start.sh</code>，稍后我们上传这个文件。</li>
<li>在自己的本地电脑创建一个脚本文件叫做 <code>start.sh</code>，写入开服指令:</li>
</ul><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>LD_LIBRARY_PATH=. ./bedrock_server</span></div></div></code></pre><div><div></div><div></div></div></figure></div><ul>
<li>在<code>服务端管理界面</code>中点击 <code>管理</code>，进入<code>文件在线管理</code>，上传这个<code>start.sh</code>的脚本文件。</li>
<li>在<code>文件在线管理</code>界面中，<code>解压</code>你刚刚上传的zip压缩包，稍作休息，耐心等待。</li>
<li>开服。</li>
</ul></section></section>
<section><h2>参考资料<a href="#参考资料"><span>#</span></a></h2><ol>
<li><a href="https://docs.mcsmanager.com/#/zh-cn/README" target="_blank">安装面板 (mcsmanager.com)</a></li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/87/</id>
      <title type="text">MCSManager：Minecraft 游戏服务端和所有控制台程序的管理面板</title>
      <published>2021-07-21T02:39:30.000Z</published>
      <updated>2024-06-06T04:29:49.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/87/"/>
      <summary type="text">#post_excerpt</summary>
      <content type="html"><![CDATA[<section><h2>MCSManager<a href="#mcsmanager"><span>#</span></a></h2><p>MCSManager 面板（简称：MCSM 面板）是一款全中文，开源，分布式，开箱即用，支持 Minecraft 游戏服务端和所有控制台程序的管理面板。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307112058526.png" alt="image-20230711175909686" /><figcaption>image-20230711175909686</figcaption></figure><p></p></section>
<section><h2>Linux 安装<a href="#linux-安装"><span>#</span></a></h2><section><h3>一行命令快速安装（适用于AMD64架构 Ubuntu/Centos/Debian/Archlinux）<a href="#一行命令快速安装适用于amd64架构-ubuntucentosdebianarchlinux"><span>#</span></a></h3><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>wget -qO- https://gitee.com/mcsmanager/script/raw/master/setup_cn.sh | bash</span></div></div></code></pre><div><div></div><div></div></div></figure></div><ul>
<li>该脚本专为 AMD64 架构的 Ubuntu/Centos/Debian/Archlinux 设计。</li>
<li>用于在安装后启动服务。<code>systemctl start mcsm-{web,daemon}</code></li>
<li>面板组件和运行时的目录：<code>/opt/mcsmanager/</code></li>
</ul><section><h4>启动面板<a href="#启动面板"><span>#</span></a></h4><p>使用一键安装脚本后，才可以使用下列命令，如果是手动安装，则需要使用screen命令，在后面会进行说明。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># 先启动面板守护进程。</span></div></div><div><div><div>2</div></div><div><span># 这是用于进程控制，终端管理的服务进程。</span></div></div><div><div><div>3</div></div><div><span>systemctl start mcsm-daemon.service</span></div></div><div><div><div>4</div></div><div><span># 再启动面板 Web 服务。</span></div></div><div><div><div>5</div></div><div><span># 这是用来实现支持网页访问和用户管理的服务。</span></div></div><div><div><div>6</div></div><div><span>systemctl start mcsm-web.service</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span># 重启面板命令</span></div></div><div><div><div>9</div></div><div><span>systemctl restart mcsm-daemon.service</span></div></div><div><div><div>10</div></div><div><span>systemctl restart mcsm-web.service</span></div></div><div><div><div>11</div></div><div>
</div></div><div><div><div>12</div></div><div><span># 停止面板命令</span></div></div><div><div><div>13</div></div><div><span>systemctl stop mcsm-web.service</span></div></div><div><div><div>14</div></div><div><span>systemctl stop mcsm-daemon.service</span></div></div></code></pre><div><div></div><div></div></div></figure></div><blockquote><p>面板 Web 服务是提供用户管理与网页访问功能的服务，守护进程是提供进程管理和容器管理的服务，两者缺一不可。如果某个功能不正常，可以只重启这一部分的服务来热修复问题。</p></blockquote></section></section><section><h3>手动安装面板并运行<a href="#手动安装面板并运行"><span>#</span></a></h3><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># 切换到安装目录，没有此目录请执行 mkdir /opt/</span></div></div><div><div><div>2</div></div><div><span>cd /opt/</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 下载运行环境</span></div></div><div><div><div>5</div></div><div><span>wget https://nodejs.org/dist/v14.17.6/node-v14.17.6-linux-x64.tar.gz</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span># 解压文件</span></div></div><div><div><div>8</div></div><div><span>tar -zxvf node-v14.17.6-linux-x64.tar.gz</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span># 链接程序到环境变量中</span></div></div><div><div><div>11</div></div><div><span>ln -s /opt/node-v14.17.6-linux-x64/bin/node /usr/bin/node</span></div></div><div><div><div>12</div></div><div><span>ln -s /opt/node-v14.17.6-linux-x64/bin/npm /usr/bin/npm</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span>#创建安装文件夹</span></div></div><div><div><div>15</div></div><div><span>mkdir /opt/mcsmanager/</span></div></div><div><div><div>16</div></div><div><span>cd /opt/mcsmanager/</span></div></div><div><div><div>17</div></div><div>
</div></div><div><div><div>18</div></div><div><span># 下载McsManager</span></div></div><div><div><div>19</div></div><div><span>wget https://github.com/MCSManager/MCSManager/releases/latest/download/mcsmanager_linux_release.tar.gz</span></div></div><div><div><div>20</div></div><div><span>tar -zxf mcsmanager_linux_release.tar.gz</span></div></div><div><div><div>21</div></div><div>
</div></div><div><div><div>22</div></div><div><span>./install-dependency.sh</span></div></div><div><div><div>23</div></div><div>
</div></div><div><div><div>24</div></div><div><span># 打开两个终端或者两个screen</span></div></div><div><div><div>25</div></div><div><span># 首先在一个screen中开启 daemon</span></div></div><div><div><div>26</div></div><div><span>./start-daemon.sh</span></div></div><div><div><div>27</div></div><div>
</div></div><div><div><div>28</div></div><div><span># 在第二个screen中代开web服务</span></div></div><div><div><div>29</div></div><div><span>./start-web.sh</span></div></div><div><div><div>30</div></div><div>
</div></div><div><div><div>31</div></div><div><span>#通过http://localhost:23333/就可以访问web服务</span></div></div><div><div><div>32</div></div><div><span>#通常，web应用程序会自动扫描并连接到本地守护进程。</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><section><h4>安装JAVA<a href="#安装java"><span>#</span></a></h4><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># 如何获取JDK安装包?</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>进入JAVA官网,注册登录后下载</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span>https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>选择你需要的版本 在这里我们选择 Linux x64 Compressed Archive ,请根据自己的架构选择版本</span></div></div><div><div><div>8</div></div><div><span>本文档创建时的版本: jdk-8u251-linux-x64.tar.gz</span></div></div><div><div><div>9</div></div><div><span>请下载后自行上传到 root 目录或者 用户目录</span></div></div><div><div><div>10</div></div><div><span>请注意!!!请根据自己下载的版本修改下面相关命令中的版本</span></div></div><div><div><div>11</div></div><div><span>比如 8u251 这一段 请修改为自己上传的版本的数字</span></div></div><div><div><div>12</div></div><div><span>修改的内容包括 解压文件 设置环境变量  软链接程序到环境变量中 这几项</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span># 切换到用户目录</span></div></div><div><div><div>15</div></div><div><span>cd ~</span></div></div><div><div><div>16</div></div><div><span># 创建安装目录</span></div></div><div><div><div>17</div></div><div><span>mkdir /usr/local/java/</span></div></div><div><div><div>18</div></div><div><span># 解压当前目录下的JDK压缩文件</span></div></div><div><div><div>19</div></div><div><span>tar -zxvf jdk-8u251-linux-x64.tar.gz -C /usr/local/java/</span></div></div><div><div><div>20</div></div><div><span># 设置环境变量(安装 VIM 输入 yum -y install vim)</span></div></div><div><div><div>21</div></div><div><span>vim /etc/profile</span></div></div><div><div><div>22</div></div><div><span># 在末尾添加对应变量</span></div></div><div><div><div>23</div></div><div><span>滚动光标到末尾 按下 键盘上的 INS 键,切换至插入模式</span></div></div><div><div><div>24</div></div><div><span>输入这几串内容后 按下 Shift + ; 输入 wq 并回车保存</span></div></div><div><div><div>25</div></div><div>
</div></div><div><div><div>26</div></div><div><span>export JAVA_HOME=/usr/local/java/jdk1.8.0_251</span></div></div><div><div><div>27</div></div><div><span>export JRE_HOME=${JAVA_HOME}/jre</span></div></div><div><div><div>28</div></div><div><span>export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib</span></div></div><div><div><div>29</div></div><div><span>export PATH=${JAVA_HOME}/bin:$PATH</span></div></div><div><div><div>30</div></div><div>
</div></div><div><div><div>31</div></div><div><span># 应用修改后的环境变量</span></div></div><div><div><div>32</div></div><div><span>source /etc/profile</span></div></div><div><div><div>33</div></div><div><span># 软链接程序到环境变量中</span></div></div><div><div><div>34</div></div><div><span>ln -s /usr/local/java/jdk1.8.0_251/bin/java /usr/bin/java</span></div></div><div><div><div>35</div></div><div><span># 测试是否安装正常，显示 java version "1.8.0_251" 则为正常</span></div></div><div><div><div>36</div></div><div><span>java -version</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h4>使用 Screen 保持后台运行<a href="#使用-screen-保持后台运行"><span>#</span></a></h4><p>先<code>Ctrl+C</code>关闭面板，我们使用 screen 软件来让面板保持后台运行。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>yum install screen # (Centos)</span></div></div><div><div><div>2</div></div><div><span>apt install screen # (Ubuntu)</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 创建一个名为 daemon 的窗口</span></div></div><div><div><div>5</div></div><div><span>screen -S daemon</span></div></div><div><div><div>6</div></div><div><span>./start-daemon.sh</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span># 创建一个名为 mcsm 的窗口</span></div></div><div><div><div>9</div></div><div><span>#首先在一个screen中开启 daemon</span></div></div><div><div><div>10</div></div><div><span>screen -S mcsm</span></div></div><div><div><div>11</div></div><div><span># 在第二个screen中打开web服务</span></div></div><div><div><div>12</div></div><div><span>./start-web.sh</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>直接断开终端连接即可，面板将保持后台运行。</p><p><strong>若要重新控制，请输入命令即可：</strong></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>screen -r mcsm</span></div></div><div><div><div>2</div></div><div><span>screen -r daemon</span></div></div></code></pre><div><div></div><div></div></div></figure></div><blockquote><p>请注意，上述步骤不会将面板组件注册到系统服务。您必须使用“屏幕”来管理它或手动注册系统服务。</p></blockquote></section></section><section><h3>Docker部署<a href="#docker部署"><span>#</span></a></h3><p>创建一个文件夹<code>/opt/docker-mcsm</code>用于保存docker部署的配置文件</p><p>面板分为**网页前端（Web）**和守护进程后端（Daemon），所以需要先备好两个 Dockerfile 文件。</p><section><h4><strong>WEB</strong><a href="#web"><span>#</span></a></h4><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>FROM node:14-slim</span></div></div><div><div><div>2</div></div><div><span>ARG INSTALL_PATH=/opt/docker-mcsm</span></div></div><div><div><div>3</div></div><div><span>ARG TZ=Asia/Shanghai</span></div></div><div><div><div>4</div></div><div><span>ENV TZ=${TZ}</span></div></div><div><div><div>5</div></div><div><span>RUN sed -i -E 's/http:\/\/deb.debian.org/http:\/\/mirrors.ustc.edu.cn/g' /etc/apt/sources.list</span></div></div><div><div><div>6</div></div><div><span>RUN apt update &amp;&amp; apt install -y git</span></div></div><div><div><div>7</div></div><div><span>RUN git clone --single-branch -b master --depth 1 https://gitee.com/MCSManager/MCSManager-Web-Production $INSTALL_PATH/releases/web</span></div></div><div><div><div>8</div></div><div><span>RUN cd $INSTALL_PATH/releases/web &amp;&amp; npm i --production --registry=https://registry.npmmirror.com</span></div></div><div><div><div>9</div></div><div><span>WORKDIR $INSTALL_PATH/releases/web</span></div></div><div><div><div>10</div></div><div><span>CMD node app.js</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>复制并保存文件名为 <code>dockerfile-web</code> 的文件</p></section><section><h4><strong>Daemon</strong><a href="#daemon"><span>#</span></a></h4><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>FROM node:14-slim</span></div></div><div><div><div>2</div></div><div><span>ARG INSTALL_PATH=/opt/docker-mcsm</span></div></div><div><div><div>3</div></div><div><span>ARG TZ=Asia/Shanghai</span></div></div><div><div><div>4</div></div><div><span>ENV TZ=${TZ}</span></div></div><div><div><div>5</div></div><div><span>RUN sed -i -E 's/http:\/\/deb.debian.org/http:\/\/mirrors.ustc.edu.cn/g' /etc/apt/sources.list</span></div></div><div><div><div>6</div></div><div><span>RUN apt update &amp;&amp; apt install -y git</span></div></div><div><div><div>7</div></div><div><span>RUN git clone --single-branch -b master --depth 1 https://gitee.com/MCSManager/MCSManager-Daemon-Production $INSTALL_PATH/releases/daemon</span></div></div><div><div><div>8</div></div><div><span>RUN cd $INSTALL_PATH/releases/daemon &amp;&amp; npm i --production --registry=https://registry.npmmirror.com</span></div></div><div><div><div>9</div></div><div><span>WORKDIR $INSTALL_PATH/releases/daemon</span></div></div><div><div><div>10</div></div><div><span>CMD node app.js</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>复制并保存文件名为 <code>dockerfile-daemon</code> 的文件</p></section><section><h4>docker-compose<a href="#docker-compose"><span>#</span></a></h4><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>version: "3"</span></div></div><div><div><div>2</div></div><div><span>services:</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>mcsm-web:</span></div></div><div><div><div>4</div></div><div><span><span>        </span></span><span>container_name: mcsm-web</span></div></div><div><div><div>5</div></div><div><span><span>        </span></span><span>build:</span></div></div><div><div><div>6</div></div><div><span><span>            </span></span><span>context: .</span></div></div><div><div><div>7</div></div><div><span><span>            </span></span><span>dockerfile: dockerfile-web</span></div></div><div><div><div>8</div></div><div><span><span>            </span></span><span>args:</span></div></div><div><div><div>9</div></div><div><span><span>                </span></span><span>INSTALL_PATH: ${INSTALL_PATH-/opt/docker-mcsm}</span></div></div><div><div><div>10</div></div><div><span><span>                </span></span><span>TZ: ${TZ-Asia/Shanghai}</span></div></div><div><div><div>11</div></div><div><span><span>        </span></span><span>network_mode: "host"</span></div></div><div><div><div>12</div></div><div><span><span>        </span></span><span>restart: always</span></div></div><div><div><div>13</div></div><div><span><span>        </span></span><span>environment:</span></div></div><div><div><div>14</div></div><div><span><span>            </span></span><span>- PUID=0</span></div></div><div><div><div>15</div></div><div><span><span>            </span></span><span>- PGID=0</span></div></div><div><div><div>16</div></div><div><span><span>            </span></span><span>- UMASK=022</span></div></div><div><div><div>17</div></div><div><span><span>        </span></span><span>volumes:</span></div></div><div><div><div>18</div></div><div><span><span>            </span></span><span>- ${INSTALL_PATH-/opt/docker-mcsm}/releases/web/data:${INSTALL_PATH-/opt/docker-mcsm}/releases/web/data</span></div></div><div><div><div>19</div></div><div><span><span>            </span></span><span>- ${INSTALL_PATH-/opt/docker-mcsm}/releases/web/logs:${INSTALL_PATH-/opt/docker-mcsm}/releases/web/logs</span></div></div><div><div><div>20</div></div><div><span><span>            </span></span><span>- ${INSTALL_PATH-/opt/docker-mcsm}/releases/daemon/data/Config:${INSTALL_PATH-/opt/docker-mcsm}/releases/daemon/data/Config:ro</span></div></div><div><div><div>21</div></div><div><span><span>    </span></span><span>mcsm-daemon:</span></div></div><div><div><div>22</div></div><div><span><span>        </span></span><span>container_name: mcsm-daemon</span></div></div><div><div><div>23</div></div><div><span><span>        </span></span><span>build:</span></div></div><div><div><div>24</div></div><div><span><span>            </span></span><span>context: .</span></div></div><div><div><div>25</div></div><div><span><span>            </span></span><span>dockerfile: dockerfile-daemon</span></div></div><div><div><div>26</div></div><div><span><span>            </span></span><span>args:</span></div></div><div><div><div>27</div></div><div><span><span>                </span></span><span>INSTALL_PATH: ${INSTALL_PATH-/opt/docker-mcsm}</span></div></div><div><div><div>28</div></div><div><span><span>                </span></span><span>TZ: ${TZ-Asia/Shanghai}</span></div></div><div><div><div>29</div></div><div><span><span>        </span></span><span>network_mode: "host"</span></div></div><div><div><div>30</div></div><div><span><span>        </span></span><span>restart: always</span></div></div><div><div><div>31</div></div><div><span><span>        </span></span><span>environment:</span></div></div><div><div><div>32</div></div><div><span><span>            </span></span><span>- PUID=0</span></div></div><div><div><div>33</div></div><div><span><span>            </span></span><span>- PGID=0</span></div></div><div><div><div>34</div></div><div><span><span>            </span></span><span>- UMASK=022</span></div></div><div><div><div>35</div></div><div><span><span>        </span></span><span>volumes:</span></div></div><div><div><div>36</div></div><div><span><span>            </span></span><span>- ${INSTALL_PATH-/opt/docker-mcsm}/releases/daemon/data:${INSTALL_PATH-/opt/docker-mcsm}/releases/daemon/data</span></div></div><div><div><div>37</div></div><div><span><span>            </span></span><span>- ${INSTALL_PATH-/opt/docker-mcsm}/releases/daemon/logs:${INSTALL_PATH-/opt/docker-mcsm}/releases/daemon/logs</span></div></div><div><div><div>38</div></div><div><span><span>            </span></span><span>- /var/run/docker.sock:/var/run/docker.sock:ro</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>复制并保存文件名为 <code>docker-compose.yml</code> 的文件</p></section><section><h4>.env<a href="#env"><span>#</span></a></h4><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>INSTALL_PATH</span><span>=</span><span>/opt/docker-mcsm</span></div></div><div><div><div>2</div></div><div><span>TZ</span><span>=</span><span>Asia/Shanghai</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section><section><h4>安装<a href="#安装"><span>#</span></a></h4><p>将四个文件放在之前创建的文件夹中，进入文件目录，运行以下命令进行部署</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>docker-compose up -d # 运行 web 和 daemon</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>docker-compose up -d mcsm-web # 仅运行 web</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span>docker-compose up -d mcsm-daemon # 仅运行 daemon</span></div></div></code></pre><div><div></div><div></div></div></figure></div><ul>
<li>发布版中不携带 java,如需运行 java 程序请在 <code>面板-&gt;环境镜像-&gt;环境镜像管理-&gt;新建镜像</code> 中自行构建
<ul>
<li>实例设置中的 <code>进程启动方式</code> 选择 <code>虚拟化容器</code></li>
</ul>
</li>
<li>关闭服务器请进入到 docker-compose.yml 文件目录运行 <code>docker-compose stop</code>
<ul>
<li>运行 <code>docker-compose down</code> 来移除容器</li>
</ul>
</li>
</ul></section><section><h4>更新容器<a href="#更新容器"><span>#</span></a></h4><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>docker-compose</span><span> </span><span>exec</span><span> </span><span>mcsm-web</span><span> </span><span>bash</span><span> </span><span>-c</span><span> </span><span>"git pull &amp;&amp; npm i --production --registry=https://registry.npmmirror.com"</span><span> </span><span># 更新 web</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>docker-compose</span><span> </span><span>exec</span><span> </span><span>mcsm-daemon</span><span> </span><span>bash</span><span> </span><span>-c</span><span> </span><span>"git pull &amp;&amp; npm i --production --registry=https://registry.npmmirror.com"</span><span> </span><span># 更新 daemon</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span>docker-compose</span><span> </span><span>restart</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section></section><section><h3>端口开放<a href="#端口开放"><span>#</span></a></h3><p>面板需要 23333（主功能） 端口与 20010 - 20200（FTP功能）端口区间。</p><p>如果你使用阿里云，腾讯云或者服务商，<strong>请进入控制台到防火墙安全组策略，放行以上端口</strong>。</p><p>如果依然无法访问，请关闭系统自带防火墙：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># 关闭防火墙，依次执行</span></div></div><div><div><div>2</div></div><div><span>systemctl stop firewalld.service</span></div></div><div><div><div>3</div></div><div><span>service iptables stop</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>其他太过复杂操作本教程不提供，请读者有想法的自己搜索。</strong></p><p>现在，访问 <a href="http://xn--ip-0p3cm89l:23333/" target="_blank">http://你的ip&lt;23333&gt;/</a> 即可进入面板。</p><ul>
<li>默认账号：#master</li>
<li>默认密码: 123456</li>
<li>请及时修改密码。</li>
</ul><p></p><figure><img src="http://imgbed.leihub.cn/img/202307112058762.png" alt="image-20230711200246024" /><figcaption>image-20230711200246024</figcaption></figure><p></p></section><section><h3>游戏实例<a href="#游戏实例"><span>#</span></a></h3><p>游戏服务端（MC服务器）或脚本（Shell)都视作为一个 <code>应用实例</code> 由面板统一管理，如下图所示。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307112058882.png" alt="image-20230711201829932" /><figcaption>image-20230711201829932</figcaption></figure><p></p><p><code>McsManager</code>的 <code>应用实例</code> 支持多种类型的程序如JAVA、基岩版等，所以这里可以指定这个实例是什么类型，不同的选项会导致一些行为不一样，比如配置文件解析，命令执行方式等等。</p></section><section><h3>守护进程<a href="#守护进程"><span>#</span></a></h3><p>如果你在 Linux 下启动面板时，会启动两个<code>服务</code>，其中 <code>daemon</code> 就代表守护进程，它是一个类似于 <code>被控端</code> 的程序，由自带网页的控制中心来控制它们，从而实现多个物理主机互相连接。</p><p>所以守护进程就是类似于一个 <code>被控端</code> 的角色，你的 MC 服务器是在这个 <code>被控端</code> 上运行，而网页就是 <code>控制中心</code> 的角色。</p><p>下图表示了从网页上连接各个地方的 <code>守护进程</code>。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307112058330.png" alt="image-20230711205651698" /><figcaption>image-20230711205651698</figcaption></figure><p></p></section></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/85/</id>
      <title type="text">青龙面板：一起愉快的刷京豆</title>
      <published>2021-07-07T07:08:01.000Z</published>
      <updated>2024-06-06T04:30:29.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/85/"/>
      <summary type="text">#post_excerpt</summary>
      <content type="html"><![CDATA[<p>青龙是一款支持 Python3、JavaScript、Shell、Typescript 的定时任务管理平台。</p>
<p>目前流行挂各种自动化签到脚本，如京东、快手和美团等，在活动多的时候，挂京豆脚本一天的收益能有一块钱，一年下来，也能包住云服务器的开销。</p>
<section><h1>安装青龙<a href="#安装青龙"><span>#</span></a></h1><p>还是老样子，推荐使用docker进行安装，不容易与本机其他应用产生冲突。</p><p>创建一个文件夹用于存放docker-compose.yml文件，容器部署后配置文件也存储在这个文件夹</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>mkdir /opt/qinglong</span></div></div><div><div><div>2</div></div><div><span>cd /opt/qinglong</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><strong>docker-compose</strong></p><p>创建docker-compose.yml文件，其中内容如下</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>version: '2'</span></div></div><div><div><div>2</div></div><div><span>services:</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>web:</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span># alpine 基础镜像版本</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>image: whyour/qinglong:latest</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span># debian-slim 基础镜像版本</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span># image: whyour/qinglong:debian</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>volumes:</span></div></div><div><div><div>9</div></div><div><span><span>      </span></span><span>- ./data:/ql/data</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>ports:</span></div></div><div><div><div>11</div></div><div><span><span>      </span></span><span>- "0.0.0.0:5700:5700"</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>environment:</span></div></div><div><div><div>13</div></div><div><span><span>      </span></span><span># 部署路径非必须，以斜杠开头和结尾，比如 /test/</span></div></div><div><div><div>14</div></div><div><span><span>      </span></span><span>QlBaseUrl: '/'</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>restart: unless-stopped</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p><strong>容器部署</strong></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>docker-compose up -d</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>容器部署成功后，通过<code>ip地址:5700</code>即可访问，首次登录需要设置账户和密码，其中推送设置可以先跳过，后续再进行设置。进入面板界面如图所示。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307130020773.png" alt="image-20230712233003115" /><figcaption>image-20230712233003115</figcaption></figure><p></p></section>
<section><h1>拉取仓库<a href="#拉取仓库"><span>#</span></a></h1><p>首先，需要拉取脚本，以<a href="https://github.com/KingRan/KR.git" target="_blank">KingRan的京东脚本库为例</a>，点开定时任务菜单，选择新建任务，命令如下。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>ql repo https://github.com/KingRan/KR.git "jd_|jx_|jdCookie" "activity|backUp" "^jd[^_]|USER|utils|function|sendNotify|ql|JDJR"</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>定时规则如下，这个cron表达式将在每天的午夜（00&lt;00&gt;）执行命令或脚本。</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>0 0 * * *</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p></p><figure><img src="http://imgbed.leihub.cn/img/202307130020074.png" alt="image-20230712231554446" /><figcaption>image-20230712231554446</figcaption></figure><p></p><blockquote><p>如果是国内的服务器，记得给github仓库地址前加个代理，在cloudflare搭建个人代理那节，我搭建了一个github代理，也可以用我的，<a href="https://github.leitingtool.cf/%E3%80%82" target="_blank">https://github.leitingtool.cf/。</a></p></blockquote><p>新建完拉库任务后，点击运行，就会根据命令中预设的规则将仓库中的脚本下载到面板中，并根据脚本中的设置，自动添加定时任务，一般来说，定时任务不需要我们自己进行修改。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307130020078.png" alt="image-20230712232721013" /><figcaption>image-20230712232721013</figcaption></figure><p></p><p>拉取完仓库如图</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307130020502.png" alt="image-20230712232842968" /><figcaption>image-20230712232842968</figcaption></figure><p></p></section>
<section><h1>获取cookie<a href="#获取cookie"><span>#</span></a></h1><p>我们要使用脚本登录京东账号，让其自动帮我们完成东东农场浇水、自动签到、自动价保等功能。而脚本登录我们账号就需要cookie来实现，而一般在浏览器中抓取到的cookie有效期都很短，之前是在一个月左右，过期后需要重新进行抓取，比较麻烦。</p><p>wskey 是<strong>移动端APP</strong>特有 Cookie 参数值， WSKEY 的有效期为半年起步，具体有效时间暂时未知，配置后可转换生成有效期为 <code>5</code> 个小时左右的 <code>cookie</code>，实现长时间挂载账号刷京豆。</p><blockquote><p><strong>注销登录</strong>（在抓取设备的APP中手动操作退出账号登录）、<strong>修改密码</strong>会导致其失效，若想在APP中切换账号直接卸载APP即可，极少数情况下存在被官方主动踢下线的可能性</p></blockquote><section><h2>抓取WSKEY<a href="#抓取wskey"><span>#</span></a></h2><p><strong>准备工具:</strong></p><p>app：VNET（抓包用）、京东；</p><p>VNET下载地址：<a href="https://www.vnet-tech.com/zh/" target="_blank">https://www.vnet-tech.com/zh/</a>
<strong>VNET抓包wskey</strong></p><p>打开已下载的VNET软件，第一步先安装CA证书；</p><p>点击右下角三角形上面的按钮按钮，选择导出CA证书，app就会将CA证书下载至手机你指定的路径里</p><img src="http://imgbed.leihub.cn/img/202307130020068.jpg" alt="_-1806192279__b155e5532bc6e72b648d9765ff9b70ec_-660483070_Screenshot_2023-07-12-23-43-23-515_com.vnet_0_wifi_0" /><p>随后在手机设置里进行安装，这里不同手机可能安装位置不同，具体根据自己的手机型号百度查询如何安装CA证书即可，以小米手机为例，在设置中搜索CA证书，选择仍然安装，可能会需要你使用指纹或者密码进行解锁，然后在文件存储中选择你刚刚保存的CA证书，CA证书名字为CA.pem。</p><img src="http://imgbed.leihub.cn/img/202307130020048.jpg" alt="_-1955488830__8ac8cf69d32924eb9d6f9bbf214da43b_349445750_Screenshot_2023-07-12-23-44-10-081_com.android_0_wifi_0" /><p>完成了CA证书的安装后，就可以进行抓包了，在VNET中选择添加京东为抓包应用，点击三角形按钮，开始抓包。切换到京东app，转到个人界面刷新一下，在VNET中就可以看到抓到的各种数据。</p><p>在看到来源于<code>**.jd.com</code>的抓包数据后，这就是我们需要的数据报，就可以停止抓包了</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307130020020.jpg" alt="_-552505781__12dff7f04db341eaf47836af5af84b3e_1135600892_Screenshot_2023-07-12-23-51-31-857-edit_com.vnet_0_wifi_0" /><figcaption>_-552505781__12dff7f04db341eaf47836af5af84b3e_1135600892_Screenshot_2023-07-12-23-51-31-857-edit_com.vnet_0_wifi_0</figcaption></figure><p></p><p>点开抓取的数据，点进去往下滑，找到cookie里的pin和wskey，这样就算获取成功了。</p><img src="http://imgbed.leihub.cn/img/202307130021387.jpg" alt="QQ图片20230713000037" /></section><section><h2><strong>青龙面板使用wskey转换脚本</strong><a href="#青龙面板使用wskey转换脚本"><span>#</span></a></h2><p>一般拉取的仓库中都有wskey转换脚本，根据青龙规定的环境变量创建规则，将刚才VNET抓取的pin和wskey添加到青龙的环境变量中，环境变量明明规则如下：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>变量名: JD_WSCK</span></div></div><div><div><div>2</div></div><div><span>参数: pin=xxxx;wskey=xxxx; # 注意分号 不要用中文分号!</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p></p><figure><img src="http://imgbed.leihub.cn/img/202307130021599.png" alt="image-20230713000807867" /><figcaption>image-20230713000807867</figcaption></figure><p></p><p>将wskey的环境变量添加完成后，便可以去执行wskey转换的脚本了，</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307130021919.png" alt="image-20230713000943302" /><figcaption>image-20230713000943302</figcaption></figure><p></p><p>执行后在环境变量里就能看到转化后的JD_COOKIE了</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307130021675.png" alt="image-20230713001047687" /><figcaption>image-20230713001047687</figcaption></figure><p></p></section></section>
<section><h1>安装依赖<a href="#安装依赖"><span>#</span></a></h1><p>有些脚本库会需要安装一些依赖，在青龙面板里，可以对依赖进行一键安装。</p><p>以KingRan大佬的库为例，直接运行时会报错，显示没有<code>ds</code>库</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307130021263.png" alt="image-20230713001420909" /><figcaption>image-20230713001420909</figcaption></figure><p></p><p>在依赖管理中，选择Nodejs，点击新建依赖，名称一栏中输入我们需要安装的库，点击确定，面板就会自动为我们安装。不同的脚本有时需要的依赖不同，需要时常查看脚本运行日志，查看脚本是否运行成功，如果失败，常常是因为确实依赖库的原因，缺少什么库，就可以在依赖管理中进行添加。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307130021354.png" alt="image-20230713001315382" /><figcaption>image-20230713001315382</figcaption></figure><p></p></section>
<section><h1>推送设置<a href="#推送设置"><span>#</span></a></h1><p>青龙面板提供了多种消息推送方式，如server酱、企业微信、push plus等。</p><p>以push plus为例，登录<a href="http://www.pushplus.plus/%EF%BC%8C%E4%BD%BF%E7%94%A8%E5%BE%AE%E4%BF%A1%E6%89%AB%E7%A0%81%E7%99%BB%E5%BD%95%EF%BC%8C%E7%BB%91%E5%AE%9A%E8%87%AA%E5%B7%B1%E7%9A%84%E5%BE%AE%E4%BF%A1%EF%BC%8C%E5%9C%A8%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%E4%B8%80%E6%A0%8F%E4%B8%AD%E9%80%89%E6%8B%A9%E4%B8%80%E5%AF%B9%E4%B8%80%E6%B6%88%E6%81%AF%EF%BC%8C%E5%88%9B%E5%BB%BA%E8%87%AA%E5%B7%B1%E7%9A%84token" target="_blank">http://www.pushplus.plus/，使用微信扫码登录，绑定自己的微信，在发送消息一栏中选择一对一消息，创建自己的token</a></p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307130029370.png" alt="image-20230713002531940" /><figcaption>image-20230713002531940</figcaption></figure><p></p><p>将获取的token填入青龙配置文件的推送设置中，点击保存。</p><p></p><figure><img src="http://imgbed.leihub.cn/img/202307130029614.png" alt="image-20230713002704078" /><figcaption>image-20230713002704078</figcaption></figure><p></p><p>后续脚本运行或者资产变动信息，就会通过push plus接口发送到绑定的微信上。</p></section>
<section><h1>青龙的内置命令<a href="#青龙的内置命令"><span>#</span></a></h1><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span># 更新并重启青龙</span></div></div><div><div><div>2</div></div><div><span>ql update</span></div></div><div><div><div>3</div></div><div><span># 运行自定义脚本extra.sh</span></div></div><div><div><div>4</div></div><div><span>ql extra</span></div></div><div><div><div>5</div></div><div><span># 添加单个脚本文件</span></div></div><div><div><div>6</div></div><div><span>ql raw &lt;file_url&gt;</span></div></div><div><div><div>7</div></div><div><span># 添加单个仓库的指定脚本</span></div></div><div><div><div>8</div></div><div><span>ql repo &lt;repo_url&gt; &lt;whitelist&gt; &lt;blacklist&gt; &lt;dependence&gt; &lt;branch&gt; &lt;extensions&gt;</span></div></div><div><div><div>9</div></div><div><span># 删除旧日志</span></div></div><div><div><div>10</div></div><div><span>ql rmlog &lt;days&gt;</span></div></div><div><div><div>11</div></div><div><span># 启动tg-bot</span></div></div><div><div><div>12</div></div><div><span>ql bot</span></div></div><div><div><div>13</div></div><div><span># 检测青龙环境并修复</span></div></div><div><div><div>14</div></div><div><span>ql check</span></div></div><div><div><div>15</div></div><div><span># 重置登录错误次数</span></div></div><div><div><div>16</div></div><div><span>ql resetlet</span></div></div><div><div><div>17</div></div><div><span># 禁用两步登录</span></div></div><div><div><div>18</div></div><div><span>ql resettfa</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span># 依次执行，如果设置了随机延迟，将随机延迟一定秒数</span></div></div><div><div><div>21</div></div><div><span>task &lt;file_path&gt;</span></div></div><div><div><div>22</div></div><div><span># 依次执行，无论是否设置了随机延迟，均立即运行，前台会输出日，同时记录在日志文件中</span></div></div><div><div><div>23</div></div><div><span>task &lt;file_path&gt; now</span></div></div><div><div><div>24</div></div><div><span># 并发执行，无论是否设置了随机延迟，均立即运行，前台不产生日，直接记录在日志文件中，且可指定账号执行</span></div></div><div><div><div>25</div></div><div><span>task &lt;file_path&gt; conc &lt;env_name&gt; &lt;account_number&gt;(可选的)</span></div></div><div><div><div>26</div></div><div><span># 指定账号执行，无论是否设置了随机延迟，均立即运行</span></div></div><div><div><div>27</div></div><div><span>task &lt;file_path&gt; desi &lt;env_name&gt; &lt;account_number&gt;</span></div></div><div><div><div>28</div></div><div><span># 设置任务超时时间</span></div></div><div><div><div>29</div></div><div><span>task -m &lt;max_time&gt; &lt;file_path&gt;</span></div></div><div><div><div>30</div></div><div><span># 实时打印任务日志，创建定时任务时，不用携带此参数</span></div></div><div><div><div>31</div></div><div><span>task -l &lt;file_path&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p><strong>参数说明</strong></p><ul>
<li>file_url: 脚本地址</li>
<li>repo_url: 仓库地址</li>
<li>whitelist: 拉取仓库时的白名单，即就是需要拉取的脚本的路径包含的字符串，多个竖线分割</li>
<li>blacklist: 拉取仓库时的黑名单，即就是需要拉取的脚本的路径不包含的字符串，多个竖线分割</li>
<li>dependence: 拉取仓库需要的依赖文件，会直接从仓库拷贝到scripts下的仓库目录，不受黑名单影响，多个竖线分割</li>
<li>extensions: 拉取仓库的文件后缀，多个竖线分割</li>
<li>branch: 拉取仓库的分支</li>
<li>days: 需要保留的日志的天数</li>
<li>file_path: 任务执行时的文件路径</li>
<li>env_name: 任务执行时需要并发或者指定时的环境变量名称</li>
<li>account_number: 任务执行时指定某个环境变量需要执行的账号序号</li>
<li>max_time: 超时时间，后缀”s”代表秒(默认值), “m”代表分, “h”代表小时, “d”代表天</li>
</ul></section>
<section><h1>参考资料<a href="#参考资料"><span>#</span></a></h1><ol>
<li><a href="https://github.com/whyour/qinglong" target="_blank">whyour/qinglong: 支持 Python3、JavaScript、Shell、Typescript 的定时任务管理平台（Timed task management platform supporting Python3, JavaScript, Shell, Typescript） (github.com)</a></li>
<li><a href="https://github.com/KingRan/KR/" target="_blank">KingRan/KR (github.com)</a></li>
<li><a href="https://www.vnet-tech.com/zh/" target="_blank">VNET-TECH – Android Packet Capture Tool</a></li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/84/</id>
      <title type="text">从Docker到Docker Compose：完整实战教程</title>
      <published>2021-07-07T07:04:40.000Z</published>
      <updated>2025-11-14T15:22:44.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/84/"/>
      <summary type="text">2025.11.12 更新docker compose使用案例和教程 一、Docker核心入门 1.1 什么是Docker？ Docker是一款开源的容器化平台，它能将应用程序及其依赖环境打包成一个标准化的“容器”，实现“一次构建，到处运行</summary>
      <content type="html"><![CDATA[<ul>
<li>2025.11.12 更新docker compose使用案例和教程</li>
</ul>
<section><h2>一、Docker核心入门<a href="#一docker核心入门"><span>#</span></a></h2><section><h3>1.1 什么是Docker？<a href="#11-什么是docker"><span>#</span></a></h3><p>Docker是一款开源的容器化平台，它能将应用程序及其依赖环境打包成一个标准化的“容器”，实现“一次构建，到处运行”的目标。与传统虚拟机相比，Docker容器更轻量、启动更快、资源占用更低——虚拟机需要模拟完整操作系统，而容器则共享宿主机内核，仅封装应用所需的运行时环境。</p><p>核心价值：解决开发环境与生产环境“不一致”的痛点，简化服务部署流程，提升运维效率。</p></section><section><h3>1.2 Docker核心概念<a href="#12-docker核心概念"><span>#</span></a></h3><ul>
<li><strong>镜像（Image）</strong>：容器的“模板”，包含运行应用所需的代码、依赖、环境变量等，可理解为只读的系统快照。</li>
<li><strong>容器（Container）</strong>：镜像的“运行实例”，是动态的、可读写的，容器间相互隔离，拥有独立的文件系统。</li>
<li><strong>仓库（Repository）</strong>：存储镜像的远程服务，类似代码仓库，Docker Hub（<a href="https://hub.docker.com/%EF%BC%89%E6%98%AF%E5%AE%98%E6%96%B9%E5%85%AC%E5%85%B1%E4%BB%93%E5%BA%93%E3%80%82" target="_blank">https://hub.docker.com/）是官方公共仓库。</a></li>
<li><strong>Docker Engine</strong>：Docker的核心服务，负责管理镜像和容器的生命周期。</li>
</ul></section></section>
<section><h2>二、Docker安装指南<a href="#二docker安装指南"><span>#</span></a></h2><p>Ubuntu 18.04及以上版本推荐使用官方脚本自动安装，步骤如下：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 下载并执行Docker官方安装脚本</span></div></div><div><div><div>2</div></div><div><span>curl</span><span> </span><span>-fsSL</span><span> </span><span>https://get.docker.com</span><span> </span><span>-o</span><span> </span><span>get-docker.sh</span></div></div><div><div><div>3</div></div><div><span>sudo</span><span> </span><span>sh</span><span> </span><span>get-docker.sh</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span># 启动Docker服务</span></div></div><div><div><div>6</div></div><div><span>sudo</span><span> </span><span>systemctl</span><span> </span><span>start</span><span> </span><span>docker</span></div></div><div><div><div>7</div></div><div><span>sudo</span><span> </span><span>systemctl</span><span> </span><span>enable</span><span> </span><span>docker</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section>
<section><h2>三、Docker基础使用命令<a href="#三docker基础使用命令"><span>#</span></a></h2><section><h3>3.1 镜像操作<a href="#31-镜像操作"><span>#</span></a></h3><p>当运行容器时，使用的镜像如果在本地中不存在，docker 就会自动从 docker 镜像仓库中下载，默认是从 Docker Hub 公共镜像源下载。</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 1. 从仓库拉取镜像（格式：docker pull 镜像名:标签，标签默认latest）</span></div></div><div><div><div>2</div></div><div><span>docker</span><span> </span><span>pull</span><span> </span><span>nginx:1.23</span><span>  </span><span># 拉取nginx 1.23版本</span></div></div><div><div><div>3</div></div><div><span>docker</span><span> </span><span>pull</span><span> </span><span>redis</span><span>       </span><span># 拉取redis最新版本</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span># 2. 查看本地镜像列表</span></div></div><div><div><div>6</div></div><div><span>docker</span><span> </span><span>images</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span># 3. 删除本地镜像（需先删除依赖该镜像的容器）</span></div></div><div><div><div>9</div></div><div><span>docker</span><span> </span><span>rmi</span><span> </span><span>nginx:1.23</span><span>  </span><span># 按镜像名删除</span></div></div><div><div><div>10</div></div><div><span>docker</span><span> </span><span>rmi</span><span> </span><span>-f</span><span> </span><span>镜像ID</span><span>    </span><span># 强制删除（-f）</span></div></div><div><div><div>11</div></div><div>
</div></div><div><div><div>12</div></div><div><span># 4. 搜索远程仓库镜像</span></div></div><div><div><div>13</div></div><div><span>docker</span><span> </span><span>search</span><span> </span><span>mysql</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section><section><h3>3.2 容器操作<a href="#32-容器操作"><span>#</span></a></h3><div><div><div><figure><figcaption><span></span><span>Terminal window</span><span>展开</span><span>收起</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 1. 创建并启动容器（格式：docker run [选项] 镜像名 [命令]）</span></div></div><div><div><div>2</div></div><div><span># -d：后台运行；-p 宿主机端口:容器端口：端口映射；--name：指定容器名</span></div></div><div><div><div>3</div></div><div><span>docker</span><span> </span><span>run</span><span> </span><span>-d</span><span> </span><span>-p</span><span> </span><span>80:80</span><span> </span><span>--name</span><span> </span><span>my-nginx</span><span> </span><span>nginx:1.23</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span># 2. 查看容器状态</span></div></div><div><div><div>6</div></div><div><span>docker</span><span> </span><span>ps</span><span>          </span><span># 查看运行中的容器</span></div></div><div><div><div>7</div></div><div><span>docker</span><span> </span><span>ps</span><span> </span><span>-a</span><span>       </span><span># 查看所有容器（包括停止的）</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span># 3. 启动/停止/重启容器</span></div></div><div><div><div>10</div></div><div><span>docker</span><span> </span><span>start</span><span> </span><span>my-nginx</span><span>   </span><span># 启动容器</span></div></div><div><div><div>11</div></div><div><span>docker</span><span> </span><span>stop</span><span> </span><span>my-nginx</span><span>    </span><span># 停止容器</span></div></div><div><div><div>12</div></div><div><span>docker</span><span> </span><span>restart</span><span> </span><span>my-nginx</span><span> </span><span># 重启容器</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span># 4. 进入运行中的容器（交互模式）</span></div></div><div><div><div>15</div></div><div><span>docker</span><span> </span><span>exec</span><span> </span><span>-it</span><span> </span><span>my-nginx</span><span> </span><span>/bin/bash</span><span>  </span><span># -it：交互终端</span></div></div><div><div><div>16</div></div><div>
</div></div><div><div><div>17</div></div><div><span># 5. 查看容器日志</span></div></div><div><div><div>18</div></div><div><span>docker</span><span> </span><span>logs</span><span> </span><span>-f</span><span> </span><span>my-nginx</span><span>  </span><span># -f：实时跟踪日志</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span># 6. 删除容器（需先停止容器，或用-f强制删除）</span></div></div><div><div><div>21</div></div><div><span>docker</span><span> </span><span>rm</span><span> </span><span>my-nginx</span></div></div><div><div><div>22</div></div><div><span>docker</span><span> </span><span>rm</span><span> </span><span>-f</span><span> </span><span>my-nginx</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section><section><h3>3.3 数据卷操作（持久化数据）<a href="#33-数据卷操作持久化数据"><span>#</span></a></h3><p>容器删除后数据会丢失，通过数据卷挂载宿主机目录或匿名卷实现数据持久化：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 1. 挂载宿主机目录到容器（格式：-v 宿主机路径:容器路径）</span></div></div><div><div><div>2</div></div><div><span>docker</span><span> </span><span>run</span><span> </span><span>-d</span><span> </span><span>-p</span><span> </span><span>80:80</span><span> </span><span>-v</span><span> </span><span>/host/nginx/html:/usr/share/nginx/html</span><span> </span><span>--name</span><span> </span><span>my-nginx</span><span> </span><span>nginx:1.23</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 2. 创建并使用命名数据卷</span></div></div><div><div><div>5</div></div><div><span>docker</span><span> </span><span>volume</span><span> </span><span>create</span><span> </span><span>nginx-data</span><span>  </span><span># 创建命名卷</span></div></div><div><div><div>6</div></div><div><span>docker</span><span> </span><span>run</span><span> </span><span>-d</span><span> </span><span>-p</span><span> </span><span>80:80</span><span> </span><span>-v</span><span> </span><span>nginx-data:/usr/share/nginx/html</span><span> </span><span>--name</span><span> </span><span>my-nginx</span><span> </span><span>nginx:1.23</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section></section>
<section><h2>四、Docker Compose进阶<a href="#四docker-compose进阶"><span>#</span></a></h2><p>当应用依赖多个服务（如 Web 服务 + 数据库 + 缓存）时，手动管理多个容器效率低下。Docker Compose 通过 YAML 文件定义多容器服务组合，一键启动 / 停止所有服务，是多容器部署的核心工具。</p><section><h3>4.1 Compose 简介与安装<a href="#41-compose-简介与安装"><span>#</span></a></h3><p>Compose 是定义和运行多容器 Docker 应用的工具，核心流程分三步：</p><ol>
<li>用 Dockerfile 定义应用环境；</li>
<li>用<code>docker-compose.yml</code>定义所有服务配置；</li>
<li>执行<code>docker-compose up</code>一键启动整个应用。</li>
</ol><section><h4>安装步骤（Linux）<a href="#安装步骤linux"><span>#</span></a></h4><p>从 Github 下载二进制包安装，最新版本可查看<a href="https://github.com/docker/compose/releases" target="_blank">Compose 官方 Releases</a>：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 下载指定版本（替换1.24.1为最新版本）</span></div></div><div><div><div>2</div></div><div><span>sudo</span><span> </span><span>curl</span><span> </span><span>-L</span><span> </span><span>"https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(</span><span>uname</span><span> </span><span>-s</span><span>)-$(</span><span>uname</span><span> </span><span>-m</span><span>)"</span><span> </span><span>-o</span><span> </span><span>/usr/local/bin/docker-compose</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 赋予可执行权限</span></div></div><div><div><div>5</div></div><div><span>sudo</span><span> </span><span>chmod</span><span> </span><span>+x</span><span> </span><span>/usr/local/bin/docker-compose</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span># 创建软链接（可选，解决命令路径问题）</span></div></div><div><div><div>8</div></div><div><span>sudo</span><span> </span><span>ln</span><span> </span><span>-s</span><span> </span><span>/usr/local/bin/docker-compose</span><span> </span><span>/usr/bin/docker-compose</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span># 验证安装成功</span></div></div><div><div><div>11</div></div><div><span>docker-compose</span><span> </span><span>--version</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><blockquote><p>提示：Alpine 系统需先安装依赖包：py-pip、python-dev、libffi-dev、openssl-dev、gcc、libc-dev、make。</p></blockquote></section></section><section><h3>4.2 Compose 配置文件核心逻辑<a href="#42-compose-配置文件核心逻辑"><span>#</span></a></h3><p><code>docker-compose.yml</code>是 Compose 的核心，文件名可自定义（需用<code>-f</code>参数指定，如<code>docker-compose -f my-compose.yml up</code>）。其层级结构严格，后一层级需比前一层级后退 2 个空格或 1 个 Tab，格式错误易导致运行失败。</p><section><h4>核心层级关系<a href="#核心层级关系"><span>#</span></a></h4><ol>
<li>第 1 级：<code>version</code>和<code>services</code>为顶层参数。<code>version</code>仅标识配置版本，不参与运行；<code>services</code>定义所有需启动的服务。</li>
<li>第 2 级：服务名称（如<code>app</code>、<code>db</code>），可自定义但不可重复，作为容器在局域网内的通信标识。</li>
<li>第 3 级：容器核心参数，包括镜像（<code>image</code>）、重启策略（<code>restart</code>）、端口映射（<code>ports</code>）、目录映射（<code>volumes</code>）等。</li>
<li>第 4 级：参数具体配置，如端口映射格式为 “宿主端口：容器端口”。</li>
</ol></section><section><h4>服务命名习惯<a href="#服务命名习惯"><span>#</span></a></h4><p>我个人习惯按功能命名服务：核心应用叫<code>app</code>、数据库叫<code>db</code>、缓存叫<code>redis</code>（或<code>cache</code>），这样仅看名称就能知晓服务角色，方便管理。</p></section><section><h4>镜像标签（tag）使用建议<a href="#镜像标签tag使用建议"><span>#</span></a></h4><ul>
<li>不推荐直接用<code>:latest</code>（默认标签）：不同时间的<code>latest</code>对应不同版本，不利于迁移和镜像复用，多个服务共用同一镜像时可能重复下载。</li>
<li>推荐用法：指定具体 tag（如<code>mysql:5.7</code>），可在 Docker Hub 查询最新版本，也可通过 RSShub 订阅版本更新。</li>
<li>特殊场景可使用<code>:latest</code>：WordPress（支持后台更新）、需频繁更新的镜像。</li>
</ul></section></section><section><h3>4.3 实战实例：WordPress 多服务部署<a href="#43-实战实例wordpress-多服务部署"><span>#</span></a></h3><p>以下是一个完整的 WordPress 部署配置，包含 Web 应用（WordPress）、数据库（MySQL）和缓存（Redis）三个服务，可直观体现 Compose 对多服务依赖的管理能力：</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>version</span><span>: </span><span>'3.0'</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>services</span><span>:</span></div></div><div><div><div>4</div></div><div><span>  </span><span># MySQL数据库服务</span></div></div><div><div><div>5</div></div><div><span>  </span><span>db</span><span>:</span></div></div><div><div><div>6</div></div><div><span>    </span><span>image</span><span>: </span><span>mysql:5.7</span><span> </span><span># 注意：arm架构机器（如M1/M2 Mac）需改为mysql:oracle</span></div></div><div><div><div>7</div></div><div><span>    </span><span>container_name</span><span>: </span><span>wordpress-db</span><span> </span><span># 自定义容器名，便于管理</span></div></div><div><div><div>8</div></div><div><span>    </span><span>restart</span><span>: </span><span>unless-stopped</span><span> </span><span># 重启策略：除非手动停止，否则总是重启</span></div></div><div><div><div>9</div></div><div><span>    </span><span># command: --max-binlog-size=200M --expire-logs-days=2 # MySQL 8.0建议添加，限制日志大小</span></div></div><div><div><div>10</div></div><div><span>    </span><span>environment</span><span>: </span><span># 数据库环境变量（核心配置，需妥善保存）</span></div></div><div><div><div>11</div></div><div><span>      </span><span>MYSQL_ROOT_PASSWORD</span><span>: </span><span>rootpassword</span><span> </span><span># 数据库root密码，建议改为复杂密码</span></div></div><div><div><div>12</div></div><div><span>      </span><span>MYSQL_DATABASE</span><span>: </span><span>wordpress</span><span> </span><span># 为WordPress创建的数据库名</span></div></div><div><div><div>13</div></div><div><span>      </span><span>MYSQL_USER</span><span>: </span><span>wordpress</span><span> </span><span># 为WordPress授权的数据库用户</span></div></div><div><div><div>14</div></div><div><span>      </span><span>MYSQL_PASSWORD</span><span>: </span><span>yourpassword</span><span> </span><span># 数据库用户密码，建议与root密码区分</span></div></div><div><div><div>15</div></div><div><span>    </span><span>volumes</span><span>: </span><span># 数据持久化：将主机目录挂载到容器，避免容器删除后数据丢失</span></div></div><div><div><div>16</div></div><div><span><span>      </span></span><span>- </span><span>'./db:/var/lib/mysql'</span></div></div><div><div><div>17</div></div><div><span>    </span><span>networks</span><span>: </span><span># 加入自定义网络，实现服务间隔离通信</span></div></div><div><div><div>18</div></div><div><span><span>      </span></span><span>- </span><span>default</span></div></div><div><div><div>19</div></div><div>
</div></div><div><div><div>20</div></div><div><span>  </span><span># WordPress应用服务</span></div></div><div><div><div>21</div></div><div><span>  </span><span>app</span><span>:</span></div></div><div><div><div>22</div></div><div><span>    </span><span>image</span><span>: </span><span>wordpress:latest</span><span> </span><span># 官方WordPress最新镜像</span></div></div><div><div><div>23</div></div><div><span>    </span><span>container_name</span><span>: </span><span>wordpress-app</span></div></div><div><div><div>24</div></div><div><span>    </span><span>restart</span><span>: </span><span>unless-stopped</span></div></div><div><div><div>25</div></div><div><span>    </span><span>ports</span><span>: </span><span># 端口映射：主机18080端口 → 容器80端口（需确保主机防火墙开放18080）</span></div></div><div><div><div>26</div></div><div><span><span>      </span></span><span>- </span><span>18080:80</span></div></div><div><div><div>27</div></div><div><span>    </span><span>environment</span><span>: </span><span># 关联数据库配置，与db服务的环境变量对应</span></div></div><div><div><div>28</div></div><div><span>      </span><span>WORDPRESS_DB_HOST</span><span>: </span><span>db</span><span> </span><span># 数据库服务名（Compose自动解析为容器IP）</span></div></div><div><div><div>29</div></div><div><span>      </span><span>WORDPRESS_DB_NAME</span><span>: </span><span>wordpress</span></div></div><div><div><div>30</div></div><div><span>      </span><span>WORDPRESS_DB_USER</span><span>: </span><span>wordpress</span></div></div><div><div><div>31</div></div><div><span>      </span><span>WORDPRESS_DB_PASSWORD</span><span>: </span><span>yourpassword</span></div></div><div><div><div>32</div></div><div><span>    </span><span>volumes</span><span>: </span><span># 持久化WordPress代码和主题文件</span></div></div><div><div><div>33</div></div><div><span><span>      </span></span><span>- </span><span>'./app:/var/www/html'</span></div></div><div><div><div>34</div></div><div><span>    </span><span>links</span><span>: </span><span># 显式关联db服务（兼容旧版本Compose，可配合depends_on使用）</span></div></div><div><div><div>35</div></div><div><span><span>      </span></span><span>- </span><span>db:db</span></div></div><div><div><div>36</div></div><div><span>    </span><span>depends_on</span><span>: </span><span># 依赖关系：确保redis和db启动后再启动app</span></div></div><div><div><div>37</div></div><div><span><span>      </span></span><span>- </span><span>redis</span></div></div><div><div><div>38</div></div><div><span><span>      </span></span><span>- </span><span>db</span></div></div><div><div><div>39</div></div><div><span>    </span><span>networks</span><span>:</span></div></div><div><div><div>40</div></div><div><span><span>      </span></span><span>- </span><span>default</span></div></div><div><div><div>41</div></div><div>
</div></div><div><div><div>42</div></div><div><span>  </span><span># Redis缓存服务（提升WordPress访问速度）</span></div></div><div><div><div>43</div></div><div><span>  </span><span>redis</span><span>:</span></div></div><div><div><div>44</div></div><div><span>    </span><span>image</span><span>: </span><span>redis:alpine</span><span> </span><span># alpine版本镜像更小，资源占用低</span></div></div><div><div><div>45</div></div><div><span>    </span><span>container_name</span><span>: </span><span>wordpress-redis</span></div></div><div><div><div>46</div></div><div><span>    </span><span>restart</span><span>: </span><span>unless-stopped</span></div></div><div><div><div>47</div></div><div><span>    </span><span>volumes</span><span>: </span><span># 持久化Redis缓存数据</span></div></div><div><div><div>48</div></div><div><span><span>      </span></span><span>- </span><span>./redis-data:/data</span></div></div><div><div><div>49</div></div><div><span>    </span><span>networks</span><span>:</span></div></div><div><div><div>50</div></div><div><span><span>      </span></span><span>- </span><span>default</span></div></div><div><div><div>51</div></div><div>
</div></div><div><div><div>52</div></div><div><span># 自定义网络：所有服务加入同一网络，服务名即主机名</span></div></div><div><div><div>53</div></div><div><span>networks</span><span>:</span></div></div><div><div><div>54</div></div><div><span>  </span><span>default</span><span>:</span></div></div><div><div><div>55</div></div><div><span>    </span><span>name</span><span>: </span><span>wordpress</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><section><h4>实例参数详解<a href="#实例参数详解"><span>#</span></a></h4><ol>
<li><strong>顶层配置</strong>
<ul>
<li><code>version: '3.0'</code>：标识 Compose 配置版本，需与 Docker Engine 版本兼容。</li>
<li><code>services</code>：定义所有服务的集合，包含<code>db</code>（数据库）、<code>app</code>（WordPress 应用）、<code>redis</code>（缓存）三个服务。</li>
<li><code>networks</code>：定义网络配置，此处创建名为<code>wordpress</code>的自定义网络，所有服务加入该网络实现隔离通信。</li>
</ul>
</li>
<li><strong>db 服务（MySQL 数据库）</strong>
<ul>
<li><code>image: mysql:5.7</code>：指定使用 MySQL 5.7 版本镜像（arm 架构需替换为<code>mysql:oracle</code>）。</li>
<li><code>container_name: wordpress-db</code>：自定义容器名称，便于识别和管理。</li>
<li><code>restart: unless-stopped</code>：重启策略，除非手动停止，否则容器退出后自动重启。</li>
<li><code>environment</code>：设置环境变量，包括数据库 root 密码、默认数据库名、用户及密码（需自行修改为复杂密码）。</li>
<li><code>volumes: - './db:/var/lib/mysql'</code>：将宿主机当前目录下的<code>db</code>文件夹挂载到容器的<code>/var/lib/mysql</code>（MySQL 数据存储目录），实现数据持久化。</li>
<li><code>networks: - default</code>：加入<code>default</code>网络（即<code>wordpress</code>网络）。</li>
</ul>
</li>
<li><strong>app 服务（WordPress 应用）</strong>
<ul>
<li><code>image: wordpress:latest</code>：使用 WordPress 最新镜像（推荐用<code>latest</code>，支持后台直接更新）。</li>
<li><code>ports: - 18080:80</code>：端口映射，宿主机 18080 端口映射到容器 80 端口（需确保宿主机防火墙开放 18080 端口）。</li>
<li><code>environment</code>：配置数据库连接信息，<code>WORDPRESS_DB_HOST: db</code>直接使用<code>db</code>服务名作为地址（Compose 自动解析为容器 IP）。</li>
<li><code>volumes: - './app:/var/www/html'</code>：挂载 WordPress 代码目录，确保主题、插件等文件持久化。</li>
<li><code>links: - db:db</code>：显式关联<code>db</code>服务，建立网络通信（兼容旧版本 Compose）。</li>
<li><code>depends_on: - redis - db</code>：定义启动顺序，确保<code>redis</code>和<code>db</code>启动后再启动<code>app</code>，避免依赖服务未就绪导致的错误。</li>
</ul>
</li>
<li><strong>redis 服务（缓存）</strong>
<ul>
<li><code>image: redis:alpine</code>：使用轻量的 Alpine 版本 Redis 镜像，减少资源占用。</li>
<li><code>volumes: - ./redis-data:/data</code>：挂载 Redis 数据目录，持久化缓存数据。</li>
</ul>
</li>
</ol></section></section><section><h3>4.4 Compose 核心命令<a href="#44-compose-核心命令"><span>#</span></a></h3><div><div><div><figure><figcaption><span></span><span>Terminal window</span><span>展开</span><span>收起</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 启动服务（前台运行，日志实时输出）</span></div></div><div><div><div>2</div></div><div><span>docker-compose</span><span> </span><span>up</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 后台启动服务（推荐）</span></div></div><div><div><div>5</div></div><div><span>docker-compose</span><span> </span><span>up</span><span> </span><span>-d</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span># 查看运行中的服务</span></div></div><div><div><div>8</div></div><div><span>docker-compose</span><span> </span><span>ps</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span># 停止服务（保留容器和数据）</span></div></div><div><div><div>11</div></div><div><span>docker-compose</span><span> </span><span>stop</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span># 停止并删除服务、容器、网络（保留数据卷）</span></div></div><div><div><div>14</div></div><div><span>docker-compose</span><span> </span><span>down</span></div></div><div><div><div>15</div></div><div>
</div></div><div><div><div>16</div></div><div><span># 停止并删除所有（包括数据卷）</span></div></div><div><div><div>17</div></div><div><span>docker-compose</span><span> </span><span>down</span><span> </span><span>-v</span></div></div><div><div><div>18</div></div><div>
</div></div><div><div><div>19</div></div><div><span># 拉取最新镜像（针对:latest标签）</span></div></div><div><div><div>20</div></div><div><span>docker-compose</span><span> </span><span>pull</span></div></div><div><div><div>21</div></div><div>
</div></div><div><div><div>22</div></div><div><span># 查看服务日志</span></div></div><div><div><div>23</div></div><div><span>docker-compose</span><span> </span><span>logs</span><span> </span><span>-f</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div></section></section>
<section><h2>五、总结<a href="#五总结"><span>#</span></a></h2><p>Docker 解决了 “环境一致性” 问题，而 Docker Compose 则解决了 “多容器管理复杂性” 问题。它将繁琐的<code>docker run</code>命令整合为结构化的 YAML 文件，不仅层级清晰、易于维护，还支持服务依赖、自定义网络等复杂场景。</p><p>对我而言，Compose 早已取代了<code>docker run</code>和后台 GUI 工具 —— 配置文件可备份、可复用，迁移时只需执行<code>docker-compose up -d</code>即可快速启动整个应用，效率大幅提升。</p></section>
<section><h2>参考<a href="#参考"><span>#</span></a></h2><ol>
<li><a href="https://www.runoob.com/docker/docker-tutorial.html" target="_blank">Docker 教程 | 菜鸟教程</a></li>
<li><a href="https://docs.docker.com/compose/" target="_blank">Docker Compose | Docker Docs</a></li>
</ol></section>]]></content>
    </entry>
    <entry>
      <id>https://blog.leihub.cn/archives/61/</id>
      <title type="text">群晖FRP内网穿透教程：公网随时访问你的NAS</title>
      <published>2021-06-21T14:23:50.000Z</published>
      <updated>2025-11-12T12:22:49.000Z</updated>
      <author><name>阿雷</name></author>
      <link rel="alternate" href="https://blog.leihub.cn/archives/61/"/>
      <summary type="text">2025.11.12 更新 增加docker compose安装 前言：为什么需要FRP穿透？ 很多朋友入手NAS后都会遇到一个问题：家里没有公网IPv4，NAS只能在WiFi下访问，出门想传个文件、看个相册都没辙。 FRP（Fast Re</summary>
      <content type="html"><![CDATA[<ul>
<li>**2025.11.12 **更新 增加docker compose安装</li>
</ul>
<section><h2>前言：为什么需要FRP穿透？<a href="#前言为什么需要frp穿透"><span>#</span></a></h2><p>很多朋友入手NAS后都会遇到一个问题：家里没有公网IPv4，NAS只能在WiFi下访问，出门想传个文件、看个相册都没辙。</p><p>FRP（Fast Reverse Proxy）就是解决这个问题的利器——它能通过一台有公网IP的云服务器，把内网的服务“映射”到公网上，能让你随时访问家里内网的NAS。</p><p>本文提供<strong>Docker</strong>和<strong>源码运行</strong>两种配置方案，跟着做就能搞定公网访问。</p></section>
<section><h2>1、前期准备<a href="#1前期准备"><span>#</span></a></h2><p>先把“弹药”备齐，避免操作到一半卡壳。新手务必逐项核对：</p><ul>
<li><strong>NAS</strong>：确保已开启SSH（控制面板→终端机和SNMP→勾选“启动SSH功能”）。</li>
<li><strong>云服务器</strong>：1核2G配置足够（学生机性价比高），必须有公网IPv4，带宽建议1M以上（决定访问速度上限），系统选CentOS或Ubuntu。</li>
<li><strong>工具</strong>：SSH客户端（Xshell、FinalShell，免费可用），文件传输工具（WinSCP，传配置文件用）。</li>
</ul></section>
<section><h2>2、核心原理：FRP怎么工作<a href="#2核心原理frp怎么工作"><span>#</span></a></h2><ul>
<li><strong>服务端（云服务器）</strong>：相当于“桥头堡”，在公网上监听请求，绑定固定端口（如7000）。</li>
<li><strong>客户端（NAS）</strong>：相当于“家里的哨兵”，主动连接云服务器的服务端，保持长连接。</li>
<li><strong>数据流向</strong>：公网访问云服务器FRP→服务端转发给NAS客户端→群晖返回数据，完成穿透。</li>
</ul></section>
<section><h2>3、服务端配置：云服务器部署FRP服务<a href="#3服务端配置云服务器部署frp服务"><span>#</span></a></h2><p>先部署服务端FRP，以CentOS 7为例，全程命令行操作，复制粘贴即可。</p><section><h3>步骤1：下载并解压FRP包<a href="#步骤1下载并解压frp包"><span>#</span></a></h3><p>用SSH工具连接云服务器，执行以下命令（64位系统通用）：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 下载FRP压缩包（0.33.0版本，若下新版本替换链接即可）</span></div></div><div><div><div>2</div></div><div><span>wget</span><span> </span><span>https://github.com/fatedier/frp/releases/download/v0.33.0/frp_0.33.0_linux_amd64.tar.gz</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 解压到当前目录</span></div></div><div><div><div>5</div></div><div><span>tar</span><span> </span><span>-zxvf</span><span> </span><span>frp_0.33.0_linux_amd64.tar.gz</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span># 进入解压后的文件夹</span></div></div><div><div><div>8</div></div><div><span>cd</span><span> </span><span>frp_0.33.0_linux_amd64</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>如果wget下载失败（网络问题），直接在本地浏览器打开链接下载，再用WinSCP上传到云服务器，然后执行解压命令。</p></section><section><h3>步骤2：编辑服务端配置文件frps.ini<a href="#步骤2编辑服务端配置文件frpsini"><span>#</span></a></h3><p>FRP服务端核心配置文件，用vi命令编辑：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>vi</span><span> </span><span>frps.ini</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>按<code>i</code>进入编辑模式，粘贴以下内容，关键参数已标注修改说明：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>[common]</span></div></div><div><div><div>2</div></div><div><span>bind_addr</span><span><span> </span><span>=</span><span> 0.0.0.0          </span></span><span># 允许所有IP连接，固定填这个</span></div></div><div><div><div>3</div></div><div><span>bind_port</span><span><span> </span><span>=</span><span> 7000             </span></span><span># 服务端与客户端通信的端口，需开放（如7000）</span></div></div><div><div><div>4</div></div><div><span>privilege_token</span><span><span> </span><span>=</span><span> 2fd165jtyjsd0g5t4hdga16  </span></span><span># 安全密钥，自己编个复杂的（字母+数字），客户端要和这个一致</span></div></div><div><div><div>5</div></div><div><span>vhost_http_port</span><span><span> </span><span>=</span><span> 5000       </span></span><span># 转发HTTP请求的端口（如5000）</span></div></div><div><div><div>6</div></div><div><span>vhost_https_port</span><span><span> </span><span>=</span><span> 6000      </span></span><span># 转发HTTPS请求的端口（如6000）</span></div></div><div><div><div>7</div></div><div><span>dashboard_port</span><span><span> </span><span>=</span><span> 7500        </span></span><span># FRP控制台端口，可查看连接状态</span></div></div><div><div><div>8</div></div><div><span>dashboard_user</span><span><span> </span><span>=</span><span> admin       </span></span><span># 控制台用户名</span></div></div><div><div><div>9</div></div><div><span>dashboard_pwd</span><span><span> </span><span>=</span><span> admin123     </span></span><span># 控制台密码</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>编辑完成后，按<code>Esc</code>，输入<code>:wq</code>保存退出。</p></section><section><h3>步骤3：开放端口+启动服务端<a href="#步骤3开放端口启动服务端"><span>#</span></a></h3><p>这步是关键！云服务器的安全组和防火墙都要开放端口（7000、5000、6000、7500）：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 1. 防火墙开放端口（CentOS用firewalld，Ubuntu用ufw，根据系统选对应命令）</span></div></div><div><div><div>2</div></div><div><span># CentOS系统执行：</span></div></div><div><div><div>3</div></div><div><span>sudo</span><span> </span><span>firewall-cmd</span><span> </span><span>--zone=public</span><span> </span><span>--add-port=7000/tcp</span><span> </span><span>--permanent</span></div></div><div><div><div>4</div></div><div><span>sudo</span><span> </span><span>firewall-cmd</span><span> </span><span>--zone=public</span><span> </span><span>--add-port=5000/tcp</span><span> </span><span>--permanent</span></div></div><div><div><div>5</div></div><div><span>sudo</span><span> </span><span>firewall-cmd</span><span> </span><span>--zone=public</span><span> </span><span>--add-port=6000/tcp</span><span> </span><span>--permanent</span></div></div><div><div><div>6</div></div><div><span>sudo</span><span> </span><span>firewall-cmd</span><span> </span><span>--zone=public</span><span> </span><span>--add-port=7500/tcp</span><span> </span><span>--permanent</span></div></div><div><div><div>7</div></div><div><span>sudo</span><span> </span><span>firewall-cmd</span><span> </span><span>--reload</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span># Ubuntu系统执行：</span></div></div><div><div><div>10</div></div><div><span>sudo</span><span> </span><span>ufw</span><span> </span><span>allow</span><span> </span><span>7000/tcp</span></div></div><div><div><div>11</div></div><div><span>sudo</span><span> </span><span>ufw</span><span> </span><span>allow</span><span> </span><span>5000/tcp</span></div></div><div><div><div>12</div></div><div><span>sudo</span><span> </span><span>ufw</span><span> </span><span>allow</span><span> </span><span>6000/tcp</span></div></div><div><div><div>13</div></div><div><span>sudo</span><span> </span><span>ufw</span><span> </span><span>allow</span><span> </span><span>7500/tcp</span></div></div><div><div><div>14</div></div><div><span>sudo</span><span> </span><span>ufw</span><span> </span><span>reload</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>然后用nohup命令让FRP在后台运行（关闭SSH窗口也不停止）：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>nohup</span><span> </span><span>./frps</span><span> </span><span>-c</span><span> </span><span>./frps.ini</span><span> &amp;</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>验证是否启动成功：打开浏览器访问<code>云服务器IP:7500</code>，输入控制台用户名密码，能看到FRP面板就说明服务端没问题了。</p><p>（直接执行<code>./frps -c ./frps.ini</code>会显示启动日志，如下图，用nohup启动不会显示日志）</p><p></p><figure><img src="http://imgbed.leihub.cn/img/20200724151227.png" alt="img" /><figcaption>img</figcaption></figure><p></p></section></section>
<section><h2>4、客户端配置：NAS连接服务端<a href="#4客户端配置nas连接服务端"><span>#</span></a></h2><p>NAS作为客户端，有两种配置方式：Docker和源码部署，选一种就行。</p><section><h3>方案A：Docker配置<a href="#方案adocker配置"><span>#</span></a></h3><p>群晖Docker套件操作简单，不用记命令，适合刚接触NAS的用户。</p><section><h4>步骤1：下载FRP镜像<a href="#步骤1下载frp镜像"><span>#</span></a></h4><ol>
<li>打开群晖<code>Docker</code>套件，切换到「注册表」。</li>
<li>搜索栏输入<code>chenhw</code>，找到<code>chenhw/frp</code>镜像，双击默认下载（标签选latest）。</li>
</ol></section><section><h4>步骤2：准备客户端配置文件frpc.ini<a href="#步骤2准备客户端配置文件frpcini"><span>#</span></a></h4><p>先在群晖里建个存放FRP配置的文件夹，方便后续修改：</p><ol>
<li>打开<code>File Station</code>，进入「docker」文件夹，新建子文件夹<code>frp</code>。</li>
<li>在本地电脑用记事本新建<code>frpc.ini</code>文件，粘贴以下内容（替换成你的信息）：</li>
</ol><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>[common]</span></div></div><div><div><div>2</div></div><div><span>server_addr</span><span><span> </span><span>=</span><span> nas.yourname.com  </span></span><span># 你的云服务器域名或公网IP</span></div></div><div><div><div>3</div></div><div><span>server_port</span><span><span> </span><span>=</span><span> 7000              </span></span><span># 和服务端bind_port一致（7000）</span></div></div><div><div><div>4</div></div><div><span>auth_token</span><span><span> </span><span>=</span><span> 2fd165jtyjsd0g5t4hdga16  </span></span><span># 和服务端privilege_token完全一致</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span># 转发群晖DSM网页服务（5000端口是群晖默认HTTP端口）</span></div></div><div><div><div>7</div></div><div><span>[synology-dsm]</span></div></div><div><div><div>8</div></div><div><span>type</span><span><span> </span><span>=</span><span> http</span></span></div></div><div><div><div>9</div></div><div><span>local_ip</span><span><span> </span><span>=</span><span> 192.168.1.100        </span></span><span># 群晖的内网IP（在群晖控制面板→网络里看）</span></div></div><div><div><div>10</div></div><div><span>local_port</span><span><span> </span><span>=</span><span> 5000</span></span></div></div><div><div><div>11</div></div><div><span>remote_port</span><span><span> </span><span>=</span><span> 5000  </span></span><span># 公网访问的端口（自定义，如5000，需在服务端开放）</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span># 转发群晖SSH（22端口，可选，方便公网SSH管理群晖）</span></div></div><div><div><div>14</div></div><div><span>[synology-ssh]</span></div></div><div><div><div>15</div></div><div><span>type</span><span><span> </span><span>=</span><span> tcp</span></span></div></div><div><div><div>16</div></div><div><span>local_ip</span><span><span> </span><span>=</span><span> 192.168.1.100</span></span></div></div><div><div><div>17</div></div><div><span>local_port</span><span><span> </span><span>=</span><span> 22</span></span></div></div><div><div><div>18</div></div><div><span>remote_port</span><span><span> </span><span>=</span><span> 2222  </span></span><span># 公网访问的端口（自定义，如2222，需在服务端开放）</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>展开</span><span>收起</span></div></div><p>将编辑好的<code>frpc.ini</code>上传到群晖的<code>docker/frp</code>文件夹。</p></section><section><h4>步骤3：创建FRP容器并配置<a href="#步骤3创建frp容器并配置"><span>#</span></a></h4><ol>
<li>Docker套件切换到「映像」，双击<code>chenhw/frp</code>镜像，进入容器创建向导。</li>
<li>点击「高级设置」，重点配置以下3项（其他保持默认）：</li>
</ol><ul>
<li><strong>基本设置</strong>：勾选「启用自动重新启动」（群晖重启后FRP自动启动）。</li>
<li><strong>卷</strong>：点击「添加文件」，左侧选群晖的<code>docker/frp/frpc.ini</code>，右侧填<code>/frp/frpc.ini</code>（容器内的配置文件路径，固定填这个）。</li>
<li><strong>环境</strong>：点击「添加」，变量名填<code>FRP_ROLE</code>，变量值填<code>client</code>（告诉容器这是客户端模式）。</li>
</ul><p>配置完成后点击「下一步」→「创建」，容器启动后，在Docker「容器」列表能看到状态为「运行中」。</p></section></section><section><h3>方案B：Docker compose配置<a href="#方案bdocker-compose配置"><span>#</span></a></h3><p>在<code>~/docker/frp</code>目录下创建配置文件：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>vim</span><span> </span><span>docker-compose.yml</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>以下配置使用 DaoCloud 镜像加速，避免国内拉取镜像缓慢，关键参数已标注说明：</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>version</span><span>: </span><span>'3.3'</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>services</span><span>:</span></div></div><div><div><div>4</div></div><div><span>  </span><span>frpc</span><span>:</span></div></div><div><div><div>5</div></div><div><span>    </span><span>image</span><span>: </span><span>docker.leitool.top/snowdreamtech/frpc:latest</span></div></div><div><div><div>6</div></div><div><span>    </span><span>container_name</span><span>: </span><span>frpc</span></div></div><div><div><div>7</div></div><div><span>    </span><span>restart</span><span>: </span><span>unless-stopped</span><span>  </span><span># 自动重启（除非手动停止）</span></div></div><div><div><div>8</div></div><div><span>    </span><span>volumes</span><span>:</span></div></div><div><div><div>9</div></div><div><span><span>      </span></span><span>- </span><span>./frpc.toml:/etc/frp/frpc.toml</span><span> </span><span># 挂载配置文件</span></div></div><div><div><div>10</div></div><div><span>    </span><span>network_mode</span><span>: </span><span>host</span><span>  </span><span># 使用主机网络模式（可选，根据需求调整）</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>配置文件<code>frpc.ini</code>与方案A是一样的，上传到群晖的<code>docker/frp</code>文件夹。</p><p>保存配置文件后，执行以下命令启动容器：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 后台启动服务</span></div></div><div><div><div>2</div></div><div><span>docker-compose</span><span> </span><span>up</span><span> </span><span>-d</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section><section><h3>方案C：执行文件部署<a href="#方案c执行文件部署"><span>#</span></a></h3><p>如果习惯命令行操作，也可以直接下载执行文件进行部署。</p><section><h4>步骤1：SSH连接群晖并下载FRP<a href="#步骤1ssh连接群晖并下载frp"><span>#</span></a></h4><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 下载FRP包（和服务端版本一致，0.33.0）</span></div></div><div><div><div>2</div></div><div><span>wget</span><span> </span><span>https://github.com/fatedier/frp/releases/download/v0.33.0/frp_0.33.0_linux_amd64.tar.gz</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 解压</span></div></div><div><div><div>5</div></div><div><span>tar</span><span> </span><span>-zxvf</span><span> </span><span>frp_0.33.0_linux_amd64.tar.gz</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span># 进入文件夹</span></div></div><div><div><div>8</div></div><div><span>cd</span><span> </span><span>frp_0.33.0_linux_amd64</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div></section><section><h4>步骤2：编辑frpc.ini（和Docker方案的配置一致）<a href="#步骤2编辑frpcini和docker方案的配置一致"><span>#</span></a></h4><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>vi</span><span> </span><span>frpc.ini</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>粘贴方案A中的frpc.ini内容，保存退出。</p></section><section><h4>步骤3：启动客户端并设置开机自启<a href="#步骤3启动客户端并设置开机自启"><span>#</span></a></h4><p>先测试启动是否正常：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>./frpc</span><span> </span><span>-c</span><span> </span><span>./frpc.ini</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>如果显示「start proxy success」，说明连接成功。按<code>Ctrl+C</code>停止，再用nohup后台启动：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>nohup</span><span> </span><span>./frpc</span><span> </span><span>-c</span><span> </span><span>./frpc.ini</span><span> &amp;</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>为了让群晖重启后FRP自动运行，创建自启脚本：</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span># 1. 创建启动脚本</span></div></div><div><div><div>2</div></div><div><span>vi</span><span> </span><span>/usr/syno/etc.defaults/rc.sysv/frpc.sh</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span># 2. 粘贴以下内容（路径替换成你的FRP文件夹路径）</span></div></div><div><div><div>5</div></div><div><span>#!/bin/sh</span></div></div><div><div><div>6</div></div><div><span>cd</span><span> </span><span>/root/frp_0.33.0_linux_amd64</span><span>  </span><span># FRP解压后的路径</span></div></div><div><div><div>7</div></div><div><span>nohup</span><span> </span><span>./frpc</span><span> </span><span>-c</span><span> </span><span>./frpc.ini</span><span> &amp;</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span># 3. 给脚本加执行权限</span></div></div><div><div><div>10</div></div><div><span>chmod</span><span> </span><span>+x</span><span> </span><span>/usr/syno/etc.defaults/rc.sysv/frpc.sh</span></div></div><div><div><div>11</div></div><div>
</div></div><div><div><div>12</div></div><div><span># 4. 加入系统启动项</span></div></div><div><div><div>13</div></div><div><span>echo</span><span> </span><span>"/usr/syno/etc.defaults/rc.sysv/frpc.sh"</span><span> &gt;&gt; </span><span>/etc/rc</span></div></div></code></pre><div><div></div><div></div></div><div></div></figure></div><p>重启群晖后，执行<code>ps aux | grep frpc</code>，能看到frpc进程就说明自启成功。</p></section></section></section>
<section><h2>参考资料<a href="#参考资料"><span>#</span></a></h2><ul>
<li>FRP官方文档：<a href="https://gofrp.org/docs/" target="_blank">https://gofrp.org/docs/</a></li>
</ul></section>]]></content>
    </entry>
</feed>
