diff --git a/.claude/skills/upload-file/SKILL.md b/.claude/skills/upload-file/SKILL.md index d2b9e17..2e59896 100644 --- a/.claude/skills/upload-file/SKILL.md +++ b/.claude/skills/upload-file/SKILL.md @@ -21,7 +21,7 @@ this file** — a stale vocabulary here is worse than none, because it produces confident wrong answers. ```bash -python3 -c "import sys;sys.path.insert(0,'scripts');import wrfiles as w;print(w.KINDS);print(w.LANGS);print(sorted(w.CONTENT_TYPES))" +python3 -c "import sys;sys.path.insert(0,'scripts');import wrfiles as w;print(w.SECTIONS);print(w.KINDS);print(w.LANGS);print(sorted(w.CONTENT_TYPES))" ``` ## What you must establish @@ -35,7 +35,7 @@ Ask for whatever is missing. Ask in one message, not four. | **subject** | Optional, and the thing most often missed. Ask whether this is *the* CAD model / manual for the product or one of several — a wheel kit, a charging dock, a battery. If there is any chance of a second file of the same kind, include it: without a subject the second one overwrites the first and nothing reports it. | | **lang** | One of `LANGS`. Look inside the document if unsure; do not assume English. | | **version** | **From the document itself**, or the issue date when the manufacturer gives none — `v2020.10.29`, read from the file's own header. Never `v1` by default. — cover page, revision table, footer. Open it and check. Never invent one, never default to `v1`: it is permanent. If genuinely unversioned, say so and agree one with the user rather than guessing. | -| **section** | The top-level content directory the page lives in: `robot`, `solution`, `peripheral`, `system`, `tutorial`, `support`. | +| **section** | One of `SECTIONS`: the top-level content directory the page lives in. | If the extension is not in `CONTENT_TYPES`, stop. Adding one is a deliberate edit to `wrfiles.py` with the right MIME type, not something to do in passing. @@ -50,7 +50,21 @@ Publishing needs the AWS CLI, boto3, credentials and `WR_FILES_DISTRIBUTION_ID` `static/_upload/
//-[-]--v.`. Copying leaves the user's original where they left it. -2. **Dry run.** `python3 scripts/publish-files.py` +2. **Put it on the page,** if it is not already there. One component covers + every document for that product: + + ```jsx + + ``` + + It belongs in *Related resources*, under **Documents we publish**, never in + the hand-maintained table beside it. Do not write a link to the file by hand. + If that table has a dead link to this document, delete the row. + +3. **Preview.** `npm run start` and check the page. The staged file shows in + the table marked `staged`. + +4. **Dry run.** `python3 scripts/publish-files.py` `--list ` first is worth it when replacing something: it shows what is already published for that product, so you can see whether this is a new @@ -60,13 +74,13 @@ Publishing needs the AWS CLI, boto3, credentials and `WR_FILES_DISTRIBUTION_ID` nothing has been uploaded — fix the name and run it again. Never work around a refusal by editing the script. -3. **Publish.** `python3 scripts/publish-files.py --publish` +5. **Publish.** `python3 scripts/publish-files.py --publish` Needs `WR_FILES_DISTRIBUTION_ID` set, or the CDN is not invalidated — harmless for a new document, since published keys are immutable, but it delays `index.json` by up to a minute. -4. **Verify it actually served.** Not optional, and not satisfied by the script +6. **Verify it actually served.** Not optional, and not satisfied by the script exiting zero: ```bash @@ -78,24 +92,21 @@ Publishing needs the AWS CLI, boto3, credentials and `WR_FILES_DISTRIBUTION_ID` looks stale, that is the invalidation propagating — re-check after a minute rather than republishing. -5. **Put it on the page,** if it is not already there. One component covers - every document for that product: - - ```jsx - - ``` - - It belongs in *Related resources*, under **Documents we publish** — never in - the hand-maintained table beside it. If the page has a dead link to the - document you just published, delete that row. - -6. **Rebuild and look.** `npm run build && npm run serve`, then the product page. +7. **Rebuild and look.** `npm run build && npm run serve`, then the product page. A local build with the file still staged shows the **local** copy, badged - `staged`. To see what a customer gets, remove `static/_upload/` first and - rebuild — that is the build CI produces. + `staged`. To see what a customer gets — the build CI produces — move + `static/_upload/` outside the repository while you build, then move it back. + Do not delete it: it can hold staged documents that are not published yet. + + ```bash + mv static/_upload ../_upload.hold + npm run build && npm run serve + # after stopping the server: + mv ../_upload.hold static/_upload + ``` -7. **Clean up.** Delete the staged copy once published; it is scaffolding, and +8. **Clean up.** Delete the staged copy once published; it is scaffolding, and the page now resolves from the store. ## Things that will bite @@ -110,8 +121,8 @@ the correct one alongside; the wrong key simply stays. Check the document, do not infer from a filename someone else chose. **`npm run check:downloads` must pass** before committing. It fails if a page -still points into `static/_upload/`, which means the document was never -uploaded and the page would 404 for everyone but you. +still points into `static/_upload/`, which would 404 for everyone but you, or +if a `` query matches nothing in the store. **Do not commit the file.** `static/_upload/` is gitignored deliberately; the repository is already ~350 MB packed and git history is permanent. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eeb4fd7..cf70591 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ Everything here is a **task**. Where a task has reasoning behind it, this file l ## Who this is for -This repository is edited by people writing documentation. **Technicians publishing a manual do not need it** — they upload through the AWS console and never clone anything. That flow is [`docs/design/file-hosting.md` §3](docs/design/file-hosting.md). +This repository is edited by people writing documentation. A technician with a manual to publish can hand the file to someone in the `DocsDownloadPublishers` group, or use the upload-file skill (`.claude/skills/upload-file/SKILL.md`). ## Before you open a pull request @@ -98,9 +98,10 @@ Manuals, SDK archives, firmware. These live in the file store, never in git — 1. Put the file in `static/_upload/
//`, **at the path it will occupy in the store**: `static/_upload/robot/wr65/wr65-user-manual-en-v2.3.pdf`. The directory is gitignored. **The name matters** — it carries all the metadata and is checked rather than trusted. See [Naming a document](#naming-a-document) below before you copy anything in. -2. `npm run start` and check the page. The link works locally, so you are reviewing the real thing. -3. `python3 scripts/publish-files.py` shows what it would do. Add `--publish` to upload and rewrite the page's link to the published URL. -4. Rebuild and look again. The second review is against exactly what a customer gets. +2. Check the page has ``, with the same `` as the directory, and add it if not. Do not write a link to the file by hand. +3. `npm run start` and check the page. The staged file shows in the table marked *staged*, so you are reviewing the real thing. +4. `python3 scripts/publish-files.py` shows what it would do. Add `--publish` to upload. +5. Rebuild and look again. The second review is against exactly what a customer gets. ### Has it actually gone up? @@ -122,7 +123,7 @@ curl -s https://download.westonrobot.net/index.json | grep wr65 That is the same file the site build reads, so if a document is in there it is live. -`npm run check:downloads` fails if a page still points into `static/_upload/`. That is not a lint rule — CI has no copy of your local file, so such a page would 404 for everyone but you. +`npm run check:downloads` fails if a page still points into `static/_upload/`. That is not a lint rule — CI has no copy of your local file, so such a page would 404 for everyone but you. It also fails if a `` query matches nothing in the store's index. If the index can't be reached, it reports those queries as not checked and does not fail. The path convention is [ADR 0001 D4](docs/adr/0001-host-downloadable-documents-on-s3.md): `/
//`, and a published path is **never renamed or deleted**. A customer's bookmark, a QR code printed on a chassis and a support email from 2024 all depend on that. @@ -137,14 +138,14 @@ static/_upload/
//-[-]--v` | one of `robot`, `solution`, `peripheral`, `system`, `tutorial`, `support` | first path segment of the URL | +| `
` | one of `robot`, `solution`, `peripheral`, `system`, `guides`, `support` | first path segment of the URL | | `` | lowercase and hyphens. **Must match the page's ``** or the document will not appear | second path segment — this is what groups every file for one robot | | `-` | the filename repeats the product slug | so the name still means something once someone has saved it to a desktop | -| `` | **one of the listed values below** — not free text | the **Document** column, tidied for display: `user-manual` → "User manual" | +| `` | **one of the listed values below** — not free text | the **File** column, tidied for display: `user-manual` → "User manual" | | `` | **optional**, free text, lowercase and hyphens. Use it when a product has more than one of a kind — a CAD model of the body *and* of a wheel kit, a manual for the robot *and* for an accessory | appended to the **File** column: `CAD · Off road wheel`. Without it two such files share a key and the second silently overwrites the first | -| `` | **one of `en`, `zh`, `zh-hans`, `zh-hant`** | the **Language** column | +| `` | **one of `en`, `zh`, `zh-hans`, `zh-hant`, `zxx`**. `zxx` means no language: CAD models, firmware images, wiring diagrams | the **Language** column, shown as English, 中文, 简体中文, 繁體中文 or — | | `v` | `v` then digits and dots: `v2`, `v2.0`, `v2.0.1` | the **Version** column, sorted numerically so `v2.1` correctly beats `v2.0.9` | -| `` | must be in the publishable set — PDF, ZIP, tar.gz, MP4, XLSX and a few others | sets `Content-Type`; an unlisted extension is refused rather than served as a generic download | +| `` | must be in the publishable set — PDF, ZIP, tar.gz, MP4, XLSX and a few others | the **Type** column, and sets `Content-Type`; an unlisted extension is refused rather than served as a generic download | **Use the version printed on the document itself.** It becomes part of a permanent URL that is never renamed (ADR 0001 D4), so a guessed version is wrong forever. @@ -163,7 +164,7 @@ A hyphenated subject renders with spaces — `off-road-wheel` becomes "Off road #### The `kind` vocabulary -Fixed on purpose, and covering what a hardware documentation site normally carries. Free text here is how a store ends up holding `cad`, `CAD`, `STP` and `STL` for the same thing — at which point `` stops being usable and the Document column reads inconsistently. +Fixed on purpose, and covering what a hardware documentation site normally carries. Free text here is how a store ends up holding `cad`, `CAD`, `STP` and `STL` for the same thing — at which point `` stops being usable and the File column reads inconsistently. | Group | Values | | --- | --- | @@ -177,7 +178,7 @@ Three that catch people out: - **`cad` covers STEP, STL and DXF.** The format is the extension; the kind is what the document *is*. - **`manual` is not a value** — use `user-manual`, so it cannot drift apart from itself. -- **Chinese is `zh`, never `cn`.** Language is one of `en`, `zh`, `zh-hans`, `zh-hant`. +- **Chinese is `zh`, never `cn`.** Language is one of `en`, `zh`, `zh-hans`, `zh-hant`, `zxx`. A file with no language in it, such as a CAD model, firmware image or wiring diagram, is `zxx`, not `en`. If something genuinely new comes along, add it to `KINDS` in `scripts/wrfiles.py`. The moment's thought about whether it duplicates a value already there is the entire point of the list. @@ -185,11 +186,11 @@ If something genuinely new comes along, add it to `KINDS` in `scripts/wrfiles.py | Filename | Renders as | URL becomes | | --- | --- | --- | -| `scout-mini-user-manual-en-v2.0.1.pdf` | User manual · en · v2.0.1 | `download.westonrobot.net/robot/scout-mini/scout-mini-user-manual-en-v2.0.1.pdf` | -| `scout-mini-user-manual-zh-v2.0.1.pdf` | User manual · zh · v2.0.1 | `download.westonrobot.net/robot/scout-mini/scout-mini-user-manual-zh-v2.0.1.pdf` | -| `scout-mini-quick-start-en-v1.pdf` | Quick start · en · v1 | `download.westonrobot.net/robot/scout-mini/scout-mini-quick-start-en-v1.pdf` | -| `scout-mini-cad-en-v1.zip` | Cad · en · v1 | `download.westonrobot.net/robot/scout-mini/scout-mini-cad-en-v1.zip` | -| `wr65-wire-protocol-en-v3.2.pdf` | Wire protocol · en · v3.2 | `download.westonrobot.net/robot/wr65/wr65-wire-protocol-en-v3.2.pdf` | +| `scout-mini-user-manual-en-v2.0.1.pdf` | User manual · English · v2.0.1 | `download.westonrobot.net/robot/scout-mini/scout-mini-user-manual-en-v2.0.1.pdf` | +| `scout-mini-user-manual-zh-v2.0.1.pdf` | User manual · 中文 · v2.0.1 | `download.westonrobot.net/robot/scout-mini/scout-mini-user-manual-zh-v2.0.1.pdf` | +| `scout-mini-quick-start-en-v1.pdf` | Quick start · English · v1 | `download.westonrobot.net/robot/scout-mini/scout-mini-quick-start-en-v1.pdf` | +| `scout-mini-cad-zxx-v1.zip` | CAD · — · v1 | `download.westonrobot.net/robot/scout-mini/scout-mini-cad-zxx-v1.zip` | +| `wr65-api-reference-wire-protocol-en-v3.2.pdf` | API reference · Wire protocol · English · v3.2 | `download.westonrobot.net/robot/wr65/wr65-api-reference-wire-protocol-en-v3.2.pdf` | The two Scout Mini rows differ only by language, and both appear in the same table — one row each, no page edit. That is the point of the convention: the store answers `product="scout-mini"` with everything it has. @@ -235,12 +236,25 @@ Anything larger, or anything re-shot on a release cadence, belongs in the file s Add a redirect in `docusaurus.config.ts`. Old URLs are in circulation with customers and pasted into support tickets, so a moved page without a redirect is a broken link for someone who has no idea the page moved. +Update `static/llms.txt` in the same change if it lists the page. The build does not check that file ([`docs/design/ia-proposal.md`](docs/design/ia-proposal.md) §10). + +## Unlisting a page + +1. Set `unlisted: true` in the page's front matter. +2. Add the route to `excludeRoutes` under `docusaurus-lunr-search` in `docusaurus.config.ts`. Search does not read the front matter. The entries are globs, so a page with its own directory needs both `**/x` and `**/x/**`. +3. Remove any `` that links to the page, such as on `robot/intro.md`. Unlisting does not hide the card. +4. Check with `npm run build && npm run serve`, not `npm start`. The dev server shows unlisted pages. + +See [`docs/LESSONS.md`](docs/LESSONS.md), *"A page hidden from the sidebar is still in site search"*. + ## Recording a decision - **Design decisions** → an ADR in `docs/adr/`, including the rejected alternatives and *why*. A decision without its discarded options cannot be re-evaluated later. - **Findings and follow-ups** → [`TODO.md`](TODO.md), with the `file:line` and how it was verified. - **Operational lessons** → [`docs/LESSONS.md`](docs/LESSONS.md), in Pattern / Correction / Context form. +**Not in a config file.** `docusaurus.config.ts`, the sidebars and CI workflows record *what* is set. A comment there may explain a mechanism a maintainer needs at that line. The reasoning behind a decision goes in an ADR, the design doc it amends, `TODO.md` or `docs/LESSONS.md`, with at most a one-line pointer left behind. If the comment would change when the decision is revisited, it moves. See [`docs/LESSONS.md`](docs/LESSONS.md), *"Rationale in a config file is filed where nobody looks for a decision"*. + If an accepted decision contradicts an existing document, fix that document in the same change. An ADR that disagrees with the design doc is worse than no ADR. ## Where things are @@ -251,6 +265,6 @@ If an accepted decision contradicts an existing document, fix that document in t | How a product page is laid out | `docs/design/product-page-template.md` | | How the file store works | `docs/design/file-hosting.md` | | Why the file store exists, and its decisions | `docs/adr/0001-host-downloadable-documents-on-s3.md` | -| Deploying the file store infrastructure | `infra/README.md` | +| Deploying the file store infrastructure | the private infrastructure repository | | Mistakes already made once | `docs/LESSONS.md` | | What is open | `TODO.md` | diff --git a/README.md b/README.md index e43d80e..dde1bf6 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Documentation is split into six independent Docusaurus docs plugin instances, ea | `/peripheral` | `peripheral/` | `sidebars-peripheral.ts` | | `/system` | `system/` | `sidebars-system.ts` | | `/solution` | `solution/` | `sidebars-solution.ts` | -| `/tutorial` | `tutorial/` | `sidebars-tutorial.ts` | +| `/guides` | `guides/` | `sidebars-guides.ts` | The `general` and `software` sections were dissolved; `docusaurus.config.ts` keeps redirects for their old URLs, because support engineers paste them into tickets. diff --git a/TODO.md b/TODO.md index ea26395..ace3974 100644 --- a/TODO.md +++ b/TODO.md @@ -33,9 +33,9 @@ New page, not yet published. It is the hardware third of the Autonomy Stack, whi - [x] **Closed 2026-09-11 — support for a solution-delivered robot is single-point-of-contact, and this diverges from the product-page convention on purpose.** A draft said base faults (locomotion, joints, the manufacturer's controls) were covered by Unitree's documentation, with only the payload and onboard software coming to us. **Removed on the owner's ruling: a robot delivered as part of the solution is supported by Weston Robot end to end, and the customer is not routed to the vendor.** Note what this does *not* contradict: `docs/design/product-page-template.md` tier 1 says "Defer. Link the vendor" for the B2, A2 and Go2 — and that stays correct on `robot/quadruped/*`, where the reader bought a bare development platform. **The same hardware carries two support models depending on how it was sold**, so do not apply the tier-1 rule to this page. The vendor pages are still linked here, but as a reference for base specifications only, never as a support route. **Also removed on the owner's instruction:** the update path's VPN-and-SSH prerequisite, which a draft raised as something to take to the customer's network-security owner before a site survey. The page now says only that Weston Robot updates the onboard software and coordinates with the customer's operations team. The prerequisite itself is real and is still recorded in `docs/design/release-pages-plan.md` §6, including that on-site SSH has been refused outright by some customers' security rules — it belongs in a deployment conversation, not on a post-purchase page. -- [ ] **`tutorial/robot-maintenance.md` §Firmware and software contradicts the Robot Platforms support model.** It tells the reader to "Record the version before and after any update", not to "update firmware mid-project", and to keep a note of "anything you built yourself — reimaging loses it". That addresses someone who manages their own platform; `solution/robot-platforms/index.md` says updates are Weston Robot's and there is nothing for the customer's team to run. The Robot Platforms page now links the maintenance guide and states in place that its firmware guidance does not apply — a patch, not a fix. **The real question is whether that guide should be split by audience, or carry a per-section note**, since it is linked from 13 robot pages that *are* self-managed as well as from here. Found while adding the "Operating and maintaining" section on 2026-09-11. +- [ ] **`guides/robot-maintenance.md` §Firmware and software contradicts the Robot Platforms support model.** It tells the reader to "Record the version before and after any update", not to "update firmware mid-project", and to keep a note of "anything you built yourself — reimaging loses it". That addresses someone who manages their own platform; `solution/robot-platforms/index.md` says updates are Weston Robot's and there is nothing for the customer's team to run. The Robot Platforms page now links the maintenance guide and states in place that its firmware guidance does not apply — a patch, not a fix. **The real question is whether that guide should be split by audience, or carry a per-section note**, since it is linked from 13 robot pages that *are* self-managed as well as from here. Found while adding the "Operating and maintaining" section on 2026-09-11. -- [ ] **Link-loss policy has no default and no setting location.** `solution/robot-platforms/index.md:77` says the behaviour is set by policy — stop safely, halt immediately, or keep going — because that is all the briefing states. Where it is set, and what ships as the default, both belong on the page and could not be found. +- [ ] **Link-loss policy has no default and no setting location.** `solution/robot-platforms/index.md:77` says the behaviour is set by policy — stop safely, halt immediately, or keep going — because that is all the briefing states. Where it is set, and what ships as the default, both belong on the page and could not be found. Pages that contradict each other on this are under *Audit 2026-10-07* › *Link-loss behaviour*. - [ ] **`robot/quadruped/b2.md` and `a2.md` are now incomplete for deployed customers.** Their `### Network layout` sections describe the bare Unitree base; a delivered robot has two Orin NX, a 5G router, a Wi-Fi router and a PoE switch behind it. The product-page template's section 4, *Solutions for this platform*, exists for exactly this and is currently used only on `peripheral/sensor/manifold_pocket2.md:154`. - [ ] Decide whether the payload cutaway renders go public. `wr_arch_docs/docs/release/202608/images/box-b2.png` and `box-a2.png` are the only images that show what "integrated" means, and they show board-level detail of our own electronics. Not used on the page. - [ ] The two draft skeletons `solution/navigation.md` and `solution/industrial-patrolling.md` are still present. `release-pages-plan.md` §2 lists both for deletion; D-R1 rejected an `industrial-patrolling` hub because naming a page after the application over-promises. @@ -75,17 +75,24 @@ New page, not yet published. It is the hardware third of the Autonomy Stack, whi - [x] Four types for both guides, though maintenance previously combined `### Quadrupeds and humanoids`. Splitting them was a small improvement rather than pure duplication: the combined section linked only Go2 and B2 diagnostics, so `g1_diag_guide` was unreachable from it. The humanoid page now links it. - [x] New tag facet **platform type** (`ugv`, `quadruped`, `humanoid`, `manipulator`) in `tutorial/tags.yml`, which previously declared four facets and now declares five. `onInlineTags: 'throw'` catches any undeclared tag, which is how this surfaced. - [x] **Figure mis-filed and corrected 2026-09-11.** `tutorial/img/robot_on_stool.jpg` is a wheeled base, not a quadruped; its alt text claimed otherwise and the migration trusted it, landing the photo on the quadruped safety page. Now on `tutorial/safety/wheeled-bases.md` with an accurate description. **No legged platform has a raised-for-testing photo** — the quadruped and humanoid safety pages carry the instruction in prose only, and a photo of a quadruped on a stand would be worth taking. -- [ ] **The A2 IP56 figure on `tutorial/safety/quadrupeds.md` depends on a section that is currently deleted.** The rating is quoted from `robot/quadruped/a2.md`'s `### Specifications` table (`IP56` body, Pro-variant core components IP67, LiDAR IPX7) — which is present in `HEAD` and on the live site, but **removed in the working tree**. If that deletion is intended, the safety page is the only place the figure survives and it should carry its own provenance; if the table is coming back, the two must agree. As2 has no published ingress figure anywhere in the repo, so its row says so rather than guessing. -- [ ] **`tutorial/maintenance/wheeled-bases.md`'s tyre-pressure table names platforms this site does not document.** Its two rows are **Scout 2.0 and later** (1.8–2.0 bar) and **Hunter 2.0** (around 0.8 bar), while the page declares Scout Mini and Ranger Mini V2/V3. `grep -rl Hunter robot/ peripheral/ system/` returns nothing — the Hunter has no product page at all, and "Scout 2.0" is a different platform from the Scout Mini. Pre-existing in `robot-maintenance.md`; the split made it visible by putting a scope line above the table. The figures are real and worth keeping, but either the declared scope or the table is wrong. Decide whether this site covers the wider AgileX range or only the three UGVs under `robot/ugv/`. +- [ ] **The A2 IP56 figure on `guides/safety/quadrupeds.md` depends on a section that is currently deleted.** The rating is quoted from `robot/quadruped/a2.md`'s `### Specifications` table (`IP56` body, Pro-variant core components IP67, LiDAR IPX7) — which is present in `HEAD` and on the live site, but **removed in the working tree**. If that deletion is intended, the safety page is the only place the figure survives and it should carry its own provenance; if the table is coming back, the two must agree. As2 has no published ingress figure anywhere in the repo, so its row says so rather than guessing. +- [ ] **`guides/maintenance/wheeled-bases.md`'s tyre-pressure table names platforms this site does not document.** Its two rows are **Scout 2.0 and later** (1.8–2.0 bar) and **Hunter 2.0** (around 0.8 bar), while the page declares Scout Mini and Ranger Mini V2/V3. `grep -rl Hunter robot/ peripheral/ system/` returns nothing — the Hunter has no product page at all, and "Scout 2.0" is a different platform from the Scout Mini. Pre-existing in `robot-maintenance.md`; the split made it visible by putting a scope line above the table. The figures are real and worth keeping, but either the declared scope or the table is wrong. Decide whether this site covers the wider AgileX range or only the three UGVs under `robot/ugv/`. - [ ] The universal sections were neutralised of cross-type wording — the danger admonition no longer surveys four types, the mixed G1/Go2/B2 IP table moved to the type pages, and the quadruped-on-a-stool figure moved to the quadruped page. **Re-read the landing pages once more for tone**: they were written as a survey across platforms and now address a single reader, so some phrasing may still read as a comparison. - [ ] Type pages carry duplicated text where the content genuinely is shared — the legged hazards appear on both quadruped and humanoid safety pages, and the joint-service caution on both maintenance pages. That is deliberate (a pointer would recreate the problem the split fixes) but it is now four files that must be edited together when the guidance changes. - [ ] `robot/quadruped/as2.md`, `a2.md`, `h2.md`, `r1.md` and the manipulator pages still link only the landing pages, not their type pages. Ten product pages remain to be repointed the way go2, g1 and scout-mini were. ## File hosting — ADR 0001 -**The store is live and empty.** Both stacks are deployed and the publish path is proven end to end (see below); what remains is content, and that is blocked on the first item. `docs/design/file-hosting.md` carries the reference design, `infra/RUNBOOK.md` the deployment procedure with measured timings. +**The store is live and holds 24 documents** (PR #44). The old SharePoint can't be recovered, so documents that were only linked from it are lost until found (listed below). `docs/design/file-hosting.md` carries the reference design, the private infrastructure repository the deployment procedure with measured timings. -- [ ] Export the 39 documents from the renamed M365 tenant (`westonrobot.sharepoint.com`). Needs tenant access, not a code change. The WR65 and WRL63 manuals are the urgent ones — they have no vendor fallback, so those products have no reachable documentation today. +- [x] **Closed 2026-10-07: can't be done.** The export from the old SharePoint is no longer possible. The WR65 and WRL63 manuals are in the store. +- [ ] **Lost until found.** These were only linked from the old SharePoint. If a copy turns up, publish it to the store and tick it off. + - [ ] `wr_arm_sdk` SDK manual (WR65, WRL63). Rewriting it or pointing at the repo instead is a separate decision. + - [ ] WR65/WRL63 Chinese user manual. The store has `user-manual` in `en` only. + - [ ] WR65/WRL63 ROS 2 manual. The published integration guide covers ROS 1 (Melodic) only. + - [ ] RM API samples (WR65, WRL63). No `api-examples` entry for either arm. + - [ ] Ranger Mini 3.0 firmware V6.0.5. Not on AgileX's site. + - MindCloud GO and MindCloud manuals (Manifold Pocket): tracked under *Manifold Pocket (first generation)* below. - [x] Hostname decided: **`download.westonrobot.net`** (ADR 0001 D1, amended). `westonrobot.net` is in Route 53 in this account under direct administration; `westonrobot.com` is on Cloudflare (`dig +short NS westonrobot.com`). `HostedZoneId` defaults to `Z016356211Y82HTRJIPRB`, so ACM creates and resolves the validation records itself and the alias comes with the stack — no manual DNS step. Note for whoever next tidies the `.net` estate: this subdomain is production and its URLs are permanent. - [x] **Deployed 2026-09-01.** Both stacks are up: `westonrobot-files-certificate` (us-east-1, 3m15s) and `westonrobot-files` (ap-southeast-1, 19m30s). Bucket `westonrobot-files`, distribution `E2SQLRWCEUM8UK`, certificate ISSUED and renewal-ELIGIBLE. Verified: TLS terminates on `download.westonrobot.net`, the raw `s3.amazonaws.com` URL returns 403 (D3 holds), and the OAC bucket policy applied with all four public-access blocks on. - [x] **Smoke test passed 2026-09-01.** One generated PDF published end to end and removed again: correct `Content-Type` and immutable `Cache-Control`, bytes identical on download, `index.json` derived with full metadata, `.sha256` sidecar matching, and a re-run correctly reporting `= published`. The store is empty again. @@ -99,9 +106,20 @@ New page, not yet published. It is the hardware third of the Autonomy Stack, whi - [ ] Consider rotating the current key. Its *identifier* was briefly committed to this public repository — not a credential, and the branch history has been rewritten, but a force-push orphans old commits rather than deleting them and they stay fetchable by SHA until GitHub garbage-collects. Rotating is the only step that does not depend on that. - [ ] `deb-internal-ci` has **two active access keys**, which usually means a rotation someone started and did not finish. Outside this project, found while checking MFA coverage. - [ ] Decide whether a service account may ever join `DocsDownloadPublishers`. The design keeps CI out of AWS entirely — the docs build reads the public `index.json` and holds no credentials — so adding one would put a long-lived key between a repository secret and customer downloads. `aptly-publisher` and `deb-internal-ci` already do exactly that for `deb.westonrobot.net`, which is the precedent worth deciding against rather than drifting into. -- [ ] Bulk-load the exported documents: stage them under `static/_upload/` at their D4 paths and run `publish-files.py --publish`, which uploads, indexes and invalidates in one pass. -- [ ] Rewrite the 48 SharePoint occurrences (34 unique documents, 8 files) to the new URLs. -- [ ] Rewrite the 4 Google Drive links added by `adce7c6` — `robot/humanoid/g1.md:51`, `robot/quadruped/b2.md:57`, `robot/quadruped/go2.md:53,54`. They are Weston Robot's own documents on opaque third-party share tokens: the same failure class as the SharePoint links, one vendor over. +- [x] **Bulk load done without the export (PR #44).** The documents were published with `publish-files.py --publish`. +- [x] **SharePoint links rewritten (PR #44)**, except the two on `peripheral/sensor/manifold_pocket.md:46-47`. See the item for that page below. +- [x] **Google Drive links rewritten (PR #44).** The 4 links added by `adce7c6` on `g1.md`, `b2.md` and `go2.md`; none are left in served content. +- [ ] **Published documents carry dead links of their own, and the slides should eventually stop being slides.** The training decks (PDF and PPTX) and at least one service manual link out to the same renamed tenant the pages did, so the links inside them died the same way — but nothing we run can see it. `onBrokenLinks` does not read file contents, and the CI link checker proposed under *Site infrastructure* would not either: a PDF is opaque to both, so these rot silently and are found only by a reader following one. Reported on PR #44: `go2-service-manual-expansion-dock-en-v2025.01.pdf` still points at `tangrobot` from inside the file. Two steps, deliberately ordered: + - **Now — fix the links and republish.** Correct the dead URLs inside the documents and publish a corrected revision under a new version, so the file itself stops handing customers broken links. Some are old enough that the surrounding content has also gone stale, in which case the document needs remaking rather than relinking — a judgement to take per document, not in bulk. + - **Eventually — lift the slide text out.** Move the prose from PDF/PPTX into Markdown and fold it into the docs site. Slides are the wrong container for reference text that has to stay correct: the content is unsearchable, unreviewable in a diff, and cannot be checked by the build, which is precisely why this failure went unnoticed. Fixing the links treats the symptom; this treats the cause. + Not yet scoped: which documents exist, where they live, and how many links each carries. That inventory is the first piece of work, and it gates both steps. +- [ ] **Remove the `_permcheck/xuebin-20260907.txt` test object from the store (needs an AWS admin).** A leftover permission check from 2026-09-07. Every index rebuild reports it, because the key has no `
//` part. Publishers can't delete objects (`docs/design/file-hosting.md` §6), so an admin runs: + ```bash + aws s3 rm s3://westonrobot-files/_permcheck/xuebin-20260907.txt + aws cloudfront create-invalidation --distribution-id E2SQLRWCEUM8UK --paths '/_permcheck/*' + # done when this returns 403 (what a missing key returns): + curl -sI https://download.westonrobot.net/_permcheck/xuebin-20260907.txt + ``` - [ ] Decide whether publishing should trigger a docs-site rebuild via `repository_dispatch`. It needs a GitHub token wherever the trigger lives, which is a secret to manage and a decision to take on its own. - [ ] Turn on access logging with the Phase 4 alarm work. It is absent from the stack because merging the logs bucket into the private one makes the CloudFront logging edge circular — see `docs/design/file-hosting.md` §2. `4xxErrorRate` is available from CloudWatch without it, so the alarm is not blocked; the logs add which keys are missing. - [ ] Find a home for video masters. `.gitignore` excludes `**/video/raw/` and says they are backed up nowhere; that is still true. Out of ADR 0001's scope, which covers public content only. @@ -112,11 +130,23 @@ Added with the Pocket2 product page and the Manifold Scanner Guides. The live wo record is the local engagement ledger; this section is its committed copy, and the bracketed `L` ids below are that ledger's row numbers. -**Complete for its current scope, with no decision or content outstanding.** One +**Complete for its current scope, with no decision or content outstanding, except the Pocket (first generation) items below.** One maintenance trigger remains, plus one question worth asking Manifold. Everything else on this list is closed. **A sourcing pass on 2026-09-04 reopened and re-closed it** — see *Closed by the 2026-09-04 sourcing pass* below; those changes are **not yet committed**. +### Manifold Pocket (first generation): discontinued, for the next branch + +The Pocket is no longer in production. PR #44 left `peripheral/sensor/manifold_pocket.md` unchanged on purpose; everything below is still open. + +- [ ] **Add a notice** at the top of `manifold_pocket.md`: the product is no longer in production or supported, with a link to `peripheral/sensor/manifold_pocket2.md`. +- [ ] **Decide whether to unlist the page** once the notice is in, as was done for As2, H2 and NERO (front matter plus `excludeRoutes`; see CONTRIBUTING *Unlisting a page*). If it is unlisted, also drop its card from `peripheral/intro.md:44`. +- [ ] **Dead manual links** (`manifold_pocket.md:46-47`, *MindCloud GO manual* and *MindCloud manual* on `tangrobot.sharepoint.com`). Lost until found. Check Manifold's download page, `version.manifoldtech.cn/download/mcs?lang=en`, then link it or remove the rows. +- [ ] **Dead app links** (`manifold_pocket.md:48-49`, *MindCloud GO* APK and *MindCloud* for Windows on `www.manifoldtech.cloud`). The site's certificate expired on 2026-07-01 and was still expired on 2026-10-07. Best effort only: with the product discontinued, the vendor may not renew it. Remove the rows or replace them with Manifold's download page. +- [ ] **Desktop software name.** `manifold_pocket.md:16`, `:20`, `:36` name "MindCloud" on Windows and say the desktop workflow matches the Pocket2's, while `guides/manifold/processing.md` uses MindCloud Studio and the Pocket2's rear Port C. Correct this when writing the notice. +- [ ] **Sibling pages call it "earlier", not discontinued.** `manifold_pocket2.md:14` ("the newer of the two") and `peripheral/intro.md:44` ("the earlier model"). Change to "replaces the discontinued Pocket". +- [ ] **Image provenance.** `peripheral/img/manifold/pocket.png` has no row in the image-provenance table in `docs/design/product-page-template.md`; its source is unrecorded. + ### Worth asking Manifold - [ ] **[L3]** Whether an unlisted Pocket2 resources area exists. `3dmanifold.com/download` shows only MindCloud Studio and its manual, yet the Pocket2 manual is served from `asset.3dmanifold.com/media/static/download/q9000/`, so there may be a Pocket2 section the site does not link. Worth raising at the same time: **their manual publishes no port diagram** — §2.1 *Physical Structure of Pocket 2* is a heading over an empty half-page, and `pdfimages -list -f 3 -l 3` returns only the header logo, which is why our port layout is operator-verified rather than vendor-sourced ([ADR 0002](docs/adr/0002-scanner-workflow-lives-in-guides-handed-over-at-the-pcd.md) D6). **Neither is a gap in our documentation.** For our current scope: no separate datasheet is known or needed, the user manual carries the getting-started and operating material, and there is no user-downloadable firmware package in the documented workflow — firmware is handled through the supported in-app mechanism. That is "not identified and not required", not a claim that no such Manifold resource exists anywhere. @@ -131,11 +161,6 @@ this list is closed. **A sourcing pass on 2026-09-04 reopened and re-closed it** - [ ] **[L13] Revalidation trigger — maintenance only, wants nothing today.** Revalidate the guides when the Manifold app, manual or software changes **or when field use or fresh screenshots reveal UI or workflow drift, even where no published version number has moved**. **The original version-based signal is void:** it was proven insufficient twice in one day — the app renamed `My` to `Profile` and the documented initialisation prompt turned out not to be observable in the field, neither announcing itself in a version number. The reliable detector is a reader with the unit. Link fragility is designed out — no version-pinned URL, PDF or installer on any customer-facing page — so nothing can break; only the prose can go stale. - [ ] Tell whoever staffs the support form that **MindCloud Studio licence requests** may arrive through it. The licence is per-machine and can be requested from Manifold directly or through us; our route is offered as a convenience, not the only one. -### Found while working, not fixed - -- [ ] All four resource links on `peripheral/sensor/manifold_pocket.md:44-47` are dead, but **for two different reasons** — corrected 2026-09-03 after re-checking. The two `tangrobot.sharepoint.com` manuals are a **DNS failure** (the host left public DNS with the tenant rename). The two `www.manifoldtech.cloud` app downloads are **not**: that host resolves to `1.15.86.130` and its Let's Encrypt chain validates, but the leaf certificate expired **2026-07-01**, so `curl` fails with exit 60, "certificate has expired". Both report `%{http_code}` as `000`, and an earlier revision of this item read that as DNS for all four — the trap `docs/LESSONS.md` names under *"verify the failure mode before diagnosing"*. Only the apex `manifoldtech.cloud` has no DNS record; the links use `www.`. The distinction matters: a lapsed certificate may come back on its own, a withdrawn hostname will not. The SharePoint pair is covered by the rewrite item under *File hosting* above; **the two `manifoldtech.cloud` links are not** — same failure class as issue #31, one vendor over, and the pinned version in `?file=MindCloudGo_0.3.0.apk` is why nobody noticed. Correct replacements are on the Pocket2 page. Left untouched deliberately, to keep that change additive. -- [ ] `peripheral/img/manifold/pocket.png` has no row in the image-provenance table in `docs/design/product-page-template.md`. Its source is unrecorded; the Pocket2 render added beside it is documented. Pre-existing gap, found while adding that row. - ### Closed by the 2026-09-04 sourcing pass Not yet committed. Started from one operator question — *was this sentence in the @@ -371,16 +396,150 @@ at 1440×1000 and 375×812 in both themes. **12 defects, 27 inconsistencies, 11 suggested fixes are in [issue #38](https://github.com/westonrobot/docs/issues/38); the working notes are in `2026-09-03-docs-conventions-audit.md`. -- [ ] Work through #38. The highest-impact items: `tutorial/unitree/g1_dev_guide.md:87,291` scrolls sideways on mobile (656 px in a 375 px viewport — the only overflowing page on the site); 11 wrong-model screenshots across the Go2 and B2 diagnostics guides; 22 positional `alt` strings the template forbids by name; 10 images that glow white in dark mode; and both live solution products missing five of the six required solution sections while the two `draft` scaffolds follow the template exactly. +- [ ] Work through #38. The highest-impact items: `guides/unitree/g1_dev_guide.md:87,291` scrolls sideways on mobile (656 px in a 375 px viewport — the only overflowing page on the site); 11 wrong-model screenshots across the Go2 and B2 diagnostics guides; 22 positional `alt` strings the template forbids by name; 10 images that glow white in dark mode; and both live solution products missing five of the six required solution sections while the two `draft` scaffolds follow the template exactly. - [ ] Decide the numbered-heading question raised there. `map-editor.md` and `mission-editing.md` use `## 1 · Load Map Data` style headings, which produce the fragile `#1--load-map-data` anchors §8 forbids — but the numbers are the product's own five-stage bar, not editorial numbering, so they cannot renumber unless the UI does. Either note the exception in the template or pin explicit anchors. -- [ ] `static/llms.txt` was not verified against the current page set — flagged in #38 as the highest-value remaining gap, since it sits outside the build and `onBrokenLinks` never sees it. +- [ ] `static/llms.txt` was not verified against the current page set — flagged in #38 as the highest-value remaining gap, since it sits outside the build and `onBrokenLinks` never sees it. For example, `static/llms.txt:18` still describes Solutions as "such as teleoperation". ## Site infrastructure - [ ] Re-check the `docker-compose` npm behaviour. The failure this item described — a bare `npm run build` in a fresh container not resolving `@docusaurus/plugin-client-redirects` — should be fixed: the Dockerfile now runs `npm ci` at build time and `/app/node_modules` is an anonymous volume, so it initialises from the image. **Not verified by actually running it.** What remains is smaller than originally written: `command:` still re-runs `npm ci` on every `up` (deliberate per the README, so a `git pull` needs no extra step, but slow), and `restart: unless-stopped` is still there rather than `"no"`. -- [ ] Add external link checking to CI — issue #31 tracks 53 dead SharePoint links. Required by ADR 0001 D6: a `download.westonrobot.net` URL is not verified by the Docusaurus build the way an in-repo asset is. +- [ ] Add external link checking to CI. Required by ADR 0001 D6: a `download.westonrobot.net` URL is not verified by the Docusaurus build the way an in-repo asset is. Of the dead SharePoint links in issue #31, only the two on `peripheral/sensor/manifold_pocket.md:46-47` remain. Exclude `support.unitree.com`: it returns 567 to non-browser clients, though the links work in a browser. ADR 0001 D6 (`:49`, `:71`) describes the check as if CI runs it; mark it as planned until it does. +- [x] **Decisions moved out of `docusaurus.config.ts` — 2026-10-05.** Eight comment blocks carried rationale rather than mechanics. Most duplicated `docs/design/ia-proposal.md` and were simply dropped: the Software section dissolved (§6), safety and maintenance belonging to Guides (§10), and the top-level axis (§2.1). Three were recorded nowhere else and are now an amendment to §11 — the Release 1 trademark renames, the `/tutorial` → `/guides` rename of 2026-09-11, and the ADT and UGV devkit version-page consolidations. The `docusaurus-lunr-search` trap became a lesson of its own. The config keeps three one-line pointers in their place, and the zoom-selector comment stayed where it was: it explains why `:not(.no-zoom)` exists, and deleting it re-breaks all 21 card images on the hub pages. Rule recorded in `CONTRIBUTING.md` and `docs/LESSONS.md` in the same change. - [ ] `deb.westonrobot.net` is served over plaintext HTTP only — a bare S3 website endpoint cannot terminate TLS. Tolerable for an apt repo, where GPG signatures make integrity independent of the transport, but it should get the same CloudFront + ACM front as `download.westonrobot.net`. Separate from ADR 0001. ## Minor - [ ] `solution/robot-management-toolbox/deployment-and-servicing.md:21` — the two subgraphs carry `direction LR`, which has no effect because neither contains edges, so the shared-cloud tenants stack vertically. Mermaid also draws the subgraphs in the reverse of the table's order (Dedicated left, Shared right). Cosmetic; the diagram reads correctly. + +## Audit 2026-10-07 + +A read-only audit of every Markdown file on 2026-10-07. The high-severity items were checked against the files; fixed items are ticked. + +### Needs an answer before anyone edits (product owner) + +- [ ] **Does Quick Dispatch pause the schedule until acknowledged?** `solution/robot-management-toolbox/mission-editing.md:234-240` says both that the errand "runs alongside a scheduled mission" and that it "pauses the schedule until you acknowledge it". See also `robot-dashboard.md:201-213`. +- [ ] **Power Regulator V2: is RS485 a control interface or for firmware upgrade only?** `peripheral/power/power_regulator_v2.md:31` and `:60` list it for control and feedback; `:136` says firmware upgrade and future extension. +- [ ] **R1: which control shuts it down?** The e-stop table at `robot/humanoid/r1.md:176` says "short press, then long press the power button"; `:64-66` documents no power button sequence and says the only button stands the robot up. Consider removing the `:176` row until answered. +- [ ] **Are saved locations held per robot or per site?** `mission-editing.md:95`, `:115` say per robot; `tenant-management.md:47` and `solution/robot-deployment-toolbox/map-editor.md:292` treat them as the site's. +- [ ] **Can an inactive mission be sent?** `solution/robot-management-toolbox/index.md:115-116` says only an activated mission is carried to the robot; `mission-editing.md:174-179` treats activation and sending as independent. + +### Safety and wrong specifications (fix first) + +- [ ] **PiPER CAN bitrate.** `robot/manipulator/piper.md:71` says the UGV CAN setup "applies here too", but `guides/agilex/ugv_base_control.md:50` sets 500 kbps and the PiPER needs 1 Mbps (piper_sdk README: `can_activate.sh can0 1000000`, "cannot be changed"). Give the PiPER its own command. +- [ ] **E-stop test on a legged robot.** `guides/operational-safety.md:37` (and the power cut at `:83`) has no instruction to support a legged robot first; a standing G1 collapses (`robot/humanoid/g1.md:137`, `:142`). The test also needs power but sits under *Before you power on*. +- [ ] **G1 ankle example.** `guides/unitree/g1_dev_guide.md:337` says it works "whether or not the robot is in debug mode", and the run section never says to suspend the robot. +- [ ] **Devkit reconfiguration.** `system/ugv_devkit/component_reconfiguration.md:10-13` has no step to switch off the base and battery before unplugging. +- [ ] **Remote power cycle.** `solution/robot-management-toolbox/robot-dashboard.md:238-240` suggests "power the robot off and on once", and every supported platform is a quadruped. Require Sit or Dock and someone at the robot, or route to support. +- [ ] **Link-loss behaviour.** `solution/robot-platforms/network-configuration.md:122` and `solution/robot-platforms/index.md:73` say a robot keeps patrolling when its link drops; `index.md:77` and `robot-dashboard.md:230-232` say it depends on the policy set at commissioning. The missing default is under *Robot Platforms page* above. +- [ ] **Devkit Nav2 guide.** `system/ugv_devkit/v1/nav2_sample_setup_guide.md:38` defaults to the Ranger Mini 2.0, which the devkit page doesn't list; `:152` hardcodes Scout Mini RTAB parameters; the Cartographer section (`:23-63`, `:93`) needs a LiDAR extension it never names. +- [ ] **RC transmitter.** `guides/agilex/ugv_base_control.md:119` says "keep the RC controller in hand"; `guides/operational-safety.md:41` and `guides/safety/wheeled-bases.md:43`, `:49` say switch it off when not driving. +- [ ] **Default SSH credentials with no "change the password" warning.** `robot/humanoid/g1.md:76`, `:107`; `robot/quadruped/go2.md:78`; `robot/quadruped/b2.md:79-81`; `robot/humanoid/h1-2.md:65`; `robot/humanoid/r1.md:125`; `robot/quadruped/a2.md:81`; `guides/unitree/g1_internet_guide.md`. Only `g1_dev_guide.md:213` warns. +- [ ] **Router on the robot subnet.** `guides/unitree/g1_dev_guide.md:210` puts a router on `192.168.123.0/24` with no warning that its DHCP can hand out addresses the robot uses. +- [ ] **apt signing key over http.** `guides/installation/apt_source.md:31` fetches it over http (https gives no response). The `$ ` prompts also break copy-paste. +- [ ] **"The motors have overheated" given as the cause of going limp for every model.** `robot/quadruped/go2.md:151`, `guides/safety/quadrupeds.md:26`, `guides/safety/humanoids.md:29`, `guides/maintenance/humanoids.md:29`. The source is the Go2 FAQ only, and low battery is another documented cause (`guides/unitree/go2_diag_guide.md:36`). +- [ ] **Docking robots linked to hand-charging rules.** `solution/robot-platforms/index.md:91` links `guides/operational-safety.md:74-75` ("do not leave charging unattended overnight"). `robot-maintenance.md:52` says unattended where `operational-safety.md:75` says overnight. +- [ ] **No emergency-stop subsection** on `h1-2.md`, `go2.md`, `b2.md`, `a2.md`. `g1.md` and `r1.md` have one. +- [ ] **B2 sealing.** `robot/quadruped/b2.md:132` says "be familiar with the sealing procedure" and doesn't link one. +- [ ] **Manual errors to raise with Realman.** The manuals we publish disagree with Realman's current parameters ([RM65](https://develop.realman-robotics.com/en/robot/robotParameter/RM65OntologyParameters/), [RML63](https://develop.realman-robotics.com/en/robot/robotParameter/RML63OntologyParameters/)), which give the same figures for Gen 3 and Gen 4. Ask which figures apply to the arms we have shipped, and whether there are corrected manuals to republish. + - `wr65-user-manual-en-v2.8.pdf`: the specification table gives J1, J4 and J5 as ±180°, where Realman give ±178°, ±178° and ±128°. The manual's own installation section gives J5 as ±128°. + - `wrl63-user-manual-en-v1.1.pdf`: contains RM65 text (an "RM65-B" spec heading, 610 mm radius, RM65 joint ranges). Its specification table gives J1, J2, J4 and J5 as ±180°, J3 as +165° to −150° and a weight of 10.2 kg, where Realman give ±178°, −178° to +145° and 10 kg. +- [x] **WR65 and WRL63 joint limits and weights — 2026-10-15.** Both pages follow Realman's current parameters again, which match the specifications restored from the archive in `6790cd8`. `8a37e9a` in PR #44 had switched them to the manuals' specification tables, which widened WR65 J5 to ±180° and WRL63 J3 to +165°. Each joint table now names its source and the manual's differing values. The 27 V maximum supply voltage from the manuals stays. +- [x] **WRL63 force-sensing weight — sourced.** Realman's current parameters give 10.1 kg for the six-axis force version and 10 kg for the standard version. +- [ ] **NanoPC 12 V claim.** `peripheral/computer/nanopc.md:35` "most robot bases we supply can feed 12 V directly" has no source. Check it against the bases before a customer over-volts a 5-20 V board. + +### Publishing tools + +- [ ] **`publish-files.py` overwrites and over-uploads.** `scripts/publish-files.py:340` uploads `! differs` items, overwriting a published key and its `.sha256` under an immutable cache header. `:312-315` treats an unreadable store as empty, so `--publish` would upload everything. Refuse both without an explicit override, and say in CONTRIBUTING what to do on `!`. +- [ ] **No manual deploy.** `.github/workflows/deploy.yml:3-7` runs only on push and pull_request, so a publish or retire doesn't reach the download tables until the next merge. Add `workflow_dispatch` and a "trigger a deploy" step to CONTRIBUTING and both skills. +- [ ] **`docs/design/file-hosting.md` says "the build fails".** `:86` and `:117` say an unresolved `` query fails the build, but it is `scripts/check-downloads.py`, a separate CI step, that fails. Two behaviours of that script stay as they are (decided 2026-10-15): an unreachable index passes with its queries reported as not checked (see the `fetch_index()` docstring), and a query that matches only retired documents passes, because retiring a document is deliberate. `CONTRIBUTING.md` now states the unreachable-index case. +- [ ] **`LOCAL_REF` misses link forms.** `scripts/check-downloads.py:32` doesn't match reference-style links, `pathname:///_upload/`, unquoted `href` or `static/_upload/`. +- [ ] **`wrfiles.py` accepts bad names.** `scripts/wrfiles.py:171-245` accepts a subject with spaces or capitals, an uppercase extension (the key keeps `.PDF`) and firmware tagged `en`. CONTRIBUTING says bad names are refused. +- [ ] **`--list` without credentials** ends in a `NoCredentialsError` traceback; `CONTRIBUTING.md:90` says it reports what's missing. +- [ ] **upload-file skill.** `.claude/skills/upload-file/SKILL.md` should say a wrong version is also retired (as `retire-file/SKILL.md:21` does); `:37` has a garbled sentence. (Step 7 now moves `static/_upload/` aside instead of deleting it, 2026-10-15.) +- [ ] **`check-video-budget.sh` extensions.** `scripts/check-video-budget.sh:41` patterns are case-sensitive and miss `.gif` and `.avi`. +- [ ] **First checks need more than python3.** `CONTRIBUTING.md:18` says so, but the video check needs bash and git. +- [ ] **What the store is for.** ADR 0001:21 and ADR 0002:42 disagree, and the store holds vendor manuals while the template says to link the vendor. Record the real rule. +- [ ] **`docs/design/file-hosting.md` §7.** Paragraphs duplicated (`:169-171` and `:184-186`); "two roles" (`:173`) against "five grants" (`:188`). The §3 example uses kind `manual` and `x-amz-meta-title`, neither valid. +- [ ] **vendor-interface-summary skill** (`.claude/skills/vendor-interface-summary/SKILL.md:10-11`) cites a `PUBLISHING.md` that was never written (`ia-proposal.md:367`). Point at the template instead. +- [ ] **Unlisted pages described as hidden from search.** `solution/navigation.md:13` and `solution/industrial-patrolling.md:13` say an unlisted page stays out of search; `docs/LESSONS.md:164` says the search plugin ignores the flag. +- [ ] **Robot Platforms plural rationale.** `docs/design/release-pages-plan.md:40` points to `TODO.md` for it, while `TODO.md:22` asks for it to go in the plan. Move it into the plan. +- [ ] **Template checklist.** `docs/design/product-page-template.md:605` ("Every section's first sentence says what the section is for") restates as an absolute the rule the template qualifies; the skeleton (`:537-541`) has no ``. + +### Public repository: wording and data to move or redact + +- [ ] **This file's AWS account details.** The MFA, access-key and service-account items under *File hosting — ADR 0001* name IAM users, key state and a once-committed key identifier, plus the HostedZoneId. Move them to the private infrastructure repository and leave a one-line pointer. +- [ ] **`docs/design/release-pages-plan.md:88-117`** carries VPN and SSH access details, customers' security rules, `VITE_AUTH_ENABLED` and internal repository paths. Move to a private location. +- [ ] **This file's own wording.** `TODO.md:7` names a customer deployment's cameras; `TODO.md:290` uses "contract violation". Reword. +- [ ] **Internal notes on unlisted pages.** `robot/quadruped/as2.md`, `robot/humanoid/h2.md` and `robot/manipulator/nero.md` show notes such as "Delete this admonition once the page is complete" and "only we can write" (and a TODO at `as2.md:23`) to anyone with the URL. Move them into MDX comments. +- [ ] **Screenshots to redact.** `guides/unitree/img/unitree_robot_sn.png` shows a full G1 serial, and is used as the Go2 and B2 SN (`go2_diag_guide.md:137`, `b2_diag_guide.md:138`); `guides/unitree/img/g1_app_conn_05.jpg` shows office and neighbouring Wi-Fi names; `peripheral/img/westonrobot/regulator_v2.jpg` shows a serial and a phone number. +- [ ] **Devkit SSH example.** `system/ugv_devkit/v1/getting_started.md:21` gives `ssh wr@10.10.0.20`, while the product page says credentials are only on the handover note. +- [ ] **`robot/humanoid/r1.md:178`** "a known immature behavior, expected to be fixed". Reword. +- [ ] **`peripheral/intro.md:8`** "Each has been tested for compatibility with our platforms" has no source. +- [ ] **`solution/robot-management-toolbox/audit-log.md:91-92`** "lists every visit" needs "under elevation". + +### Customer pages: contradictions and gaps + +Robot pages: + +- [ ] **`robot/quadruped/go2.md:134`** refers to a "Connection Mode" table that doesn't exist; `:136` "to top it up, contact us" links to the ticket-prep page. +- [ ] **Scout Mini SDK name.** `robot/ugv/scout-mini.md:71` names `wrp_sdk`, `:39` and `:61` name `ugv_sdk`. The Scout Mini and Ranger pages say Robot Base Control covers `ugv_sdk`, which it doesn't. +- [ ] **Ranger Mini 3.0 firmware.** `robot/ugv/ranger-mini-v3.md:69-71` publishes no firmware list, and no page says how to read the firmware version. The V6.0.5 image is under *Lost until found*. +- [ ] **As2, H2 and NERO are unlisted and incomplete.** Finish each page and relist it: front matter, its `excludeRoutes` entry, and a card on `robot/intro.md`. Production already hides them from the sidebar. +- [ ] **R1 tables.** `robot/humanoid/r1.md:68-108` has full spec and torque tables on a tier-1 page; wrist roll (`:104`) isn't marked Basic/EDU only, though the Air omits it (`:108`). +- [ ] **A2 status.** `robot/quadruped/a2.md:32-35` caution and the TODO at `:162` are out of date; `robot/intro.md:35`, `:49` still say A2 and R1 are "in preparation". +- [ ] **"Official documentation" duplicates the product page link** on `piper.md:19`, `kinova-gen3-lite.md:19`, `scout-mini.md:19`, `ranger-mini-v2.md:28`, `ranger-mini-v3.md:19`. +- [ ] **Button sequence.** `robot/quadruped/a2.md:45` and `robot/humanoid/r1.md:66` refer to a Go2/B2 short-press-then-long-press sequence that neither the Go2 nor the B2 page documents. +- [ ] **WR65 and WRL63** (`wr65.md`, `wrl63.md:51`, `:79-88`) compare against "our 2023 documentation" figures that aren't in the published manuals. +- [ ] **`robot/quadruped/a2.md:172`** "disable it in the SDK" names no call. +- [ ] **FAQ "the recovery sequence" links to `operational-safety#if-something-goes-wrong`, which has none.** `g1.md:173`, `go2.md:167`, `b2.md:160`, `a2.md:180`, `r1.md:198`, `h2.md:110`, `as2.md:112`. +- [ ] **Empty "Troubleshooting & FAQ" headings** on `wr65`, `wrl63`, `xarm`, `z1`, `piper`, `kinova-gen3-lite`, `ranger-mini-v2`, `ranger-mini-v3`, `scout-mini`. +- [ ] **Serial number subsection** missing on `h1-2`, `r1`, `wr65`, `wrl63`, `xarm`, `z1`, `piper`, `kinova-gen3-lite`, `scout-mini` and both Rangers; misplaced on `b2.md:43` and `g1.md:85`. + +Peripheral, system and support pages: + +- [ ] **"Includes the commands" no longer true.** About 24 pages, plus `docs/design/product-page-template.md:590`, `src/pages/index.tsx:93` and `static/llms.txt:29` ("with the commands to collect it"), say *Before you contact us* includes the commands; they were removed in `9a95552`. `support/before-you-contact-us.md` asks only for a robot sticker, which doesn't fit peripherals or the Pocket2. +- [ ] **Devkit power-up.** `system/ugv_devkit/index.md:47` "let the kit come up with it" against `:132`, `:186` "every channel is off by default". +- [ ] **Power Regulator V2 gaps.** "Every port fused" (`power_regulator_v2.md:29`) against the extension output (`:129`); no CAN or RS485 connector type, location or pinout (`:39`, `:92`); no way to tell V2.1 from V2.2 and no V2.2 EDS filename (`:102`, `:204-238`). +- [ ] **`peripheral/network/industrial_5g_router.md`** gives no login (`:45-49`), no reset if the LAN address is lost (`:121-133`) and no APN or cellular setup (`:32-35`). +- [ ] **Unclear support routes** for the Pocket2 (`peripheral/sensor/manifold_pocket2.md:58`, `:60`, `:184`) and for devkit customisation (`system/ugv_devkit/index.md:99`). +- [ ] **"No GPU" on the NanoPC.** `system/ugv_devkit/index.md:170` and `peripheral/computer/cm4.md:92`; the RK3588 has a Mali GPU. Say "CUDA-capable". +- [ ] **`component_reconfiguration.md:46-50`** "frame dimensions" figure shows no dimensions. +- [ ] **Devkit v1 guides.** `v1/getting_started.md:15`, `:24` give no Wi-Fi details and a relative config path; `v1/nav2_sample_setup_guide.md:15`, `:20-21`, `:107`, `:116-121` have plain-text "links" and a malformed camera table. +- [ ] **Missing fitting steps.** `mid360_extension.md:2`, `vision_extension.md:2` and `system/ugv_devkit/index.md:179-180` promise fitting steps the pages don't have; `vision_extension.md:40` "2.7inch" sensor is likely 1/2.7". +- [ ] **CM4 and NanoPC details.** `cm4.md:56-61`, `:72` give no RS485 or CAN device names and no shipped OS; `nanopc.md:85` and `:95` disagree on txqueuelen (1000 and 10000); `nanopc.md:88-111` assumes ifupdown and net-tools. + +Solution pages: + +- [ ] **Internet access.** `solution/robot-management-toolbox/deployment-and-servicing.md:38`, `:57-58` ignore the 5G uplink and don't answer "do robots need internet access?". (Charging rules against docking robots are under *Safety* above.) +- [ ] **Who authors maps.** `robot-management-toolbox/index.md:64` and `tenant-management.md:57` against `robot-deployment-toolbox/index.md:16-24`. +- [ ] **`network-configuration.md`** (`:3`, `:47`, `:88`, `:95-102`, `:114`, `:118`) promises Wi-Fi change procedures it doesn't give, and is unclear about who switches off the access point. +- [ ] **Audit log roles.** `audit-log.md:81` "your platform administrator" isn't a customer role; `robot-management-toolbox/index.md:226` overstates what's recorded. +- [ ] **"Set each robot's home"** (`robot-management-toolbox/index.md:111`) has no procedure or role. +- [ ] **"Errand" and "dispatch" each mean two things.** `mission-editing.md:25`, `:148` against `:232-243`; `robot-management-toolbox/index.md:185` against `mission-editing.md:199`. +- [ ] **`map-inspector.md:57`, `:66-67`** overstate what validation proves (`map-editor.md:205`, `:268`). +- [ ] **`detection-review.md:45`** "reviewable" against `:25`, `:27` "not reviewable". +- [ ] **`robot-dashboard.md:256-257`** "controls unavailable" FAQ leaves out causes listed on the same page. +- [ ] **`tenant-management.md` consistency.** `:137`, `:184` "never changes map part-way" against `:150`, `:172`; role containment at `:53` breaks at Auditor; `:189-190` says E-Stop needs Operator, `:45` says Observer can E-Stop; `robot-dashboard.md:175` doesn't say what "resumed" means under E-Stop. +- [ ] **Old or partial product names.** "Deployment Toolbox" (`robot-deployment-toolbox/index.md:145`, `map-editor.md:50`); "Management Toolbox" (`robot-dashboard.md:201`, `mission-editing.md:95`, `:119`, `:180-181`, `:247`, `:256`, `:292`); capitalised "Fleet" (`robot-deployment-toolbox/index.md:21-22`, `:92-93`). +- [ ] **Map size advice.** `map-editor.md:73` "downsample first" against the scanner guide's 10 cm hand-off; its crop advice disagrees with `guides/manifold/processing.md:113`, `:228`, `:239-246`; `map-editor.md:48` "all of it over Wi-Fi". +- [ ] **"Used once per site"** (`solution/intro.md:20` and others) against re-mapping when the site changes. +- [ ] **ADT.** `solution/adt/intro.md` is retired but still links support (`:427-429`); its v1 install runs `apt-get install` before `update` and skips the apt source step (`:176-179`). + +Guides: + +- [ ] **`g1_internet_guide.md:126`** `echo "1" > /proc/sys/net/ipv4/ip_forward` fails without root. Use `sudo sysctl -w net.ipv4.ip_forward=1`. +- [ ] **`guides/safety/humanoids.md:33`** links to the unlisted H2 page. +- [ ] **Two G1 internet procedures.** `g1_dev_guide.md:207-210` and `g1_internet_guide.md` differ. Keep one. +- [ ] **`g1_internet_guide.md:54-90` method 2** names no adapter, gives no way to get a shell, and shows an "UNASSIGNED" interface against `eth0` in the example; `:61` may overwrite an existing netplan file. +- [ ] **`go2_diag_guide.md:107`** "upgrade to the latest firmware" against `robot-maintenance.md:79-80`. +- [ ] **`go2_slam.md`.** Press Q before placing the robot (`:186-187`); `:qa` should be `:q!` (`:136`, `:141`); the RViz files aren't on the User PC (`:176`); "try adding sudo", `chmod 777 -R` and `sudo git clone` (`:50`, `:87`, `:91-93`). +- [ ] **Battery guidance disagrees.** Monthly against every two months (`robot-maintenance.md:32`, `:55`, `:70`; `guides/manifold/scanning.md:244`); "storage level" isn't defined. (Unattended against overnight charging is under *Safety* above.) +- [ ] **`guides/manifold/processing.md:25`** version claim against the v0.2.12 screenshots. +- [ ] **"Ratings by platform" anchor.** `robot-maintenance.md:60` and the g1, go2, b2 and as2 pages link to an anchor that no longer has ratings. +- [ ] **Titles.** `g1_internet_guide.md:6` "Access" against "Connection"; `go2_slam.md:7` H1 "Go2 & Go2-W"; `guides/intro.md:62` "the most detailed guide on this site". +- [ ] **Alt text.** 12 positional or wrong-model alt strings in the Go2, B2 and G1 diagnostics guides; `g1_internet_guide.md:15`, `:33`, `:55`. `b2_diag_guide.md:9-12`, `:87`, `:91` and `go2_diag_guide.md:81`, `:85` reuse G1 captures. +- [ ] **Check against vendor docs.** G1 MID-360 IP (`g1_dev_guide.md:205`, .20 or .120); charging order (`robot-maintenance.md:40-46`); "using the RC will immediately stop SLAM navigation" (`go2_slam.md:214`); manipulator brake joints and 900 mm reach (`guides/safety/manipulators.md:23-25`); "29 joints" (`g1_dev_guide.md:36`). + +### Unsourced frequency and absolute claims + +- [ ] **Keep the instruction, drop the ranking** ("most common", "always", "never" with no source). Robot pages: `g1.md:30`, `:177`; `r1.md:32`; `h2.md:43`; `a2.md:41`; `as2.md:46`; `ranger-mini-v2.md:88`; `ranger-mini-v3.md:77`; `z1.md:77`; `h1-2.md:70`; `kinova-gen3-lite.md:75`; `go2.md:151`. Guides: `operational-safety.md:41`, `:56`; `safety/quadrupeds.md:46`; `safety/humanoids.md:24`, `:39`; `robot-maintenance.md:9`, `:38`; `maintenance/manipulators.md:14`, `:16`; `maintenance/wheeled-bases.md:33`; `manifold/scanning.md:9`. Solution: `map-editor.md:94`, `:150`; `mission-editing.md:86`; `robot-management-toolbox/index.md:226`, `:279`; `map-inspector.md:51`; `robot-dashboard.md:257`. diff --git a/docs/LESSONS.md b/docs/LESSONS.md index 5b40a71..ad76ef9 100644 --- a/docs/LESSONS.md +++ b/docs/LESSONS.md @@ -152,3 +152,15 @@ Operational lessons for this repository, in Pattern / Correction / Context form. - **Pattern:** `fleet-stream-settings.png` was captured against a robot reporting no streams, so its **Enabled Streams** section is a heading with nothing under it and all four Stream Assignment slots read *None*. Nothing was wrong while the page only discussed layout. Moving the figure onto a section that teaches *enabling streams* made the empty region load-bearing, and a first draft of the caption said the dialog shows "which streams are enabled" — pointing the reader at blank space. - **Correction:** Before writing a caption or a sentence beside an existing figure, open the image file and check that the state it captured still supports what the new prose claims. Where it does not and a recapture is not available, say so in the caption in one clause and log the recapture in `TODO.md` — an acknowledged gap costs a reader nothing, an unacknowledged one costs them their confidence in the page. A figure that moves between sections is the moment to run this check; the image did not change, its job did. - **Context:** `solution/robot-management-toolbox/robot-dashboard.md`. The converse of the alt-text lesson: there the image changed under the text, here the text changed under the image. + +### Rationale in a config file is filed where nobody looks for a decision + +- **Pattern:** `docusaurus.config.ts` accumulated eight comment blocks carrying decisions rather than mechanics: why the Software section was dissolved, why a path survived the IA rename, how far two pages overlapped, and why the old top level was hard to navigate. Each was true, and each was written at the point it was acted on, which is why it went there. Two costs followed. The decisions are invisible to anyone re-deciding them later, because `docs/adr/` is where decisions are kept and a config file is not — a reader auditing the IA finds the config only if they already suspect it. And `westonrobot/docs` is public, so a candid assessment of our own content — which pages are incomplete, what was an oversight, what was unfindable — publishes in a file nobody reviews as prose, because review attention goes to the pages. +- **Correction:** A config file records *what* is set. The moment a comment explains *why it was decided*, it belongs in `docs/adr/`, the design doc it amends, `TODO.md` or here, with at most a one-line pointer left behind. The test is whether the comment would change if the decision were revisited: a note explaining why a selector excludes `a > div > img` is mechanics and stays, because deleting it re-breaks 21 card images; a note explaining why a section was dissolved is a decision and moves. Where the comment also states the condition of our own content, "Check the repository's visibility, not the content's intended audience" applies as well — that lesson covers operational detail, this one covers our own editorial state, and the two fail the same way. +- **Context:** `docusaurus.config.ts`, and any file whose job is configuration — the `sidebars-*.ts` files and CI workflows. The tell is a comment with a date, a percentage, or a judgement in it. + +### A page hidden from the sidebar is still in site search + +- **Pattern:** `unlisted: true` removes a page from the sidebar and the sitemap, which reads like "hidden". `docusaurus-lunr-search` does not read that front matter at all, so As2, H2 and NERO stayed searchable after being unlisted and were removed only by naming each route in the plugin's `excludeRoutes` (`348049a`, `c1f24a9`). Unlisting is therefore a two-place change, and the second place is a config file nobody opens while editing a page. The trap has a second half: the dev server renders unlisted pages in full by design, so `npm start` shows the page present in the sidebar and looks like the flag did nothing — on 2026-10-05 that reading cost a round of "the change didn't work" against a branch where it had worked all along. +- **Correction:** When unlisting a page, set the front matter **and** add its route to `excludeRoutes`, then verify with `npm run build && npm run serve`, never `npm start`. More generally, before trusting a front-matter flag, establish which consumers honour it: the sidebar, the sitemap, the search index and the router are four separate readers, and a flag honoured by two of them is a partial hide that looks total from the one place you checked. +- **Context:** `docusaurus-lunr-search`, `docusaurus.config.ts`. Sits beside "Never publish a safety net you have not seen fire" — both are about confirming a mechanism fired rather than assuming it did. diff --git a/docs/design/file-hosting.md b/docs/design/file-hosting.md index 65a3a25..0c442e9 100644 --- a/docs/design/file-hosting.md +++ b/docs/design/file-hosting.md @@ -2,9 +2,9 @@ How the downloadable-document store should be built and operated. [`../adr/0001-host-downloadable-documents-on-s3.md`](../adr/0001-host-downloadable-documents-on-s3.md) decides *what* and *why*; this document covers *how*, and the operational practice around it. -Scope: public customer-facing files — product manuals, SDK and protocol specs, training decks, software archives, firmware, video. Roughly 39 documents today, growing per product and per release. +Scope: public customer-facing files — product manuals, SDK and protocol specs, training decks, software archives, firmware, video. 24 documents in the store today, growing per product and per release. -**Right-sizing is part of the design.** Every control below earns its place at this scale or is marked as deferred. A store of 39 documents does not need the topology of a package registry, and copying one in produces a system nobody maintains. Where a practice is standard but not yet worth it here, it is listed under §12 with the trigger that would change the answer. +**Right-sizing is part of the design.** Every control below earns its place at this scale or is marked as deferred. A store of a few dozen documents does not need the topology of a package registry, and copying one in produces a system nobody maintains. Where a practice is standard but not yet worth it here, it is listed under §12 with the trigger that would change the answer. ## 0. Four principles @@ -92,7 +92,7 @@ The component resolves that query against the index at build time. **A page cann | 1 | Stage the file under `static/_upload/`, at its published path | Anyone editing the page | none — local | | 2 | `publish-files.py --publish` uploads it with content type, cache headers, metadata and a `.sha256` sidecar | The publisher | `DocsDownloadPublish` | | 3 | The same run regenerates `index.json` from the bucket and invalidates the CDN | " | " | -| 4 | It rewrites the page's local link to the published URL | " | none — local | +| 4 | The page's `` query finds the document in the new index, so the page needs no edit. A hand-written link into `_upload/` is rewritten to the published URL | " | none — local | | 5 | Rebuild the docs site | CI, on `repository_dispatch` or the next push | none — the index is public | **The publish grant carries no `DeleteObject`.** Published paths are permanent (D4) and a manual for hardware still in the field outlives any reason to tidy it away (§10), so the worst a publisher can do is overwrite an existing key — which versioning makes recoverable. Removing an object is an admin act, done deliberately by someone who knows why. @@ -111,7 +111,7 @@ So the engineer's path starts in the working tree: The name is deliberate. It is not `_publish/`, because dropping a file there does not publish it — a file sits there through however many local builds it takes to get the page right, and only `publish-files.py --publish` sends it anywhere. The directory holds things queued for upload, and is named for that. 2. **Reference it locally and build.** `npm start` shows the real page with the real document attached — the thing no console-first flow can offer. A `` query resolves against staged files too, and marks them `staged` so a local build is never mistaken for a published one. -3. **Run the publish script when the page is right.** It derives the D4 key from the local path, computes the digest, uploads with the right content type and cache headers, writes the checksum sidecar, regenerates the index, invalidates the CDN, and rewrites the page's local reference to the published one. One command, and the document is live. +3. **Run the publish script when the page is right.** It derives the D4 key from the local path, computes the digest, uploads with the right content type and cache headers, writes the checksum sidecar, regenerates the index and invalidates the CDN. The page's `` query needs no edit, because it finds the document in the new index; a hand-written link into `_upload/` is rewritten to the published URL. One command, and the document is live. 4. **Rebuild and review again.** The second review is against exactly what a customer will get. **The gitignore is the enforcement, and this is the load-bearing part.** CI has no local files, because they are not in the repository. A page committed before its document was uploaded therefore cannot resolve, and the build fails. The author saw a working page; CI sees the truth; the discrepancy surfaces in a pipeline rather than in a support ticket. It is the same mechanism as the video budget check (ADR 0001 D8) — a guarantee that comes from git and the filesystem disagreeing in a controlled, deliberate way. @@ -212,7 +212,7 @@ A CloudWatch alarm on 404 rate is the piece that has to exist from day one. Acce **Effectively zero at this volume, and that is now measured rather than assumed.** Rates below were read from the AWS Pricing API on 2026-08-31 (`aws pricing get-products --service-code AmazonCloudFront`), not recalled; they are list prices, so any negotiated agreement only moves them down. -| Line | Rate | At 39 documents | +| Line | Rate | At 24 documents | | --- | --- | --- | | CloudFront egress, first 1 TB/month | **$0.00** — perpetual, not a trial | $0.00 | | CloudFront egress beyond that, Asia Pacific | $0.12/GB (0–10 TB), $0.085/GB in Europe and the US | — | @@ -229,7 +229,7 @@ The levers, in order of effect, for whenever it does matter: - **Storage class.** Standard for served content. Archive tiers apply to masters, which are out of scope here. - **A billing alarm**, so video growth is noticed as a number rather than as an invoice. $20/month is a reasonable threshold — comfortably above zero, far below anything that would be a surprise. -**Still a measurement to take:** total corpus size once the 39 documents are exported. Storage is a rounding error at any plausible figure, but the number is worth knowing before the first bulk load rather than after. +**Measured 2026-10-07:** the 24 documents total about 146 MB, the sum of `bytes` in `index.json`. Storage is a rounding error at that size. ## 10. Content lifecycle and retention @@ -246,9 +246,9 @@ The levers, in order of effect, for whenever it does matter: Ordered so each phase is independently useful and nothing is blocked on the phase after it. -**Phase 0 — Unblock. Still blocked.** Export the 39 documents from the renamed M365 tenant. Everything downstream waits on this; WR65 and WRL63 first, since those products have no reachable documentation at all. +**Phase 0 — Unblock. Closed without the export.** The old SharePoint can't be recovered, so the export from the renamed M365 tenant won't happen. The store was loaded in PR #44 instead, including the WR65 and WRL63 manuals. Documents that were only behind the old links are listed in `TODO.md` as lost until found. -**Phase 1 — Serve it correctly. Infrastructure done 2026-09-01.** Bucket, CloudFront, ACM, OAC, Block Public Access, versioning — deployed and verified; `infra/README.md` records what exists. The bulk load and the link rewrite wait on Phase 0. +**Phase 1 — Serve it correctly. Infrastructure done 2026-09-01.** Bucket, CloudFront, ACM, OAC, Block Public Access, versioning — deployed and verified; the private infrastructure repository records what exists. The bulk load and the link rewrite landed in PR #44. **Phase 2 — Make it repeatable. Done.** The publish script and the gitignored `_upload/` convention, plus — added once the need appeared — `--list` to see what is published and `--retire` to withdraw a document without breaking its URL. @@ -265,7 +265,7 @@ Listed with the trigger that would change the answer, so the decision is revisit | Practice | Why not now | Trigger to revisit | | --- | --- | --- | | Cross-region replication | S3 durability within a region already exceeds the risk this addresses; versioning covers the realistic failure | A contractual availability commitment, or a second region for compliance | -| A staging *environment* — a second distribution serving unpublished content for preview | 39 mostly-static documents; review happens on the page, before publishing. Nothing unpublished exists to preview: a document is either staged on someone's laptop or live | Publishing becoming frequent enough that a bad publish is likely | +| A staging *environment* — a second distribution serving unpublished content for preview | A few dozen mostly-static documents; review happens on the page, before publishing. Nothing unpublished exists to preview: a document is either staged on someone's laptop or live | Publishing becoming frequent enough that a bad publish is likely | | Signed URLs / access control | ADR 0001 scope is public content only (decided 2026-08-31) | Any licence-gated SDK or customer-specific deliverable | | Object Lock / WORM | No regulatory retention requirement identified | A compliance or safety-certification requirement on firmware provenance | | A mainland-China mirror | Deferred by decision | Chinese customer download experience becoming a support burden | diff --git a/docs/design/ia-proposal.md b/docs/design/ia-proposal.md index 949e5df..2e51359 100644 --- a/docs/design/ia-proposal.md +++ b/docs/design/ia-proposal.md @@ -161,7 +161,7 @@ A solution is a capability we develop and deploy, not a component the customer i | Stage | Flag | Behaviour | | --- | --- | --- | | Drafting | `draft: true` | Visible in `npm run start`, **absent from production builds** | -| Pilot customers | `unlisted: true` | Live and reachable by direct URL, excluded from sidebar, sitemap and search | +| Pilot customers | `unlisted: true` | Live and reachable by direct URL, excluded from sidebar and sitemap. Search needs an `excludeRoutes` entry too (`CONTRIBUTING.md`, *Unlisting a page*) | | GA | neither | Full publish | ### Solution hub template @@ -220,7 +220,7 @@ The decision procedure, so the per-model versus cross-cutting question stops bei | Differs by **software** version of a solution | Versioned docs | Docusaurus versioning (D3) | | Vendor-published reference | Not duplicated | link out, name the vendor | -Still outstanding under these rules (Phase 7): the devkit `v1.0`/`v1.1` reconfiguration pages are **87% identical** and will drift, and the three ADT versions are near-parallel. +Phase 7 applied these rules to the devkit `v1.0`/`v1.1` reconfiguration pages and the three ADT versions; both are now single pages (§11). ### Document the model, not the interface @@ -266,12 +266,16 @@ Governance is enforced, not conventional: `onInlineTags: 'throw'` is set on ever The payoff: every product page with tagged guides carries a **Guides for this product** section linking its tag page. Publish a new guide, tag it, and it appears on the right products with no edit to those pages. +**Amended 2026-10-07 — a fifth facet.** *Platform type* (`ugv`, `quadruped`, `humanoid`, `manipulator`) was added on 2026-09-11, when Operational Safety and Robot Maintenance were split by type (§10). It is the axis that split is organised on, and it is separate from *model*: a guide tagged `quadruped` applies to every quadruped, including ones with no model tag. The file is now `guides/tags.yml` and declares 27 tags. + --- ## 10. Support section ✅ implemented — scope deliberately reduced > **Reversal — safety and maintenance.** Revision 2 put `/support/safety` and `/support/maintenance` in this section. They are now under **Guides** instead, as `/guides/operational-safety` and `/guides/robot-maintenance`, because they are procedures you follow — one before operating, one on a schedule — which is the Guides axis. Keeping them here made Support a catch-all; Support is now scoped strictly to "something is wrong, or I need a human". Tagging them `safety` and `maintenance` also gives them more reach than a Support sub-page: a tag surfaces from any product page, whereas a Support page is only visited once there is already a problem. +> **Amended 2026-09-11 — split by platform type.** Both guides keep their landing URLs, which carry what holds for every robot and route by a table to one whole page per type: wheeled bases, quadrupeds, humanoids, manipulators. The hazards and checks that come from having legs, wheels or a single arm differ enough that a humanoid owner reading UGV guidance is reading someone else's document, so the table routes to pages rather than to anchors in a mixed page. This replaces the earlier choice to keep all safety guidance on one page so that none of it was a click away. That trade-off was weighed, and the split was chosen. + Per §0 this is the highest-value section on the site. Every page is one a support engineer currently retypes by hand. | Page | Status | What it still needs | @@ -314,6 +318,14 @@ Per §0 this is the highest-value section on the site. Every page is one a suppo Unchanged: every `/robot/*`, `/peripheral/*` and `/system/*` URL. +**Amended 2026-10-05 — three later moves, recorded here because their reasoning lived only in `docusaurus.config.ts`.** + +*Release 1 product renames.* The two Release 1 products were renamed to their trademark names — Robot Management Toolbox and Robot Deployment Toolbox — and their directories renamed to match: `/solution/fleet-management/*` → `/solution/robot-management-toolbox/*` (eight URLs) and `/solution/deployment-toolbox/*` → `/solution/robot-deployment-toolbox/*` (three). Every one is redirected, for the reason given at the top of this section: they are in circulation with customers and in support tickets. + +*The Guides tab kept its old route.* The tab was renamed in this restructure but its route stayed `/tutorial/*`, and none of the revisions above records a reason to keep it. Renamed to `/guides/*` on 2026-09-11 so the URL matches the tab a customer clicked. All twenty-four old URLs redirected. + +*Version pages consolidated.* ADT v1/v2/v3 were three pages, with v2 and v3 largely duplicating each other, now one page tabbed by version (`/solution/adt/v1` `v2` `v3` → `/solution/adt/intro`). The two UGV devkit version pages largely duplicated each other, now one page whose differences are a comparison table and a few tabbed images (`/system/ugv_devkit/v1.0` `v1.1` → `/system/ugv_devkit`). Both sets of old URLs are in circulation. This is §7 applied. The devkit reconfiguration pages were merged the same way, into one page tabbed by generation. + > **Caveat — redirects are client-side, not HTTP 301.** GitHub Pages cannot serve redirects, so `@docusaurus/plugin-client-redirects` emits a stub page with ``, a canonical link, and a JS fallback that preserves the query string and hash. It works in a browser, including anchors. Two consequences: `curl` sees `200` at the old URL rather than a `30x`, and search engines weight these below a real 301. > **Caveat — the 91 anchor changes cannot be redirected at all.** Fragments are client-side only. Any `#2-1-electrical-interfaces` already pasted into a support ticket lands on the right page at the wrong scroll position. This is precisely why doing it before the product hubs exist was cheaper than after. diff --git a/docs/design/product-page-template.md b/docs/design/product-page-template.md index 48bc43f..5c452e4 100644 --- a/docs/design/product-page-template.md +++ b/docs/design/product-page-template.md @@ -352,7 +352,7 @@ An admonition block announcing missing data reads as unfinished. A sentence expl **No manual heading numbers.** `## 1. Overview` produces the anchor `#1-overview`, which breaks the moment a section is inserted above it — silently invalidating every anchor a support engineer has pasted into a ticket. See `ia-proposal.md` §8. -**Sentence case applies to `##` and below, not to the page title.** Product page titles are the product's name, so the question rarely comes up there — but it does under `tutorial/`, where every existing guide's `

` is Title Case (`G1 Diagnostics Guide`, `Ranger Mini Steering Calibration`). These are two rules rather than one applied inconsistently: **Title Case for a page title, sentence case for headings within it.** Recorded because the first draft of the Manifold Scanner Guides got it wrong, which is what an unstated convention invites. See [ADR 0002](../adr/0002-scanner-workflow-lives-in-guides-handed-over-at-the-pcd.md) D5. +**Sentence case applies to `##` and below, not to the page title.** Product page titles are the product's name, so the question rarely comes up there — but it does under `guides/`, where every existing guide's `

` is Title Case (`G1 Diagnostics Guide`, `Ranger Mini Steering Calibration`). These are two rules rather than one applied inconsistently: **Title Case for a page title, sentence case for headings within it.** Recorded because the first draft of the Manifold Scanner Guides got it wrong, which is what an unstated convention invites. See [ADR 0002](../adr/0002-scanner-workflow-lives-in-guides-handed-over-at-the-pcd.md) D5. **Do not duplicate a guide.** Link it. The bring-up procedure lives in the guide; the product page points at it. @@ -366,7 +366,7 @@ Anchors into them are still validated at build time by `onBrokenAnchors: 'throw' **The tag page is the canonical guide list.** Naming the guides inline is good for readers; the tag link is what stops the list rotting. Include both. -**Tags must be declared** in `tutorial/tags.yml` before use. `onInlineTags: 'throw'` fails the build on an undeclared tag. +**Tags must be declared** in `guides/tags.yml` before use. `onInlineTags: 'throw'` fails the build on an undeclared tag. ## Beyond tables: diagrams and other elements @@ -404,7 +404,7 @@ Hero images are almost always **the vendor's copyright**, not ours. As their dis | `peripheral/img/manifold/pocket2-rear-port-c.jpg` | Pocket2 Scanner | **Photographed in-house** by the operator | **Ours — no rights question.** The red ellipse marking Port C is the operator's annotation and is load-bearing, so do not crop or clean it out. Manifold publish no port diagram at all — manual §2.1 is a heading over an empty half-page — so this photograph is the only port reference that exists ([ADR 0002](../adr/0002-scanner-workflow-lives-in-guides-handed-over-at-the-pcd.md) D6) | | `peripheral/img/manifold/pocket2.png` | Pocket2 Scanner | Manifold Tech [Pocket2 product page](https://www.3dmanifold.com/products/pocket2) (`pocket2-device.640.webp`) | Vendor render, transparent cutout. **640 px is the largest published** — the wider `srcset` entries 404, so this is under the 1400 px cap by necessity rather than choice. Alpha-trimmed 640 × 640 → 208 × 505; 74 % of the canvas was padding. The `POCKET 2` and `MANIFOLD TECH` marks are on the product itself and are untouched | -**Screenshots and photographs we take ourselves need none of this.** The ten MindCloud Go and MindCloud Studio captures under `tutorial/manifold/img/` and the Pocket2 port photograph above are operator captures of software we license and hardware we supply — ours to publish, with no vendor agreement in play. They are listed here only so that fact is on the record; guide assets do not otherwise belong in this table. What they *do* need is a check for incidental content before publishing: a real site, real people, a visible serial number or a local filesystem path in a window title are all things a screenshot picks up without anyone intending it. +**Screenshots and photographs we take ourselves need none of this.** The ten MindCloud Go and MindCloud Studio captures under `guides/manifold/img/` and the Pocket2 port photograph above are operator captures of software we license and hardware we supply — ours to publish, with no vendor agreement in play. They are listed here only so that fact is on the record; guide assets do not otherwise belong in this table. What they *do* need is a check for incidental content before publishing: a real site, real people, a visible serial number or a local filesystem path in a window title are all things a screenshot picks up without anyone intending it. Every **vendor** render in the table is **pending confirmation** that our agreements cover documentation use. Replace with vendor-supplied assets if that is cleaner. The regulator photo is our own and needs no such check. (This sentence said "the three vendor renders" while the table held four; a count in prose beside a table it describes is a count that goes stale on the next row.) @@ -617,7 +617,7 @@ includes the commands to gather it. - [ ] Serial number location recorded on the product page under Key information **Wiring** -- [ ] Model has a declared tag in `tutorial/tags.yml` +- [ ] Model has a declared tag in `guides/tags.yml` - [ ] Tag page linked as well as guides named inline - [ ] Shared FAQ answers linked by anchor, not copied - [ ] `npm run build` passes — this is what validates links, anchors and tags diff --git a/docs/design/release-pages-plan.md b/docs/design/release-pages-plan.md index 7d24508..f22aaa3 100644 --- a/docs/design/release-pages-plan.md +++ b/docs/design/release-pages-plan.md @@ -37,9 +37,11 @@ Per D0 the site serves existing customers post-purchase, so every page starts fr | Site-suitability guide | The envelope: where this works and where it does not | | *(delete)* `industrial-patrolling.md`, `navigation.md` | Empty skeletons, never published, both 404 today | +**Amended 2026-10-07 — order and the Robot Platforms directory.** The Solutions sidebar and the cards on `solution/intro.md` list Robot Platforms, Robot Deployment Toolbox, then Robot Management Toolbox. That is the order a deployment runs in: the robot the customer has, the site mapped before anything can run, and the system it is run from afterwards. It is not ordered by how often a page is opened. Robot Platforms was created as `robot-platforms/index.md` so that adding a sub-page would not move its URL; network configuration was added as one on 2026-09-11, and the index stays the category's landing page. The plural name is explained in `TODO.md` under *Robot Platforms page*. + ### Phase 2 — operator and technician guides -Task guides under `tutorial/`, tagged so they surface from product pages: planning a mission, monitoring and teleoperation, reviewing events and detections, managing users and roles, surveying and publishing a site map. +Task guides under `guides/`, tagged so they surface from product pages: planning a mission, monitoring and teleoperation, reviewing events and detections, managing users and roles, surveying and publishing a site map. ### Phase 3 — hardware diff --git a/docusaurus.config.ts b/docusaurus.config.ts index f07b280..6b57e3d 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -66,24 +66,16 @@ const config: Config = { [ '@docusaurus/plugin-client-redirects', { - // The Software section was dissolved: its pages were a solution (ADT) - // and two task guides, none of which belonged in a section of their - // own. These redirects keep old URLs working, which matters because - // support engineers paste them into tickets. + // Old URLs stay working because support engineers paste them into + // tickets. Why each move happened: docs/design/ia-proposal.md §11. redirects: [ {from: '/software/toolbox/assisted_driving_toolbox', to: '/solution/adt/intro'}, {from: '/software/toolbox/adt_v1', to: '/solution/adt/intro'}, {from: '/software/toolbox/adt_v2', to: '/solution/adt/intro'}, {from: '/software/toolbox/adt_v3', to: '/solution/adt/intro'}, - // ADT v1/v2/v3 were three pages, v2 and v3 75% identical. Now one - // page tabbed by version. {from: '/solution/adt/v1', to: '/solution/adt/intro'}, {from: '/solution/adt/v2', to: '/solution/adt/intro'}, {from: '/solution/adt/v3', to: '/solution/adt/intro'}, - // Release 1's two products were renamed to their trademark names, - // Robot Management Toolbox and Robot Deployment Toolbox, and their - // directories renamed to match. Every one of these old URLs is in - // circulation with customers and in support tickets. {from: '/solution/fleet-management', to: '/solution/robot-management-toolbox'}, {from: '/solution/fleet-management/robot-dashboard', to: '/solution/robot-management-toolbox/robot-dashboard'}, {from: '/solution/fleet-management/robot-teleoperation', to: '/solution/robot-management-toolbox/robot-teleoperation'}, @@ -95,11 +87,6 @@ const config: Config = { {from: '/solution/deployment-toolbox', to: '/solution/robot-deployment-toolbox'}, {from: '/solution/deployment-toolbox/map-editor', to: '/solution/robot-deployment-toolbox/map-editor'}, {from: '/solution/deployment-toolbox/map-inspector', to: '/solution/robot-deployment-toolbox/map-inspector'}, - // The Guides tab was renamed in the IA restructure but its route stayed - // `/tutorial/*` — an oversight, not a decision: nothing in - // ia-proposal.md records a reason to keep it. Renamed to `/guides/*` - // on 2026-09-11 so the URL matches the tab a customer clicked. Every - // old URL is redirected because these are in support tickets. {from: '/tutorial/intro', to: '/guides/intro'}, {from: '/tutorial/agilex/ranger_mini_calibration', to: '/guides/agilex/ranger_mini_calibration'}, {from: '/tutorial/agilex/ugv_base_control', to: '/guides/agilex/ugv_base_control'}, @@ -127,14 +114,8 @@ const config: Config = { {from: '/software/installation/apt_source', to: '/guides/installation/apt_source'}, {from: '/software/slam/go2_slam', to: '/guides/unitree/go2_slam'}, {from: '/software/intro', to: '/solution/intro'}, - // Safety and maintenance are procedures you follow, which makes - // them Guides rather than Support. Support is scoped to "something - // is wrong or I need a human". {from: '/general/operational-safety', to: '/guides/operational-safety'}, {from: '/general/robot-maintenance', to: '/guides/robot-maintenance'}, - // The two UGV devkit version pages were 76% identical. They are now - // one page whose differences are a comparison table and a few tabbed - // images. Both old URLs are in circulation with customers. {from: '/system/ugv_devkit/v1.0', to: '/system/ugv_devkit'}, {from: '/system/ugv_devkit/v1.1', to: '/system/ugv_devkit'}, { @@ -159,12 +140,14 @@ const config: Config = { indexDocs: true, indexBlog: false, indexPages: true, - // The plugin does not honour `unlisted: true` front matter, so an - // unlisted page still turns up in site search unless named here. - // Keep this in step with any page carrying that flag. + // This plugin does not read `unlisted: true`. Every page carrying + // that flag must also be named here. See docs/LESSONS.md. excludeRoutes: [ '**/robot/ugv/ranger-mini-v2', '**/solution/adt/intro', + '**/robot/quadruped/as2', + '**/robot/humanoid/h2', + '**/robot/manipulator/nero', ] } ], @@ -262,10 +245,7 @@ const config: Config = { src: 'img/wr-logo.png', }, items: [ - // The top level runs on a single axis: what you own, what capability - // you deploy, what you want to do, and reference. It previously mixed - // product taxonomy (Robots/Peripherals/Systems) with document type - // (Software/Tutorials), which is why nothing was findable. + // Top level runs on a single axis. See docs/design/ia-proposal.md §2.1. { type: 'dropdown', label: 'Products', diff --git a/guides/agilex/ranger_mini_calibration.md b/guides/agilex/ranger_mini_calibration.md index 039cb91..59ef497 100644 --- a/guides/agilex/ranger_mini_calibration.md +++ b/guides/agilex/ranger_mini_calibration.md @@ -12,7 +12,7 @@ Two methods: autocalibration, which the robot performs itself, and manual calibr :::caution Autocalibration needs the right firmware -Not every firmware build supports autocalibration. On the Ranger Mini 2.0, `V5.8.3` includes it and `V5.8.7` does not. Check which build your robot is running — see the firmware list on the [Ranger Mini 2.0](/robot/ugv/ranger-mini-v2) or [Ranger Mini 3.0](/robot/ugv/ranger-mini-v3) page — and use manual calibration if yours lacks it. +Not every firmware build supports autocalibration, so check which build your robot is running and use manual calibration if yours lacks it. On the Ranger Mini 2.0, `V5.8.3` includes it and `V5.8.7` does not; the [Ranger Mini 2.0](/robot/ugv/ranger-mini-v2) page lists the builds. On the Ranger Mini 3.0, [submit a support request](https://forms.office.com/r/qELKzYF33W) quoting your version to ask whether it supports autocalibration. ::: diff --git a/guides/tags.yml b/guides/tags.yml index 9e54812..22b787e 100644 --- a/guides/tags.yml +++ b/guides/tags.yml @@ -4,14 +4,9 @@ # so a tag that is not declared here fails the build rather than quietly # creating a near-duplicate tag page. Add new tags here first. # -# Five facets: model, platform type, vendor, solution, topic. Keep them flat — -# Docusaurus tags have no hierarchy — and prefer adding to an existing facet over -# inventing one. -# -# "platform type" was added 2026-09-11 when Operational Safety and Robot -# Maintenance were split per type. It is the axis that structure is organised on, -# and it is deliberately distinct from "model": a guide tagged `quadruped` -# applies to every quadruped including ones with no model tag of their own. +# Five facets: model, platform type, vendor, solution, topic. Docusaurus tags +# have no hierarchy, so keep them flat and prefer an existing facet to a new one. +# Facet rationale: docs/design/ia-proposal.md §9. # --- model ------------------------------------------------------------------- g1: diff --git a/plugins/file-index/index.js b/plugins/file-index/index.js index aae492f..8fa7120 100644 --- a/plugins/file-index/index.js +++ b/plugins/file-index/index.js @@ -20,20 +20,59 @@ const UPLOAD_DIR = '_upload'; const DEFAULT_BASE_URL = process.env.WR_FILES_BASE_URL || 'https://download.westonrobot.net'; +// Copies of wrfiles.KINDS and wrfiles.LANGS; scripts/test_wrfiles.py fails if +// they drift. +const KINDS = [ + 'user-manual', + 'quick-start', + 'installation-guide', + 'service-manual', + 'troubleshooting', + 'datasheet', + 'safety-manual', + 'certificate', + 'spare-parts', + 'cad', + 'wiring-diagram', + 'firmware', + 'sdk-manual', + 'api-reference', + 'api-examples', + 'integration-guide', + 'training', + 'release-notes', +]; +const LANGS = ['en', 'zh', 'zh-hans', 'zh-hant', 'zxx']; + +const byLengthDesc = (a, b) => b.length - a.length; +const LANG_TAIL = new RegExp( + `-(${[...LANGS].sort(byLengthDesc).join('|')})-v(\\d+(?:\\.\\d+)*)$`, +); + /** Re-derive a record from a key, matching wrfiles.metadata_for. */ function metadataForKey(key) { const [section, product, filename] = key.split('/'); - const stem = filename.replace(/\.tar\.gz$/, '').replace(/\.[^.]+$/, ''); + const stem = filename.replace(/\.tar\.gz$/i, '').replace(/\.[^.]+$/, ''); let rest = stem.slice(product.length + 1); let lang = ''; let version = ''; - const m = rest.match(/-([a-z]{2}(?:-[a-z]+)?)-v(\d+(?:\.\d+)*)$/); + const m = rest.match(LANG_TAIL); if (m) { lang = m[1]; version = m[2]; rest = rest.slice(0, m.index); } - return {section, product, kind: rest, lang, version}; + // Longest kind that prefixes the middle wins, as in wrfiles.split_kind. + let kind = rest; + let subject = ''; + for (const k of [...KINDS].sort(byLengthDesc)) { + if (rest === k || rest.startsWith(`${k}-`)) { + kind = k; + subject = rest.slice(k.length + 1); + break; + } + } + return {section, product, kind, subject, lang, version}; } function scanStaged(siteDir) { diff --git a/robot/humanoid/g1.md b/robot/humanoid/g1.md index ab34aaf..0fbbb59 100644 --- a/robot/humanoid/g1.md +++ b/robot/humanoid/g1.md @@ -46,9 +46,15 @@ A quick reference for the things you reach for most often, collected so you can Files and repositories you clone or download to work with the robot. +**Documents we publish** — generated from the file store, so a new revision appears here without this page being edited. + + + +**Everything else** — Unitree's own resources and code, maintained by them. + | Resource | What it is | Where | | --- | --- | --- | -| Training slides | Weston Robot's G1 basic training deck | [G1 Basic Training](https://drive.google.com/file/d/1bxRCtmtrvQ1vH279HSRvdj0IkLV-axV7/view?usp=drive_link) | +| User manual | Unitree's G1 user manual | [G1 user manual](https://marketing.unitree.com/article/en/G1/User_Manual.html) | | URDF / CAD | Robot model for simulation and mechanical design | [Unitree developer downloads](https://support.unitree.com/home/en/G1_developer/get_sdk) | | C++ SDK | Primary development interface | [unitree_sdk2](https://github.com/unitreerobotics/unitree_sdk2) | | Python SDK | Python bindings for the same interface | [unitree_sdk2_python](https://github.com/unitreerobotics/unitree_sdk2_python) | diff --git a/robot/humanoid/h1-2.md b/robot/humanoid/h1-2.md index d15f1a5..fba6e94 100644 --- a/robot/humanoid/h1-2.md +++ b/robot/humanoid/h1-2.md @@ -50,6 +50,7 @@ Files and repositories you clone or download to work with the robot. | Resource | What it is | Where | | --- | --- | --- | +| User manual | Unitree's H1-2 user manual | [H1-2 user manual](https://marketing.unitree.com/article/en/H1-2/User_Manual.html) | | C++ SDK | Primary development interface | [unitree_sdk2](https://github.com/unitreerobotics/unitree_sdk2) | | ROS 2 package | ROS 2 integration | [unitree_ros2](https://github.com/unitreerobotics/unitree_ros2) | diff --git a/robot/humanoid/h2.md b/robot/humanoid/h2.md index 7d1ae27..3cd2cb9 100644 --- a/robot/humanoid/h2.md +++ b/robot/humanoid/h2.md @@ -1,6 +1,7 @@ --- sidebar_position: 4 description: "Unitree H2 humanoid: setup, logins, interfaces and support resources." +unlisted: true --- # H2 @@ -60,6 +61,7 @@ Files and repositories you clone or download to work with the robot. | Resource | What it is | Where | | --- | --- | --- | +| User manual | Unitree's H2 user manual | [H2 user manual](https://marketing.unitree.com/article/en/H2/User_Manual.html) | | Developer documentation | Unitree's H2 documentation | [H2 developer](https://support.unitree.com/home/en/H2_developer) | | C++ SDK | **TODO** — confirm which SDK applies to the H2 | | | ROS 2 package | **TODO** | | diff --git a/robot/humanoid/r1.md b/robot/humanoid/r1.md index 214b8d6..f41f44e 100644 --- a/robot/humanoid/r1.md +++ b/robot/humanoid/r1.md @@ -48,6 +48,7 @@ Files and repositories you clone or download to work with the robot. | Resource | What it is | Where | | --- | --- | --- | +| User manual | Unitree's R1 user manual | [R1 user manual](https://marketing.unitree.com/article/en/R1/User_Manual.html) | | Developer documentation | Unitree's R1 documentation | [R1 developer](https://support.unitree.com/home/en/R1_developer) | | C++ SDK | Primary development interface (same repo as Go2/B2/A2/G1) | [unitree_sdk2](https://github.com/unitreerobotics/unitree_sdk2) | | Python SDK | Python bindings for the same interface | [unitree_sdk2_python](https://github.com/unitreerobotics/unitree_sdk2_python) | diff --git a/robot/intro.md b/robot/intro.md index 1a1c1c7..a45d6bd 100644 --- a/robot/intro.md +++ b/robot/intro.md @@ -32,8 +32,6 @@ particular can fall without warning during development. Compact quadruped supplied as a development platform, with LiDAR and an expansion dock. -Unitree's compact industrial quadruped. Documentation in preparation. - Unitree's A2 quadruped. Documentation in preparation. Large industrial quadruped for payload-carrying and outdoor inspection. @@ -50,8 +48,6 @@ particular can fall without warning during development. Unitree's R1 humanoid. Documentation in preparation. -Unitree's full-size H2 humanoid. Documentation in preparation. - ## Manipulators @@ -68,8 +64,6 @@ particular can fall without warning during development. AgileX's lightweight 6-DOF arm for research and light handling. -AgileX's 7-DOF research arm. Documentation in preparation. - Kinova's compact 6-DOF research arm. diff --git a/robot/manipulator/kinova-gen3-lite.md b/robot/manipulator/kinova-gen3-lite.md index 049ec42..1962a6f 100644 --- a/robot/manipulator/kinova-gen3-lite.md +++ b/robot/manipulator/kinova-gen3-lite.md @@ -38,7 +38,7 @@ Bring-up in outline: 3. **Reach the arm** through the KORTEX web interface to confirm it is alive. 4. **Move to the API** — C++ or Python via KORTEX, or one of the ROS integrations. -The [Start Guide](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EcuGhYgXKs5JtWMZoSnipRMBEWyYHV7YaTmaZAf57OIg_w?e=fJHUdH) is the shortest path, and Kinova's [KORTEX how-to series](https://www.youtube.com/watch?v=zQewb08M4sA&list=PLz1XwEYRuku5rZjJWBr6SDi93jgWZ4FHL) walks through the software. +Kinova's [quick start guide](https://www.kinovarobotics.com/resource/gen3-lite-quick-start-guide) is the shortest path, and Kinova's [KORTEX how-to series](https://www.youtube.com/watch?v=zQewb08M4sA&list=PLz1XwEYRuku5rZjJWBr6SDi93jgWZ4FHL) walks through the software. ## Key information @@ -48,13 +48,15 @@ A quick reference for the things you reach for most often, collected so you can Files and repositories you clone or download to work with the arm. +Kinova maintain their own documentation and revise it on their schedule — the links below go to their resource pages so you always get the current revision rather than a copy of ours. + | Resource | What it is | Where | | --- | --- | --- | -| User guide | Full manual | [User Guide PDF](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/Ec0kSpCAL-9JhKc6299RtrcBsy1Vvc0eolHHusPnqm_hlA?e=O8bN5Q) | -| Start guide | The shortest path to first motion | [Start Guide PDF](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EcuGhYgXKs5JtWMZoSnipRMBEWyYHV7YaTmaZAf57OIg_w?e=fJHUdH) | -| System overview | How KORTEX fits together | [Kinova Kortex PDF](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EeDH7SJp2CFJpmC3eTI_OOIBkzGOgqK6GYkxt7O1yfbbEg?e=wddhLM) | -| Firmware release notes | What changed, and update procedure | [Release Notes PDF](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EdrqH5oIMkdJgx7gIsi6-60BURHPDimf6rviOIhmubDdzQ?e=sV36ea) | -| CAD model | STEP file for mechanical design | [Gen3 Lite STEP](https://tangrobot.sharepoint.com/:u:/s/Public-Outgoing/ES0-WAcngaJBq0OggTQ34lMBAZ9P8QKvrli2RDojayINZw?e=GlLPa3) | +| User guide | Full manual | [Gen3 lite user guide](https://www.kinovarobotics.com/resource/gen3-lite-user-guide) | +| Start guide | The shortest path to first motion | [Quick start guide](https://www.kinovarobotics.com/resource/gen3-lite-quick-start-guide) | +| Firmware release notes | What changed, and update procedure | [Release notes](https://artifactory.kinovaapps.com/artifactory/generic-documentation-public/Documentation/Gen3%20lite/Technical%20documentation/Release%20Notes/) | +| CAD model | STEP file for mechanical design | [CAD & drawings](https://artifactory.kinovaapps.com/artifactory/generic-documentation-public/Documentation/Gen3%20lite/CAD%20%26%20Drawings/) | +| Specifications | Dimensions, payload, reach and ratings | [Product specifications](https://artifactory.kinovaapps.com/artifactory/generic-documentation-public/Documentation/Gen3%20lite/Technical%20documentation/Product%20specifications/) | | Robot model | URDF / XACRO for simulation | [kortex_description](https://github.com/Kinovarobotics/ros_kortex/tree/kinetic-devel/kortex_description/arms/gen3_lite/6dof/urdf) | | C++ / Python API | Primary development interface | [Kinova KORTEX API](https://github.com/Kinovarobotics/Kinova-kortex2_Gen3_G3L/) | | ROS 1 | ROS integration | [ros_kortex](https://github.com/kinovarobotics/ros_kortex) | diff --git a/robot/manipulator/nero.md b/robot/manipulator/nero.md index 603b76b..bdf3c79 100644 --- a/robot/manipulator/nero.md +++ b/robot/manipulator/nero.md @@ -1,6 +1,7 @@ --- sidebar_position: 6 description: "AgileX NERO 7-DOF manipulator: setup, control interface, resources and support." +unlisted: true --- # NERO diff --git a/robot/manipulator/piper.md b/robot/manipulator/piper.md index 8746656..8db0500 100644 --- a/robot/manipulator/piper.md +++ b/robot/manipulator/piper.md @@ -35,10 +35,10 @@ Bring-up in outline: 1. **Mount the arm** on a rigid surface, or on the base it will run on. 2. **Connect power and a CAN interface** to your computer. -3. **Bring up CAN** and confirm the arm responds — the [CAN protocol reference](https://tangrobot.sharepoint.com/:x:/s/Public-Outgoing/EXt0lngMwfpEuhgttEqFuYIBtMUkrF6Ou1ovQOHQbsWm8A?e=2FoZtv) documents the frames. -4. **Drive it from code** using `piper_sdk`, or from the Windows application for a first check. +3. **Bring up CAN** and confirm the arm responds — the CAN protocol reference under [Related resources](#related-resources) documents the frames (in Chinese). +4. **Drive it from code** using `piper_sdk`. -The [Quick Start Guide](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EZQW2Y1CL_pHm8SymXTjTsMBVfHFpi-THuqaTYGQ3FMW1g?e=rQMw0H) is the shortest path, and the unboxing and gripper-installation videos below cover the mechanical side. +The quick start guide under [Related resources](#related-resources) is the shortest path, and the unboxing and gripper-installation videos below cover the mechanical side. ## Key information @@ -48,18 +48,19 @@ A quick reference for the things you reach for most often, collected so you can Files and repositories you clone or download to work with the arm. +**Documents we publish** — generated from the file store, so a new revision appears here without this page being edited. + + + +**Everything else** — code repositories, maintained by hand. + | Resource | What it is | Where | | --- | --- | --- | -| User manual | Full manual | [EN](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EfqPP2v-mhFKv-VARWnYcyUB-xQBw-88Vx5Pro3mZsgmGg?e=KTfP6b) · [CN](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EasMrjngL_pNmaawLe8mlCgBTgPMNG1hp6PRw32CDxccow?e=7q5abC) | -| Quick start guide | The shortest path to first motion | [EN](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EZQW2Y1CL_pHm8SymXTjTsMBVfHFpi-THuqaTYGQ3FMW1g?e=rQMw0H) · [CN](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EQBRJZsY1gdDg_do070o2goBCWjyDwGL9dohA4xCFqkNog?e=38opB8) | -| CAN protocol | Frame reference for the control interface | [Protocol (CN)](https://tangrobot.sharepoint.com/:x:/s/Public-Outgoing/EXt0lngMwfpEuhgttEqFuYIBtMUkrF6Ou1ovQOHQbsWm8A?e=2FoZtv) | -| Windows application | Drive the arm without writing code | [Application](https://tangrobot.sharepoint.com/:u:/s/Public-Outgoing/EUN0qfdCSLVCqZPctXXr_SwB6CCPON8HHcWR5ybNwy1aOQ?e=zekJyS) | | SDK | Primary development interface | [piper_sdk](https://github.com/agilexrobotics/piper_sdk) · [examples](https://github.com/agilexrobotics/piper_sdk_demo) | | ROS 1 | ROS Noetic integration | [Piper_ros noetic](https://github.com/agilexrobotics/Piper_ros/tree/ros-noetic-no-aloha) | | ROS 2 | ROS 2 integration | [Humble](https://github.com/agilexrobotics/Piper_ros/tree/ros-humble-no-aloha) · [Foxy](https://github.com/agilexrobotics/Piper_ros/tree/ros-foxy-no-aloha) | | Simulation | Gazebo, Isaac Sim and MoveIt 2 | [Gazebo / MoveIt 2](https://github.com/agilexrobotics/agilex_open_class/tree/master/piper) · [Isaac Sim](https://github.com/agilexrobotics/piper_isaac_sim) | | URDF | Robot model | [urdf](https://github.com/agilexrobotics/Piper_ros/tree/ros-noetic-no-aloha/src/piper_description/urdf) | -| CAD models | STEP files | [Arm](https://tangrobot.sharepoint.com/:u:/s/Public-Outgoing/Edhy2bZ_K1VEtaVOmVpe7AEBsh_b-1CXjWN9vhLG7VqNMw?e=qyKYmB) · [Gripper](https://tangrobot.sharepoint.com/:u:/s/Public-Outgoing/EYwTc-zvbopOqe_LtjsbhscBrMTgOvUHuVOVgNnWEDmt5w?e=WzT6bk) · [Drag teaching tool](https://tangrobot.sharepoint.com/:u:/s/Public-Outgoing/EfaGx4MK2hxHonUwllRgDGgBz9ciPUZrmXTq3Hu4o4WAyQ?e=ZVX6uK) | Installing Weston Robot packages on your host? Add our package repository first: [Weston Robot Apt Source](/guides/installation/apt_source). diff --git a/robot/manipulator/wr65.md b/robot/manipulator/wr65.md index b2448ed..891feda 100644 --- a/robot/manipulator/wr65.md +++ b/robot/manipulator/wr65.md @@ -40,7 +40,7 @@ Bring-up in outline: 3. **Confirm the arm responds** before writing any motion code. 4. **Move to the SDK** — `wr_arm_sdk`, or the ROS packages if you are integrating into an existing stack. -The [SDK manual](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EZ16f6SHNoxNvpkJ8o1ijTMBhU4XZkE8KfvYXObn9SeuCA?e=ZVbTYn) covers the software side in detail. +The API reference and wire protocol documents under [Related resources](#related-resources) cover the software side in detail. ## Key information @@ -50,13 +50,14 @@ A quick reference for the things you reach for most often. Values are as configu Files and repositories you clone or download to work with the arm. The manuals below are the ones we ship with the arm and are the ones to work from. +**Documents we publish** — generated from the file store, so a new revision appears here without this page being edited. + + + +**Everything else** — code repositories, maintained by hand. + | Resource | What it is | Where | | --- | --- | --- | -| Manual | Full product manual | [EN](https://tangrobot.sharepoint.com/:f:/s/Public-Outgoing/Eki4t2rSYfZJj0C1oM8muAYBSaEVZZLccVLizd3KZ0QOnA?e=fCpuuF) · [CN](https://tangrobot.sharepoint.com/:f:/s/Public-Outgoing/EsX7ahL2QwlJpUZvi-B5peIBLllti9KVbqd4ZK0kSwMKsg?e=bAlbLE) | -| SDK manual | Using `wr_arm_sdk` | [SDK Manual](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EZ16f6SHNoxNvpkJ8o1ijTMBhU4XZkE8KfvYXObn9SeuCA?e=ZVbTYn) | -| ROS manuals | ROS 1 and ROS 2 integration | [ROS 1](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/ET4USOMo1wBJo1MX9l_mMJEBZ_7MkDZKw51P5VzWy0ydeA?e=DL1nBT) · [ROS 2](https://tangrobot.sharepoint.com/:f:/s/Public-Outgoing/EkJTVQwtYqpJohPR-o-jFrABCfdmQFwSOrEVZ-JEdJPDcg?e=Wcc9cQ) | -| JSON protocol | The wire protocol, if you are not using the SDK | [Protocol Manual](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EZ7t0oc9qnBDpLFsvta_lS4BvWJMEUFE7YfafvXfA6m0Bw?e=UxWjki) | -| API examples | Worked samples against the Realman API | [RM API samples](https://tangrobot.sharepoint.com/:f:/s/Public-Outgoing/EiDbCkGaSA5CgOpQ8tcnw1IBrzKiorH_cXctCj9KcP5dmA?e=OZItiH) | | C++ SDK | Primary development interface | [wr_arm_sdk](https://github.com/westonrobot/wr_arm_sdk) | | ROS package | ROS 1 integration | [wr65b_ros](https://github.com/westonrobot/wr65b_ros) | | ROS 2 package | ROS 2 integration | [wr_arm_ros2](https://github.com/westonrobot/wr_arm_ros2) | @@ -84,7 +85,8 @@ and their figures for the force-sensing variant differ from ours — 627 mm reac Reach and force-sensor accuracy are the two values to confirm from the manual supplied with your arm, or from [Realman's current page](https://www.realman-robotics.com/en/products/rm65.html), -before you rely on them. The figures below are the ones that are consistent across both. +before you rely on them. Where Realman's current figures and our manual differ, the +figures below follow Realman. ::: @@ -97,7 +99,7 @@ before you rely on them. The figures below are the ones that are consistent acro | Repeatability | ±0.05 mm | | Body weight | 7.2 kg (`-B`) · 7.3 kg (force-sensing variants) | | Working radius | 610 mm (`-B`) — see the caution above for the others | -| Power supply | DC 20–30 V, rated 24 V | +| Power supply | DC 24 V rated, 27 V maximum | | Power consumption | ≤ 200 W maximum, ≤ 100 W comprehensive | | Protection level | IP54 (arm body) | | Materials | Aluminium alloy | @@ -107,7 +109,9 @@ before you rely on them. The figures below are the ones that are consistent acro #### Joint limits and speeds -From our manual, and identical across the variants. Worth having in front of you when you +From [Realman's current parameters](https://develop.realman-robotics.com/en/robot/robotParameter/RM65OntologyParameters/), +and identical across the variants. The specification table in the manual we publish gives +±180° for J1, J4 and J5; plan to the ranges here. Worth having in front of you when you are planning trajectories — a pose that looks reachable can sit outside J2 or J5. | Joint | Motion range | Maximum speed | @@ -121,7 +125,7 @@ are planning trajectories — a pose that looks reachable can sit outside J2 or ### Control interface -The arm is driven through `wr_arm_sdk`, or directly over its **JSON protocol** if you are integrating from a language or environment the SDK does not cover — the [protocol manual](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EZ7t0oc9qnBDpLFsvta_lS4BvWJMEUFE7YfafvXfA6m0Bw?e=UxWjki) documents the messages. +The arm is driven through `wr_arm_sdk`, or directly over its **JSON protocol** if you are integrating from a language or environment the SDK does not cover — the wire protocol document under [Related resources](#related-resources) documents the messages. `wr_arm_sdk` and `wr_arm_ros2` are shared across the arm range; the ROS 1 package is per-model, so use `wr65b_ros` for the WR65 specifically. diff --git a/robot/manipulator/wrl63.md b/robot/manipulator/wrl63.md index d6eacd4..e4c6885 100644 --- a/robot/manipulator/wrl63.md +++ b/robot/manipulator/wrl63.md @@ -40,7 +40,7 @@ Bring-up in outline: 3. **Confirm the arm responds** before writing any motion code. 4. **Move to the SDK** — `wr_arm_sdk`, or the ROS packages if you are integrating into an existing stack. -The [SDK manual](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EZ16f6SHNoxNvpkJ8o1ijTMBhU4XZkE8KfvYXObn9SeuCA?e=ZVbTYn) covers the software side in detail. +The API reference and wire protocol documents under [Related resources](#related-resources) cover the software side in detail. ## Key information @@ -50,13 +50,14 @@ A quick reference for the things you reach for most often. Values are as configu Files and repositories you clone or download to work with the arm. The manuals below are the ones we ship with the arm and are the ones to work from. +**Documents we publish** — generated from the file store, so a new revision appears here without this page being edited. + + + +**Everything else** — code repositories, maintained by hand. + | Resource | What it is | Where | | --- | --- | --- | -| Manual | Full product manual | [EN](https://tangrobot.sharepoint.com/:f:/s/Public-Outgoing/Eki4t2rSYfZJj0C1oM8muAYBSaEVZZLccVLizd3KZ0QOnA?e=fCpuuF) · [CN](https://tangrobot.sharepoint.com/:f:/s/Public-Outgoing/EsX7ahL2QwlJpUZvi-B5peIBLllti9KVbqd4ZK0kSwMKsg?e=bAlbLE) | -| SDK manual | Using `wr_arm_sdk` | [SDK Manual](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EZ16f6SHNoxNvpkJ8o1ijTMBhU4XZkE8KfvYXObn9SeuCA?e=ZVbTYn) | -| ROS manuals | ROS 1 and ROS 2 integration | [ROS 1](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/ET4USOMo1wBJo1MX9l_mMJEBZ_7MkDZKw51P5VzWy0ydeA?e=DL1nBT) · [ROS 2](https://tangrobot.sharepoint.com/:f:/s/Public-Outgoing/EkJTVQwtYqpJohPR-o-jFrABCfdmQFwSOrEVZ-JEdJPDcg?e=Wcc9cQ) | -| JSON protocol | The wire protocol, if you are not using the SDK | [Protocol Manual](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EZ7t0oc9qnBDpLFsvta_lS4BvWJMEUFE7YfafvXfA6m0Bw?e=UxWjki) | -| API examples | Worked samples against the Realman API | [RM API samples](https://tangrobot.sharepoint.com/:f:/s/Public-Outgoing/EiDbCkGaSA5CgOpQ8tcnw1IBrzKiorH_cXctCj9KcP5dmA?e=OZItiH) | | C++ SDK | Primary development interface | [wr_arm_sdk](https://github.com/westonrobot/wr_arm_sdk) | | ROS package | ROS 1 integration | [wrl63b_ros](https://github.com/westonrobot/wrl63b_ros) | | ROS 2 package | ROS 2 integration | [wr_arm_ros2](https://github.com/westonrobot/wr_arm_ros2) | @@ -84,7 +85,8 @@ and their figures for the force-sensing variant differ from ours — 917 mm reac Reach and force-sensor accuracy are the two values to confirm from the manual supplied with your arm, or from [Realman's current page](https://www.realman-robotics.com/en/products/rml63.html), -before you rely on them. The figures below are the ones that are consistent across both. +before you rely on them. Where Realman's current figures and our manual differ, the +figures below follow Realman. ::: @@ -97,7 +99,7 @@ before you rely on them. The figures below are the ones that are consistent acro | Repeatability | ±0.05 mm | | Body weight | 10.0 kg (`-B`) · 10.1 kg (force-sensing variants) | | Working radius | 900 mm (`-B`) — see the caution above for the others | -| Power supply | DC 20–30 V, rated 24 V | +| Power supply | DC 24 V rated, 27 V maximum | | Power consumption | ≤ 200 W maximum, ≤ 100 W comprehensive | | Protection level | IP54 (arm body) | | Materials | Aluminium alloy | @@ -109,8 +111,11 @@ Note the trade against the [WR65](/robot/manipulator/wr65): half again the reach #### Joint limits and speeds -From our manual, and identical across the variants. Worth having in front of you when you -are planning trajectories — note that **J3 is asymmetric**, unlike every other joint. +From [Realman's current parameters](https://develop.realman-robotics.com/en/robot/robotParameter/RML63OntologyParameters/), +and identical across the variants. The specification table in the manual we publish gives +±180° for J1, J2, J4 and J5 and +165° to −150° for J3; plan to the ranges here. Worth +having in front of you when you are planning trajectories — note that **J3 is asymmetric**, +unlike every other joint. | Joint | Motion range | Maximum speed | | --- | --- | --- | @@ -123,7 +128,7 @@ are planning trajectories — note that **J3 is asymmetric**, unlike every other ### Control interface -The arm is driven through `wr_arm_sdk`, or directly over its **JSON protocol** if you are integrating from a language or environment the SDK does not cover — the [protocol manual](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EZ7t0oc9qnBDpLFsvta_lS4BvWJMEUFE7YfafvXfA6m0Bw?e=UxWjki) documents the messages. +The arm is driven through `wr_arm_sdk`, or directly over its **JSON protocol** if you are integrating from a language or environment the SDK does not cover — the wire protocol document under [Related resources](#related-resources) documents the messages. `wr_arm_sdk` and `wr_arm_ros2` are shared across the arm range; the ROS 1 package is per-model, so use `wrl63b_ros` for the WRL63 specifically. diff --git a/robot/manipulator/z1.md b/robot/manipulator/z1.md index 9642179..9b5e21f 100644 --- a/robot/manipulator/z1.md +++ b/robot/manipulator/z1.md @@ -16,7 +16,7 @@ This page does not repeat or replace Unitree's documentation. It highlights the Unitree's own documentation: * [Official product page](https://www.unitree.com/z1) -* [Official documentation](https://dev-z1.unitree.com/) +* [Official documentation](https://support.unitree.com/home/en/Z1_developer/sdk_intro) @@ -38,7 +38,7 @@ Bring-up in outline: 3. **Connect Ethernet** and reach the controller. 4. **Run the controller and an SDK example** to confirm the chain works. -Unitree's [documentation](https://dev-z1.unitree.com/) covers each step in detail. We do not publish a Z1 bring-up guide of our own. +Unitree's [documentation](https://support.unitree.com/home/en/Z1_developer/sdk_intro) covers each step in detail. We do not publish a Z1 bring-up guide of our own. ## Key information diff --git a/robot/quadruped/a2.md b/robot/quadruped/a2.md index 53b3ed3..b5f5100 100644 --- a/robot/quadruped/a2.md +++ b/robot/quadruped/a2.md @@ -20,9 +20,6 @@ Unitree's own documentation: * [Official product page](https://www.unitree.com/A2) * [Official documentation](https://support.unitree.com/home/en/A2_SDK_Development_Guide) -Not the robot you have? The [As2](/robot/quadruped/as2) is Unitree's compact -industrial quadruped and is documented separately. -
+ +**Everything else** — Unitree's own resources and code, maintained by them. + | Resource | What it is | Where | | --- | --- | --- | -| Training slides | Weston Robot's B2 training deck | [B2 Training](https://drive.google.com/file/d/1z1GGaev0Nk5_6UeacQ8n_3tlFgu0M0nZ/view?usp=drive_link) | +| User manual | Unitree's B2 user manual | [B2 user manual](https://marketing.unitree.com/article/en/B2/User_Manual.html) | | URDF / CAD | Robot model for simulation and mechanical design | [Unitree developer downloads](https://support.unitree.com/home/en/B2_developer/Obtain%20SDK) | | C++ SDK | Primary development interface | [unitree_sdk2](https://github.com/unitreerobotics/unitree_sdk2) | | Python SDK | Python bindings for the same interface | [unitree_sdk2_python](https://github.com/unitreerobotics/unitree_sdk2_python) | diff --git a/robot/quadruped/go2.md b/robot/quadruped/go2.md index 036a5a4..c8006cb 100644 --- a/robot/quadruped/go2.md +++ b/robot/quadruped/go2.md @@ -48,10 +48,15 @@ A quick reference for the things you reach for most often, collected so you can Files and repositories you clone or download to work with the robot. +**Documents we publish** — generated from the file store, so a new revision appears here without this page being edited. + + + +**Everything else** — Unitree's own resources and code, maintained by them. + | Resource | What it is | Where | | --- | --- | --- | -| User guide | Weston Robot's Go2 user guide | [Go2 User Guide](https://drive.google.com/file/d/1J8djR9AM04yRQpGwCmQbvIni2ymwxlwV/view?usp=drive_link) | -| Expansion dock reflash | Recovering or updating the dock's firmware | [Reflash guide](https://drive.google.com/file/d/14RwW_kDcGxX9-G442ri5mWq_qUPuTa0j/view?usp=drive_link) | +| User manual | Unitree's Go2 user manual | [Go2 user manual](https://marketing.unitree.com/article/en/Go2/User_Manual.html) | | Payload mounting | Mechanical mounting guidance | [Unitree payload guide](https://support.unitree.com/home/en/developer/Payload) | | URDF / CAD | Robot model for simulation and mechanical design | [Unitree developer downloads](https://support.unitree.com/home/en/developer/Obtain%20SDK) | | C++ SDK | Primary development interface | [unitree_sdk2](https://github.com/unitreerobotics/unitree_sdk2) | diff --git a/robot/ugv/ranger-mini-v2.md b/robot/ugv/ranger-mini-v2.md index ab6901f..bee0863 100644 --- a/robot/ugv/ranger-mini-v2.md +++ b/robot/ugv/ranger-mini-v2.md @@ -61,8 +61,6 @@ Files and repositories you clone or download to work with the robot. | Resource | What it is | Where | | --- | --- | --- | -| Manual | Ranger Mini 2.0 user manual | [EN](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/Eagd2Vrmnw9IiTzl4HaXjEwBuQJJ1unetL-IEpGHdBejag?e=YY4be5) · [CN](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EdlhLdKQBDlKlYL35YiVYDwBqyHDFgfliUiPDEmwy0WACA?e=TnIw9y) | -| CAD model | STEP file for mechanical design | [Ranger Mini 2.0 STEP](https://tangrobot.sharepoint.com/:u:/s/Public-Outgoing/Efcf9NZa15JGkcNRaEoGLNsBfNuwNNzcgjNtEsDMMHAM4A?e=YcQ9AB) | | C++ SDK | Primary development interface | [ugv_sdk](https://github.com/westonrobot/ugv_sdk) | | ROS package | ROS 1 integration | [ranger_ros](https://github.com/westonrobot/ranger_ros) | | ROS 2 package | ROS 2 integration | [ranger_ros2](https://github.com/westonrobot/ranger_ros2) | @@ -75,11 +73,13 @@ Dimensions, payload, speed and battery figures are on the [official product page Which build you are running changes what the robot can do, so check before troubleshooting. +We supply firmware images on request — [submit a support request](https://forms.office.com/r/qELKzYF33W) quoting the version you are running. + | Version | What is different | | --- | --- | -| [V5.9.1](https://tangrobot.sharepoint.com/:u:/s/Public-Outgoing/EasKzBaC07dIrhxGs9_4_WEBY-2gf81qeoZFdDFCFB0Ibw?e=CFUJ6T) | E-stop parks the wheels | -| [V5.8.7](https://tangrobot.sharepoint.com/:u:/s/Public-Outgoing/ESydg3zKcnhHizjnudyNDcgBiSuX7mgCCOMeiZ4ncy_faQ?e=2Up90z) | **No** autocalibration — use [manual calibration](/guides/agilex/ranger_mini_calibration#manual-calibration) | -| [V5.8.3](https://tangrobot.sharepoint.com/:u:/s/Public-Outgoing/EXvKUHspMMZCvaDj1uvucD8BVPiIHzmzNm1JJ2N29_58_g?e=tWXt2J) | Includes autocalibration | +| **V5.9.1** | E-stop parks the wheels | +| **V5.8.7** | **No** autocalibration — use [manual calibration](/guides/agilex/ranger_mini_calibration#manual-calibration) | +| **V5.8.3** | Includes autocalibration | ### Control interface diff --git a/robot/ugv/ranger-mini-v3.md b/robot/ugv/ranger-mini-v3.md index ff2bc9d..76fc47f 100644 --- a/robot/ugv/ranger-mini-v3.md +++ b/robot/ugv/ranger-mini-v3.md @@ -50,10 +50,14 @@ A quick reference for the things you reach for most often, collected so you can Files and repositories you clone or download to work with the robot. +**Documents we publish** — generated from the file store, so a new revision appears here without this page being edited. + + + +**Everything else** — code repositories, maintained by hand. + | Resource | What it is | Where | | --- | --- | --- | -| Manual | Ranger Mini 3.0 user manual | [EN](https://tangrobot.sharepoint.com/:b:/s/Public-Outgoing/EUjRgOZIXK9KnW006BR8w3sB2jU6vFv3z7WgxDFmJ_PPQQ?e=mcYaJs) | -| CAD model | STEP file for mechanical design | [Ranger Mini 3.0 STEP](https://tangrobot.sharepoint.com/:u:/s/Public-Outgoing/EcOIV7nLuutLoPvKU2WfbkIBu7Izpp4fykdaXQnlAck0dw?e=85bhT2) | | C++ SDK | Primary development interface | [ugv_sdk](https://github.com/westonrobot/ugv_sdk) | | ROS package | ROS 1 integration | [ranger_ros](https://github.com/westonrobot/ranger_ros) | | ROS 2 package | ROS 2 integration | [ranger_ros2](https://github.com/westonrobot/ranger_ros2) | @@ -64,9 +68,7 @@ Dimensions, payload, speed and battery figures are on the [official product page ### Firmware -| Version | What is different | -| --- | --- | -| [V6.0.5](https://tangrobot.sharepoint.com/:u:/s/Public-Outgoing/ET8rMyZGlnxBha4NuIoY3IYB3Cc9yJJ1DvJQ5UmqF_8MgQ?e=xVwAza) | Current release | +Firmware images are not currently published here. [Submit a support request](https://forms.office.com/r/qELKzYF33W) for the current release, quoting the version you are running. ### Control interface diff --git a/scripts/check-downloads.py b/scripts/check-downloads.py index 9fbbc67..582d54a 100755 --- a/scripts/check-downloads.py +++ b/scripts/check-downloads.py @@ -25,6 +25,9 @@ import urllib.error import urllib.request +sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent)) +import wrfiles # noqa: E402 + REPO = pathlib.Path(__file__).resolve().parent.parent LOCAL_REF = re.compile(r"[\"'(]\s*(/_upload/[^\s\"')]+)") DOWNLOADS_TAG = re.compile(r"]*?)/?>", re.S) @@ -41,7 +44,7 @@ # reference scan. `docs/` is deliberately absent: it is internal engineering # documentation, never served, and its examples are examples rather than # queries — scanning it made this gate report five findings against itself. -CONTENT_ROOTS = ("robot", "solution", "peripheral", "system", "tutorial", "support") +CONTENT_ROOTS = wrfiles.SECTIONS SCAN_ROOTS = CONTENT_ROOTS + ("src", "plugins") diff --git a/scripts/test_wrfiles.py b/scripts/test_wrfiles.py index f60e530..9e142ce 100644 --- a/scripts/test_wrfiles.py +++ b/scripts/test_wrfiles.py @@ -8,10 +8,15 @@ Run: python3 -m unittest discover -s scripts -t scripts """ +import importlib.util +import pathlib +import re import unittest import wrfiles as w +REPO = pathlib.Path(__file__).resolve().parent.parent + class BothRoutesAgree(unittest.TestCase): """The engineer's directories and the technician's `__` segments are one @@ -183,7 +188,7 @@ def test_metadata_for_stays_lenient(self): class KindAndLanguageAreControlledVocabularies(unittest.TestCase): """Free text here is how a store ends up holding cad, CAD, STP and STL for the same thing — at which point `` stops being usable - and the Document column reads inconsistently.""" + and the File column reads inconsistently.""" def key(self, name): return w.key_from_upload_path(f"_upload/robot/scout-mini/{name}") @@ -316,3 +321,42 @@ def test_the_document_beside_it_is(self): def test_the_index_itself_is_not(self): self.assertFalse(w.is_content_key("index.json")) + + +def docs_plugin_paths(): + config = (REPO / "docusaurus.config.ts").read_text(encoding="utf-8") + return set(re.findall(r"^\s*path:\s*'([^']+)',", config, re.M)) + + +class SectionsAreTheSiteSections(unittest.TestCase): + """`SECTIONS` must equal the `path` of every docs plugin instance in + `docusaurus.config.ts`, and `check-downloads.py` must scan the same set.""" + + def test_sections_match_the_config(self): + paths = docs_plugin_paths() + self.assertTrue(paths, "no `path:` entries found in docusaurus.config.ts") + self.assertEqual(set(w.SECTIONS), paths) + + def test_check_downloads_scans_the_sections(self): + spec = importlib.util.spec_from_file_location( + "check_downloads", REPO / "scripts" / "check-downloads.py") + check_downloads = importlib.util.module_from_spec(spec) + spec.loader.exec_module(check_downloads) + self.assertEqual(set(check_downloads.CONTENT_ROOTS), set(w.SECTIONS)) + + +def plugin_list(name): + source = (REPO / "plugins" / "file-index" / "index.js").read_text(encoding="utf-8") + m = re.search(rf"^const {name} = \[(.*?)\];", source, re.M | re.S) + return tuple(re.findall(r"'([^']+)'", m.group(1))) if m else () + + +class PluginVocabularyIsWrfiles(unittest.TestCase): + """The file-index plugin re-derives staged documents' metadata from their + keys, so its copies of `KINDS` and `LANGS` must be the ones here.""" + + def test_kinds_match(self): + self.assertEqual(set(plugin_list("KINDS")), set(w.KINDS)) + + def test_langs_match(self): + self.assertEqual(set(plugin_list("LANGS")), set(w.LANGS)) diff --git a/scripts/wrfiles.py b/scripts/wrfiles.py index e0e9df1..1cbaa2f 100644 --- a/scripts/wrfiles.py +++ b/scripts/wrfiles.py @@ -16,13 +16,13 @@ # The six Docusaurus plugin instances. A key's first segment must be one of # these: it is structural, unlike the taxonomy below it (ADR 0001 D4). -SECTIONS = ("robot", "solution", "peripheral", "system", "tutorial", "support") +SECTIONS = ("robot", "solution", "peripheral", "system", "guides", "support") UPLOAD_DIR = "_upload" # Controlled vocabulary for the `` segment. Free text here is how a store # ends up holding cad, CAD, STP and STL for the same thing, at which point -# `` stops being usable and the Document column reads +# `` stops being usable and the File column reads # inconsistently. Derived from what the dead SharePoint links actually were. # # Extending it is a deliberate act, like CONTENT_TYPES: add the value here with diff --git a/sidebars-guides.ts b/sidebars-guides.ts index 978da35..226b350 100644 --- a/sidebars-guides.ts +++ b/sidebars-guides.ts @@ -7,12 +7,8 @@ const sidebarsGuides: SidebarsConfig = { type: 'category', label: 'Before You Operate', items: [ - // Each landing page carries what holds for every robot and routes to - // the pages below by a table. The per-type pages exist because the - // hazards and checks that come from having legs, wheels or a single - // arm differ enough that a humanoid owner reading UGV guidance is - // reading someone else's document. Same category shape as Manifold - // Scanner Guides: the landing page is the category's own doc. + // The landing page is the category's own doc, as in Manifold Scanner + // Guides. Why per-type pages: docs/design/ia-proposal.md §10. { type: 'category', label: 'Operational Safety', @@ -74,9 +70,7 @@ const sidebarsGuides: SidebarsConfig = { type: 'category', label: 'Manifold Scanner Guides', // The index is the category's own landing page, so clicking the category - // goes to the overview that explains where the workflow starts and stops - // instead of just expanding. Same shape as Robot Deployment Toolbox in - // sidebars-solution.ts. + // opens the overview instead of just expanding. link: {type: 'doc', id: 'manifold/index'}, // Ordered as the workflow runs: connect, capture, process. items: [ diff --git a/sidebars-solution.ts b/sidebars-solution.ts index c602562..853d72e 100644 --- a/sidebars-solution.ts +++ b/sidebars-solution.ts @@ -3,20 +3,8 @@ import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; const sidebarsSolution: SidebarsConfig = { solutionSidebar: [ 'intro', - // Ordered by the workflow, not by how often a page is opened: a Robot - // Platform is what a customer physically has, a site is mapped with the - // Robot Deployment Toolbox before anything can be run, and the Robot - // Management Toolbox is what it is run from afterwards. The overview - // page's cards are in the same order, so the sidebar and the page agree. - // - // Plural on purpose. The page presents a set — three supported bases and a - // comparison matrix — not one product, and the singular collides with the - // glossary's `Platform`, which means base + low-level hardware and so - // excludes the payload this page is mostly about. - // - // A category since 2026-09-11, when network configuration was added. The - // index stays the category's landing page, so the URL never moved — which - // is why the page was put in a directory on day one. + // Same order as the cards on solution/intro.md; change both together. + // Why this order: docs/design/release-pages-plan.md §2. { type: 'category', label: 'Robot Platforms', @@ -25,10 +13,8 @@ const sidebarsSolution: SidebarsConfig = { 'robot-platforms/network-configuration', ], }, - // - // Capturing the scan the deployment toolbox starts from is a scanner - // procedure rather than a solution (ADR 0002), so it is not listed here — - // Manifold Scanner Guides is linked from the deployment toolbox instead. + // Scan capture is a scanner procedure, so it is in Manifold Scanner Guides + // rather than here. See docs/adr/0002. { type: 'category', label: 'Robot Deployment Toolbox', @@ -58,13 +44,11 @@ const sidebarsSolution: SidebarsConfig = { 'robot-management-toolbox/deployment-and-servicing', ], }, - // The Assisted Driving Toolbox is retired and `unlisted`, so it is not - // listed here. Its URL stays alive because seven redirects from the old - // /software/toolbox/* paths point at it (§11) and those are in - // circulation with customers. - // navigation and industrial-patrolling are draft: true, so they are - // stripped from production builds and must not be listed here — a sidebar - // entry pointing at a draft document fails the build. + // solution/adt/intro is `unlisted`, so it is not listed here. Old + // /software/toolbox/* and /solution/adt/v1-v3 URLs redirect to it. + // + // navigation and industrial-patrolling are `draft: true`. A sidebar entry + // pointing at a draft document fails the production build. ], }; diff --git a/sidebars-system.ts b/sidebars-system.ts index e8938e9..d8d9462 100644 --- a/sidebars-system.ts +++ b/sidebars-system.ts @@ -10,9 +10,6 @@ const sidebarsSystem: SidebarsConfig = { // category goes somewhere useful instead of just expanding. link: {type: 'doc', id: 'ugv_devkit/index'}, items: [ - // Previously only the two version pages were listed, which left the - // guides below reachable only through inline links — and - // getting_started reachable from nowhere at all. 'ugv_devkit/v1/getting_started', 'ugv_devkit/component_reconfiguration', 'ugv_devkit/v1/nav2_sample_setup_guide', diff --git a/static/llms.txt b/static/llms.txt index bcafa29..70699eb 100644 --- a/static/llms.txt +++ b/static/llms.txt @@ -19,10 +19,10 @@ product page links its manufacturer's own documentation near the top. ## Guides -- [Operational Safety](https://docs.westonrobot.com/tutorial/operational-safety): read before first power-on; covers wheeled bases, quadrupeds, humanoids and manipulators -- [Robot Maintenance](https://docs.westonrobot.com/tutorial/robot-maintenance): routine checks, batteries, cleaning, storage -- [Weston Robot Apt Source](https://docs.westonrobot.com/tutorial/installation/apt_source): add before installing any of our packages -- [All guides](https://docs.westonrobot.com/tutorial/intro): setup, development and diagnostics, tagged by platform +- [Operational Safety](https://docs.westonrobot.com/guides/operational-safety): read before first power-on; covers wheeled bases, quadrupeds, humanoids and manipulators +- [Robot Maintenance](https://docs.westonrobot.com/guides/robot-maintenance): routine checks, batteries, cleaning, storage +- [Weston Robot Apt Source](https://docs.westonrobot.com/guides/installation/apt_source): add before installing any of our packages +- [All guides](https://docs.westonrobot.com/guides/intro): setup, development and diagnostics, tagged by platform ## Support