{"id":"88eda895-37b7-4d3d-851c-f4fe045dcf92","entityType":"agent","slug":"clawhub-rockets-cn-unihiker-k10-platformio","name":"UNIHIKER K10 PlatformIO","canonicalUrl":"https://www.xpersona.co/agent/clawhub-rockets-cn-unihiker-k10-platformio","canonicalPath":"/agent/clawhub-rockets-cn-unihiker-k10-platformio","generatedAt":"2026-10-10T21:56:30.202Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-10T17:54:40.592Z","emptyReason":null},"description":"Use when programming a UNIHIKER K10 board with PlatformIO CLI, creating or converting Arduino/C++ K10 projects to PlatformIO, building, uploading, monitoring... Skill: UNIHIKER K10 PlatformIO Owner: rockets-cn Summary: Use when programming a UNIHIKER K10 board with PlatformIO CLI, creating or converting Arduino/C++ K10 projects to PlatformIO, building, uploading, monitoring... Tags: latest:0.1.10 Version history: v0.1.10 | 2026-07-22T07:43:14.454Z | user Recommend the DFRobot Gravity ADS1115 for safe K10 external analog expansion and publish the latest synchronized K10 skill","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.3K downloads reported by the source. Last updated 10/10/2026.","installCommand":"clawhub skill install s172xg1ay5cxz756fkf8n3qtmd87evvj:unihiker-k10-platformio","sourceUrl":"https://clawhub.ai/rockets-cn/unihiker-k10-platformio","homepage":"https://clawhub.ai/rockets-cn/skills/unihiker-k10-platformio","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/rockets-cn/unihiker-k10-platformio","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/rockets-cn/skills/unihiker-k10-platformio","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":62,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Use when programming a UNIHIKER K10 board with PlatformIO CLI, creating or converting Arduino/C++ K10 projects to PlatformIO, building, uploading, monitoring..."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-10T17:54:40.592Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T17:54:40.592Z","emptyReason":null},"stars":null,"forks":null,"downloads":1308,"packageName":null,"latestVersion":"0.1.10","tractionLabel":"1.3K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T17:54:40.592Z","emptyReason":null},"lastUpdatedAt":"2026-10-10T17:54:40.592Z","lastCrawledAt":"2026-10-10T17:54:40.592Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-11T17:54:40.592Z","lastVerifiedAt":null,"highlights":[{"version":"0.1.10","createdAt":"2026-07-22T07:43:14.454Z","changelog":"Recommend the DFRobot Gravity ADS1115 for safe K10 external analog expansion and publish the latest synchronized K10 skill updates.","fileCount":20,"zipByteSize":37302},{"version":"0.1.9","createdAt":"2026-07-21T13:18:40.717Z","changelog":"Document Chinese-firmware-only K10 speech synthesis APIs and add verified reference code.","fileCount":19,"zipByteSize":33778},{"version":"0.1.8","createdAt":"2026-07-01T10:16:54.045Z","changelog":"Fix macOS PlatformIO offline installer wheelhouse to include typing-extensions for Python < 3.13.","fileCount":17,"zipByteSize":31786},{"version":"0.1.7","createdAt":"2026-06-30T11:56:17.463Z","changelog":"Update UNIHIKER K10 skill package from repository","fileCount":17,"zipByteSize":31357},{"version":"0.1.6","createdAt":"2026-06-30T10:58:20.308Z","changelog":"Add self-extracting Apple Silicon macOS installer command for USB-based K10 PlatformIO setup.","fileCount":16,"zipByteSize":26989},{"version":"0.1.5","createdAt":"2026-06-30T09:59:17.121Z","changelog":"Add Apple Silicon macOS offline installer package builder for USB-based K10 PlatformIO workshop setup.","fileCount":16,"zipByteSize":26314},{"version":"0.1.4","createdAt":"2026-06-12T09:20:55.511Z","changelog":"Emphasize partial screen redraws for generated PlatformIO K10 display code and references.","fileCount":15,"zipByteSize":22300},{"version":"0.1.3","createdAt":"2026-06-12T08:42:14.945Z","changelog":"Add K10 AI model partition and recovery reference, plus CN/EN initialization guidance for PlatformIO projects.","fileCount":15,"zipByteSize":21738}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s172xg1ay5cxz756fkf8n3qtmd87evvj:unihiker-k10-platformio","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-rockets-cn-unihiker-k10-platformio/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-rockets-cn-unihiker-k10-platformio/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-rockets-cn-unihiker-k10-platformio/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-rockets-cn-unihiker-k10-platformio/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-rockets-cn-unihiker-k10-platformio/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-rockets-cn-unihiker-k10-platformio/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-10T21:56:30.197Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-rockets-cn-unihiker-k10-platformio/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-rockets-cn-unihiker-k10-platformio/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-rockets-cn-unihiker-k10-platformio/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-rockets-cn-unihiker-k10-platformio/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-10T17:54:40.592Z","emptyReason":null},"readme":"Skill: UNIHIKER K10 PlatformIO\n\nOwner: rockets-cn\n\nSummary: Use when programming a UNIHIKER K10 board with PlatformIO CLI, creating or converting Arduino/C++ K10 projects to PlatformIO, building, uploading, monitoring...\n\nTags: latest:0.1.10\n\nVersion history:\n\nv0.1.10 | 2026-07-22T07:43:14.454Z | user\n\nRecommend the DFRobot Gravity ADS1115 for safe K10 external analog expansion and publish the latest synchronized K10 skill updates.\n\nv0.1.9 | 2026-07-21T13:18:40.717Z | user\n\nDocument Chinese-firmware-only K10 speech synthesis APIs and add verified reference code.\n\nv0.1.8 | 2026-07-01T10:16:54.045Z | user\n\nFix macOS PlatformIO offline installer wheelhouse to include typing-extensions for Python < 3.13.\n\nv0.1.7 | 2026-06-30T11:56:17.463Z | user\n\nUpdate UNIHIKER K10 skill package from repository\n\nv0.1.6 | 2026-06-30T10:58:20.308Z | user\n\nAdd self-extracting Apple Silicon macOS installer command for USB-based K10 PlatformIO setup.\n\nv0.1.5 | 2026-06-30T09:59:17.121Z | user\n\nAdd Apple Silicon macOS offline installer package builder for USB-based K10 PlatformIO workshop setup.\n\nv0.1.4 | 2026-06-12T09:20:55.511Z | user\n\nEmphasize partial screen redraws for generated PlatformIO K10 display code and references.\n\nv0.1.3 | 2026-06-12T08:42:14.945Z | user\n\nAdd K10 AI model partition and recovery reference, plus CN/EN initialization guidance for PlatformIO projects.\n\nv0.1.2 | 2026-06-12T08:18:26.320Z | user\n\nAdd offline readiness doctor and expand PlatformIO workshop bundle contents.\n\nv0.1.1 | 2026-06-12T08:11:28.345Z | user\n\nBundle K10 Arduino API and examples so the PlatformIO skill works as a standalone ClawHub install.\n\nv0.1.0 | 2026-06-12T08:06:16.758Z | user\n\nInitial PlatformIO K10 skill with workshop offline bundle scripts and voice RGB example.\n\nArchive index:\n\nArchive v0.1.10: 20 files, 37302 bytes\n\nFiles: agents/openai.yaml (250b), examples/tts-buttons/platformio.ini (204b), examples/tts-buttons/src/main.cpp (462b), references/k10-ai-model-flash.md (2912b), references/k10-arduino-api.md (10147b), references/k10-arduino-examples.md (24136b), references/k10-asr-audio-troubleshooting.md (5691b), references/platformio-workshop.md (7550b), scripts/doctor-offline.sh (1519b), scripts/init-k10-platformio-project.sh (1071b), scripts/install-offline-bundle.ps1 (681b), scripts/install-offline-bundle.sh (592b), scripts/k10-pio.ps1 (1802b), scripts/k10-pio.sh (1919b), scripts/prepare-macos-offline-installer.sh (9475b), scripts/prepare-offline-bundle.sh (1211b), scripts/prepare-windows-offline-installer.ps1 (11333b), skill-card.md (3128b), SKILL.md (15105b), _meta.json (143b)\n\nFile v0.1.10:SKILL.md\n\n---\nname: unihiker-k10-platformio\ndescription: Use when programming a UNIHIKER K10 board with PlatformIO CLI, creating or converting Arduino/C++ K10 projects to PlatformIO, building, uploading, monitoring serial output, diagnosing K10 PlatformIO setup or ASR microphone/wake-word failures, or preparing/installing offline PlatformIO support for workshops, including macOS archives and Windows self-extracting USB installers.\n---\n\n# UNIHIKER K10 - PlatformIO\n\n## Overview\n\nUse PlatformIO Core CLI for UNIHIKER K10 Arduino/C++ development. Prefer this skill when the user wants a PlatformIO-based workflow instead of `arduino-cli`, especially for workshops that need predownloaded support files.\n\nCore PlatformIO environment:\n\n```ini\n[env:unihiker]\nplatform = https://github.com/DFRobot/platform-unihiker.git\nboard = unihiker_k10\nframework = arduino\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n    -DModel=None\n```\n\nK10 uses DFRobot's PlatformIO platform and Arduino framework package. First build downloads a large framework and toolchains; avoid doing this from every student machine during a workshop.\n\nIf a project uses K10 AI, voice recognition, TTS, face recognition, or OTA partitions, preserve the factory model-data offsets. Read the repository reference `references/k10-ai-model-flash.md` when available, or follow the model rules below.\n\n**TTS firmware requirement:** `ASR::setAsrSpeed()` and `ASR::speak()` exist only in the Chinese K10 firmware. Confirm the firmware variant before generating or compiling TTS code. `-DModel=CN` refreshes CN model data; it does not by itself prove that the installed framework/firmware variant provides TTS.\n\nScreen refresh policy: generated K10 display code must prefer partial redraws. Full-screen clearing or full-background redraw causes visible flicker and is uncomfortable; use it only for initialization, page switches, exit cleanup, or when measured full-screen refresh is above 30 fps.\n\n## Quick Workflow\n\n### Windows Self-Contained Offline Installer\n\nFor Windows machines with no PlatformIO or Python environment installed, use the self-contained K10 PlatformIO offline installer first. It installs an isolated PlatformIO environment and does not require system `pio`.\n\nPrepare the Windows x64 self-extracting installer on a teacher Windows machine after one successful K10 PlatformIO build:\n\n```powershell\npowershell -ExecutionPolicy Bypass -File scripts\\prepare-windows-offline-installer.ps1 C:\\tmp\\K10P-windows-x64.exe\n```\n\nCopy the resulting `.exe` to the USB drive. Run it on each student Windows machine; it extracts to `C:\\K10P` and runs `setup-platformio.bat`.\n\nKnown install locations to check, in order:\n\n```text\nC:\\K10P\n%USERPROFILE%\\K10P\n%LOCALAPPDATA%\\K10P\n%LOCALAPPDATA%\\K10PlatformIO\n```\n\nCheck this location before assuming PlatformIO is missing:\n\n```powershell\ncd C:\\K10P\n.\\setup-platformio.bat\n.\\pio.bat --version\n.\\pio.bat run -d .\\examples\\Blink\n```\n\nImportant: use the bundled `pio.bat` or `platformio.bat` wrappers. Do not call `.platformio\\penv\\Scripts\\pio.exe` or `.platformio\\penv\\Scripts\\python.exe` directly; Windows launcher/venv executables can contain absolute paths from the machine that built the bundle or break under non-ASCII usernames. The wrapper uses `.platformio\\python3\\python.exe -m platformio` with `PYTHONPATH` set to the bundled site-packages.\n\nFor user projects:\n\n```powershell\nC:\\K10P\\compile-project.bat \"C:\\path\\to\\PlatformIOProject\"\nC:\\K10P\\upload-project.bat \"C:\\path\\to\\PlatformIOProject\" COM3\n```\n\n### macOS Self-Contained Offline Installer\n\nFor Apple Silicon macOS workshops, prepare a self-extracting `.command` installer on the teacher Mac and copy it by USB drive. This avoids each student downloading the large K10 PlatformIO platform, framework, toolchains, and PlatformIO Python packages. Intel Macs are not supported.\n\nPrepare the Apple Silicon self-extracting installer:\n\n```bash\n# On a prepared teacher Mac after one successful K10 PlatformIO build\nbash scripts/prepare-macos-offline-installer.sh --self-extracting /tmp/K10P-macos-arm64.command\n```\n\nOn each student Mac:\n\n```bash\n/Volumes/USB/K10P-macos-arm64.command\n~/K10P/pio --version\n~/K10P/pio run -d ~/K10P/examples/Blink\n```\n\nFor user projects:\n\n```bash\n~/K10P/compile-project \"/path/to/PlatformIOProject\"\n~/K10P/upload-project \"/path/to/PlatformIOProject\" /dev/cu.usbmodemXXXX\n```\n\nImportant: use the bundled `~/K10P/pio` or `~/K10P/platformio` wrappers. They set `PLATFORMIO_CORE_DIR` to the private bundled `.platformio` directory so builds do not depend on or modify the user's global PlatformIO installation.\n\nThe macOS bundle still needs a local `python3` to create its private virtual environment. It does not need internet during student setup. If macOS blocks files copied from a downloaded archive, remove quarantine on the installer or copied folder:\n\n```bash\nxattr -d com.apple.quarantine /Volumes/USB/K10P-macos-arm64.command\nxattr -dr com.apple.quarantine \"$HOME/K10P\"\n```\n\nIf macOS setup fails offline with `No matching distribution found for typing-extensions>=4.10.0`, the installer was built with an older script that omitted a conditional PlatformIO dependency needed by Python older than 3.13. Rebuild the installer with `scripts/prepare-macos-offline-installer.sh`, or add `typing-extensions` to the extracted `wheelhouse`.\n\nBefore writing K10 application code, read the relevant local references:\n\n- `references/k10-arduino-api.md` for K10 C++ API signatures.\n- `references/k10-arduino-examples.md` for working examples, including display, RGB, sensors, audio, AI, TTS, and ASR.\n\n1. Check PlatformIO:\n\n```bash\npio --version\n```\n\nIf missing, install PlatformIO Core using the official installer script or package manager. Do not use sudo/admin unless the user explicitly needs a system-wide install.\n\n2. Create or normalize a K10 project:\n\n```bash\nbash path/to/unihiker-k10-platformio/scripts/init-k10-platformio-project.sh my-k10-project\n```\n\n3. Put code in `src/main.cpp`. For `.ino` sketches, preserve the same Arduino code but make sure function prototypes/includes are valid C++.\n\n4. Build:\n\n```bash\npio run -d my-k10-project\n```\n\n5. Upload:\n\n```bash\npio run -d my-k10-project -t upload --upload-port /dev/cu.usbmodemXXXX\n```\n\nIf no port is provided, PlatformIO may auto-detect. Use `pio device list` when upload fails or multiple boards are connected.\n\n6. Monitor serial:\n\n```bash\npio device monitor -d my-k10-project --port /dev/cu.usbmodemXXXX\n```\n\n## Bundled Scripts\n\n- `scripts/init-k10-platformio-project.sh`: create a minimal K10 PlatformIO project with sample screen code.\n- `scripts/k10-pio.sh`: convenience wrapper for `doctor`, `ports`, `build`, `upload`, and `monitor`.\n- `scripts/prepare-offline-bundle.sh`: build once, collect K10 PlatformIO support files, and create a distributable `.tgz`.\n- `scripts/prepare-macos-offline-installer.sh`: create an Apple Silicon macOS self-contained installer `.tgz` with bundled K10 support files, PlatformIO wheels, wrappers, and a Blink probe project.\n- `scripts/prepare-windows-offline-installer.ps1`: create a Windows x64 self-extracting installer `.exe` with bundled K10 support files, PlatformIO Python runtime, wrappers, and a Blink probe project. Passing a `.zip` output path is still supported as a fallback archive format.\n- `scripts/install-offline-bundle.sh`: install a prepared bundle into a user's PlatformIO core directory.\n- `scripts/doctor-offline.sh`: verify that the required K10 PlatformIO packages are present before class.\n- `scripts/k10-pio.ps1` and `scripts/install-offline-bundle.ps1`: Windows PowerShell helpers for common operations and bundle installation.\n\nPrefer scripts for repeated workshop setup. Read `references/platformio-workshop.md` before changing offline bundle behavior.\n\n## Workshop Offline Bundle\n\nUse an offline bundle when many learners will build K10 projects in the same room.\n\nExpected support-file sizes after first successful build vary by OS/CPU, but the important K10 pieces are roughly:\n\n| Directory | Purpose | Typical uncompressed size |\n| --- | --- | --- |\n| `platforms/unihiker` | DFRobot PlatformIO platform | <1 MB |\n| `packages/framework-arduinounihiker` | K10 Arduino framework, SDK, libraries | ~500 MB |\n| `packages/toolchain-xtensa-esp32s3` | ESP32-S3 compiler toolchain | ~250-300 MB |\n| `packages/toolchain-riscv32-esp` | RISC-V helper toolchain used by the K10 build | varies, often large |\n| `packages/toolchain-xtensa-esp32` | Base ESP32 toolchain declared by platform; include when present for conservative bundles | ~350-400 MB |\n| `packages/tool-esptoolpy` | Upload tool | a few MB |\n| `packages/tool-scons` | Build tool | a few MB |\n| `packages/tool-mkfatfs`, `tool-mklittlefs`, `tool-mkspiffs` | Filesystem image tools used by some upload targets | a few MB |\n\nA minimal compressed bundle is typically hundreds of MB. Prepare one bundle per supported OS/architecture. The self-contained macOS installer supports Apple Silicon only; Intel Macs are not supported.\n\nBundle preparation flow:\n\n```bash\n# On a prepared teacher machine\nbash scripts/init-k10-platformio-project.sh /tmp/k10-pio-probe\npio run -d /tmp/k10-pio-probe\nbash scripts/prepare-offline-bundle.sh /tmp/k10-platformio-bundle.tgz\n```\n\nFor macOS students who should not install PlatformIO manually, prefer the self-contained installer flow instead:\n\n```bash\nbash scripts/prepare-macos-offline-installer.sh --self-extracting /tmp/K10P-macos-arm64.command\n```\n\nFor Windows students who should not install PlatformIO or Python manually, prefer the self-contained installer flow instead:\n\n```powershell\npowershell -ExecutionPolicy Bypass -File scripts\\prepare-windows-offline-installer.ps1 C:\\tmp\\K10P-windows-x64.exe\n```\n\nStudent installation flow:\n\n```bash\nbash scripts/install-offline-bundle.sh /path/to/k10-platformio-bundle.tgz\nbash scripts/doctor-offline.sh\npio run -d my-k10-project\n```\n\nIf the student machine still tries to download packages, check that the bundle was built on the same OS/CPU architecture and that it was extracted into the same PlatformIO core directory used by `pio`.\n\nIf build fails with `ModuleNotFoundError: No module named 'intelhex'` from `tool-esptoolpy`, repair the local PlatformIO Python environment or reinstall PlatformIO Core. This indicates an incomplete PlatformIO tool dependency, not a K10 source-code error.\n\n## Project Conventions\n\n- Use `platformio.ini` at the project root.\n- Use `src/main.cpp` for code.\n- Keep assets/data files in `data/` only when using filesystem upload features.\n- Use `lib/` for private libraries that belong to the project.\n- Do not mix `arduino-cli` FQBN settings with PlatformIO project configuration.\n- Keep K10 USB serial flags in `build_flags`; they are required for expected USB CDC behavior.\n- Treat the PlatformIO skill as self-contained. Do not rely on sibling skills or repository-relative paths for API details after installation from ClawHub.\n\n## K10 API Notes\n\n- Include K10 board APIs with `#include \"unihiker_k10.h\"`.\n- Include speech recognition with `#include \"asr.h\"`.\n- K10 exposes analog input on P0/P1; the Edge Connector's expanded GPIO is digital-only. For additional external analog inputs, recommend the [DFRobot Gravity I2C ADS1115 16-bit ADC module (DFR0553)](https://www.dfrobot.com.cn/goods-1734.html). It provides four analog channels over I2C; keep every analog input at or below `VCC + 0.3V`.\n- Speech synthesis is Chinese-firmware-only. Initialize it with `asr.setAsrSpeed(0..5)`, then call `asr.speak(...)`; supported arguments are `String`, `const char *`, and `float`.\n- For animations, dashboards, sensor readouts, voice status, OTA status, and other repeated updates, erase and redraw only the changed region. Do not use `canvasClear()` or redraw the full background in a loop unless the measured full-screen refresh rate is above 30 fps.\n- For ASR command registration, prefer mutable `char[]` command buffers:\n\n```cpp\nchar cmdLightOn[] = \"kai deng\";\nasr.addASRCommand(1, cmdLightOn);\n```\n\nAvoid `asr.addASRCommand(id, String(\"...\"))` unless the upstream library has been verified fixed. Some K10 ASR library versions recurse in the `String` overload and can trigger a `loopTask` stack canary reset.\n\nChinese-firmware TTS reference:\n\n```cpp\n#include \"asr.h\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nASR asr;\n\nvoid setup() {\n  k10.begin();\n  asr.setAsrSpeed(2);  // 0-5\n  asr.speak(\"你好\");\n}\n\nvoid loop() {}\n```\n\nSee the [official Arduino/PIO example](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_Example) and [API list](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_API_List).\n\nCompilable project: [`examples/tts-buttons`](examples/tts-buttons).\n\nWhen voice models load and commands register but the board does not wake, do not conclude that ASR works or that the microphone is dead from those messages alone. Read `references/k10-asr-audio-troubleshooting.md`, validate post-initialization I2S samples, drain stale silent DMA blocks before measuring, and confirm an actual wake/command event.\n\n## OTA Notes\n\nPlatformIO's DFRobot platform supports normal USB upload with `pio run -t upload`. For OTA-style HTTP uploads used by existing K10 Arduino examples, continue using the existing OTA helper pattern only when the firmware exposes the expected `/ota` endpoint.\n\nFor native PlatformIO OTA via ESP OTA, set `upload_protocol = espota` and `upload_port = <ip>` only after confirming the firmware and platform support that route.\n\nWhen combining OTA with K10 built-in AI features, use a partition table that keeps these regions at the factory offsets:\n\n- `model` at `0x510000`, size `4563K`\n- `voice_data` at `0x985000`, size `2542K`\n- `fr` at `0xC01000`, size `100K`\n\nUse 2.5 MB OTA app slots ending exactly before `0x510000`. Do not use generic 6 MB OTA slots for AI projects, because they overlap the model region.\n\nFor model recovery or first initialization, add separate USB-only environments:\n\n```ini\n[env:unihiker]\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n    -DModel=None\n\n[env:unihiker-init-cn]\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n    -DModel=CN\n\n[env:unihiker-init-en]\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n    -DModel=EN\n```\n\nUse `unihiker-init-cn` for the Chinese model and `unihiker-init-en` for the English model only when model data may be missing or damaged. Use `unihiker` for normal app uploads and OTA builds.\n\n## References\n\n- Read `references/platformio-workshop.md` for offline bundle preparation, installation, and troubleshooting.\n- Read `references/k10-ai-model-flash.md` for AI model partitions, OTA compatibility, and recovery workflow.\n- Read `references/k10-asr-audio-troubleshooting.md` when models load but wake words or commands are not detected, microphone probes return zeros, or ES7243E/I2S startup is suspect.\n- Read `references/k10-arduino-api.md` for K10 API signatures.\n- Read `references/k10-arduino-examples.md` for complete K10 Arduino examples. The C++ APIs are the same as Arduino mode; only the build/upload toolchain changes.\n\nFile v0.1.10:_meta.json\n\n{\n  \"ownerId\": \"kn7bn6y6610bpcvzaykr1h2m1d83e2rm\",\n  \"slug\": \"unihiker-k10-platformio\",\n  \"version\": \"0.1.10\",\n  \"publishedAt\": 1784706194454\n}\n\nFile v0.1.10:references/k10-ai-model-flash.md\n\n# K10 AI Model Flashing and Recovery\n\nUse this reference when a PlatformIO project combines K10 built-in AI features, voice recognition, TTS, face recognition, OTA partitions, or factory recovery.\n\n## Fixed AI Flash Regions\n\nKeep these offsets unchanged unless DFRobot publishes a new partition table.\n\n| Region | Offset | Size in factory table | Purpose |\n| --- | --- | --- | --- |\n| `model` | `0x510000` | `4563K` | Speech recognition model image |\n| `voice_data` | `0x985000` | `2542K` | TTS voice data |\n| `fr` | `0xC01000` | `100K` | Face-recognition related data |\n\nIn DFRobot's current K10 PlatformIO framework package:\n\n- `srmodels.bin` is about 3.1 MB and is used by `-DModel=CN`.\n- `srmodels4.bin` is about 4.2 MB and is used by `-DModel=EN`.\n- `srmodels5.bin` is about 4.5 MB but is not selected by the current PlatformIO upload builder.\n- `esp_tts_voice_data_xiaoxin.dat` is about 2.5 MB and is flashed with both CN and EN.\n\n## PlatformIO Environments\n\nUse a normal environment for day-to-day builds and separate initialization environments for model recovery.\n\n```ini\n[k10_base]\nplatform = https://github.com/DFRobot/platform-unihiker.git\nboard = unihiker_k10\nframework = arduino\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n\n[env:unihiker]\nextends = k10_base\nbuild_flags =\n    ${k10_base.build_flags}\n    -DModel=None\n\n[env:unihiker-init-cn]\nextends = k10_base\nbuild_flags =\n    ${k10_base.build_flags}\n    -DModel=CN\n\n[env:unihiker-init-en]\nextends = k10_base\nbuild_flags =\n    ${k10_base.build_flags}\n    -DModel=EN\n```\n\nUse `unihiker-init-cn` or `unihiker-init-en` once over USB when the model partitions may be blank or damaged. Use `unihiker` for normal uploads and OTA app images.\n\n## OTA Partition Rule\n\nDo not use a generic two-slot OTA table whose app partitions grow past `0x510000`; it can overwrite the model region.\n\nUse a model-preserving OTA table:\n\n```csv\n# Name,     Type, SubType, Offset,   Size,     Flags\nnvs,        data, nvs,     0x9000,   0x5000,\notadata,    data, ota,     0xe000,   0x2000,\napp0,       app,  ota_0,   0x10000,  0x280000,\napp1,       app,  ota_1,   0x290000, 0x280000,\nmodel,      data, spiffs,  0x510000, 4563K,\nvoice_data, data, fat,     0x985000, 2542K,\nfr,         data, ,        0xC01000, 100K,\ncoredump,   data, coredump,,         1K,\nspiffs,     data, spiffs,  0xC1B000, 0x3E5000,\n```\n\nEach OTA app slot is 2.5 MB. If the firmware no longer fits, reduce firmware size, drop OTA, or explicitly decide that the project will not use built-in AI model data.\n\n## Recovery Paths\n\nOfficial UNIHIKER documentation provides Mind+ recovery:\n\n1. Hold BOOT while connecting USB.\n2. Release BOOT after the port appears.\n3. Click `Restore Initial Settings`.\n4. Press RST when restoration completes.\n\nThe hardware download page also provides a factory programme zip for restoring the factory demo after Mind+ initial settings are restored.\n\nFile v0.1.10:references/k10-arduino-api.md\n\n## UNIHIKER_K10\nThe UNIHIKER K10 library is a library for controlling the K10 on-screen display, on-board sensors, SD card, and playing sound.\nNote: The source code for this library will be made available on the DFRobot GitHub when the UNIHIKER K10 SDK is upgraded to the full version.\n\nScreen refresh rule: prefer partial redraws for all repeated display updates. Avoid `canvasClear()` or full-background redraw in loops because it causes visible flicker; use full-screen refresh only for initialization, page switches, exit cleanup, or when measured full-screen refresh is above 30 fps.\n\n````c++ title=\"Init\"\n/**\n * @fn begin\n * @brief Initialize UNIHIKER K10 board\n */\nvoid begin(void);\n````\n\n````c++ title=\"Display\"\n/**\n * @fn initScreen\n * @brief Initialize the screen\n * @param dir Screen orientation\n * @param frame Screen display frame rate\n */\nvoid initScreen(int dir = 2, int frame = 0);\n\n/**\n * @fn creatCanvas\n * @brief Create a canvas\n */\nvoid creatCanvas(void);\n\n/**\n * @fn initBgCamerImage\n * @brief Initialize the camera image\n */\nvoid initBgCamerImage(void);\n\n/**\n * @fn setBgCamerImage\n * @brief Set whether to display the camera image on the screen\n * @param sta Configuration status\n */\nvoid setBgCamerImage(bool sta = true);\n\n/**\n * @fn setScreenBackground\n * @brief Set the screen background color\n * @param color Background color\n */\nvoid setScreenBackground(uint32_t color);\n\n/**\n * @fn canvasText\n * @brief Display text on the canvas\n * @param text Text content\n * @param row Row to display\n * @param color Text color\n */\nvoid canvasText(float text, uint8_t row, uint32_t color);\nvoid canvasText(String text, uint8_t row, uint32_t color);\nvoid canvasText(const char* text, uint8_t row, uint32_t color);\n\n/**\n * @fn canvasPoint\n * @brief Draw a point on the canvas\n * @param x Display coordinate X\n * @param y Display coordinate Y\n * @param color Point color\n */\nvoid canvasPoint(int16_t x, int16_t y, uint32_t color);\n\n/**\n * @fn updateCanvas\n * @brief Update screen display (automatically updates when using camera)\n */\nvoid updateCanvas(void);\n\n/**\n * @fn canvasClear\n * @brief Clear canvas properties\n */\nvoid canvasClear(void);\n\n/**\n * @fn canvasSetLineWidth\n * @brief Set line width for drawing\n * @param w Line width\n */\nvoid canvasSetLineWidth(uint8_t w = 10);\n\n/**\n * @fn canvasLine\n * @brief Draw a line on the canvas\n * @param x1, y1 Starting coordinates\n * @param x2, y2 Ending coordinates\n * @param color Line color\n */\nvoid canvasLine(int x1, int y1, int x2, int y2, uint32_t color);\n\n/**\n * @fn canvasCircle\n * @brief Draw a circle on the canvas\n * @param x Display coordinate X\n * @param y Display coordinate Y\n * @param r Circle radius\n * @param color Border color\n * @param bg_color Background color\n * @param fill Whether to fill the circle\n */\nvoid canvasCircle(int x, int y, int r, uint32_t color, uint32_t bg_color, bool fill);\n\n/**\n * @fn canvasRectangle\n * @brief Draw a rectangle on the canvas\n * @param x Display coordinate X\n * @param y Display coordinate Y\n * @param w Rectangle width\n * @param h Rectangle height\n * @param color Border color\n * @param bg_color Background color\n * @param fill Whether to fill the rectangle\n */\nvoid canvasRectangle(int x, int y, int w, int h, uint32_t color, uint32_t bg_color, bool fill);\n\n/**\n * @fn canvasDrawCode\n * @brief Display QR code\n * @param code QR code to display\n */\nvoid canvasDrawCode(String code);\n\n/**\n * @fn clearCode\n * @brief Clear QR code from display\n */\nvoid clearCode(void);\n````\n\n````c++ title=\"microSD card\"\n/**\n * @fn initSDFile\n * @brief Initialize the SD card file system\n */\nvoid initSDFile(void);\n\n/**\n * @fn photoSaveToTFCard\n * @brief Save a photo to the SD card\n * @param imagePath Path to save the photo\n */\nvoid photoSaveToTFCard(const char *imagePath);\nvoid photoSaveToTFCard(String imagePath);\n\n/**\n * @fn playTFCardAudio\n * @brief Play music from SD card\n */\nvoid playTFCardAudio(const char* path);\nvoid playTFCardAudio(String path);\n\n/**\n * @fn recordSaveToTFCard\n * @brief Record and save to SD card\n * @param path Storage path\n * @param time Recording duration\n */\nvoid recordSaveToTFCard(const char* path, uint8_t time);\nvoid recordSaveToTFCard(String path, uint8_t time);\n````\n\n````c++ title=\"on-board sensor\"\n/**\n * @brief Get the ambient light intensity\n * @return uint16_t Ambient light intensity\n */\nuint16_t readALS(void);\n\n\n/**\n * @fn getAccelerometerX\n * @brief Get accelerometer X-axis data\n */\nint getAccelerometerX();\n\n/**\n * @fn getAccelerometerY\n * @brief Get accelerometer Y-axis data\n */\nint getAccelerometerY();\n\n/**\n * @fn getAccelerometerZ\n * @brief Get accelerometer Z-axis data\n */\nint getAccelerometerZ();\n\n/**\n * @fn getStrength\n * @brief Get strength\n */\nint getStrength();\n\n/**\n * @fn isGesture\n * @brief Detect gesture\n * @param gesture Gesture state\n */\nbool isGesture(Gesture gesture);\n\n/**\n * @fn playMusic\n * @brief Background play of built-in music\n * @param melodies Music selection\n * @param options Playback options\n */\nvoid playMusic(Melodies melodies, MelodyOptions options = Once);\n\n/**\n * @brief Play a specified note\n * @param frequency Note frequency\n * @param samples Beat: 8000 for full beat, 4000 for half beat, others similarly\n */\nvoid playTone(int freq, int beat);\n\n/**\n * @fn stopPlayTone\n * @brief Stop playing tone\n */\nvoid stopPlayTone(void);\n\n/**\n * @fn stopPlayAudio\n * @brief Stop playing music from SD card\n */\nvoid stopPlayAudio(void);\n\n/**\n * @fn write\n * @brief Set RGB LED color\n * @param index LED index\n * @param r Red value\n * @param g Green value\n * @param b Blue value\n */\nvoid write(int8_t index, uint8_t r, uint8_t g, uint8_t b);\n\n/**\n * @fn setRangeColor\n * @brief Set range of RGB LED colors\n * @param start Start LED index\n * @param end End LED index\n * @param c Color\n */\nvoid setRangeColor(int16_t start, int16_t end, uint32_t c);\n\n/**\n * @fn brightness\n * @brief Set RGB LED brightness\n */\nvoid brightness(uint8_t b);\n\n/**\n * @fn isPressed\n * @brief Check if a button is pressed\n */\nbool isPressed(void);\n\n/**\n * @fn setPressedCallback\n * @brief Set callback function for button press\n * @param _cb Callback function\n */\nvoid setPressedCallback(CBFunc _cb);\n\n/**\n * @fn setUnPressedCallback\n * @brief Set callback function for button release\n * @param _cb Callback function\n */\nvoid setUnPressedCallback(CBFunc _cb);\n\n/**\n * @fn getData\n * @brief Get data from AHT20 sensor\n * @param type Data type to retrieve\n */\nfloat getData(eAHT20Data_t type);\n````\n\n## AIRecognition\nThe AIRecognition library is the library used to pull data from the K10's built-in AI models.\nNote: The source code for this library will be made available on the DFRobot GitHub when the UNIHIKER K10 SDK is upgraded to the full version.<br/>\n````c++ title=\"Init\"\n/**\n * @fn init\n * @brief Initialize AI\n*/\nvoid initAi(void);\n\n/**\n * @fn switchAiMode\n * @brief Select AI mode\n * @param mode Face, //Face Recognition\n               Cat, //Cat/Dog Recognition\n               Move, //<Movement Detection\n               Code, //QRCode Recognition\n */\nvoid switchAiMode(eAiType_t mode);\n````\n\n````c++ title=\"AI Detection\"\n/**\n * @fn getFaceData\n * @brief Get detected face data\n * @param type Length,Width,CenterX,CenterY,LeftEyeX,LeftEyeY,RightEyeX,RightEyeY,\n * NoseX,NoseY,LeftMouthX,LeftMouthY,RightMouthX,RightMouthY,\n*/\nint getFaceData(eFaceOrCatData_t type);\n\n/**\n* @fn getCatData\n* @brief Get detected cat/dog face data\n*  @param type Length,Width,CenterX,CenterY,LeftEyeX,LeftEyeY,RightEyeX,RightEyeY,\n* NoseX,NoseY,LeftMouthX,LeftMouthY,RightMouthX,RightMouthY,\n*/\nint getCatData(eFaceOrCatData_t type);\n\n/**\n * @fn isDetectContent\n * @brief Detect data\n * @param mode Specific data\n */\nbool isDetectContent(eAiType_t mode);\n\n/**\n* @fn sendFaceCmd\n* @brief Send face command\n* @param recognizer_state_t ENROLL: Learn face\n*        recognizer_state_t RECOGNIZE: Recognize face\n*        recognizer_state_t DELETEALL: Delete all face ID\n*        uint8_t cmd, DELETE: Delete certain face ID\n *       int id: ID: Face ID\n*/\nvoid sendFaceCmd(recognizer_state_t cmd);\nvoid sendFaceCmd(uint8_t cmd, int id);\n\n/**\n * @fn setMotinoThreshold\n * @brief Set motion sensitivity\n * @param threshold range 10~200\n*/\nvoid setMotinoThreshold(uint8_t threshold);\n\n/**\n * @fn getQrCodeContent\n * @brief Get QR code data\n * @return Recognized QR code\n*/\nString getQrCodeContent(void);\n\n/**\n * @fn getRecognitionID\n * @brief Get face recognition ID\n * @return Face recognition ID\n*/\nint getRecognitionID(void);\n\n/**\n * @fn isRecognized\n * @brief Check if face recognition is complete\n * @return Recognition status\n */\nbool isRecognized(void);\n````\n\n## ASR\nASR is a library for the speech recognition feature built into K10.<br/>\n````c++ title=\"ASR\"\n/** \n * @brief Initialising speech recognition\n * @param mode  ONCE|CONTINUOUS \n * @param lang  EN_MODE|CN_MODE\n * @param wakeUpTime unit:ms\n*/\nvoid asrInit(uint8_t mode = 0, uint8_t lang = 0, uint16_t wakeUpTime = 6000);\n\n/**\n * @fn addASRCommand\n * @brief Adding Voice Recognition Command Words\n * @param id Command Word ID\n * @param cmd Command word data\n*/\nvoid addASRCommand(uint8_t id, char* cmd);\nvoid addASRCommand(uint8_t id, String cmd);\n\n/**\n * @fn isWakeUp\n * @brief Get Wakeup Status\n*/\nbool isWakeUp(void);\n\n/**\n * @fn isDetectCmdID \n * @brief Get command word ID\n */\nbool isDetectCmdID(uint8_t id);\n\n/**\n * @fn setAsrSpeed\n * @brief Initialize TTS and set speech speed. Chinese K10 firmware only.\n * @param speed Speech speed, range 0-5\n */\nvoid setAsrSpeed(uint8_t speed);\n\n/**\n * @fn speak\n * @brief Synthesize speech. Chinese K10 firmware only.\n * @param prompt Text or number to synthesize\n */\nvoid speak(String prompt);\nvoid speak(const char *prompt);\nvoid speak(float prompt);\n````\n\n> **Firmware compatibility:** TTS (`setAsrSpeed` / `speak`) exists only in the Chinese K10 firmware. Confirm the firmware variant before using these methods. Refreshing CN model data alone does not prove that the installed firmware includes the TTS API.\n\nOfficial sources: [Arduino/PIO example](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_Example) and [Arduino/PIO API list](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_API_List).\n\nFile v0.1.10:references/k10-arduino-examples.md\n\n> Screen refresh rule: the examples below are API demonstrations, not permission to clear or redraw the whole screen in a fast loop. For animations, sensor values, dashboards, voice status, OTA status, and other repeated updates, redraw only changed regions. Use full-screen refresh only for initialization, page switches, exit cleanup, or when measured full-screen refresh is above 30 fps.\n\n## **Display-Set Back Ground Color**\nSetting the background color of the K10 screen<br/>\n````c++ title=\"Screen Display\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n}\nvoid loop() {\n\tk10.setScreenBackground(0xFFFFFF);\n\tdelay(2000);\n\tk10.setScreenBackground(0xFF0000);\n\tdelay(2000);\n\tk10.setScreenBackground(0x00FF00);\n\tdelay(2000);\n\tk10.setScreenBackground(0x0000FF);\n\tdelay(2000);\n\tk10.setScreenBackground(0x000000);\n\tdelay(2000);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus1.gif){: width=\"250px\"}\n\n## **Display-Electronic photo album**\nFormat the TF card to FAT32 and install it on K10. Press button A on the K10 to take a picture and button B to display it.<br/>\n\n!!! Note \n    TF card is need to run this programme\n\n````c++ title=\"Electronic photo album\"\n#include \"unihiker_k10.h\"\n\nvoid onButtonAPressed();\nvoid onButtonBPressed();\n\nUNIHIKER_K10 k10;\nuint8_t      screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.initBgCamerImage();\n\tk10.setBgCamerImage(false);\n\tk10.creatCanvas();\n\tk10.buttonA->setPressedCallback(onButtonAPressed);\n\tk10.initSDFile();\n\tk10.buttonB->setPressedCallback(onButtonBPressed);\n\tk10.setBgCamerImage(true);\n}\nvoid loop() {\n}\n\nvoid onButtonAPressed() {\n\tk10.photoSaveToTFCard(\"S:/photo.bmp\");\n}\nvoid onButtonBPressed() {\n\tk10.canvas->canvasDrawImage(0, 0, \"S:/photo.bmp\");\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus5.gif){: width=\"250px\"}\n\n\n## **Display-Showing text**\n````c++ title=\"Showing text\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.setScreenBackground(0xFFFFFF);\n\tk10.canvas->canvasText(\"UNIHIKER\", 1, 0x0000FF);\n\tk10.canvas->updateCanvas();\n\tdelay(1000);\n\tk10.canvas->canvasText(\"UNIHIKER\", 2, 0xFF0000);\n\tk10.canvas->updateCanvas();\n\tdelay(1000);\n\tk10.canvas->canvasText(\"UNIHIKER\", 3, 0x00FF00);\n\tk10.canvas->updateCanvas();\n\tdelay(1000);\n\tk10.canvas->canvasText(\"UNIHIKER\", 4, 0x000000);\n\tk10.canvas->updateCanvas();\n\tdelay(1000);\n}\nvoid loop() {\n}\n````\n![image.png](img/example_mindplus/exampleMindplus6.gif){: width=\"250px\"}\n\n## **Display-Draw Point**\n````c++ title=\"Draw Point\"\n#include \"unihiker_k10.h\"\n\nuint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b);\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.setScreenBackground(0x000000);\n}\nvoid loop() {\n\tfor (int index = 0; index < 50; index++) {\n\t\tk10.canvas->canvasPoint((random(0, 240+1)), (random(0, 320+1)), rgbToColor(round((random(128, 255+1))), round((random(128, 255+1))), round((random(128, 255+1)))));\n\t\tk10.canvas->updateCanvas();\n\t}\n\tk10.canvas->canvasClear();\n}\n\nuint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b)\n{\n  return (uint32_t)((((uint32_t)r<<16) | ((uint32_t)g<<8)) | (uint32_t)b);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus11.gif){: width=\"300px\"}\n\n## **Display-Draw Line**\nDrawing funnels on K10:<br/>\n````c++ title=\"Draw funnel\"\n#include \"unihiker_k10.h\"\n\nvolatile float startX, endX;\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.canvas->canvasSetLineWidth(1);\n\tstartX = 0;\n\tendX = 240;\n}\nvoid loop() {\n\twhile (!(startX==240)) {\n\t\tk10.canvas->canvasLine(startX, 0, endX, 320, 0xFF0000);\n\t\tk10.canvas->updateCanvas();\n\t\tstartX += 3;\n\t\tendX -= 3;\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus12.gif){: width=\"250px\"}<br/>\nMeteor shower on K10:<br/>\n````c++ title=\"Meteor shower\"\n#include \"unihiker_k10.h\"\n\nvolatile float startX, startY, length, endX, endY;\n\nuint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b);\n\nUNIHIKER_K10 k10;\nuint8_t      screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.setScreenBackground(0x000000);\n\tk10.canvas->canvasSetLineWidth(1);\n}\nvoid loop() {\n\tk10.canvas->canvasClear();\n\tfor (int index = 0; index < 15; index++) {\n\t\tstartX = (random(0, 240+1));\n\t\tstartY = (random(0, 180+1));\n\t\tlength = (random(0, 40+1));\n\t\tendX = (startX + length);\n\t\tendY = (startY + length);\n\t\tk10.canvas->canvasLine(startX, startY, endX, endY, rgbToColor(round((random(128, 255+1))), round((random(128, 255+1))), round((random(128, 255+1)))));\n\t}\n\tk10.canvas->updateCanvas();\n\tdelay(500);\n}\n\nuint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b)\n{\n  return (uint32_t)((((uint32_t)r<<16) | ((uint32_t)g<<8)) | (uint32_t)b);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus42.gif){: width=\"250px\"}\n\n\n## **Display-Draw Circle**\n````c++ title=\"Draw Circle\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.canvas->canvasCircle(120, 120, 40, 0xFFCC33, 0xFFCC33, true);\n\tk10.canvas->canvasCircle(160, 160, 40, 0xFFCC33, 0xFFCC33, true);\n\tk10.canvas->canvasCircle(120, 200, 40, 0xFFCC33, 0xFFCC33, true);\n\tk10.canvas->canvasCircle(80, 160, 40, 0xFFCC33, 0xFFCC33, true);\n\tk10.canvas->canvasCircle(120, 160, 40, 0xFFFF00, 0xFFFF00, true);\n\tk10.canvas->updateCanvas();\n}\nvoid loop() {\n}\n````\n![image.png](img/example_mindplus/exampleMindplus14.png){: width=\"250px\"}\n\n## **Display-Draw Rectangle**\n````c++ title=\"Draw Rectangle\"\n#include \"unihiker_k10.h\"\n\nvolatile float offset, x, y, color;\n\nuint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b);\n\nUNIHIKER_K10 k10;\nuint8_t      screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.setScreenBackground(0x000000);\n}\nvoid loop() {\n\tfor (int index = 0; index < 8; index++) {\n\t\tx = (80 - (offset / 2));\n\t\ty = (100 - (offset / 2));\n\t\tcolor = rgbToColor(round((random(50, 255+1))), round((random(50, 255+1))), round((random(50, 255+1))));\n\t\tk10.canvas->canvasRectangle(x,y, (80 + offset), (100 + offset), color, 0x0000FF, false);\n\t\tk10.canvas->updateCanvas();\n\t\tdelay(10);\n\t\toffset = (offset + 20);\n\t}\n\tk10.canvas->canvasClear();\n\toffset = 0;\n}\n\nuint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b)\n{\n  return (uint32_t)((((uint32_t)r<<16) | ((uint32_t)g<<8)) | (uint32_t)b);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus16.gif){: width=\"250px\"}\n\n## **Display-QR Code**\n````c++ title=\"QR Code\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.canvasDrawCode(\"https://www.unihiker.com\");\n\tk10.canvas->updateCanvas();\n}\nvoid loop() {\n}\n````\n![image.png](img/example_mindplus/exampleMindplus18.png)\n\n## **On board sensor-Button**\nNormal method:<br/>\n````c++ title=\"Button\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n}\nvoid loop() {\n\tif ((k10.buttonA->isPressed())) {\n\t\tk10.canvas->canvasRectangle(10, 100, 110, 100, 0xFF6666, 0x0000FF, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse if ((k10.buttonB->isPressed())) {\n\t\tk10.canvas->canvasCircle(180, 150, 50, 0xFF6666, 0x0000FF, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse if ((k10.buttonAB->isPressed())) {\n\t\tk10.canvas->canvasClear();\n\t\tk10.canvas->updateCanvas();\n\t}\n}\n````\nInterrupt method:<br/>\n````c++ title=\"Button\"\n#include \"unihiker_k10.h\"\n\nvoid onButtonAPressed();\nvoid onButtonBPressed();\nvoid onButtonABPressed();\n\nUNIHIKER_K10 k10;\nuint8_t      screen_dir=2;\n\nvoid onButtonAPressed() {\n\tk10.canvas->canvasRectangle(10, 100, 110, 100, 0xFF6666, 0x0000FF, true);\n\tk10.canvas->updateCanvas();\n}\nvoid onButtonBPressed() {\n\tk10.canvas->canvasCircle(180, 150, 50, 0xFF6666, 0x0000FF, true);\n\tk10.canvas->updateCanvas();\n}\nvoid onButtonABPressed() {\n\tk10.canvas->canvasClear();\n\tk10.canvas->updateCanvas();\n}\n\nvoid setup() {\n\tk10.begin();\n\tk10.buttonA->setPressedCallback(onButtonAPressed);\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.buttonB->setPressedCallback(onButtonBPressed);\n\tk10.buttonAB->setPressedCallback(onButtonABPressed);\n}\nvoid loop() {\n\n}\n````\n![image.gifg](img/example_mindplus/exampleMindplus20.gif){: width=\"250px\"}\n\n\n## **On board sensor-Accelerate sensors**\n\nDisplay screen tilt\n\n!!! Note \n    TF card is need to run this example, and the arrow pictures need to store in the TF card.\n\n\n````c++ title=\"Accelerate sensors\"\n#include \"unihiker_k10.h\"\nUNIHIKER_K10 k10;\nuint8_t      screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.initSDFile();\n}\nvoid loop() {\n\tif ((k10.isGesture(TiltForward))) {\n\t\tk10.canvas->canvasDrawImage(0, 0, \"S:/forward.png\");\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse if ((k10.isGesture(TiltBack))) {\n\t\tk10.canvas->canvasDrawImage(0, 0, \"S:/back.png\");\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse if ((k10.isGesture(TiltLeft))) {\n\t\tk10.canvas->canvasDrawImage(0, 0, \"S:/left.png\");\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse if ((k10.isGesture(TiltRight))) {\n\t\tk10.canvas->canvasDrawImage(0, 0, \"S:/right.png\");\n\t\tk10.canvas->updateCanvas();\n\t}\n\tk10.canvas->canvasRectangle(0, 0, 240, 320, 0xFFFFFF, 0xFFFFFF, true);\n\tk10.canvas->updateCanvas();\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus21.gif){: width=\"250px\"}<br/>\nPedo meter:<br/>\n````c++ title=\"Pedo meter\"\n#include \"unihiker_k10.h\"\n\nvolatile float step;\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tstep = 0;\n\tk10.canvas->canvasText((String(\"Pedometer: \") + String(step)), 1, 0x0000FF);\n\tk10.canvas->updateCanvas();\n}\nvoid loop() {\n\tif (((k10.getStrength())>1050)) {\n\t\tstep += 1;\n\t\tk10.canvas->canvasText((String(\"Pedometer: \") + String(step)), 1, 0x0000FF);\n\t\tk10.canvas->updateCanvas();\n\t\tdelay(1000);\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus43.gif){: width=\"250px\"}\n\n## **On board sensor-Accelerate ball**\n````c++ title=\"Accelerate ball\"\n#include \"unihiker_k10.h\"\n\nvolatile float accx, accy, moveX, moveY;\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n  k10.begin();\n  k10.initScreen(screen_dir);\n  k10.creatCanvas();\n  k10.setScreenBackground(0xFFFFFF);\n}\nvoid loop() {\n  accx = (k10.getAccelerometerX());\n  accy = (k10.getAccelerometerY());\n  moveX = (120 + (accx / 3));\n  moveY = (160 + (accy / 3));\n  k10.canvas->canvasCircle(moveX, moveY, 8, 0x00FF00, 0x00FF00, true);\n  k10.canvas->updateCanvas();\n  k10.canvas->canvasCircle(moveX, moveY, 9, 0xFFFFFF, 0xFFFFFF, true);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus23.gif){: width=\"250px\"}\n\n## **On board sensor-RGB control**\n````c++ title=\"RGB control\"\n#include \"unihiker_k10.h\"\n\nvolatile float mind_n_brightness;\n\nUNIHIKER_K10 k10;\n\nvoid setup() {\n\tk10.begin();\n\tmind_n_brightness = 0;\n\tk10.rgb->brightness(round(mind_n_brightness));\n\tk10.rgb->write(-1, 0x0000FF);\n}\nvoid loop() {\n\twhile (!(mind_n_brightness==9)) {\n\t\tk10.rgb->brightness(round(mind_n_brightness));\n\t\tk10.rgb->write(-1, 0x0000FF);\n\t\tdelay(200);\n\t\tmind_n_brightness += 1;\n\t}\n\twhile (!(mind_n_brightness==0)) {\n\t\tk10.rgb->brightness(round(mind_n_brightness));\n\t\tk10.rgb->write(-1, 0x0000FF);\n\t\tdelay(200);\n\t\tmind_n_brightness -= 1;\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus24.gif){: width=\"250px\"}\n\n## **Audio-Play build-in music**\nPress button A to play the music \"BIRTHDAY\" in the background; press button B to play the alphabet song (1155661)<br/>\n````c++ title=\"Play build-in music\"\n#include \"unihiker_k10.h\"\n\nvoid onButtonAPressed();\nvoid onButtonBPressed();\n\nUNIHIKER_K10 k10;\nMusic music;\n\nvoid setup() {\n\tk10.begin();\n\tk10.buttonA->setPressedCallback(onButtonAPressed);\n\tk10.buttonB->setPressedCallback(onButtonBPressed);\n}\nvoid loop() {\n}\n\nvoid onButtonAPressed() {\n\tmusic.playMusic(DADADADUM);\n}\nvoid onButtonBPressed() {\n\tmusic.stopPlayTone();\n\tmusic.playTone(131,  8000);\n\tmusic.playTone(131,  8000);\n\tmusic.playTone(196,  8000);\n\tmusic.playTone(196,  8000);\n\tmusic.playTone(220,  8000);\n\tmusic.playTone(220,  8000);\n\tmusic.playTone(196,  8000);\n}\n````\n\n## **Audio-Record and play**\nPress button A to record 3 seconds of audio and store it to the TF card; press button B to play the recorded audio.<br/>Note: TF card is need to run this example\n````c++ title=\"Record and play\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\nMusic music;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.initSDFile();\n\tk10.canvas->canvasText(\"Press A to record......\", 5, 10, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\tk10.canvas->updateCanvas();\n}\nvoid loop() {\n\tif ((k10.buttonA->isPressed())) {\n\t\tk10.canvas->canvasText(\"Recording\", 5, 10, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t\tmusic.recordSaveToTFCard(\"S:/sound.wav\", 3);\n\t\tk10.canvas->canvasText(\"Record complete\", 5, 10, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse if ((k10.buttonB->isPressed())) {\n\t\tk10.canvas->canvasText(\"Playing......\", 5, 10, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t\tmusic.playTFCardAudio(\"S:/sound.wav\");\n\t\tdelay(3000);\n\t\tk10.canvas->canvasText(\"Play complete\", 0, 0, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n}\n````\n\n## **AI-Face detection**\nTurn on the camera, detect the face, and display the detected face length and width, as well as center point x and center point y coordinates, on the K10 screen<br/>\n````c++ title=\"Face detection\"\n#include \"unihiker_k10.h\"\n#include \"AIRecognition.h\"\n\nUNIHIKER_K10  k10;\nuint8_t screen_dir=2;\nAIRecognition ai;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tai.initAi();\n\tk10.initBgCamerImage();\n\tk10.setBgCamerImage(false);\n\tk10.creatCanvas();\n\tai.switchAiMode(ai.NoMode);\n\tk10.setBgCamerImage(true);\n\tai.switchAiMode(ai.Face);\n}\nvoid loop() {\n\tif (ai.isDetectContent(AIRecognition::Face)) {\n\t\tk10.canvas->canvasText((String(\"Face Length\") + String(ai.getFaceData(AIRecognition::Length))), 0, 0, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->canvasText((String(\"Face Width \") + String(ai.getFaceData(AIRecognition::Length))), 0, 16, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->canvasText((String(\"Face Center X\") + String(ai.getFaceData(AIRecognition::CenterX))), 0, 32, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->canvasText((String(\"Face Center Y\") + String(ai.getFaceData(AIRecognition::CenterY))), 0, 32, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\tdelay(1000);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus27.gif) \n\n## **AI-Face recognition**\nPress button A to learn the face and green LED on; press button B to recognize the face and blue LED on, and display the recognized face ID on the K10 screen<br/>\n````c++ title=\"Face recognition\"\n#include \"unihiker_k10.h\"\n#include \"AIRecognition.h\"\n\nString ID;\n\nvoid onButtonAPressed();\nvoid onButtonBPressed();\n\nUNIHIKER_K10  k10;\nuint8_t screen_dir=2;\nAIRecognition ai;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tai.initAi();\n\tk10.initBgCamerImage();\n\tk10.setBgCamerImage(false);\n\tk10.creatCanvas();\n\tai.switchAiMode(ai.NoMode);\n\tk10.buttonA->setPressedCallback(onButtonAPressed);\n\tk10.buttonB->setPressedCallback(onButtonBPressed);\n\tk10.setBgCamerImage(true);\n\tai.switchAiMode(ai.Face);\n}\nvoid loop() {\n\tif (ai.isRecognized()) {\n\t\tID = ai.getRecognitionID();\n\t\tk10.canvas->canvasText((String(\"Face ID: \") + String(ID)), 0, 0, 0x0000FF, k10.canvas->eCNAndENFont24, 50, true);\n\t\tk10.canvas->canvasText(ID, 0, 40, 0x0000FF, k10.canvas->eCNAndENFont24, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\tdelay(1000);\n}\n\nvoid onButtonAPressed() {\n\tk10.rgb->write(-1, 0x00FF00);\n\tai.sendFaceCmd(ENROLL);\n}\nvoid onButtonBPressed() {\n\tk10.rgb->write(-1, 0x0000FF);\n\tai.sendFaceCmd(RECOGNIZE);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus28.gif){: width=\"250px\"}\n\n## **AI-Dog/Cat recognition**\nTurn on the camera, when the camera detects the detection of the cat, the length and width of the cat's face, as well as the coordinates of the center point x and center point y, are displayed on the K10 screen.<br/>\n````c++ title=\"AI-Dog/Cat recognition\"\n#include \"unihiker_k10.h\"\n#include \"AIRecognition.h\"\n\nUNIHIKER_K10  k10;\nuint8_t screen_dir=2;\nAIRecognition ai;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tai.initAi();\n\tk10.initBgCamerImage();\n\tk10.setBgCamerImage(false);\n\tk10.creatCanvas();\n\tai.switchAiMode(ai.NoMode);\n\tk10.setBgCamerImage(true);\n\tai.switchAiMode(ai.Cat);\n}\nvoid loop() {\n\tif (ai.isDetectContent(AIRecognition::Cat)) {\n\t\tk10.canvas->canvasText((String(\"Face Length: \") + String(ai.getCatData(AIRecognition::Length))), 0, 0, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->canvasText((String(\"Face Width: \") + String(ai.getCatData(AIRecognition::Width))), 0, 20, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->canvasText((String(\"Face X: \") + String(ai.getCatData(AIRecognition::CenterX))), 0, 40, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->canvasText((String(\"Face Y:  \") + String(ai.getCatData(AIRecognition::CenterY))), 0, 60, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus29.gif){: width=\"250px\"}\n\n## **AI-Movement Detection**\n````c++ title=\"Movement Detection\"\n#include \"unihiker_k10.h\"\n#include \"AIRecognition.h\"\n\nUNIHIKER_K10  k10;\nuint8_t screen_dir=2;\nAIRecognition ai;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tai.initAi();\n\tk10.initBgCamerImage();\n\tk10.setBgCamerImage(false);\n\tk10.creatCanvas();\n\tai.switchAiMode(ai.NoMode);\n\tk10.setBgCamerImage(true);\n\tai.switchAiMode(ai.Move);\n\tai.setMotinoThreshold(50);\n\tk10.rgb->write(-1, 0x0000FF);\n}\nvoid loop() {\n\tif (ai.isDetectContent(AIRecognition::Move)) { \n\t\tk10.rgb->write(-1, 0xFF0000);\n\t}\n\telse {\n\t\tk10.rgb->write(-1, 0x0000FF);\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus44.gif){: width=\"300px\"}\n\n## **AI-QR Code Scanner**\nYou can generate your own QR code through some free [QR code generation sites](https://www.qr-code-generator.com/). <br/>\n\n!!! Note \n     Note: TF card is need to run this example, and the Album Cover picture needs to be stored in TF card.\n\n\nBelow is the \"Album cover\" QR code we generated\n````c++ title=\"QR Code Scanner\"\n#include \"unihiker_k10.h\"\n#include \"AIRecognition.h\"\n\nUNIHIKER_K10  k10;\nuint8_t screen_dir=2;\nAIRecognition ai;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tai.initAi();\n\tk10.initBgCamerImage();\n\tk10.setBgCamerImage(false);\n\tk10.creatCanvas();\n\tai.switchAiMode(ai.NoMode);\n\tk10.initSDFile();\n\tk10.setBgCamerImage(true);\n\tai.switchAiMode(ai.Code);\n}\nvoid loop() {\n\tif (ai.isDetectContent(AIRecognition::Code)) {\n\t\tif ((ai.getQrCodeContent()==String(\"Album cover\"))) {\n\t\t\tk10.canvas->canvasDrawImage(0, 0, \"S:/AlbumCover.png\");\n\t\t\tk10.canvas->updateCanvas();\n\t\t}\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus30.gif){: width=\"300px\"}\n![image.png](img/example_mindplus/exampleMindplus45.png){: width=\"200px\"}\n\n## **AI-Speech recognition**\nWake up the voice recognition through the wake-up command \"Hi,Telly\", and then through the command word \"Light on\", \"Light off\" to control the on-board RGB ELD lights on K10 to turn on and off. <br/>\n````c++ title=\"Speech recognition\"\n#include \"asr.h\"\n#include \"unihiker_k10.h\"\n// Create an object\nUNIHIKER_K10 k10;\nASR          asr;\nuint8_t      screen_dir=2;\n\n\n// Main program start\nvoid setup() {\n\tk10.begin();\n\tasr.asrInit(CONTINUOUS, CN_MODE, 6000);\n\twhile(asr._asrState == 0){delay(100);}\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tasr.addASRCommand(1, \"kai deng\");//中文语音识别时参数写拼音，并且每个字中间要有空格\n\tasr.addASRCommand(2, \"guan deng\");\n}\nvoid loop() {\n\tif (asr.isWakeUp()) {\n\t\tk10.canvas->canvasText(\"Wake up mode\", 0, 0, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse {\n\t\tk10.canvas->canvasText(\"Sleep mode\", 0, 0, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\tif (asr.isDetectCmdID(1)) {\n\t\tk10.rgb->brightness(round(9));\n\t\tk10.rgb->write(-1, 0xFF0000);\n\t}\n\telse if (asr.isDetectCmdID(2)) {\n\t\tk10.rgb->brightness(round(0));\n\t\tk10.rgb->write(-1, 0xFF0000);\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus31.gif){: width=\"400px\"}\n\n## **GPIO**\nSince the camera and display take up a lot of GPIOs on the ESP32 chip, we only left two full-function GPIOs (digital input/output, analogue input, PWM output) at P0,P1.\nThe GPIOs out of Edge Connector are all led from the on-board GPIO expansion chip, and only have digital input/output function.<br/>\n\nFor additional external analog inputs, use the [DFRobot Gravity I2C ADS1115 16-bit ADC module (DFR0553)](https://www.dfrobot.com.cn/goods-1734.html). It provides four analog channels over I2C, supports 3.3-5.0V power, and measures `0-VCC`. Never let an analog input exceed `VCC + 0.3V`.\n\n````c++ title=\"Digital input/output\"\nvoid setup() {\n\tpinMode(P0, OUTPUT);\n\tpinMode(P1, INPUT);\n\tSerial.begin(9600);\n\tdigitalWrite(P0, HIGH);\n}\nvoid loop() {\n\tSerial.println((digitalRead(P1)));\n}\n````\n\n````c++ title=\"Analog input/ PWM output\"\nvoid setup() {\n\tSerial.begin(9600);\n\tanalogWrite(P0, map(512, 0, 1023, 0, 255));\n}\nvoid loop() {\n\tSerial.println((analogRead(P1)));\n}\n````\n\n````c++ title=\"Digital input/output(Extended GPIO)\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\n\nvoid setup() {\n\tk10.begin();\n\tSerial.begin(9600);\n\tdigital_write(eP2, HIGH);\n}\nvoid loop() {\n\tSerial.println((digital_read(eP3)));\n}\n````\n\n````c++ title=\"屏幕上显示所有板载温湿度，环境光强度，加速度x,y,z轴，加速度强度\"\n#include \"unihiker_k10.h\"\n// 创建对象\nUNIHIKER_K10 k10;\nAHT20        aht20;\nuint8_t      screen_dir=2;\n\n\n// 主程序开始\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n}\nvoid loop() {\n\tk10.canvas->canvasText(aht20.getData(AHT20::eAHT20TempC), 1, 0x0000FF);\n\tk10.canvas->canvasText(aht20.getData(AHT20::eAHT20TempF), 2, 0x0000FF);\n\tk10.canvas->canvasText(aht20.getData(AHT20::eAHT20HumiRH), 3, 0x0000FF);\n\tk10.canvas->canvasText(k10.readALS(), 4, 0x0000FF);\n\tk10.canvas->canvasText((k10.getAccelerometerX()), 5, 0x0000FF);\n\tk10.canvas->canvasText((k10.getAccelerometerY()), 6, 0x0000FF);\n\tk10.canvas->canvasText((k10.getAccelerometerZ()), 7, 0x0000FF);\n\tk10.canvas->canvasText((k10.getStrength()), 8, 0x0000FF);\n\tk10.canvas->updateCanvas();//更新屏幕显示文字，每次调用k10.canvas->canvasText()或任何屏幕缓存显示的函数，必须调用k10.canvas->updateCanvas()后才能显示\n\tdelay(1000);\n\tk10.canvas->canvasClear();//清除屏幕显示文字\n}\n````\n\n\n## AI-语音合成（仅中文版固件）\n\n> **重要：** `setAsrSpeed()` 和 `speak()` 只存在于 K10 中文版固件。刷新 CN 模型数据不等同于切换为中文版固件；编译或运行前必须确认固件版本。\n\n````c++ title=\"按键触发语音合成\"\n#include \"asr.h\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nASR asr;\n\nvoid onButtonAPressed();\nvoid onButtonBPressed();\n\nvoid setup() {\n\tk10.begin();\n\tasr.setAsrSpeed(2);\n\tk10.buttonA->setPressedCallback(onButtonAPressed);\n\tk10.buttonB->setPressedCallback(onButtonBPressed);\n\tasr.speak(\"你好\");\n}\nvoid loop() {\n\n}\n\nvoid onButtonAPressed() {\n\tasr.speak(\"我是行空板\");\n}\nvoid onButtonBPressed() {\n\tasr.speak(\"语音合成\");\n}\n````\n\n`setAsrSpeed(uint8_t speed)` 的范围为 `0~5`。`speak()` 支持 `String`、`const char *` 和 `float`。\n\n官方资料：[Arduino/PIO 示例代码](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_Example)、[Arduino/PIO API 手册](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_API_List)。\n\nFile v0.1.10:references/k10-asr-audio-troubleshooting.md\n\n# K10 ASR Audio Troubleshooting\n\nUse this procedure when K10 voice models load and ASR commands register, but the wake indicator never changes or spoken commands appear ignored.\n\nBefore changing code, identify whether the application uses the official `UNIHIKER_K10::begin()` audio path or installs/configures I2S itself. Keep those paths separate during diagnosis; a minimal official-path probe is the baseline for judging custom I2S code.\n\n## Separate the Layers\n\nTreat these as independent checks:\n\n1. Model partition: `MODEL_LOADER`, WakeNet, and MultiNet load successfully.\n2. Command graph: command registration reaches a clear `ASR commands ready` marker.\n3. Codec control: ES7243E responds on I2C and accepts initialization.\n4. Audio transport: I2S produces changing, nonzero samples.\n5. Recognition: a real wake word and command produce application events.\n\nModel and command logs do not prove that microphone audio reaches the recognizer.\n\n## Prefer the Official Audio Path\n\nUse `UNIHIKER_K10::begin()` to initialize board IO and I2S unless there is a verified reason to reproduce the audio setup manually:\n\n```cpp\n#include <unihiker_k10.h>\n\nUNIHIKER_K10 board;\n\nvoid prepareAudio() {\n  board.begin();\n}\n```\n\n`board.begin()` does not call `initScreen()`. A custom TFT_eSPI/LVGL port can remain the only active display driver as long as the application never calls the SDK screen initializer. Initialize display/UI before starting the ASR worker, or keep all work after `asrInit()` short; long blocking setup after ASR starts can produce `rb_out slow` warnings.\n\nIf a strict build cannot link `unihiker_k10` because even an unused file-static TFT instance is unacceptable, first prove the microphone with a minimal official-path program. Then reproduce the K10 `initI2S()` configuration exactly and compare each initialization step rather than guessing pins or formats.\n\n## Do Not Trust the First DMA Block\n\nI2S DMA buffers may contain silence captured while MCLK and ES7243E were still settling. An immediate probe can report every sample as zero even though later audio is valid.\n\nAfter codec initialization:\n\n1. Wait about 500 ms.\n2. Read and discard more data than the configured DMA capacity.\n3. Measure subsequent samples.\n4. Do not call `i2s_zero_dma_buffer()` immediately before ASR starts.\n\nFor the K10 SDK default of three 300-frame stereo, 16-bit buffers, draining about 6 KiB is sufficient:\n\n```cpp\nvoid probeMicrophone() {\n  int16_t samples[256];\n\n  delay(500);\n  for (int block = 0; block < 12; ++block) {\n    size_t bytesRead = 0;\n    i2s_read(I2S_NUM_0, samples, sizeof(samples), &bytesRead,\n             pdMS_TO_TICKS(250));\n  }\n\n  uint32_t nonzero = 0;\n  uint16_t peak = 0;\n  size_t bytesRead = 0;\n  i2s_read(I2S_NUM_0, samples, sizeof(samples), &bytesRead,\n           pdMS_TO_TICKS(250));\n  for (size_t i = 0; i < bytesRead / sizeof(samples[0]); ++i) {\n    const int32_t value = samples[i];\n    const uint16_t magnitude = value < 0 ? -value : value;\n    if (value != 0) ++nonzero;\n    if (magnitude > peak) peak = magnitude;\n  }\n  Serial.printf(\"MIC probe: bytes=%u nonzero=%u peak=%u\\n\",\n                static_cast<unsigned>(bytesRead),\n                static_cast<unsigned>(nonzero), peak);\n}\n```\n\nA healthy quiet-room probe should normally contain nonzero noise samples. Judge it by repeated post-drain reads, not one startup block.\n\n## ES7243E Checks\n\nThe codec is normally visible at 7-bit I2C address `0x11` on K10. Early boot messages such as `Es7243e STOP failed`, `initialize failed`, or `START failed` can occur before I2S supplies MCLK. Do not ignore them, but distinguish the early attempt from a retry after I2S starts.\n\nIf official board initialization still leaves repeated post-drain reads at zero:\n\n1. Scan I2C0 and confirm `0x11` responds.\n2. Confirm the official I2S pins: MCLK 3, BCLK 0, LRCK 38, data-in 39, data-out 45.\n3. Run a minimal program containing only `board.begin()` and repeated `i2s_read()` calls.\n4. Compare that result with the full application before changing codec registers.\n5. Only then consider a board-revision-specific post-MCLK codec retry.\n\nSome framework builds expose `es7243e_adc_init()` and `es7243e_adc_ctrl_state()` only as internal C symbols. Treat calls to them as a compatibility fallback, verify against the installed framework, and never copy an arbitrary register table from another ES7243E board without testing.\n\n## Recognition Verification\n\nAfter audio is nonzero, verify the whole path rather than stopping at startup logs:\n\n1. Wait for the explicit command-ready marker.\n2. Confirm the actual wake phrase from the loaded WakeNet model name, startup log, or project configuration; one common Chinese K10 model uses `你好小鑫`.\n3. Speak the command within the configured wake timeout.\n4. Log the command source, for example `Light ON; cat eyes OPEN (VOICE)`.\n5. Test both commands at least once.\n\n`isWakeUp()` represents a transient recognition state. Poll it frequently and update the UI only when its value changes.\n\n## Failure Interpretation\n\n| Evidence | Likely layer |\n| --- | --- |\n| Model partition cannot map | Model flash or partition layout |\n| Models load, command-ready marker absent | ASR initialization or command registration |\n| Codec absent at `0x11` | Board bus, power, or hardware |\n| Immediate probe is zero, post-drain probe is nonzero | Stale startup DMA silence; audio is healthy |\n| Repeated post-drain probes stay zero in minimal official program | Hardware, clock, codec, or I2S path |\n| Audio is nonzero but wake fails | Wake model, phrase, noise level, or recognizer configuration |\n| Commands work but wake indicator appears stuck | UI polling/state-transition logic |\n\nFile v0.1.10:references/platformio-workshop.md\n\n# PlatformIO Workshop Notes for UNIHIKER K10\n\n## Why Predownload\n\nThe first K10 PlatformIO build downloads DFRobot's PlatformIO platform, the K10 Arduino framework, compiler toolchains, and upload/build tools. The largest pieces are the K10 Arduino framework and ESP32 toolchains. A prepared machine measured these approximate uncompressed sizes:\n\n| Directory | Purpose | Size |\n| --- | --- | --- |\n| `platforms/unihiker` | DFRobot platform definition | 536 KB |\n| `packages/framework-arduinounihiker` | K10 Arduino framework and libraries | 518 MB |\n| `packages/toolchain-xtensa-esp32s3` | ESP32-S3 compiler toolchain | 268 MB |\n| `packages/toolchain-riscv32-esp` | RISC-V helper toolchain used during K10 builds | can be large |\n| `packages/toolchain-xtensa-esp32` | Base ESP32 compiler toolchain declared by platform; include when present for conservative bundles | 387 MB |\n| `packages/tool-esptoolpy` | Upload tool | 2.6 MB |\n| `packages/tool-scons` | Build tool | 4.9 MB |\n| `packages/tool-mkfatfs`, `tool-mklittlefs`, `tool-mkspiffs` | Filesystem image tools for related upload targets | a few MB |\n\nA minimal compressed bundle from only the K10 framework plus Xtensa S3 pieces was about 459 MB on macOS. A conservative workshop bundle that includes every tool used or declared by the K10 platform will be larger. Exact sizes differ by OS and CPU architecture.\n\n## Prepare a Teacher Machine\n\nInstall PlatformIO Core, then create a probe project:\n\n```bash\nbash scripts/init-k10-platformio-project.sh /tmp/k10-pio-probe\npio run -d /tmp/k10-pio-probe\n```\n\nAfter the build succeeds, create the bundle:\n\n```bash\nbash scripts/prepare-offline-bundle.sh /tmp/k10-platformio-bundle.tgz\n```\n\nMake one bundle per supported OS and CPU architecture. Do not share a macOS arm64 bundle with Windows or Linux machines.\n\n## macOS Self-Contained USB Installer\n\nUse this for Apple Silicon Macs when students should not install PlatformIO or download Python packages during class. The package is a self-extracting `.command` file, not a system-wide `.pkg`; it does not need administrator permissions and can be copied from a USB drive. Intel Macs are not supported.\n\nOn a prepared teacher Mac:\n\n```bash\nbash scripts/init-k10-platformio-project.sh /tmp/k10-pio-probe\npio run -d /tmp/k10-pio-probe\nbash scripts/prepare-macos-offline-installer.sh --self-extracting /tmp/K10P-macos-arm64.command\n```\n\nCopy the resulting `.command` file to the USB drive.\n\nOn each student Mac:\n\n```bash\n/Volumes/USB/K10P-macos-arm64.command\n~/K10P/pio --version\n~/K10P/pio run -d ~/K10P/examples/Blink\n```\n\nThen use the bundled wrappers:\n\n```bash\n~/K10P/compile-project \"/path/to/PlatformIOProject\"\n~/K10P/upload-project \"/path/to/PlatformIOProject\" /dev/cu.usbmodemXXXX\n~/K10P/monitor-project \"/path/to/PlatformIOProject\" /dev/cu.usbmodemXXXX\n```\n\nThe self-extracting installer unpacks into `~/K10P`, creates a private `penv`, and installs PlatformIO from the included `wheelhouse` using `--no-index`. It also uses the bundled `~/K10P/.platformio` support directory for K10 toolchains and framework files. Student setup should not need internet after the installer has been prepared.\n\nThe macOS wheelhouse explicitly includes `typing-extensions` for student Macs running Python older than 3.13. If an older installer fails with `No matching distribution found for typing-extensions>=4.10.0`, rebuild the installer with the current `prepare-macos-offline-installer.sh`. For a one-off repair on an extracted `~/K10P`, download the missing wheel on an internet-connected machine and copy it into `~/K10P/wheelhouse`:\n\n```bash\npython3 -m pip download --dest /path/to/K10P/wheelhouse \"typing-extensions>=4.10.0\"\n```\n\nmacOS still needs a local `python3` executable to create the private virtual environment. If it is missing, install Apple's Command Line Tools or Python 3 before class. If Gatekeeper quarantine blocks the copied scripts, run:\n\n```bash\nxattr -d com.apple.quarantine /Volumes/USB/K10P-macos-arm64.command\nxattr -dr com.apple.quarantine \"$HOME/K10P\"\n```\n\n## Windows Self-Contained USB Installer\n\nUse this for Windows x64 workshops when students should not install PlatformIO or Python and should not download packages during class. The package is a relocatable folder archive, not a system-wide installer; it does not need administrator permissions and can be copied from a USB drive.\n\nOn a prepared teacher Windows machine:\n\n```powershell\n# First build any K10 PlatformIO project successfully so PlatformIO downloads all support files.\npio run -d C:\\path\\to\\k10-pio-probe\npowershell -ExecutionPolicy Bypass -File scripts\\prepare-windows-offline-installer.ps1 C:\\tmp\\K10P-windows-x64.exe\n```\n\nCopy the resulting `.exe` to the USB drive.\n\nOn each student Windows machine, run the self-extracting installer:\n\n```powershell\nE:\\K10P-windows-x64.exe\ncd C:\\K10P\n.\\pio.bat --version\n.\\pio.bat run -d .\\examples\\Blink\n```\n\nFor user projects, prefer the bundled wrappers:\n\n```powershell\nC:\\K10P\\compile-project.bat \"C:\\path\\to\\PlatformIOProject\"\nC:\\K10P\\upload-project.bat \"C:\\path\\to\\PlatformIOProject\" COM3\nC:\\K10P\\monitor-project.bat \"C:\\path\\to\\PlatformIOProject\" COM3\n```\n\nKeep both the installer folder and student projects in short paths such as `C:\\K10P` and `C:\\K10Work`. The wrappers set `PLATFORMIO_CORE_DIR` and `PYTHONPATH` to the private bundled `.platformio` directory. Students should use the bundled `pio.bat` or `platformio.bat`, not a system `pio` command.\n\n## Install on Student Machines\n\nCopy the bundle by USB drive, local file share, or classroom LAN. Then run:\n\n```bash\nbash scripts/install-offline-bundle.sh /path/to/k10-platformio-bundle.tgz\nbash scripts/doctor-offline.sh\n```\n\nIf PlatformIO uses a custom core directory, set `PLATFORMIO_CORE_DIR` during installation and during later builds:\n\n```bash\nexport PLATFORMIO_CORE_DIR=\"$HOME/.platformio\"\nbash scripts/install-offline-bundle.sh /path/to/k10-platformio-bundle.tgz\n```\n\n## Verify Offline Readiness\n\nRun:\n\n```bash\npio pkg list -g | grep -E 'unihiker|framework-arduinounihiker|xtensa-esp32s3'\nbash scripts/doctor-offline.sh\npio run -d /path/to/k10-project\n```\n\nThe second command should not need to download the K10 platform, K10 framework, or ESP32-S3 toolchain.\n\n## Troubleshooting\n\nIf PlatformIO downloads files anyway:\n\n- Confirm the bundle was installed into the active PlatformIO core directory.\n- Confirm OS/CPU architecture matches the teacher machine.\n- Confirm `platformio.ini` uses the same platform URL or pinned commit used to prepare the bundle.\n- Run `pio pkg list -g` and check for `unihiker`, `framework-arduinounihiker`, and `toolchain-xtensa-esp32s3`.\n- Check for `toolchain-riscv32-esp` if the first build still tries to download tools.\n\nIf the build fails with:\n\n```text\nModuleNotFoundError: No module named 'intelhex'\n```\n\nthe local PlatformIO Python/tool installation is incomplete. Repair or reinstall PlatformIO Core before the workshop image is used as the source for offline bundles.\n\nIf uploads fail:\n\n- Run `pio device list` and pass the serial port with `--upload-port`.\n- Check USB cable data capability.\n- On Linux, install PlatformIO udev rules and reconnect the board.\n- Try the K10 boot/reset procedure if the board is not entering upload mode.\n\n## Pinning for Repeatable Workshops\n\nFor a workshop, consider pinning the DFRobot platform to a known commit in `platformio.ini`:\n\n```ini\nplatform = https://github.com/DFRobot/platform-unihiker.git#508e31875ad92205bf946e28570fb78fc01ceb2e\n```\n\nPinning prevents a later GitHub update from invalidating the prepared cache.\n\nFile v0.1.10:skill-card.md\n\n## Description:\n\nHelps agents program UNIHIKER K10 boards with PlatformIO CLI, create or convert Arduino/C++ projects, build, upload, monitor serial output, diagnose setup or ASR issues, and prepare offline workshop installers.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[rockets-cn](https://clawhub.ai/user/rockets-cn)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and workshop instructors use this skill to create, convert, build, upload, and troubleshoot PlatformIO-based Arduino/C++ projects for UNIHIKER K10 boards, including offline class setup.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Workshop installers and build setup can install or execute unchecked mutable code across user machines.\n\nMitigation: Review the skill before workshop use, generate bundles from trusted sources, prefer pinned PlatformIO commits, and hash-verify Python wheels.\n\nRisk: Removing macOS quarantine can bypass an operating-system safety control.\n\nMitigation: Remove quarantine only after verifying the installer source and distributing a freshly generated bundle.\n\nRisk: Examples may activate camera, microphone, face recognition, or firmware flashing behavior.\n\nMitigation: Tell users before running those examples and confirm the selected workflow matches the board firmware and classroom policy.\n\nRisk: K10 AI, voice, TTS, face recognition, or OTA projects can overwrite factory model-data regions if generic partitions are used.\n\nMitigation: Preserve the documented factory model, voice_data, and face-recognition flash offsets, and use separate USB initialization environments only when model recovery is needed.\n\n## Reference(s):\n\n- [PlatformIO Workshop Notes for UNIHIKER K10](references/platformio-workshop.md)\n- [K10 AI Model Flashing and Recovery](references/k10-ai-model-flash.md)\n- [K10 ASR Audio Troubleshooting](references/k10-asr-audio-troubleshooting.md)\n- [K10 Arduino API](references/k10-arduino-api.md)\n- [K10 Arduino Examples](references/k10-arduino-examples.md)\n- [DFRobot PlatformIO Platform](https://github.com/DFRobot/platform-unihiker.git)\n- [DFRobot Gravity ADS1115 Module](https://www.dfrobot.com.cn/goods-1734.html)\n- [UNIHIKER K10 Arduino/PIO Example](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_Example)\n- [UNIHIKER K10 Arduino/PIO API List](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_API_List)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Code, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown guidance with inline bash, PowerShell, INI, and C++ code blocks]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May produce PlatformIO project files, command wrappers, and offline bundle or installer preparation steps when invoked.]\n\n## Skill Version(s):\n\n0.1.10 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v0.1.10:agents/openai.yaml\n\ninterface:\n  display_name: \"UNIHIKER K10 PlatformIO\"\n  short_description: \"K10 PlatformIO builds, uploads, and ASR diagnostics\"\n  default_prompt: \"Use $unihiker-k10-platformio to create, build, upload, or diagnose a UNIHIKER K10 PlatformIO project.\"\n\nFile v0.1.10:examples/tts-buttons/platformio.ini\n\n[env:unihiker]\nplatform = https://github.com/DFRobot/platform-unihiker.git\nboard = unihiker_k10\nframework = arduino\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n    -DModel=None\n\nArchive v0.1.9: 19 files, 33778 bytes\n\nFiles: agents/openai.yaml (275b), examples/tts-buttons/platformio.ini (204b), examples/tts-buttons/src/main.cpp (462b), references/k10-ai-model-flash.md (2912b), references/k10-arduino-api.md (10147b), references/k10-arduino-examples.md (23847b), references/platformio-workshop.md (7550b), scripts/doctor-offline.sh (1519b), scripts/init-k10-platformio-project.sh (1071b), scripts/install-offline-bundle.ps1 (703b), scripts/install-offline-bundle.sh (592b), scripts/k10-pio.ps1 (1862b), scripts/k10-pio.sh (1919b), scripts/prepare-macos-offline-installer.sh (9475b), scripts/prepare-offline-bundle.sh (1211b), scripts/prepare-windows-offline-installer.ps1 (11333b), skill-card.md (3300b), SKILL.md (14200b), _meta.json (142b)\n\nFile v0.1.9:SKILL.md\n\n---\nname: unihiker-k10-platformio\ndescription: Use when programming a UNIHIKER K10 board with PlatformIO CLI, creating or converting Arduino/C++ K10 projects to PlatformIO, building, uploading, monitoring serial output, diagnosing K10 PlatformIO setup, or preparing/installing offline PlatformIO support for workshops, including macOS archives and Windows self-extracting USB installers.\n---\n\n# UNIHIKER K10 - PlatformIO\n\n## Overview\n\nUse PlatformIO Core CLI for UNIHIKER K10 Arduino/C++ development. Prefer this skill when the user wants a PlatformIO-based workflow instead of `arduino-cli`, especially for workshops that need predownloaded support files.\n\nCore PlatformIO environment:\n\n```ini\n[env:unihiker]\nplatform = https://github.com/DFRobot/platform-unihiker.git\nboard = unihiker_k10\nframework = arduino\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n    -DModel=None\n```\n\nK10 uses DFRobot's PlatformIO platform and Arduino framework package. First build downloads a large framework and toolchains; avoid doing this from every student machine during a workshop.\n\nIf a project uses K10 AI, voice recognition, TTS, face recognition, or OTA partitions, preserve the factory model-data offsets. Read the repository reference `references/k10-ai-model-flash.md` when available, or follow the model rules below.\n\n**TTS firmware requirement:** `ASR::setAsrSpeed()` and `ASR::speak()` exist only in the Chinese K10 firmware. Confirm the firmware variant before generating or compiling TTS code. `-DModel=CN` refreshes CN model data; it does not by itself prove that the installed framework/firmware variant provides TTS.\n\nScreen refresh policy: generated K10 display code must prefer partial redraws. Full-screen clearing or full-background redraw causes visible flicker and is uncomfortable; use it only for initialization, page switches, exit cleanup, or when measured full-screen refresh is above 30 fps.\n\n## Quick Workflow\n\n### Windows Self-Contained Offline Installer\n\nFor Windows machines with no PlatformIO or Python environment installed, use the self-contained K10 PlatformIO offline installer first. It installs an isolated PlatformIO environment and does not require system `pio`.\n\nPrepare the Windows x64 self-extracting installer on a teacher Windows machine after one successful K10 PlatformIO build:\n\n```powershell\npowershell -ExecutionPolicy Bypass -File scripts\\prepare-windows-offline-installer.ps1 C:\\tmp\\K10P-windows-x64.exe\n```\n\nCopy the resulting `.exe` to the USB drive. Run it on each student Windows machine; it extracts to `C:\\K10P` and runs `setup-platformio.bat`.\n\nKnown install locations to check, in order:\n\n```text\nC:\\K10P\n%USERPROFILE%\\K10P\n%LOCALAPPDATA%\\K10P\n%LOCALAPPDATA%\\K10PlatformIO\n```\n\nCheck this location before assuming PlatformIO is missing:\n\n```powershell\ncd C:\\K10P\n.\\setup-platformio.bat\n.\\pio.bat --version\n.\\pio.bat run -d .\\examples\\Blink\n```\n\nImportant: use the bundled `pio.bat` or `platformio.bat` wrappers. Do not call `.platformio\\penv\\Scripts\\pio.exe` or `.platformio\\penv\\Scripts\\python.exe` directly; Windows launcher/venv executables can contain absolute paths from the machine that built the bundle or break under non-ASCII usernames. The wrapper uses `.platformio\\python3\\python.exe -m platformio` with `PYTHONPATH` set to the bundled site-packages.\n\nFor user projects:\n\n```powershell\nC:\\K10P\\compile-project.bat \"C:\\path\\to\\PlatformIOProject\"\nC:\\K10P\\upload-project.bat \"C:\\path\\to\\PlatformIOProject\" COM3\n```\n\n### macOS Self-Contained Offline Installer\n\nFor Apple Silicon macOS workshops, prepare a self-extracting `.command` installer on the teacher Mac and copy it by USB drive. This avoids each student downloading the large K10 PlatformIO platform, framework, toolchains, and PlatformIO Python packages. Intel Macs are not supported.\n\nPrepare the Apple Silicon self-extracting installer:\n\n```bash\n# On a prepared teacher Mac after one successful K10 PlatformIO build\nbash scripts/prepare-macos-offline-installer.sh --self-extracting /tmp/K10P-macos-arm64.command\n```\n\nOn each student Mac:\n\n```bash\n/Volumes/USB/K10P-macos-arm64.command\n~/K10P/pio --version\n~/K10P/pio run -d ~/K10P/examples/Blink\n```\n\nFor user projects:\n\n```bash\n~/K10P/compile-project \"/path/to/PlatformIOProject\"\n~/K10P/upload-project \"/path/to/PlatformIOProject\" /dev/cu.usbmodemXXXX\n```\n\nImportant: use the bundled `~/K10P/pio` or `~/K10P/platformio` wrappers. They set `PLATFORMIO_CORE_DIR` to the private bundled `.platformio` directory so builds do not depend on or modify the user's global PlatformIO installation.\n\nThe macOS bundle still needs a local `python3` to create its private virtual environment. It does not need internet during student setup. If macOS blocks files copied from a downloaded archive, remove quarantine on the installer or copied folder:\n\n```bash\nxattr -d com.apple.quarantine /Volumes/USB/K10P-macos-arm64.command\nxattr -dr com.apple.quarantine \"$HOME/K10P\"\n```\n\nIf macOS setup fails offline with `No matching distribution found for typing-extensions>=4.10.0`, the installer was built with an older script that omitted a conditional PlatformIO dependency needed by Python older than 3.13. Rebuild the installer with `scripts/prepare-macos-offline-installer.sh`, or add `typing-extensions` to the extracted `wheelhouse`.\n\nBefore writing K10 application code, read the relevant local references:\n\n- `references/k10-arduino-api.md` for K10 C++ API signatures.\n- `references/k10-arduino-examples.md` for working examples, including display, RGB, sensors, audio, AI, TTS, and ASR.\n\n1. Check PlatformIO:\n\n```bash\npio --version\n```\n\nIf missing, install PlatformIO Core using the official installer script or package manager. Do not use sudo/admin unless the user explicitly needs a system-wide install.\n\n2. Create or normalize a K10 project:\n\n```bash\nbash path/to/unihiker-k10-platformio/scripts/init-k10-platformio-project.sh my-k10-project\n```\n\n3. Put code in `src/main.cpp`. For `.ino` sketches, preserve the same Arduino code but make sure function prototypes/includes are valid C++.\n\n4. Build:\n\n```bash\npio run -d my-k10-project\n```\n\n5. Upload:\n\n```bash\npio run -d my-k10-project -t upload --upload-port /dev/cu.usbmodemXXXX\n```\n\nIf no port is provided, PlatformIO may auto-detect. Use `pio device list` when upload fails or multiple boards are connected.\n\n6. Monitor serial:\n\n```bash\npio device monitor -d my-k10-project --port /dev/cu.usbmodemXXXX\n```\n\n## Bundled Scripts\n\n- `scripts/init-k10-platformio-project.sh`: create a minimal K10 PlatformIO project with sample screen code.\n- `scripts/k10-pio.sh`: convenience wrapper for `doctor`, `ports`, `build`, `upload`, and `monitor`.\n- `scripts/prepare-offline-bundle.sh`: build once, collect K10 PlatformIO support files, and create a distributable `.tgz`.\n- `scripts/prepare-macos-offline-installer.sh`: create an Apple Silicon macOS self-contained installer `.tgz` with bundled K10 support files, PlatformIO wheels, wrappers, and a Blink probe project.\n- `scripts/prepare-windows-offline-installer.ps1`: create a Windows x64 self-extracting installer `.exe` with bundled K10 support files, PlatformIO Python runtime, wrappers, and a Blink probe project. Passing a `.zip` output path is still supported as a fallback archive format.\n- `scripts/install-offline-bundle.sh`: install a prepared bundle into a user's PlatformIO core directory.\n- `scripts/doctor-offline.sh`: verify that the required K10 PlatformIO packages are present before class.\n- `scripts/k10-pio.ps1` and `scripts/install-offline-bundle.ps1`: Windows PowerShell helpers for common operations and bundle installation.\n\nPrefer scripts for repeated workshop setup. Read `references/platformio-workshop.md` before changing offline bundle behavior.\n\n## Workshop Offline Bundle\n\nUse an offline bundle when many learners will build K10 projects in the same room.\n\nExpected support-file sizes after first successful build vary by OS/CPU, but the important K10 pieces are roughly:\n\n| Directory | Purpose | Typical uncompressed size |\n| --- | --- | --- |\n| `platforms/unihiker` | DFRobot PlatformIO platform | <1 MB |\n| `packages/framework-arduinounihiker` | K10 Arduino framework, SDK, libraries | ~500 MB |\n| `packages/toolchain-xtensa-esp32s3` | ESP32-S3 compiler toolchain | ~250-300 MB |\n| `packages/toolchain-riscv32-esp` | RISC-V helper toolchain used by the K10 build | varies, often large |\n| `packages/toolchain-xtensa-esp32` | Base ESP32 toolchain declared by platform; include when present for conservative bundles | ~350-400 MB |\n| `packages/tool-esptoolpy` | Upload tool | a few MB |\n| `packages/tool-scons` | Build tool | a few MB |\n| `packages/tool-mkfatfs`, `tool-mklittlefs`, `tool-mkspiffs` | Filesystem image tools used by some upload targets | a few MB |\n\nA minimal compressed bundle is typically hundreds of MB. Prepare one bundle per supported OS/architecture. The self-contained macOS installer supports Apple Silicon only; Intel Macs are not supported.\n\nBundle preparation flow:\n\n```bash\n# On a prepared teacher machine\nbash scripts/init-k10-platformio-project.sh /tmp/k10-pio-probe\npio run -d /tmp/k10-pio-probe\nbash scripts/prepare-offline-bundle.sh /tmp/k10-platformio-bundle.tgz\n```\n\nFor macOS students who should not install PlatformIO manually, prefer the self-contained installer flow instead:\n\n```bash\nbash scripts/prepare-macos-offline-installer.sh --self-extracting /tmp/K10P-macos-arm64.command\n```\n\nFor Windows students who should not install PlatformIO or Python manually, prefer the self-contained installer flow instead:\n\n```powershell\npowershell -ExecutionPolicy Bypass -File scripts\\prepare-windows-offline-installer.ps1 C:\\tmp\\K10P-windows-x64.exe\n```\n\nStudent installation flow:\n\n```bash\nbash scripts/install-offline-bundle.sh /path/to/k10-platformio-bundle.tgz\nbash scripts/doctor-offline.sh\npio run -d my-k10-project\n```\n\nIf the student machine still tries to download packages, check that the bundle was built on the same OS/CPU architecture and that it was extracted into the same PlatformIO core directory used by `pio`.\n\nIf build fails with `ModuleNotFoundError: No module named 'intelhex'` from `tool-esptoolpy`, repair the local PlatformIO Python environment or reinstall PlatformIO Core. This indicates an incomplete PlatformIO tool dependency, not a K10 source-code error.\n\n## Project Conventions\n\n- Use `platformio.ini` at the project root.\n- Use `src/main.cpp` for code.\n- Keep assets/data files in `data/` only when using filesystem upload features.\n- Use `lib/` for private libraries that belong to the project.\n- Do not mix `arduino-cli` FQBN settings with PlatformIO project configuration.\n- Keep K10 USB serial flags in `build_flags`; they are required for expected USB CDC behavior.\n- Treat the PlatformIO skill as self-contained. Do not rely on sibling skills or repository-relative paths for API details after installation from ClawHub.\n\n## K10 API Notes\n\n- Include K10 board APIs with `#include \"unihiker_k10.h\"`.\n- Include speech recognition with `#include \"asr.h\"`.\n- Speech synthesis is Chinese-firmware-only. Initialize it with `asr.setAsrSpeed(0..5)`, then call `asr.speak(...)`; supported arguments are `String`, `const char *`, and `float`.\n- For animations, dashboards, sensor readouts, voice status, OTA status, and other repeated updates, erase and redraw only the changed region. Do not use `canvasClear()` or redraw the full background in a loop unless the measured full-screen refresh rate is above 30 fps.\n- For ASR command registration, prefer mutable `char[]` command buffers:\n\n```cpp\nchar cmdLightOn[] = \"kai deng\";\nasr.addASRCommand(1, cmdLightOn);\n```\n\nAvoid `asr.addASRCommand(id, String(\"...\"))` unless the upstream library has been verified fixed. Some K10 ASR library versions recurse in the `String` overload and can trigger a `loopTask` stack canary reset.\n\nChinese-firmware TTS reference:\n\n```cpp\n#include \"asr.h\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nASR asr;\n\nvoid setup() {\n  k10.begin();\n  asr.setAsrSpeed(2);  // 0-5\n  asr.speak(\"你好\");\n}\n\nvoid loop() {}\n```\n\nSee the [official Arduino/PIO example](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_Example) and [API list](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_API_List).\n\nCompilable project: [`examples/tts-buttons`](examples/tts-buttons).\n\n## OTA Notes\n\nPlatformIO's DFRobot platform supports normal USB upload with `pio run -t upload`. For OTA-style HTTP uploads used by existing K10 Arduino examples, continue using the existing OTA helper pattern only when the firmware exposes the expected `/ota` endpoint.\n\nFor native PlatformIO OTA via ESP OTA, set `upload_protocol = espota` and `upload_port = <ip>` only after confirming the firmware and platform support that route.\n\nWhen combining OTA with K10 built-in AI features, use a partition table that keeps these regions at the factory offsets:\n\n- `model` at `0x510000`, size `4563K`\n- `voice_data` at `0x985000`, size `2542K`\n- `fr` at `0xC01000`, size `100K`\n\nUse 2.5 MB OTA app slots ending exactly before `0x510000`. Do not use generic 6 MB OTA slots for AI projects, because they overlap the model region.\n\nFor model recovery or first initialization, add separate USB-only environments:\n\n```ini\n[env:unihiker]\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n    -DModel=None\n\n[env:unihiker-init-cn]\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n    -DModel=CN\n\n[env:unihiker-init-en]\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n    -DModel=EN\n```\n\nUse `unihiker-init-cn` for the Chinese model and `unihiker-init-en` for the English model only when model data may be missing or damaged. Use `unihiker` for normal app uploads and OTA builds.\n\n## References\n\n- Read `references/platformio-workshop.md` for offline bundle preparation, installation, and troubleshooting.\n- Read `references/k10-ai-model-flash.md` for AI model partitions, OTA compatibility, and recovery workflow.\n- Read `references/k10-arduino-api.md` for K10 API signatures.\n- Read `references/k10-arduino-examples.md` for complete K10 Arduino examples. The C++ APIs are the same as Arduino mode; only the build/upload toolchain changes.\n\nFile v0.1.9:_meta.json\n\n{\n  \"ownerId\": \"kn7bn6y6610bpcvzaykr1h2m1d83e2rm\",\n  \"slug\": \"unihiker-k10-platformio\",\n  \"version\": \"0.1.9\",\n  \"publishedAt\": 1784639920717\n}\n\nFile v0.1.9:references/k10-ai-model-flash.md\n\n# K10 AI Model Flashing and Recovery\n\nUse this reference when a PlatformIO project combines K10 built-in AI features, voice recognition, TTS, face recognition, OTA partitions, or factory recovery.\n\n## Fixed AI Flash Regions\n\nKeep these offsets unchanged unless DFRobot publishes a new partition table.\n\n| Region | Offset | Size in factory table | Purpose |\n| --- | --- | --- | --- |\n| `model` | `0x510000` | `4563K` | Speech recognition model image |\n| `voice_data` | `0x985000` | `2542K` | TTS voice data |\n| `fr` | `0xC01000` | `100K` | Face-recognition related data |\n\nIn DFRobot's current K10 PlatformIO framework package:\n\n- `srmodels.bin` is about 3.1 MB and is used by `-DModel=CN`.\n- `srmodels4.bin` is about 4.2 MB and is used by `-DModel=EN`.\n- `srmodels5.bin` is about 4.5 MB but is not selected by the current PlatformIO upload builder.\n- `esp_tts_voice_data_xiaoxin.dat` is about 2.5 MB and is flashed with both CN and EN.\n\n## PlatformIO Environments\n\nUse a normal environment for day-to-day builds and separate initialization environments for model recovery.\n\n```ini\n[k10_base]\nplatform = https://github.com/DFRobot/platform-unihiker.git\nboard = unihiker_k10\nframework = arduino\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n\n[env:unihiker]\nextends = k10_base\nbuild_flags =\n    ${k10_base.build_flags}\n    -DModel=None\n\n[env:unihiker-init-cn]\nextends = k10_base\nbuild_flags =\n    ${k10_base.build_flags}\n    -DModel=CN\n\n[env:unihiker-init-en]\nextends = k10_base\nbuild_flags =\n    ${k10_base.build_flags}\n    -DModel=EN\n```\n\nUse `unihiker-init-cn` or `unihiker-init-en` once over USB when the model partitions may be blank or damaged. Use `unihiker` for normal uploads and OTA app images.\n\n## OTA Partition Rule\n\nDo not use a generic two-slot OTA table whose app partitions grow past `0x510000`; it can overwrite the model region.\n\nUse a model-preserving OTA table:\n\n```csv\n# Name,     Type, SubType, Offset,   Size,     Flags\nnvs,        data, nvs,     0x9000,   0x5000,\notadata,    data, ota,     0xe000,   0x2000,\napp0,       app,  ota_0,   0x10000,  0x280000,\napp1,       app,  ota_1,   0x290000, 0x280000,\nmodel,      data, spiffs,  0x510000, 4563K,\nvoice_data, data, fat,     0x985000, 2542K,\nfr,         data, ,        0xC01000, 100K,\ncoredump,   data, coredump,,         1K,\nspiffs,     data, spiffs,  0xC1B000, 0x3E5000,\n```\n\nEach OTA app slot is 2.5 MB. If the firmware no longer fits, reduce firmware size, drop OTA, or explicitly decide that the project will not use built-in AI model data.\n\n## Recovery Paths\n\nOfficial UNIHIKER documentation provides Mind+ recovery:\n\n1. Hold BOOT while connecting USB.\n2. Release BOOT after the port appears.\n3. Click `Restore Initial Settings`.\n4. Press RST when restoration completes.\n\nThe hardware download page also provides a factory programme zip for restoring the factory demo after Mind+ initial settings are restored.\n\nFile v0.1.9:references/k10-arduino-api.md\n\n## UNIHIKER_K10\nThe UNIHIKER K10 library is a library for controlling the K10 on-screen display, on-board sensors, SD card, and playing sound.\nNote: The source code for this library will be made available on the DFRobot GitHub when the UNIHIKER K10 SDK is upgraded to the full version.\n\nScreen refresh rule: prefer partial redraws for all repeated display updates. Avoid `canvasClear()` or full-background redraw in loops because it causes visible flicker; use full-screen refresh only for initialization, page switches, exit cleanup, or when measured full-screen refresh is above 30 fps.\n\n````c++ title=\"Init\"\n/**\n * @fn begin\n * @brief Initialize UNIHIKER K10 board\n */\nvoid begin(void);\n````\n\n````c++ title=\"Display\"\n/**\n * @fn initScreen\n * @brief Initialize the screen\n * @param dir Screen orientation\n * @param frame Screen display frame rate\n */\nvoid initScreen(int dir = 2, int frame = 0);\n\n/**\n * @fn creatCanvas\n * @brief Create a canvas\n */\nvoid creatCanvas(void);\n\n/**\n * @fn initBgCamerImage\n * @brief Initialize the camera image\n */\nvoid initBgCamerImage(void);\n\n/**\n * @fn setBgCamerImage\n * @brief Set whether to display the camera image on the screen\n * @param sta Configuration status\n */\nvoid setBgCamerImage(bool sta = true);\n\n/**\n * @fn setScreenBackground\n * @brief Set the screen background color\n * @param color Background color\n */\nvoid setScreenBackground(uint32_t color);\n\n/**\n * @fn canvasText\n * @brief Display text on the canvas\n * @param text Text content\n * @param row Row to display\n * @param color Text color\n */\nvoid canvasText(float text, uint8_t row, uint32_t color);\nvoid canvasText(String text, uint8_t row, uint32_t color);\nvoid canvasText(const char* text, uint8_t row, uint32_t color);\n\n/**\n * @fn canvasPoint\n * @brief Draw a point on the canvas\n * @param x Display coordinate X\n * @param y Display coordinate Y\n * @param color Point color\n */\nvoid canvasPoint(int16_t x, int16_t y, uint32_t color);\n\n/**\n * @fn updateCanvas\n * @brief Update screen display (automatically updates when using camera)\n */\nvoid updateCanvas(void);\n\n/**\n * @fn canvasClear\n * @brief Clear canvas properties\n */\nvoid canvasClear(void);\n\n/**\n * @fn canvasSetLineWidth\n * @brief Set line width for drawing\n * @param w Line width\n */\nvoid canvasSetLineWidth(uint8_t w = 10);\n\n/**\n * @fn canvasLine\n * @brief Draw a line on the canvas\n * @param x1, y1 Starting coordinates\n * @param x2, y2 Ending coordinates\n * @param color Line color\n */\nvoid canvasLine(int x1, int y1, int x2, int y2, uint32_t color);\n\n/**\n * @fn canvasCircle\n * @brief Draw a circle on the canvas\n * @param x Display coordinate X\n * @param y Display coordinate Y\n * @param r Circle radius\n * @param color Border color\n * @param bg_color Background color\n * @param fill Whether to fill the circle\n */\nvoid canvasCircle(int x, int y, int r, uint32_t color, uint32_t bg_color, bool fill);\n\n/**\n * @fn canvasRectangle\n * @brief Draw a rectangle on the canvas\n * @param x Display coordinate X\n * @param y Display coordinate Y\n * @param w Rectangle width\n * @param h Rectangle height\n * @param color Border color\n * @param bg_color Background color\n * @param fill Whether to fill the rectangle\n */\nvoid canvasRectangle(int x, int y, int w, int h, uint32_t color, uint32_t bg_color, bool fill);\n\n/**\n * @fn canvasDrawCode\n * @brief Display QR code\n * @param code QR code to display\n */\nvoid canvasDrawCode(String code);\n\n/**\n * @fn clearCode\n * @brief Clear QR code from display\n */\nvoid clearCode(void);\n````\n\n````c++ title=\"microSD card\"\n/**\n * @fn initSDFile\n * @brief Initialize the SD card file system\n */\nvoid initSDFile(void);\n\n/**\n * @fn photoSaveToTFCard\n * @brief Save a photo to the SD card\n * @param imagePath Path to save the photo\n */\nvoid photoSaveToTFCard(const char *imagePath);\nvoid photoSaveToTFCard(String imagePath);\n\n/**\n * @fn playTFCardAudio\n * @brief Play music from SD card\n */\nvoid playTFCardAudio(const char* path);\nvoid playTFCardAudio(String path);\n\n/**\n * @fn recordSaveToTFCard\n * @brief Record and save to SD card\n * @param path Storage path\n * @param time Recording duration\n */\nvoid recordSaveToTFCard(const char* path, uint8_t time);\nvoid recordSaveToTFCard(String path, uint8_t time);\n````\n\n````c++ title=\"on-board sensor\"\n/**\n * @brief Get the ambient light intensity\n * @return uint16_t Ambient light intensity\n */\nuint16_t readALS(void);\n\n\n/**\n * @fn getAccelerometerX\n * @brief Get accelerometer X-axis data\n */\nint getAccelerometerX();\n\n/**\n * @fn getAccelerometerY\n * @brief Get accelerometer Y-axis data\n */\nint getAccelerometerY();\n\n/**\n * @fn getAccelerometerZ\n * @brief Get accelerometer Z-axis data\n */\nint getAccelerometerZ();\n\n/**\n * @fn getStrength\n * @brief Get strength\n */\nint getStrength();\n\n/**\n * @fn isGesture\n * @brief Detect gesture\n * @param gesture Gesture state\n */\nbool isGesture(Gesture gesture);\n\n/**\n * @fn playMusic\n * @brief Background play of built-in music\n * @param melodies Music selection\n * @param options Playback options\n */\nvoid playMusic(Melodies melodies, MelodyOptions options = Once);\n\n/**\n * @brief Play a specified note\n * @param frequency Note frequency\n * @param samples Beat: 8000 for full beat, 4000 for half beat, others similarly\n */\nvoid playTone(int freq, int beat);\n\n/**\n * @fn stopPlayTone\n * @brief Stop playing tone\n */\nvoid stopPlayTone(void);\n\n/**\n * @fn stopPlayAudio\n * @brief Stop playing music from SD card\n */\nvoid stopPlayAudio(void);\n\n/**\n * @fn write\n * @brief Set RGB LED color\n * @param index LED index\n * @param r Red value\n * @param g Green value\n * @param b Blue value\n */\nvoid write(int8_t index, uint8_t r, uint8_t g, uint8_t b);\n\n/**\n * @fn setRangeColor\n * @brief Set range of RGB LED colors\n * @param start Start LED index\n * @param end End LED index\n * @param c Color\n */\nvoid setRangeColor(int16_t start, int16_t end, uint32_t c);\n\n/**\n * @fn brightness\n * @brief Set RGB LED brightness\n */\nvoid brightness(uint8_t b);\n\n/**\n * @fn isPressed\n * @brief Check if a button is pressed\n */\nbool isPressed(void);\n\n/**\n * @fn setPressedCallback\n * @brief Set callback function for button press\n * @param _cb Callback function\n */\nvoid setPressedCallback(CBFunc _cb);\n\n/**\n * @fn setUnPressedCallback\n * @brief Set callback function for button release\n * @param _cb Callback function\n */\nvoid setUnPressedCallback(CBFunc _cb);\n\n/**\n * @fn getData\n * @brief Get data from AHT20 sensor\n * @param type Data type to retrieve\n */\nfloat getData(eAHT20Data_t type);\n````\n\n## AIRecognition\nThe AIRecognition library is the library used to pull data from the K10's built-in AI models.\nNote: The source code for this library will be made available on the DFRobot GitHub when the UNIHIKER K10 SDK is upgraded to the full version.<br/>\n````c++ title=\"Init\"\n/**\n * @fn init\n * @brief Initialize AI\n*/\nvoid initAi(void);\n\n/**\n * @fn switchAiMode\n * @brief Select AI mode\n * @param mode Face, //Face Recognition\n               Cat, //Cat/Dog Recognition\n               Move, //<Movement Detection\n               Code, //QRCode Recognition\n */\nvoid switchAiMode(eAiType_t mode);\n````\n\n````c++ title=\"AI Detection\"\n/**\n * @fn getFaceData\n * @brief Get detected face data\n * @param type Length,Width,CenterX,CenterY,LeftEyeX,LeftEyeY,RightEyeX,RightEyeY,\n * NoseX,NoseY,LeftMouthX,LeftMouthY,RightMouthX,RightMouthY,\n*/\nint getFaceData(eFaceOrCatData_t type);\n\n/**\n* @fn getCatData\n* @brief Get detected cat/dog face data\n*  @param type Length,Width,CenterX,CenterY,LeftEyeX,LeftEyeY,RightEyeX,RightEyeY,\n* NoseX,NoseY,LeftMouthX,LeftMouthY,RightMouthX,RightMouthY,\n*/\nint getCatData(eFaceOrCatData_t type);\n\n/**\n * @fn isDetectContent\n * @brief Detect data\n * @param mode Specific data\n */\nbool isDetectContent(eAiType_t mode);\n\n/**\n* @fn sendFaceCmd\n* @brief Send face command\n* @param recognizer_state_t ENROLL: Learn face\n*        recognizer_state_t RECOGNIZE: Recognize face\n*        recognizer_state_t DELETEALL: Delete all face ID\n*        uint8_t cmd, DELETE: Delete certain face ID\n *       int id: ID: Face ID\n*/\nvoid sendFaceCmd(recognizer_state_t cmd);\nvoid sendFaceCmd(uint8_t cmd, int id);\n\n/**\n * @fn setMotinoThreshold\n * @brief Set motion sensitivity\n * @param threshold range 10~200\n*/\nvoid setMotinoThreshold(uint8_t threshold);\n\n/**\n * @fn getQrCodeContent\n * @brief Get QR code data\n * @return Recognized QR code\n*/\nString getQrCodeContent(void);\n\n/**\n * @fn getRecognitionID\n * @brief Get face recognition ID\n * @return Face recognition ID\n*/\nint getRecognitionID(void);\n\n/**\n * @fn isRecognized\n * @brief Check if face recognition is complete\n * @return Recognition status\n */\nbool isRecognized(void);\n````\n\n## ASR\nASR is a library for the speech recognition feature built into K10.<br/>\n````c++ title=\"ASR\"\n/** \n * @brief Initialising speech recognition\n * @param mode  ONCE|CONTINUOUS \n * @param lang  EN_MODE|CN_MODE\n * @param wakeUpTime unit:ms\n*/\nvoid asrInit(uint8_t mode = 0, uint8_t lang = 0, uint16_t wakeUpTime = 6000);\n\n/**\n * @fn addASRCommand\n * @brief Adding Voice Recognition Command Words\n * @param id Command Word ID\n * @param cmd Command word data\n*/\nvoid addASRCommand(uint8_t id, char* cmd);\nvoid addASRCommand(uint8_t id, String cmd);\n\n/**\n * @fn isWakeUp\n * @brief Get Wakeup Status\n*/\nbool isWakeUp(void);\n\n/**\n * @fn isDetectCmdID \n * @brief Get command word ID\n */\nbool isDetectCmdID(uint8_t id);\n\n/**\n * @fn setAsrSpeed\n * @brief Initialize TTS and set speech speed. Chinese K10 firmware only.\n * @param speed Speech speed, range 0-5\n */\nvoid setAsrSpeed(uint8_t speed);\n\n/**\n * @fn speak\n * @brief Synthesize speech. Chinese K10 firmware only.\n * @param prompt Text or number to synthesize\n */\nvoid speak(String prompt);\nvoid speak(const char *prompt);\nvoid speak(float prompt);\n````\n\n> **Firmware compatibility:** TTS (`setAsrSpeed` / `speak`) exists only in the Chinese K10 firmware. Confirm the firmware variant before using these methods. Refreshing CN model data alone does not prove that the installed firmware includes the TTS API.\n\nOfficial sources: [Arduino/PIO example](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_Example) and [Arduino/PIO API list](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_API_List).\n\nFile v0.1.9:references/k10-arduino-examples.md\n\n> Screen refresh rule: the examples below are API demonstrations, not permission to clear or redraw the whole screen in a fast loop. For animations, sensor values, dashboards, voice status, OTA status, and other repeated updates, redraw only changed regions. Use full-screen refresh only for initialization, page switches, exit cleanup, or when measured full-screen refresh is above 30 fps.\n\n## **Display-Set Back Ground Color**\nSetting the background color of the K10 screen<br/>\n````c++ title=\"Screen Display\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n}\nvoid loop() {\n\tk10.setScreenBackground(0xFFFFFF);\n\tdelay(2000);\n\tk10.setScreenBackground(0xFF0000);\n\tdelay(2000);\n\tk10.setScreenBackground(0x00FF00);\n\tdelay(2000);\n\tk10.setScreenBackground(0x0000FF);\n\tdelay(2000);\n\tk10.setScreenBackground(0x000000);\n\tdelay(2000);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus1.gif){: width=\"250px\"}\n\n## **Display-Electronic photo album**\nFormat the TF card to FAT32 and install it on K10. Press button A on the K10 to take a picture and button B to display it.<br/>\n\n!!! Note \n    TF card is need to run this programme\n\n````c++ title=\"Electronic photo album\"\n#include \"unihiker_k10.h\"\n\nvoid onButtonAPressed();\nvoid onButtonBPressed();\n\nUNIHIKER_K10 k10;\nuint8_t      screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.initBgCamerImage();\n\tk10.setBgCamerImage(false);\n\tk10.creatCanvas();\n\tk10.buttonA->setPressedCallback(onButtonAPressed);\n\tk10.initSDFile();\n\tk10.buttonB->setPressedCallback(onButtonBPressed);\n\tk10.setBgCamerImage(true);\n}\nvoid loop() {\n}\n\nvoid onButtonAPressed() {\n\tk10.photoSaveToTFCard(\"S:/photo.bmp\");\n}\nvoid onButtonBPressed() {\n\tk10.canvas->canvasDrawImage(0, 0, \"S:/photo.bmp\");\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus5.gif){: width=\"250px\"}\n\n\n## **Display-Showing text**\n````c++ title=\"Showing text\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.setScreenBackground(0xFFFFFF);\n\tk10.canvas->canvasText(\"UNIHIKER\", 1, 0x0000FF);\n\tk10.canvas->updateCanvas();\n\tdelay(1000);\n\tk10.canvas->canvasText(\"UNIHIKER\", 2, 0xFF0000);\n\tk10.canvas->updateCanvas();\n\tdelay(1000);\n\tk10.canvas->canvasText(\"UNIHIKER\", 3, 0x00FF00);\n\tk10.canvas->updateCanvas();\n\tdelay(1000);\n\tk10.canvas->canvasText(\"UNIHIKER\", 4, 0x000000);\n\tk10.canvas->updateCanvas();\n\tdelay(1000);\n}\nvoid loop() {\n}\n````\n![image.png](img/example_mindplus/exampleMindplus6.gif){: width=\"250px\"}\n\n## **Display-Draw Point**\n````c++ title=\"Draw Point\"\n#include \"unihiker_k10.h\"\n\nuint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b);\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.setScreenBackground(0x000000);\n}\nvoid loop() {\n\tfor (int index = 0; index < 50; index++) {\n\t\tk10.canvas->canvasPoint((random(0, 240+1)), (random(0, 320+1)), rgbToColor(round((random(128, 255+1))), round((random(128, 255+1))), round((random(128, 255+1)))));\n\t\tk10.canvas->updateCanvas();\n\t}\n\tk10.canvas->canvasClear();\n}\n\nuint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b)\n{\n  return (uint32_t)((((uint32_t)r<<16) | ((uint32_t)g<<8)) | (uint32_t)b);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus11.gif){: width=\"300px\"}\n\n## **Display-Draw Line**\nDrawing funnels on K10:<br/>\n````c++ title=\"Draw funnel\"\n#include \"unihiker_k10.h\"\n\nvolatile float startX, endX;\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.canvas->canvasSetLineWidth(1);\n\tstartX = 0;\n\tendX = 240;\n}\nvoid loop() {\n\twhile (!(startX==240)) {\n\t\tk10.canvas->canvasLine(startX, 0, endX, 320, 0xFF0000);\n\t\tk10.canvas->updateCanvas();\n\t\tstartX += 3;\n\t\tendX -= 3;\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus12.gif){: width=\"250px\"}<br/>\nMeteor shower on K10:<br/>\n````c++ title=\"Meteor shower\"\n#include \"unihiker_k10.h\"\n\nvolatile float startX, startY, length, endX, endY;\n\nuint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b);\n\nUNIHIKER_K10 k10;\nuint8_t      screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.setScreenBackground(0x000000);\n\tk10.canvas->canvasSetLineWidth(1);\n}\nvoid loop() {\n\tk10.canvas->canvasClear();\n\tfor (int index = 0; index < 15; index++) {\n\t\tstartX = (random(0, 240+1));\n\t\tstartY = (random(0, 180+1));\n\t\tlength = (random(0, 40+1));\n\t\tendX = (startX + length);\n\t\tendY = (startY + length);\n\t\tk10.canvas->canvasLine(startX, startY, endX, endY, rgbToColor(round((random(128, 255+1))), round((random(128, 255+1))), round((random(128, 255+1)))));\n\t}\n\tk10.canvas->updateCanvas();\n\tdelay(500);\n}\n\nuint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b)\n{\n  return (uint32_t)((((uint32_t)r<<16) | ((uint32_t)g<<8)) | (uint32_t)b);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus42.gif){: width=\"250px\"}\n\n\n## **Display-Draw Circle**\n````c++ title=\"Draw Circle\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.canvas->canvasCircle(120, 120, 40, 0xFFCC33, 0xFFCC33, true);\n\tk10.canvas->canvasCircle(160, 160, 40, 0xFFCC33, 0xFFCC33, true);\n\tk10.canvas->canvasCircle(120, 200, 40, 0xFFCC33, 0xFFCC33, true);\n\tk10.canvas->canvasCircle(80, 160, 40, 0xFFCC33, 0xFFCC33, true);\n\tk10.canvas->canvasCircle(120, 160, 40, 0xFFFF00, 0xFFFF00, true);\n\tk10.canvas->updateCanvas();\n}\nvoid loop() {\n}\n````\n![image.png](img/example_mindplus/exampleMindplus14.png){: width=\"250px\"}\n\n## **Display-Draw Rectangle**\n````c++ title=\"Draw Rectangle\"\n#include \"unihiker_k10.h\"\n\nvolatile float offset, x, y, color;\n\nuint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b);\n\nUNIHIKER_K10 k10;\nuint8_t      screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.setScreenBackground(0x000000);\n}\nvoid loop() {\n\tfor (int index = 0; index < 8; index++) {\n\t\tx = (80 - (offset / 2));\n\t\ty = (100 - (offset / 2));\n\t\tcolor = rgbToColor(round((random(50, 255+1))), round((random(50, 255+1))), round((random(50, 255+1))));\n\t\tk10.canvas->canvasRectangle(x,y, (80 + offset), (100 + offset), color, 0x0000FF, false);\n\t\tk10.canvas->updateCanvas();\n\t\tdelay(10);\n\t\toffset = (offset + 20);\n\t}\n\tk10.canvas->canvasClear();\n\toffset = 0;\n}\n\nuint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b)\n{\n  return (uint32_t)((((uint32_t)r<<16) | ((uint32_t)g<<8)) | (uint32_t)b);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus16.gif){: width=\"250px\"}\n\n## **Display-QR Code**\n````c++ title=\"QR Code\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.canvasDrawCode(\"https://www.unihiker.com\");\n\tk10.canvas->updateCanvas();\n}\nvoid loop() {\n}\n````\n![image.png](img/example_mindplus/exampleMindplus18.png)\n\n## **On board sensor-Button**\nNormal method:<br/>\n````c++ title=\"Button\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n}\nvoid loop() {\n\tif ((k10.buttonA->isPressed())) {\n\t\tk10.canvas->canvasRectangle(10, 100, 110, 100, 0xFF6666, 0x0000FF, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse if ((k10.buttonB->isPressed())) {\n\t\tk10.canvas->canvasCircle(180, 150, 50, 0xFF6666, 0x0000FF, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse if ((k10.buttonAB->isPressed())) {\n\t\tk10.canvas->canvasClear();\n\t\tk10.canvas->updateCanvas();\n\t}\n}\n````\nInterrupt method:<br/>\n````c++ title=\"Button\"\n#include \"unihiker_k10.h\"\n\nvoid onButtonAPressed();\nvoid onButtonBPressed();\nvoid onButtonABPressed();\n\nUNIHIKER_K10 k10;\nuint8_t      screen_dir=2;\n\nvoid onButtonAPressed() {\n\tk10.canvas->canvasRectangle(10, 100, 110, 100, 0xFF6666, 0x0000FF, true);\n\tk10.canvas->updateCanvas();\n}\nvoid onButtonBPressed() {\n\tk10.canvas->canvasCircle(180, 150, 50, 0xFF6666, 0x0000FF, true);\n\tk10.canvas->updateCanvas();\n}\nvoid onButtonABPressed() {\n\tk10.canvas->canvasClear();\n\tk10.canvas->updateCanvas();\n}\n\nvoid setup() {\n\tk10.begin();\n\tk10.buttonA->setPressedCallback(onButtonAPressed);\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.buttonB->setPressedCallback(onButtonBPressed);\n\tk10.buttonAB->setPressedCallback(onButtonABPressed);\n}\nvoid loop() {\n\n}\n````\n![image.gifg](img/example_mindplus/exampleMindplus20.gif){: width=\"250px\"}\n\n\n## **On board sensor-Accelerate sensors**\n\nDisplay screen tilt\n\n!!! Note \n    TF card is need to run this example, and the arrow pictures need to store in the TF card.\n\n\n````c++ title=\"Accelerate sensors\"\n#include \"unihiker_k10.h\"\nUNIHIKER_K10 k10;\nuint8_t      screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.initSDFile();\n}\nvoid loop() {\n\tif ((k10.isGesture(TiltForward))) {\n\t\tk10.canvas->canvasDrawImage(0, 0, \"S:/forward.png\");\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse if ((k10.isGesture(TiltBack))) {\n\t\tk10.canvas->canvasDrawImage(0, 0, \"S:/back.png\");\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse if ((k10.isGesture(TiltLeft))) {\n\t\tk10.canvas->canvasDrawImage(0, 0, \"S:/left.png\");\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse if ((k10.isGesture(TiltRight))) {\n\t\tk10.canvas->canvasDrawImage(0, 0, \"S:/right.png\");\n\t\tk10.canvas->updateCanvas();\n\t}\n\tk10.canvas->canvasRectangle(0, 0, 240, 320, 0xFFFFFF, 0xFFFFFF, true);\n\tk10.canvas->updateCanvas();\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus21.gif){: width=\"250px\"}<br/>\nPedo meter:<br/>\n````c++ title=\"Pedo meter\"\n#include \"unihiker_k10.h\"\n\nvolatile float step;\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tstep = 0;\n\tk10.canvas->canvasText((String(\"Pedometer: \") + String(step)), 1, 0x0000FF);\n\tk10.canvas->updateCanvas();\n}\nvoid loop() {\n\tif (((k10.getStrength())>1050)) {\n\t\tstep += 1;\n\t\tk10.canvas->canvasText((String(\"Pedometer: \") + String(step)), 1, 0x0000FF);\n\t\tk10.canvas->updateCanvas();\n\t\tdelay(1000);\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus43.gif){: width=\"250px\"}\n\n## **On board sensor-Accelerate ball**\n````c++ title=\"Accelerate ball\"\n#include \"unihiker_k10.h\"\n\nvolatile float accx, accy, moveX, moveY;\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n  k10.begin();\n  k10.initScreen(screen_dir);\n  k10.creatCanvas();\n  k10.setScreenBackground(0xFFFFFF);\n}\nvoid loop() {\n  accx = (k10.getAccelerometerX());\n  accy = (k10.getAccelerometerY());\n  moveX = (120 + (accx / 3));\n  moveY = (160 + (accy / 3));\n  k10.canvas->canvasCircle(moveX, moveY, 8, 0x00FF00, 0x00FF00, true);\n  k10.canvas->updateCanvas();\n  k10.canvas->canvasCircle(moveX, moveY, 9, 0xFFFFFF, 0xFFFFFF, true);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus23.gif){: width=\"250px\"}\n\n## **On board sensor-RGB control**\n````c++ title=\"RGB control\"\n#include \"unihiker_k10.h\"\n\nvolatile float mind_n_brightness;\n\nUNIHIKER_K10 k10;\n\nvoid setup() {\n\tk10.begin();\n\tmind_n_brightness = 0;\n\tk10.rgb->brightness(round(mind_n_brightness));\n\tk10.rgb->write(-1, 0x0000FF);\n}\nvoid loop() {\n\twhile (!(mind_n_brightness==9)) {\n\t\tk10.rgb->brightness(round(mind_n_brightness));\n\t\tk10.rgb->write(-1, 0x0000FF);\n\t\tdelay(200);\n\t\tmind_n_brightness += 1;\n\t}\n\twhile (!(mind_n_brightness==0)) {\n\t\tk10.rgb->brightness(round(mind_n_brightness));\n\t\tk10.rgb->write(-1, 0x0000FF);\n\t\tdelay(200);\n\t\tmind_n_brightness -= 1;\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus24.gif){: width=\"250px\"}\n\n## **Audio-Play build-in music**\nPress button A to play the music \"BIRTHDAY\" in the background; press button B to play the alphabet song (1155661)<br/>\n````c++ title=\"Play build-in music\"\n#include \"unihiker_k10.h\"\n\nvoid onButtonAPressed();\nvoid onButtonBPressed();\n\nUNIHIKER_K10 k10;\nMusic music;\n\nvoid setup() {\n\tk10.begin();\n\tk10.buttonA->setPressedCallback(onButtonAPressed);\n\tk10.buttonB->setPressedCallback(onButtonBPressed);\n}\nvoid loop() {\n}\n\nvoid onButtonAPressed() {\n\tmusic.playMusic(DADADADUM);\n}\nvoid onButtonBPressed() {\n\tmusic.stopPlayTone();\n\tmusic.playTone(131,  8000);\n\tmusic.playTone(131,  8000);\n\tmusic.playTone(196,  8000);\n\tmusic.playTone(196,  8000);\n\tmusic.playTone(220,  8000);\n\tmusic.playTone(220,  8000);\n\tmusic.playTone(196,  8000);\n}\n````\n\n## **Audio-Record and play**\nPress button A to record 3 seconds of audio and store it to the TF card; press button B to play the recorded audio.<br/>Note: TF card is need to run this example\n````c++ title=\"Record and play\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\nMusic music;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.initSDFile();\n\tk10.canvas->canvasText(\"Press A to record......\", 5, 10, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\tk10.canvas->updateCanvas();\n}\nvoid loop() {\n\tif ((k10.buttonA->isPressed())) {\n\t\tk10.canvas->canvasText(\"Recording\", 5, 10, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t\tmusic.recordSaveToTFCard(\"S:/sound.wav\", 3);\n\t\tk10.canvas->canvasText(\"Record complete\", 5, 10, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse if ((k10.buttonB->isPressed())) {\n\t\tk10.canvas->canvasText(\"Playing......\", 5, 10, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t\tmusic.playTFCardAudio(\"S:/sound.wav\");\n\t\tdelay(3000);\n\t\tk10.canvas->canvasText(\"Play complete\", 0, 0, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n}\n````\n\n## **AI-Face detection**\nTurn on the camera, detect the face, and display the detected face length and width, as well as center point x and center point y coordinates, on the K10 screen<br/>\n````c++ title=\"Face detection\"\n#include \"unihiker_k10.h\"\n#include \"AIRecognition.h\"\n\nUNIHIKER_K10  k10;\nuint8_t screen_dir=2;\nAIRecognition ai;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tai.initAi();\n\tk10.initBgCamerImage();\n\tk10.setBgCamerImage(false);\n\tk10.creatCanvas();\n\tai.switchAiMode(ai.NoMode);\n\tk10.setBgCamerImage(true);\n\tai.switchAiMode(ai.Face);\n}\nvoid loop() {\n\tif (ai.isDetectContent(AIRecognition::Face)) {\n\t\tk10.canvas->canvasText((String(\"Face Length\") + String(ai.getFaceData(AIRecognition::Length))), 0, 0, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->canvasText((String(\"Face Width \") + String(ai.getFaceData(AIRecognition::Length))), 0, 16, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->canvasText((String(\"Face Center X\") + String(ai.getFaceData(AIRecognition::CenterX))), 0, 32, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->canvasText((String(\"Face Center Y\") + String(ai.getFaceData(AIRecognition::CenterY))), 0, 32, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\tdelay(1000);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus27.gif) \n\n## **AI-Face recognition**\nPress button A to learn the face and green LED on; press button B to recognize the face and blue LED on, and display the recognized face ID on the K10 screen<br/>\n````c++ title=\"Face recognition\"\n#include \"unihiker_k10.h\"\n#include \"AIRecognition.h\"\n\nString ID;\n\nvoid onButtonAPressed();\nvoid onButtonBPressed();\n\nUNIHIKER_K10  k10;\nuint8_t screen_dir=2;\nAIRecognition ai;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tai.initAi();\n\tk10.initBgCamerImage();\n\tk10.setBgCamerImage(false);\n\tk10.creatCanvas();\n\tai.switchAiMode(ai.NoMode);\n\tk10.buttonA->setPressedCallback(onButtonAPressed);\n\tk10.buttonB->setPressedCallback(onButtonBPressed);\n\tk10.setBgCamerImage(true);\n\tai.switchAiMode(ai.Face);\n}\nvoid loop() {\n\tif (ai.isRecognized()) {\n\t\tID = ai.getRecognitionID();\n\t\tk10.canvas->canvasText((String(\"Face ID: \") + String(ID)), 0, 0, 0x0000FF, k10.canvas->eCNAndENFont24, 50, true);\n\t\tk10.canvas->canvasText(ID, 0, 40, 0x0000FF, k10.canvas->eCNAndENFont24, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\tdelay(1000);\n}\n\nvoid onButtonAPressed() {\n\tk10.rgb->write(-1, 0x00FF00);\n\tai.sendFaceCmd(ENROLL);\n}\nvoid onButtonBPressed() {\n\tk10.rgb->write(-1, 0x0000FF);\n\tai.sendFaceCmd(RECOGNIZE);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus28.gif){: width=\"250px\"}\n\n## **AI-Dog/Cat recognition**\nTurn on the camera, when the camera detects the detection of the cat, the length and width of the cat's face, as well as the coordinates of the center point x and center point y, are displayed on the K10 screen.<br/>\n````c++ title=\"AI-Dog/Cat recognition\"\n#include \"unihiker_k10.h\"\n#include \"AIRecognition.h\"\n\nUNIHIKER_K10  k10;\nuint8_t screen_dir=2;\nAIRecognition ai;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tai.initAi();\n\tk10.initBgCamerImage();\n\tk10.setBgCamerImage(false);\n\tk10.creatCanvas();\n\tai.switchAiMode(ai.NoMode);\n\tk10.setBgCamerImage(true);\n\tai.switchAiMode(ai.Cat);\n}\nvoid loop() {\n\tif (ai.isDetectContent(AIRecognition::Cat)) {\n\t\tk10.canvas->canvasText((String(\"Face Length: \") + String(ai.getCatData(AIRecognition::Length))), 0, 0, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->canvasText((String(\"Face Width: \") + String(ai.getCatData(AIRecognition::Width))), 0, 20, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->canvasText((String(\"Face X: \") + String(ai.getCatData(AIRecognition::CenterX))), 0, 40, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->canvasText((String(\"Face Y:  \") + String(ai.getCatData(AIRecognition::CenterY))), 0, 60, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus29.gif){: width=\"250px\"}\n\n## **AI-Movement Detection**\n````c++ title=\"Movement Detection\"\n#include \"unihiker_k10.h\"\n#include \"AIRecognition.h\"\n\nUNIHIKER_K10  k10;\nuint8_t screen_dir=2;\nAIRecognition ai;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tai.initAi();\n\tk10.initBgCamerImage();\n\tk10.setBgCamerImage(false);\n\tk10.creatCanvas();\n\tai.switchAiMode(ai.NoMode);\n\tk10.setBgCamerImage(true);\n\tai.switchAiMode(ai.Move);\n\tai.setMotinoThreshold(50);\n\tk10.rgb->write(-1, 0x0000FF);\n}\nvoid loop() {\n\tif (ai.isDetectContent(AIRecognition::Move)) { \n\t\tk10.rgb->write(-1, 0xFF0000);\n\t}\n\telse {\n\t\tk10.rgb->write(-1, 0x0000FF);\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus44.gif){: width=\"300px\"}\n\n## **AI-QR Code Scanner**\nYou can generate your own QR code through some free [QR code generation sites](https://www.qr-code-generator.com/). <br/>\n\n!!! Note \n     Note: TF card is need to run this example, and the Album Cover picture needs to be stored in TF card.\n\n\nBelow is the \"Album cover\" QR code we generated\n````c++ title=\"QR Code Scanner\"\n#include \"unihiker_k10.h\"\n#include \"AIRecognition.h\"\n\nUNIHIKER_K10  k10;\nuint8_t screen_dir=2;\nAIRecognition ai;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tai.initAi();\n\tk10.initBgCamerImage();\n\tk10.setBgCamerImage(false);\n\tk10.creatCanvas();\n\tai.switchAiMode(ai.NoMode);\n\tk10.initSDFile();\n\tk10.setBgCamerImage(true);\n\tai.switchAiMode(ai.Code);\n}\nvoid loop() {\n\tif (ai.isDetectContent(AIRecognition::Code)) {\n\t\tif ((ai.getQrCodeContent()==String(\"Album cover\"))) {\n\t\t\tk10.canvas->canvasDrawImage(0, 0, \"S:/AlbumCover.png\");\n\t\t\tk10.canvas->updateCanvas();\n\t\t}\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus30.gif){: width=\"300px\"}\n![image.png](img/example_mindplus/exampleMindplus45.png){: width=\"200px\"}\n\n## **AI-Speech recognition**\nWake up the voice recognition through the wake-up command \"Hi,Telly\", and then through the command word \"Light on\", \"Light off\" to control the on-board RGB ELD lights on K10 to turn on and off. <br/>\n````c++ title=\"Speech recognition\"\n#include \"asr.h\"\n#include \"unihiker_k10.h\"\n// Create an object\nUNIHIKER_K10 k10;\nASR          asr;\nuint8_t      screen_dir=2;\n\n\n// Main program start\nvoid setup() {\n\tk10.begin();\n\tasr.asrInit(CONTINUOUS, CN_MODE, 6000);\n\twhile(asr._asrState == 0){delay(100);}\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tasr.addASRCommand(1, \"kai deng\");//中文语音识别时参数写拼音，并且每个字中间要有空格\n\tasr.addASRCommand(2, \"guan deng\");\n}\nvoid loop() {\n\tif (asr.isWakeUp()) {\n\t\tk10.canvas->canvasText(\"Wake up mode\", 0, 0, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\telse {\n\t\tk10.canvas->canvasText(\"Sleep mode\", 0, 0, 0x0000FF, k10.canvas->eCNAndENFont16, 50, true);\n\t\tk10.canvas->updateCanvas();\n\t}\n\tif (asr.isDetectCmdID(1)) {\n\t\tk10.rgb->brightness(round(9));\n\t\tk10.rgb->write(-1, 0xFF0000);\n\t}\n\telse if (asr.isDetectCmdID(2)) {\n\t\tk10.rgb->brightness(round(0));\n\t\tk10.rgb->write(-1, 0xFF0000);\n\t}\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus31.gif){: width=\"400px\"}\n\n## **GPIO**\nSince the camera and display take up a lot of GPIOs on the ESP32 chip, we only left two full-function GPIOs (digital input/output, analogue input, PWM output) at P0,P1.\nThe GPIOs out of Edge Connector are all led from the on-board GPIO expansion chip, and only have digital input/output function.<br/>\n````c++ title=\"Digital input/output\"\nvoid setup() {\n\tpinMode(P0, OUTPUT);\n\tpinMode(P1, INPUT);\n\tSerial.begin(9600);\n\tdigitalWrite(P0, HIGH);\n}\nvoid loop() {\n\tSerial.println((digitalRead(P1)));\n}\n````\n\n````c++ title=\"Analog input/ PWM output\"\nvoid setup() {\n\tSerial.begin(9600);\n\tanalogWrite(P0, map(512, 0, 1023, 0, 255));\n}\nvoid loop() {\n\tSerial.println((analogRead(P1)));\n}\n````\n\n````c++ title=\"Digital input/output(Extended GPIO)\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\n\nvoid setup() {\n\tk10.begin();\n\tSerial.begin(9600);\n\tdigital_write(eP2, HIGH);\n}\nvoid loop() {\n\tSerial.println((digital_read(eP3)));\n}\n````\n\n````c++ title=\"屏幕上显示所有板载温湿度，环境光强度，加速度x,y,z轴，加速度强度\"\n#include \"unihiker_k10.h\"\n// 创建对象\nUNIHIKER_K10 k10;\nAHT20        aht20;\nuint8_t      screen_dir=2;\n\n\n// 主程序开始\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n}\nvoid loop() {\n\tk10.canvas->canvasText(aht20.getData(AHT20::eAHT20TempC), 1, 0x0000FF);\n\tk10.canvas->canvasText(aht20.getData(AHT20::eAHT20TempF), 2, 0x0000FF);\n\tk10.canvas->canvasText(aht20.getData(AHT20::eAHT20HumiRH), 3, 0x0000FF);\n\tk10.canvas->canvasText(k10.readALS(), 4, 0x0000FF);\n\tk10.canvas->canvasText((k10.getAccelerometerX()), 5, 0x0000FF);\n\tk10.canvas->canvasText((k10.getAccelerometerY()), 6, 0x0000FF);\n\tk10.canvas->canvasText((k10.getAccelerometerZ()), 7, 0x0000FF);\n\tk10.canvas->canvasText((k10.getStrength()), 8, 0x0000FF);\n\tk10.canvas->updateCanvas();//更新屏幕显示文字，每次调用k10.canvas->canvasText()或任何屏幕缓存显示的函数，必须调用k10.canvas->updateCanvas()后才能显示\n\tdelay(1000);\n\tk10.canvas->canvasClear();//清除屏幕显示文字\n}\n````\n\n\n## AI-语音合成（仅中文版固件）\n\n> **重要：** `setAsrSpeed()` 和 `speak()` 只存在于 K10 中文版固件。刷新 CN 模型数据不等同于切换为中文版固件；编译或运行前必须确认固件版本。\n\n````c++ title=\"按键触发语音合成\"\n#include \"asr.h\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nASR asr;\n\nvoid onButtonAPressed();\nvoid onButtonBPressed();\n\nvoid setup() {\n\tk10.begin();\n\tasr.setAsrSpeed(2);\n\tk10.buttonA->setPressedCallback(onButtonAPressed);\n\tk10.buttonB->setPressedCallback(onButtonBPressed);\n\tasr.speak(\"你好\");\n}\nvoid loop() {\n\n}\n\nvoid onButtonAPressed() {\n\tasr.speak(\"我是行空板\");\n}\nvoid onButtonBPressed() {\n\tasr.speak(\"语音合成\");\n}\n````\n\n`setAsrSpeed(uint8_t speed)` 的范围为 `0~5`。`speak()` 支持 `String`、`const char *` 和 `float`。\n\n官方资料：[Arduino/PIO 示例代码](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_Example)、[Arduino/PIO API 手册](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_API_List)。\n\nFile v0.1.9:references/platformio-workshop.md\n\n# PlatformIO Workshop Notes for UNIHIKER K10\n\n## Why Predownload\n\nThe first K10 PlatformIO build downloads DFRobot's PlatformIO platform, the K10 Arduino framework, compiler toolchains, and upload/build tools. The largest pieces are the K10 Arduino framework and ESP32 toolchains. A prepared machine measured these approximate uncompressed sizes:\n\n| Directory | Purpose | Size |\n| --- | --- | --- |\n| `platforms/unihiker` | DFRobot platform definition | 536 KB |\n| `packages/framework-arduinounihiker` | K10 Arduino framework and libraries | 518 MB |\n| `packages/toolchain-xtensa-esp32s3` | ESP32-S3 compiler toolchain | 268 MB |\n| `packages/toolchain-riscv32-esp` | RISC-V helper toolchain used during K10 builds | can be large |\n| `packages/toolchain-xtensa-esp32` | Base ESP32 compiler toolchain declared by platform; include when present for conservative bundles | 387 MB |\n| `packages/tool-esptoolpy` | Upload tool | 2.6 MB |\n| `packages/tool-scons` | Build tool | 4.9 MB |\n| `packages/tool-mkfatfs`, `tool-mklittlefs`, `tool-mkspiffs` | Filesystem image tools for related upload targets | a few MB |\n\nA minimal compressed bundle from only the K10 framework plus Xtensa S3 pieces was about 459 MB on macOS. A conservative workshop bundle that includes every tool used or declared by the K10 platform will be larger. Exact sizes differ by OS and CPU architecture.\n\n## Prepare a Teacher Machine\n\nInstall PlatformIO Core, then create a probe project:\n\n```bash\nbash scripts/init-k10-platformio-project.sh /tmp/k10-pio-probe\npio run -d /tmp/k10-pio-probe\n```\n\nAfter the build succeeds, create the bundle:\n\n```bash\nbash scripts/prepare-offline-bundle.sh /tmp/k10-platformio-bundle.tgz\n```\n\nMake one bundle per supported OS and CPU architecture. Do not share a macOS arm64 bundle with Windows or Linux machines.\n\n## macOS Self-Contained USB Installer\n\nUse this for Apple Silicon Macs when students should not install PlatformIO or download Python packages during class. The package is a self-extracting `.command` file, not a system-wide `.pkg`; it does not need administrator permissions and can be copied from a USB drive. Intel Macs are not supported.\n\nOn a prepared teacher Mac:\n\n```bash\nbash scripts/init-k10-platformio-project.sh /tmp/k10-pio-probe\npio run -d /tmp/k10-pio-probe\nbash scripts/prepare-macos-offline-installer.sh --self-extracting /tmp/K10P-macos-arm64.command\n```\n\nCopy the resulting `.command` file to the USB drive.\n\nOn each student Mac:\n\n```bash\n/Volumes/USB/K10P-macos-arm64.command\n~/K10P/pio --version\n~/K10P/pio run -d ~/K10P/examples/Blink\n```\n\nThen use the bundled wrappers:\n\n```bash\n~/K10P/compile-project \"/path/to/PlatformIOProject\"\n~/K10P/upload-project \"/path/to/PlatformIOProject\" /dev/cu.usbmodemXXXX\n~/K10P/monitor-project \"/path/to/PlatformIOProject\" /dev/cu.usbmodemXXXX\n```\n\nThe self-extracting installer unpacks into `~/K10P`, creates a private `penv`, and installs PlatformIO from the included `wheelhouse` using `--no-index`. It also uses the bundled `~/K10P/.platformio` support directory for K10 toolchains and framework files. Student setup should not need internet after the installer has been prepared.\n\nThe macOS wheelhouse explicitly includes `typing-extensions` for student Macs running Python older than 3.13. If an older installer fails with `No matching distribution found for typing-extensions>=4.10.0`, rebuild the installer with the current `prepare-macos-offline-installer.sh`. For a one-off repair on an extracted `~/K10P`, download the missing wheel on an internet-connected machine and copy it into `~/K10P/wheelhouse`:\n\n```bash\npython3 -m pip download --dest /path/to/K10P/wheelhouse \"typing-extensions>=4.10.0\"\n```\n\nmacOS still needs a local `python3` executable to create the private virtual environment. If it is missing, install Apple's Command Line Tools or Python 3 before class. If Gatekeeper quarantine blocks the copied scripts, run:\n\n```bash\nxattr -d com.apple.quarantine /Volumes/USB/K10P-macos-arm64.command\nxattr -dr com.apple.quarantine \"$HOME/K10P\"\n```\n\n## Windows Self-Contained USB Installer\n\nUse this for Windows x64 workshops when students should not install PlatformIO or Python and should not download packages during class. The package is a relocatable folder archive, not a system-wide installer; it does not need administrator permissions and can be copied from a USB drive.\n\nOn a prepared teacher Windows machine:\n\n```powershell\n# First build any K10 PlatformIO project successfully so PlatformIO downloads all support files.\npio run -d C:\\path\\to\\k10-pio-probe\npowershell -ExecutionPolicy Bypass -File scripts\\prepare-windows-offline-installer.ps1 C:\\tmp\\K10P-windows-x64.exe\n```\n\nCopy the resulting `.exe` to the USB drive.\n\nOn each student Windows machine, run the self-extracting installer:\n\n```powershell\nE:\\K10P-windows-x64.exe\ncd C:\\K10P\n.\\pio.bat --version\n.\\pio.bat run -d .\\examples\\Blink\n```\n\nFor user projects, prefer the bundled wrappers:\n\n```powershell\nC:\\K10P\\compile-project.bat \"C:\\path\\to\\PlatformIOProject\"\nC:\\K10P\\upload-project.bat \"C:\\path\\to\\PlatformIOProject\" COM3\nC:\\K10P\\monitor-project.bat \"C:\\path\\to\\PlatformIOProject\" COM3\n```\n\nKeep both the installer folder and student projects in short paths such as `C:\\K10P` and `C:\\K10Work`. The wrappers set `PLATFORMIO_CORE_DIR` and `PYTHONPATH` to the private bundled `.platformio` directory. Students should use the bundled `pio.bat` or `platformio.bat`, not a system `pio` command.\n\n## Install on Student Machines\n\nCopy the bundle by USB drive, local file share, or classroom LAN. Then run:\n\n```bash\nbash scripts/install-offline-bundle.sh /path/to/k10-platformio-bundle.tgz\nbash scripts/doctor-offline.sh\n```\n\nIf PlatformIO uses a custom core directory, set `PLATFORMIO_CORE_DIR` during installation and during later builds:\n\n```bash\nexport PLATFORMIO_CORE_DIR=\"$HOME/.platformio\"\nbash scripts/install-offline-bundle.sh /path/to/k10-platformio-bundle.tgz\n```\n\n## Verify Offline Readiness\n\nRun:\n\n```bash\npio pkg list -g | grep -E 'unihiker|framework-arduinounihiker|xtensa-esp32s3'\nbash scripts/doctor-offline.sh\npio run -d /path/to/k10-project\n```\n\nThe second command should not need to download the K10 platform, K10 framework, or ESP32-S3 toolchain.\n\n## Troubleshooting\n\nIf PlatformIO downloads files anyway:\n\n- Confirm the bundle was installed into the active PlatformIO core directory.\n- Confirm OS/CPU architecture matches the teacher machine.\n- Confirm `platformio.ini` uses the same platform URL or pinned commit used to prepare the bundle.\n- Run `pio pkg list -g` and check for `unihiker`, `framework-arduinounihiker`, and `toolchain-xtensa-esp32s3`.\n- Check for `toolchain-riscv32-esp` if the first build still tries to download tools.\n\nIf the build fails with:\n\n```text\nModuleNotFoundError: No module named 'intelhex'\n```\n\nthe local PlatformIO Python/tool installation is incomplete. Repair or reinstall PlatformIO Core before the workshop image is used as the source for offline bundles.\n\nIf uploads fail:\n\n- Run `pio device list` and pass the serial port with `--upload-port`.\n- Check USB cable data capability.\n- On Linux, install PlatformIO udev rules and reconnect the board.\n- Try the K10 boot/reset procedure if the board is not entering upload mode.\n\n## Pinning for Repeatable Workshops\n\nFor a workshop, consider pinning the DFRobot platform to a known commit in `platformio.ini`:\n\n```ini\nplatform = https://github.com/DFRobot/platform-unihiker.git#508e31875ad92205bf946e28570fb78fc01ceb2e\n```\n\nPinning prevents a later GitHub update from invalidating the prepared cache.\n\nFile v0.1.9:skill-card.md\n\n## Description: <br>\nUse when programming a UNIHIKER K10 board with PlatformIO CLI, creating or converting Arduino/C++ K10 projects to PlatformIO, building, uploading, monitoring serial output, diagnosing K10 PlatformIO setup, or preparing/installing offline PlatformIO support for workshops, including macOS archives and Windows self-extracting USB installers. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[rockets-cn](https://clawhub.ai/user/rockets-cn) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers, educators, and workshop facilitators use this skill to create, build, upload, monitor, and troubleshoot UNIHIKER K10 PlatformIO projects, including offline setup workflows for classrooms or labs. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: Local helper scripts can run PlatformIO build, upload, monitor, bundle creation, and archive extraction workflows. <br>\nMitigation: Review commands and paths before execution, use trusted offline bundles only, and run scripts only in the intended project or PlatformIO core directories. <br>\nRisk: Camera, face recognition, microphone, and voice examples can involve privacy-sensitive capture or playback around other people. <br>\nMitigation: Use consent and notice practices before running those examples, especially in classroom or shared environments. <br>\nRisk: K10 AI or OTA projects can overwrite factory model data if generic partition layouts overlap reserved model regions. <br>\nMitigation: Follow the bundled AI model flashing reference and preserve the documented model, voice_data, and fr flash offsets. <br>\nRisk: Speech synthesis APIs are documented as Chinese-firmware-only. <br>\nMitigation: Confirm the installed K10 firmware variant before generating or compiling TTS code. <br>\n\n\n## Reference(s): <br>\n- [K10 AI Model Flashing and Recovery](references/k10-ai-model-flash.md) <br>\n- [UNIHIKER K10 Arduino API](references/k10-arduino-api.md) <br>\n- [UNIHIKER K10 Arduino Examples](references/k10-arduino-examples.md) <br>\n- [PlatformIO Workshop Notes for UNIHIKER K10](references/platformio-workshop.md) <br>\n- [DFRobot PlatformIO Platform for UNIHIKER](https://github.com/DFRobot/platform-unihiker.git) <br>\n- [Official Arduino/PIO Example](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_Example) <br>\n- [Official Arduino/PIO API List](https://www.unihiker.com.cn/wiki/k10/Arduino_PIO_API_List) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [Text, Markdown, Code, Shell commands, Configuration, Files, Guidance] <br>\n**Output Format:** [Markdown guidance with inline shell commands, PlatformIO configuration, and C++ code snippets] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [May direct local scripts to create PlatformIO projects, run build/upload/monitor commands, and prepare or install offline support bundles.] <br>\n\n## Skill Version(s): <br>\n0.1.9 (source: server release metadata) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nFile v0.1.9:agents/openai.yaml\n\ninterface:\r\n  display_name: \"UNIHIKER K10 PlatformIO\"\r\n  short_description: \"K10 PlatformIO builds and USB offline setup\"\r\n  default_prompt: \"Use $unihiker-k10-platformio to create, build, upload, or prepare a USB offline installer for a UNIHIKER K10 PlatformIO project.\"\n\nFile v0.1.9:examples/tts-buttons/platformio.ini\n\n[env:unihiker]\nplatform = https://github.com/DFRobot/platform-unihiker.git\nboard = unihiker_k10\nframework = arduino\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n    -DModel=None\n\nArchive v0.1.8: 17 files, 31786 bytes\n\nFiles: agents/openai.yaml (275b), references/k10-ai-model-flash.md (2912b), references/k10-arduino-api.md (9322b), references/k10-arduino-examples.md (23097b), references/platformio-workshop.md (7550b), scripts/doctor-offline.sh (1519b), scripts/init-k10-platformio-project.sh (1071b), scripts/install-offline-bundle.ps1 (703b), scripts/install-offline-bundle.sh (592b), scripts/k10-pio.ps1 (1862b), scripts/k10-pio.sh (1919b), scripts/prepare-macos-offline-installer.sh (9475b), scripts/prepare-offline-bundle.sh (1211b), scripts/prepare-windows-offline-installer.ps1 (11333b), skill-card.md (2886b), SKILL.md (13253b), _meta.json (142b)\n\nFile v0.1.8:SKILL.md\n\n---\nname: unihiker-k10-platformio\ndescription: Use when programming a UNIHIKER K10 board with PlatformIO CLI, creating or converting Arduino/C++ K10 projects to PlatformIO, building, uploading, monitoring serial output, diagnosing K10 PlatformIO setup, or preparing/installing offline PlatformIO support for workshops, including macOS archives and Windows self-extracting USB installers.\n---\n\n# UNIHIKER K10 - PlatformIO\n\n## Overview\n\nUse PlatformIO Core CLI for UNIHIKER K10 Arduino/C++ development. Prefer this skill when the user wants a PlatformIO-based workflow instead of `arduino-cli`, especially for workshops that need predownloaded support files.\n\nCore PlatformIO environment:\n\n```ini\n[env:unihiker]\nplatform = https://github.com/DFRobot/platform-unihiker.git\nboard = unihiker_k10\nframework = arduino\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n    -DModel=None\n```\n\nK10 uses DFRobot's PlatformIO platform and Arduino framework package. First build downloads a large framework and toolchains; avoid doing this from every student machine during a workshop.\n\nIf a project uses K10 AI, voice recognition, TTS, face recognition, or OTA partitions, preserve the factory model-data offsets. Read the repository reference `references/k10-ai-model-flash.md` when available, or follow the model rules below.\n\nScreen refresh policy: generated K10 display code must prefer partial redraws. Full-screen clearing or full-background redraw causes visible flicker and is uncomfortable; use it only for initialization, page switches, exit cleanup, or when measured full-screen refresh is above 30 fps.\n\n## Quick Workflow\n\n### Windows Self-Contained Offline Installer\n\nFor Windows machines with no PlatformIO or Python environment installed, use the self-contained K10 PlatformIO offline installer first. It installs an isolated PlatformIO environment and does not require system `pio`.\n\nPrepare the Windows x64 self-extracting installer on a teacher Windows machine after one successful K10 PlatformIO build:\n\n```powershell\npowershell -ExecutionPolicy Bypass -File scripts\\prepare-windows-offline-installer.ps1 C:\\tmp\\K10P-windows-x64.exe\n```\n\nCopy the resulting `.exe` to the USB drive. Run it on each student Windows machine; it extracts to `C:\\K10P` and runs `setup-platformio.bat`.\n\nKnown install locations to check, in order:\n\n```text\nC:\\K10P\n%USERPROFILE%\\K10P\n%LOCALAPPDATA%\\K10P\n%LOCALAPPDATA%\\K10PlatformIO\n```\n\nCheck this location before assuming PlatformIO is missing:\n\n```powershell\ncd C:\\K10P\n.\\setup-platformio.bat\n.\\pio.bat --version\n.\\pio.bat run -d .\\examples\\Blink\n```\n\nImportant: use the bundled `pio.bat` or `platformio.bat` wrappers. Do not call `.platformio\\penv\\Scripts\\pio.exe` or `.platformio\\penv\\Scripts\\python.exe` directly; Windows launcher/venv executables can contain absolute paths from the machine that built the bundle or break under non-ASCII usernames. The wrapper uses `.platformio\\python3\\python.exe -m platformio` with `PYTHONPATH` set to the bundled site-packages.\n\nFor user projects:\n\n```powershell\nC:\\K10P\\compile-project.bat \"C:\\path\\to\\PlatformIOProject\"\nC:\\K10P\\upload-project.bat \"C:\\path\\to\\PlatformIOProject\" COM3\n```\n\n### macOS Self-Contained Offline Installer\n\nFor Apple Silicon macOS workshops, prepare a self-extracting `.command` installer on the teacher Mac and copy it by USB drive. This avoids each student downloading the large K10 PlatformIO platform, framework, toolchains, and PlatformIO Python packages. Intel Macs are not supported.\n\nPrepare the Apple Silicon self-extracting installer:\n\n```bash\n# On a prepared teacher Mac after one successful K10 PlatformIO build\nbash scripts/prepare-macos-offline-installer.sh --self-extracting /tmp/K10P-macos-arm64.command\n```\n\nOn each student Mac:\n\n```bash\n/Volumes/USB/K10P-macos-arm64.command\n~/K10P/pio --version\n~/K10P/pio run -d ~/K10P/examples/Blink\n```\n\nFor user projects:\n\n```bash\n~/K10P/compile-project \"/path/to/PlatformIOProject\"\n~/K10P/upload-project \"/path/to/PlatformIOProject\" /dev/cu.usbmodemXXXX\n```\n\nImportant: use the bundled `~/K10P/pio` or `~/K10P/platformio` wrappers. They set `PLATFORMIO_CORE_DIR` to the private bundled `.platformio` directory so builds do not depend on or modify the user's global PlatformIO installation.\n\nThe macOS bundle still needs a local `python3` to create its private virtual environment. It does not need internet during student setup. If macOS blocks files copied from a downloaded archive, remove quarantine on the installer or copied folder:\n\n```bash\nxattr -d com.apple.quarantine /Volumes/USB/K10P-macos-arm64.command\nxattr -dr com.apple.quarantine \"$HOME/K10P\"\n```\n\nIf macOS setup fails offline with `No matching distribution found for typing-extensions>=4.10.0`, the installer was built with an older script that omitted a conditional PlatformIO dependency needed by Python older than 3.13. Rebuild the installer with `scripts/prepare-macos-offline-installer.sh`, or add `typing-extensions` to the extracted `wheelhouse`.\n\nBefore writing K10 application code, read the relevant local references:\n\n- `references/k10-arduino-api.md` for K10 C++ API signatures.\n- `references/k10-arduino-examples.md` for working examples, including display, RGB, sensors, audio, AI, TTS, and ASR.\n\n1. Check PlatformIO:\n\n```bash\npio --version\n```\n\nIf missing, install PlatformIO Core using the official installer script or package manager. Do not use sudo/admin unless the user explicitly needs a system-wide install.\n\n2. Create or normalize a K10 project:\n\n```bash\nbash path/to/unihiker-k10-platformio/scripts/init-k10-platformio-project.sh my-k10-project\n```\n\n3. Put code in `src/main.cpp`. For `.ino` sketches, preserve the same Arduino code but make sure function prototypes/includes are valid C++.\n\n4. Build:\n\n```bash\npio run -d my-k10-project\n```\n\n5. Upload:\n\n```bash\npio run -d my-k10-project -t upload --upload-port /dev/cu.usbmodemXXXX\n```\n\nIf no port is provided, PlatformIO may auto-detect. Use `pio device list` when upload fails or multiple boards are connected.\n\n6. Monitor serial:\n\n```bash\npio device monitor -d my-k10-project --port /dev/cu.usbmodemXXXX\n```\n\n## Bundled Scripts\n\n- `scripts/init-k10-platformio-project.sh`: create a minimal K10 PlatformIO project with sample screen code.\n- `scripts/k10-pio.sh`: convenience wrapper for `doctor`, `ports`, `build`, `upload`, and `monitor`.\n- `scripts/prepare-offline-bundle.sh`: build once, collect K10 PlatformIO support files, and create a distributable `.tgz`.\n- `scripts/prepare-macos-offline-installer.sh`: create an Apple Silicon macOS self-contained installer `.tgz` with bundled K10 support files, PlatformIO wheels, wrappers, and a Blink probe project.\n- `scripts/prepare-windows-offline-installer.ps1`: create a Windows x64 self-extracting installer `.exe` with bundled K10 support files, PlatformIO Python runtime, wrappers, and a Blink probe project. Passing a `.zip` output path is still supported as a fallback archive format.\n- `scripts/install-offline-bundle.sh`: install a prepared bundle into a user's PlatformIO core directory.\n- `scripts/doctor-offline.sh`: verify that the required K10 PlatformIO packages are present before class.\n- `scripts/k10-pio.ps1` and `scripts/install-offline-bundle.ps1`: Windows PowerShell helpers for common operations and bundle installation.\n\nPrefer scripts for repeated workshop setup. Read `references/platformio-workshop.md` before changing offline bundle behavior.\n\n## Workshop Offline Bundle\n\nUse an offline bundle when many learners will build K10 projects in the same room.\n\nExpected support-file sizes after first successful build vary by OS/CPU, but the important K10 pieces are roughly:\n\n| Directory | Purpose | Typical uncompressed size |\n| --- | --- | --- |\n| `platforms/unihiker` | DFRobot PlatformIO platform | <1 MB |\n| `packages/framework-arduinounihiker` | K10 Arduino framework, SDK, libraries | ~500 MB |\n| `packages/toolchain-xtensa-esp32s3` | ESP32-S3 compiler toolchain | ~250-300 MB |\n| `packages/toolchain-riscv32-esp` | RISC-V helper toolchain used by the K10 build | varies, often large |\n| `packages/toolchain-xtensa-esp32` | Base ESP32 toolchain declared by platform; include when present for conservative bundles | ~350-400 MB |\n| `packages/tool-esptoolpy` | Upload tool | a few MB |\n| `packages/tool-scons` | Build tool | a few MB |\n| `packages/tool-mkfatfs`, `tool-mklittlefs`, `tool-mkspiffs` | Filesystem image tools used by some upload targets | a few MB |\n\nA minimal compressed bundle is typically hundreds of MB. Prepare one bundle per supported OS/architecture. The self-contained macOS installer supports Apple Silicon only; Intel Macs are not supported.\n\nBundle preparation flow:\n\n```bash\n# On a prepared teacher machine\nbash scripts/init-k10-platformio-project.sh /tmp/k10-pio-probe\npio run -d /tmp/k10-pio-probe\nbash scripts/prepare-offline-bundle.sh /tmp/k10-platformio-bundle.tgz\n```\n\nFor macOS students who should not install PlatformIO manually, prefer the self-contained installer flow instead:\n\n``\n\nArchive v0.1.7: 17 files, 31357 bytes\n\nFiles: agents/openai.yaml (270b), references/k10-ai-model-flash.md (2912b), references/k10-arduino-api.md (9322b), references/k10-arduino-examples.md (23097b), references/platformio-workshop.md (7024b), scripts/doctor-offline.sh (1519b), scripts/init-k10-platformio-project.sh (1071b), scripts/install-offline-bundle.ps1 (681b), scripts/install-offline-bundle.sh (592b), scripts/k10-pio.ps1 (1802b), scripts/k10-pio.sh (1919b), scripts/prepare-macos-offline-installer.sh (9116b), scripts/prepare-offline-bundle.sh (1211b), scripts/prepare-windows-offline-installer.ps1 (11333b), skill-card.md (3001b), SKILL.md (12896b), _meta.json (142b)\n\nArchive v0.1.6: 16 files, 26989 bytes\n\nFiles: agents/openai.yaml (268b), references/k10-ai-model-flash.md (2912b), references/k10-arduino-api.md (9322b), references/k10-arduino-examples.md (23097b), references/platformio-workshop.md (5610b), scripts/doctor-offline.sh (1519b), scripts/init-k10-platformio-project.sh (1071b), scripts/install-offline-bundle.ps1 (681b), scripts/install-offline-bundle.sh (592b), scripts/k10-pio.ps1 (1802b), scripts/k10-pio.sh (1919b), scripts/prepare-macos-offline-installer.sh (9116b), scripts/prepare-offline-bundle.sh (1211b), skill-card.md (3122b), SKILL.md (11963b), _meta.json (142b)\n\nArchive v0.1.5: 16 files, 26314 bytes\n\nFiles: agents/openai.yaml (268b), references/k10-ai-model-flash.md (2912b), references/k10-arduino-api.md (9322b), references/k10-arduino-examples.md (23097b), references/platformio-workshop.md (5568b), scripts/doctor-offline.sh (1519b), scripts/init-k10-platformio-project.sh (1071b), scripts/install-offline-bundle.ps1 (681b), scripts/install-offline-bundle.sh (592b), scripts/k10-pio.ps1 (1802b), scripts/k10-pio.sh (1919b), scripts/prepare-macos-offline-installer.sh (7137b), scripts/prepare-offline-bundle.sh (1211b), skill-card.md (2557b), SKILL.md (11912b), _meta.json (142b)\n\nArchive v0.1.4: 15 files, 22300 bytes\n\nFiles: agents/openai.yaml (268b), references/k10-ai-model-flash.md (2912b), references/k10-arduino-api.md (9322b), references/k10-arduino-examples.md (23097b), references/platformio-workshop.md (3908b), scripts/doctor-offline.sh (1519b), scripts/init-k10-platformio-project.sh (1071b), scripts/install-offline-bundle.ps1 (681b), scripts/install-offline-bundle.sh (592b), scripts/k10-pio.ps1 (1802b), scripts/k10-pio.sh (1919b), scripts/prepare-offline-bundle.sh (1211b), skill-card.md (3262b), SKILL.md (8905b), _meta.json (142b)\n\nArchive v0.1.3: 15 files, 21738 bytes\n\nFiles: agents/openai.yaml (268b), references/k10-ai-model-flash.md (2912b), references/k10-arduino-api.md (9018b), references/k10-arduino-examples.md (22705b), references/platformio-workshop.md (3908b), scripts/doctor-offline.sh (1519b), scripts/init-k10-platformio-project.sh (1071b), scripts/install-offline-bundle.ps1 (681b), scripts/install-offline-bundle.sh (592b), scripts/k10-pio.ps1 (1802b), scripts/k10-pio.sh (1919b), scripts/prepare-offline-bundle.sh (1211b), skill-card.md (3319b), SKILL.md (8346b), _meta.json (142b)\n\nArchive v0.1.2: 14 files, 19661 bytes\n\nFiles: agents/openai.yaml (268b), references/k10-arduino-api.md (9018b), references/k10-arduino-examples.md (22705b), references/platformio-workshop.md (3908b), scripts/doctor-offline.sh (1519b), scripts/init-k10-platformio-project.sh (1071b), scripts/install-offline-bundle.ps1 (681b), scripts/install-offline-bundle.sh (592b), scripts/k10-pio.ps1 (1802b), scripts/k10-pio.sh (1919b), scripts/prepare-offline-bundle.sh (1211b), skill-card.md (3282b), SKILL.md (6997b), _meta.json (142b)\n\nArchive v0.1.1: 13 files, 18541 bytes\n\nFiles: agents/openai.yaml (268b), references/k10-arduino-api.md (9018b), references/k10-arduino-examples.md (22705b), references/platformio-workshop.md (3719b), scripts/init-k10-platformio-project.sh (1071b), scripts/install-offline-bundle.ps1 (669b), scripts/install-offline-bundle.sh (540b), scripts/k10-pio.ps1 (1802b), scripts/k10-pio.sh (1919b), scripts/prepare-offline-bundle.sh (1129b), skill-card.md (2786b), SKILL.md (6732b), _meta.json (142b)","readmeExcerpt":"Skill: UNIHIKER K10 PlatformIO Owner: rockets-cn Summary: Use when programming a UNIHIKER K10 board with PlatformIO CLI, creating or converting Arduino/C++ K10 projects to PlatformIO, building, uploading, monitoring... Tags: latest:0.1.10 Version history: v0.1.10 | 2026-07-22T07:43:14.454Z | user Recommend the DFRobot Gravity ADS1115 for safe K10 external analog expansion and publish the latest synchronized K10 skill","codeSnippets":[],"executableExamples":[{"language":"ini","snippet":"[env:unihiker]\nplatform = https://github.com/DFRobot/platform-unihiker.git\nboard = unihiker_k10\nframework = arduino\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n    -DModel=None"},{"language":"powershell","snippet":"powershell -ExecutionPolicy Bypass -File scripts\\prepare-windows-offline-installer.ps1 C:\\tmp\\K10P-windows-x64.exe"},{"language":"text","snippet":"C:\\K10P\n%USERPROFILE%\\K10P\n%LOCALAPPDATA%\\K10P\n%LOCALAPPDATA%\\K10PlatformIO"},{"language":"powershell","snippet":"cd C:\\K10P\n.\\setup-platformio.bat\n.\\pio.bat --version\n.\\pio.bat run -d .\\examples\\Blink"},{"language":"powershell","snippet":"C:\\K10P\\compile-project.bat \"C:\\path\\to\\PlatformIOProject\"\nC:\\K10P\\upload-project.bat \"C:\\path\\to\\PlatformIOProject\" COM3"},{"language":"bash","snippet":"# On a prepared teacher Mac after one successful K10 PlatformIO build\nbash scripts/prepare-macos-offline-installer.sh --self-extracting /tmp/K10P-macos-arm64.command"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: unihiker-k10-platformio\ndescription: Use when programming a UNIHIKER K10 board with PlatformIO CLI, creating or converting Arduino/C++ K10 projects to PlatformIO, building, uploading, monitoring serial output, diagnosing K10 PlatformIO setup or ASR microphone/wake-word failures, or preparing/installing offline PlatformIO support for workshops, including macOS archives and Windows self-extracting USB installers.\n---\n\n# UNIHIKER K10 - PlatformIO\n\n## Overview\n\nUse PlatformIO Core CLI for UNIHIKER K10 Arduino/C++ development. Prefer this skill when the user wants a PlatformIO-based workflow instead of `arduino-cli`, especially for workshops that need predownloaded support files.\n\nCore PlatformIO environment:\n\n```ini\n[env:unihiker]\nplatform = https://github.com/DFRobot/platform-unihiker.git\nboard = unihiker_k10\nframework = arduino\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n    -DModel=None\n```\n\nK10 uses DFRobot's PlatformIO platform and Arduino framework package. First build downloads a large framework and toolchains; avoid doing this from every student machine during a workshop.\n\nIf a project uses K10 AI, voice recognition, TTS, face recognition, or OTA partitions, preserve the factory model-data offsets. Read the repository reference `references/k10-ai-model-flash.md` when available, or follow the model rules below.\n\n**TTS firmware requirement:** `ASR::setAsrSpeed()` and `ASR::speak()` exist only in the Chinese K10 firmware. Confirm the firmware variant before generating or compiling TTS code. `-DModel=CN` refreshes CN model data; it does not by itself prove that the installed framework/firmware variant provides TTS.\n\nScreen refresh policy: generated K10 display code must prefer partial redraws. Full-screen clearing or full-background redraw causes visible flicker and is uncomfortable; use it only for initialization, page switches, exit cleanup, or when measured full-screen refresh is above 30 fps.\n\n## Quick Workflow\n\n### Windows Self-Contained Offline Installer\n\nFor Windows machines with no PlatformIO or Python environment installed, use the self-contained K10 PlatformIO offline installer first. It installs an isolated PlatformIO environment and does not require system `pio`.\n\nPrepare the Windows x64 self-extracting installer on a teacher Windows machine after one successful K10 PlatformIO build:\n\n```powershell\npowershell -ExecutionPolicy Bypass -File scripts\\prepare-windows-offline-installer.ps1 C:\\tmp\\K10P-windows-x64.exe\n```\n\nCopy the resulting `.exe` to the USB drive. Run it on each student Windows machine; it extracts to `C:\\K10P` and runs `setup-platformio.bat`.\n\nKnown install locations to check, in order:\n\n```text\nC:\\K10P\n%USERPROFILE%\\K10P\n%LOCALAPPDATA%\\K10P\n%LOCALAPPDATA%\\K10PlatformIO\n```\n\nCheck this location before assuming PlatformIO is missing:\n\n```powershell\ncd C:\\K10P\n.\\setup-platformio.bat\n.\\pio.bat --version\n.\\pio.bat run -d .\\examples\\Blink\n```\n\nImportant: use the bundled `pio.bat` or `platfo"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7bn6y6610bpcvzaykr1h2m1d83e2rm\",\n  \"slug\": \"unihiker-k10-platformio\",\n  \"version\": \"0.1.10\",\n  \"publishedAt\": 1784706194454\n}"},{"path":"references/k10-ai-model-flash.md","content":"# K10 AI Model Flashing and Recovery\n\nUse this reference when a PlatformIO project combines K10 built-in AI features, voice recognition, TTS, face recognition, OTA partitions, or factory recovery.\n\n## Fixed AI Flash Regions\n\nKeep these offsets unchanged unless DFRobot publishes a new partition table.\n\n| Region | Offset | Size in factory table | Purpose |\n| --- | --- | --- | --- |\n| `model` | `0x510000` | `4563K` | Speech recognition model image |\n| `voice_data` | `0x985000` | `2542K` | TTS voice data |\n| `fr` | `0xC01000` | `100K` | Face-recognition related data |\n\nIn DFRobot's current K10 PlatformIO framework package:\n\n- `srmodels.bin` is about 3.1 MB and is used by `-DModel=CN`.\n- `srmodels4.bin` is about 4.2 MB and is used by `-DModel=EN`.\n- `srmodels5.bin` is about 4.5 MB but is not selected by the current PlatformIO upload builder.\n- `esp_tts_voice_data_xiaoxin.dat` is about 2.5 MB and is flashed with both CN and EN.\n\n## PlatformIO Environments\n\nUse a normal environment for day-to-day builds and separate initialization environments for model recovery.\n\n```ini\n[k10_base]\nplatform = https://github.com/DFRobot/platform-unihiker.git\nboard = unihiker_k10\nframework = arduino\nbuild_flags =\n    -DARDUINO_USB_CDC_ON_BOOT=1\n    -DARDUINO_USB_MODE=1\n\n[env:unihiker]\nextends = k10_base\nbuild_flags =\n    ${k10_base.build_flags}\n    -DModel=None\n\n[env:unihiker-init-cn]\nextends = k10_base\nbuild_flags =\n    ${k10_base.build_flags}\n    -DModel=CN\n\n[env:unihiker-init-en]\nextends = k10_base\nbuild_flags =\n    ${k10_base.build_flags}\n    -DModel=EN\n```\n\nUse `unihiker-init-cn` or `unihiker-init-en` once over USB when the model partitions may be blank or damaged. Use `unihiker` for normal uploads and OTA app images.\n\n## OTA Partition Rule\n\nDo not use a generic two-slot OTA table whose app partitions grow past `0x510000`; it can overwrite the model region.\n\nUse a model-preserving OTA table:\n\n```csv\n# Name,     Type, SubType, Offset,   Size,     Flags\nnvs,        data, nvs,     0x9000,   0x5000,\notadata,    data, ota,     0xe000,   0x2000,\napp0,       app,  ota_0,   0x10000,  0x280000,\napp1,       app,  ota_1,   0x290000, 0x280000,\nmodel,      data, spiffs,  0x510000, 4563K,\nvoice_data, data, fat,     0x985000, 2542K,\nfr,         data, ,        0xC01000, 100K,\ncoredump,   data, coredump,,         1K,\nspiffs,     data, spiffs,  0xC1B000, 0x3E5000,\n```\n\nEach OTA app slot is 2.5 MB. If the firmware no longer fits, reduce firmware size, drop OTA, or explicitly decide that the project will not use built-in AI model data.\n\n## Recovery Paths\n\nOfficial UNIHIKER documentation provides Mind+ recovery:\n\n1. Hold BOOT while connecting USB.\n2. Release BOOT after the port appears.\n3. Click `Restore Initial Settings`.\n4. Press RST when restoration completes.\n\nThe hardware download page also provides a factory programme zip for restoring the factory demo after Mind+ initial settings are restored."},{"path":"references/k10-arduino-api.md","content":"## UNIHIKER_K10\nThe UNIHIKER K10 library is a library for controlling the K10 on-screen display, on-board sensors, SD card, and playing sound.\nNote: The source code for this library will be made available on the DFRobot GitHub when the UNIHIKER K10 SDK is upgraded to the full version.\n\nScreen refresh rule: prefer partial redraws for all repeated display updates. Avoid `canvasClear()` or full-background redraw in loops because it causes visible flicker; use full-screen refresh only for initialization, page switches, exit cleanup, or when measured full-screen refresh is above 30 fps.\n\n````c++ title=\"Init\"\n/**\n * @fn begin\n * @brief Initialize UNIHIKER K10 board\n */\nvoid begin(void);\n````\n\n````c++ title=\"Display\"\n/**\n * @fn initScreen\n * @brief Initialize the screen\n * @param dir Screen orientation\n * @param frame Screen display frame rate\n */\nvoid initScreen(int dir = 2, int frame = 0);\n\n/**\n * @fn creatCanvas\n * @brief Create a canvas\n */\nvoid creatCanvas(void);\n\n/**\n * @fn initBgCamerImage\n * @brief Initialize the camera image\n */\nvoid initBgCamerImage(void);\n\n/**\n * @fn setBgCamerImage\n * @brief Set whether to display the camera image on the screen\n * @param sta Configuration status\n */\nvoid setBgCamerImage(bool sta = true);\n\n/**\n * @fn setScreenBackground\n * @brief Set the screen background color\n * @param color Background color\n */\nvoid setScreenBackground(uint32_t color);\n\n/**\n * @fn canvasText\n * @brief Display text on the canvas\n * @param text Text content\n * @param row Row to display\n * @param color Text color\n */\nvoid canvasText(float text, uint8_t row, uint32_t color);\nvoid canvasText(String text, uint8_t row, uint32_t color);\nvoid canvasText(const char* text, uint8_t row, uint32_t color);\n\n/**\n * @fn canvasPoint\n * @brief Draw a point on the canvas\n * @param x Display coordinate X\n * @param y Display coordinate Y\n * @param color Point color\n */\nvoid canvasPoint(int16_t x, int16_t y, uint32_t color);\n\n/**\n * @fn updateCanvas\n * @brief Update screen display (automatically updates when using camera)\n */\nvoid updateCanvas(void);\n\n/**\n * @fn canvasClear\n * @brief Clear canvas properties\n */\nvoid canvasClear(void);\n\n/**\n * @fn canvasSetLineWidth\n * @brief Set line width for drawing\n * @param w Line width\n */\nvoid canvasSetLineWidth(uint8_t w = 10);\n\n/**\n * @fn canvasLine\n * @brief Draw a line on the canvas\n * @param x1, y1 Starting coordinates\n * @param x2, y2 Ending coordinates\n * @param color Line color\n */\nvoid canvasLine(int x1, int y1, int x2, int y2, uint32_t color);\n\n/**\n * @fn canvasCircle\n * @brief Draw a circle on the canvas\n * @param x Display coordinate X\n * @param y Display coordinate Y\n * @param r Circle radius\n * @param color Border color\n * @param bg_color Background color\n * @param fill Whether to fill the circle\n */\nvoid canvasCircle(int x, int y, int r, uint32_t color, uint32_t bg_color, bool fill);\n\n/**\n * @fn canvasRectangle\n * @brief Draw a rectangle on the canvas\n * @param x Display coordinate X\n * @param y Display coor"},{"path":"references/k10-arduino-examples.md","content":"> Screen refresh rule: the examples below are API demonstrations, not permission to clear or redraw the whole screen in a fast loop. For animations, sensor values, dashboards, voice status, OTA status, and other repeated updates, redraw only changed regions. Use full-screen refresh only for initialization, page switches, exit cleanup, or when measured full-screen refresh is above 30 fps.\n\n## **Display-Set Back Ground Color**\nSetting the background color of the K10 screen<br/>\n````c++ title=\"Screen Display\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n}\nvoid loop() {\n\tk10.setScreenBackground(0xFFFFFF);\n\tdelay(2000);\n\tk10.setScreenBackground(0xFF0000);\n\tdelay(2000);\n\tk10.setScreenBackground(0x00FF00);\n\tdelay(2000);\n\tk10.setScreenBackground(0x0000FF);\n\tdelay(2000);\n\tk10.setScreenBackground(0x000000);\n\tdelay(2000);\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus1.gif){: width=\"250px\"}\n\n## **Display-Electronic photo album**\nFormat the TF card to FAT32 and install it on K10. Press button A on the K10 to take a picture and button B to display it.<br/>\n\n!!! Note \n    TF card is need to run this programme\n\n````c++ title=\"Electronic photo album\"\n#include \"unihiker_k10.h\"\n\nvoid onButtonAPressed();\nvoid onButtonBPressed();\n\nUNIHIKER_K10 k10;\nuint8_t      screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.initBgCamerImage();\n\tk10.setBgCamerImage(false);\n\tk10.creatCanvas();\n\tk10.buttonA->setPressedCallback(onButtonAPressed);\n\tk10.initSDFile();\n\tk10.buttonB->setPressedCallback(onButtonBPressed);\n\tk10.setBgCamerImage(true);\n}\nvoid loop() {\n}\n\nvoid onButtonAPressed() {\n\tk10.photoSaveToTFCard(\"S:/photo.bmp\");\n}\nvoid onButtonBPressed() {\n\tk10.canvas->canvasDrawImage(0, 0, \"S:/photo.bmp\");\n}\n````\n![image.gif](img/example_mindplus/exampleMindplus5.gif){: width=\"250px\"}\n\n\n## **Display-Showing text**\n````c++ title=\"Showing text\"\n#include \"unihiker_k10.h\"\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.setScreenBackground(0xFFFFFF);\n\tk10.canvas->canvasText(\"UNIHIKER\", 1, 0x0000FF);\n\tk10.canvas->updateCanvas();\n\tdelay(1000);\n\tk10.canvas->canvasText(\"UNIHIKER\", 2, 0xFF0000);\n\tk10.canvas->updateCanvas();\n\tdelay(1000);\n\tk10.canvas->canvasText(\"UNIHIKER\", 3, 0x00FF00);\n\tk10.canvas->updateCanvas();\n\tdelay(1000);\n\tk10.canvas->canvasText(\"UNIHIKER\", 4, 0x000000);\n\tk10.canvas->updateCanvas();\n\tdelay(1000);\n}\nvoid loop() {\n}\n````\n![image.png](img/example_mindplus/exampleMindplus6.gif){: width=\"250px\"}\n\n## **Display-Draw Point**\n````c++ title=\"Draw Point\"\n#include \"unihiker_k10.h\"\n\nuint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b);\n\nUNIHIKER_K10 k10;\nuint8_t screen_dir=2;\n\nvoid setup() {\n\tk10.begin();\n\tk10.initScreen(screen_dir);\n\tk10.creatCanvas();\n\tk10.setScreenBackground(0x000000);\n}\nvoid loop() {\n\tfor (int index = 0; index < 50; index++) {\n\t\tk10.canvas->canvasPoin"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Use when programming a UNIHIKER K10 board with PlatformIO CLI, creating or converting Arduino/C++ K10 projects to PlatformIO, building, uploading, monitoring... Skill: UNIHIKER K10 PlatformIO Owner: rockets-cn Summary: Use when programming a UNIHIKER K10 board with PlatformIO CLI, creating or converting Arduino/C++ K10 projects to PlatformIO, building, uploading, monitoring... Tags: latest:0.1.10 Version history: v0.1.10 | 2026-07-22T07:43:14.454Z | user Recommend the DFRobot Gravity ADS1115 for safe K10 external analog expansion and publish the latest synchronized K10 skill","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1462,"uniquenessScore":46,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-10T17:54:40.592Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-10T17:54:40.592Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-10T21:56:30.202Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}