8 Commits

Author SHA1 Message Date
pNexus 4c9e3e3ea0 chore: 引入仓库根 .clang-format 与 .gitignore
平衡板从 firmware 主仓拆出后,作为独立产品需要自己的代码风格和忽略规则。
.clang-format 沿用主仓 projects/.clang-format 的全套约定(C++/Zephyr 风格),
保证拆出前后 reformat 结果一致;.gitignore 在主仓基础上裁剪掉 Android、
Unity 相关条目,仅保留嵌入式构建产物、IDE 本地配置和 OS 临时文件。
2026-05-27 10:04:59 +08:00
pNexus 6e0fa5870e Merge branch 'gml670x4/dev' into dev 2026-05-27 09:43:09 +08:00
pNexus d05ffd27ad Merge branch 'debug/ads1256-reg-issue' into gml670x4/dev 2026-05-27 09:42:17 +08:00
zhifeige 99c01e9d15 Merge pull request 'dev' (#7) from dev into main
Reviewed-on: http://git.kiwii.ai/Kiwii-AI/firmware/pulls/7
2026-05-24 08:06:45 +00:00
pNexus 393eb16fb3 Merge branch 'dongle/dev' into dev 2026-05-22 18:08:37 +08:00
pNexus 11673a70f2 feat(doc): 添加力量电机接入说明文档,包含连接流程和力控参数设置 2026-05-21 10:12:15 +08:00
pNexus 8fb033c3be feat(docs): 添加力量电机说明文档,包含连接流程和力控参数设置 2026-05-21 10:01:22 +08:00
pNexus 633459caee refactor(protocol): 移除未使用的消息队列获取函数 2026-05-20 21:02:40 +08:00
6 changed files with 736 additions and 13 deletions
+320
View File
@@ -0,0 +1,320 @@
---
Language: Cpp
AlignAfterOpenBracket: true
AccessModifierOffset: -2
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: true
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: true
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseArrows: false
AlignCaseColons: false
AlignConsecutiveTableGenBreakingDAGArgColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenCondOperatorColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenDefinitionColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments:
AlignPPAndNotPP: true
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowBreakBeforeNoexceptSpecifier: Never
AllowBreakBeforeQtProperty: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseExpressionOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AllowShortNamespacesOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AttributeMacros:
- __capability
BinPackArguments: true
BinPackLongBracedList: true
BinPackParameters: OnePerLine
BitFieldColonSpacing: Both
BracedInitializerIndentWidth: -1
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: true
AfterFunction: false
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: false
AfterUnion: false
BeforeCatch: true
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakAfterOpenBracketBracedList: false
BreakAfterOpenBracketFunction: true
BreakAfterOpenBracketIf: false
BreakAfterOpenBracketLoop: false
BreakAfterOpenBracketSwitch: false
BreakAfterReturnType: None
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeCloseBracketBracedList: false
BreakBeforeCloseBracketFunction: false
BreakBeforeCloseBracketIf: false
BreakBeforeCloseBracketLoop: false
BreakBeforeCloseBracketSwitch: false
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Custom
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTemplateCloser: false
BreakBeforeTernaryOperators: true
BreakBinaryOperations: Never
BreakConstructorInitializers: BeforeColon
BreakFunctionDefinitionParameters: false
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
BreakTemplateDeclarations: MultiLine
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: Block
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
EnumTrailingComma: Leave
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExportBlock: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigitsInsert: 0
BinaryMaxDigitsRemove: 0
Decimal: 0
DecimalMinDigitsInsert: 0
DecimalMaxDigitsRemove: 0
Hex: 0
HexMinDigitsInsert: 0
HexMaxDigitsRemove: 0
BinaryMinDigits: 0
DecimalMinDigits: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLines:
AtEndOfFile: false
AtStartOfBlock: true
AtStartOfFile: true
KeepFormFeed: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
MainIncludeChar: Quote
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
NumericLiteralCase:
ExponentLetter: Leave
HexDigit: Leave
Prefix: Leave
Suffix: Leave
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
OneLineFormatOffRegex: ''
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakBeforeMemberAccess: 150
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Right
PPIndentWidth: -1
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: Always
RemoveBracesLLVM: false
RemoveEmptyLinesInUnwrappedLines: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes:
Enabled: true
IgnoreCase: false
IgnoreExtension: false
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterOperatorKeyword: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterNot: false
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBraces: Never
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
ExceptDoubleParentheses: false
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TableGenBreakInsideDAGArg: DontBreak
TabWidth: 4
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
WrapNamespaceBodyWithEmptyLines: Leave
...
+34 -2
View File
@@ -1,6 +1,38 @@
# editors
# =========================================================
# Editor swap / backup
# =========================================================
*.swp
*~
# build
# =========================================================
# IDE 本地配置
# =========================================================
.idea/
*.iml
.vscode/
.codex
.claude
# =========================================================
# Embedded / CMake / Zephyr 构建产物
# =========================================================
/build*/
build/
**/build/
**/zephyr/
**/output/
*.o
*.obj
*.elf
*.bin
*.hex
*.map
*.ninja
.ninja_deps
.ninja_log
# =========================================================
# OS 临时文件
# =========================================================
.DS_Store
Thumbs.db
+191
View File
@@ -0,0 +1,191 @@
# BLE 接入说明
本文档只说明客户实现“连接蓝牙”和“设置力控参数”所需的最小协议。
## 1. BLE 连接
设备使用 Nordic UART Service 风格的 BLE 服务。
| 用途 | UUID | 方向 |
| --- | --- | --- |
| Service | `6e400001-b5a3-f393-e0a9-e50e24dcca9e` | - |
| TX characteristic | `6e400002-b5a3-f393-e0a9-e50e24dcca9e` | 客户 App 写入设备 |
| RX characteristic | `6e400003-b5a3-f393-e0a9-e50e24dcca9e` | 设备 notify 给客户 App |
连接流程:
1. 扫描 BLE 设备,设备名通常包含 `YRobot`
2. 连接目标设备。
3. 对 RX characteristic 开启 notify。
4. 向 TX characteristic 写入力控参数帧。
单包最大长度建议不超过 `250 bytes`
## 2. 左右侧设备
力控参数帧的 `key` 需要区分左右侧。
| 侧别 | 写入 key |
| --- | --- |
| 左侧 | `0x6F` |
| 右侧 | `0xAF` |
| 不区分左右侧 | `0x2F` |
现有工具通过设备名判断左右侧:
- 右侧:设备名包含 `ZDR`, `ZDB`, `ZCR`, `ZCB`, `ARR`, `ARB`, `ASR`, `ASB`
- 左侧:设备名包含 `ZDL`, `ZCL`, `ARL`, `ASL`
如果设备名无法判断,客户 App 需要让用户手动选择左/右侧。
## 3. 力控参数帧格式
设置力控参数使用 JSON 字符串,通过 TX characteristic 写入。
帧格式:
```text
[0] key
[1] length
[2] crc
[3] command
[4...] utf8(json)
```
字段说明:
| 字段 | 说明 |
| --- | --- |
| `key` | 左侧 `0x6F`,右侧 `0xAF` |
| `length` | 整帧长度,即 `json_payload_len + 4` |
| `crc` | 固定填 `0x00` |
| `command` | 设置参数固定填 `0x01` |
| `json` | UTF-8 编码的 JSON 参数 |
也就是:
```text
payload = [0x01] + UTF8(json_string)
frame = [key, len(payload) + 3, 0x00] + payload
```
## 4. 设置力控模式和参数
### 力控参数表
所有 key 都定义在 `TuningParams::RegisterForceModeCtrl()` 中。
| JSON key | 默认值 | 单位 | 说明 |
| --- | ---: | --- | --- |
| `fm_mode` | `0.0` | - | 力控模式选择,四舍五入后映射到模式枚举 |
| `fm_mset` | `0.1` | kg | 用户设定重量 |
| `fm_kin` | `0.0` | - | 惯性比例系数,虚拟质量 = `fm_kin * fm_mset` |
| `fm_bfr` | `0.0` | N/(m/s) | 线性摩擦/阻尼系数 |
| `fm_kecc` | `0.1` | - | 离心倍率,离心力 = `fm_kecc * 向心力` |
| `fm_vth` | `0.3` | m/s | 离心/向心平滑切换速度阈值 |
| `fm_cdrv` | `0.1` | N/(m/s)^2 | 粘滞模式拉出方向平方阻尼系数 |
| `fm_crec` | `0.1` | N/(m/s) | 粘滞模式回收方向线性阻尼系数 |
| `fm_k` | `0.0` | N/m | 弹性刚度 |
| `fm_x0` | `0.0` | m | 弹性零点位置 |
| `fm_vmax` | `1.0` | m/s | 等速模式最大速度 |
| `fm_gwall` | `0.0` | N/(m/s) | 等速速度墙增益 |
| `fm_sp_v` | `0.1` | m/s | Spotter 触发速度阈值 |
| `fm_sp_t` | `5.0` | s | Spotter 触发时间阈值 |
| `fm_sp_d` | `5.0` | s | Spotter 减重衰减时长 |
| `fm_sp_home` | `0.0` | m | Spotter 参考初始位置 |
| `fm_sp_rng` | `-0.10` | m | Spotter 负重判定位置阈值 |
| `fm_sp_rec` | `1.0` | s | Spotter 恢复时长;当前实现中会被同步为 `fm_sp_t` |
| `fm_rad` | `0.2` | m | 滑轮半径,输出扭矩 = 输出力 * `fm_rad` |
### 力控模式
`fm_mode` 会先四舍五入,再限幅到 `0...6`
| `fm_mode` | 模式 | 主要参数 | 说明 |
| ---: | --- | --- | --- |
| `0` | None | - | 输出力为 0 |
| `1` | FreeWeight | `fm_mset`, `fm_kin`, `fm_bfr`, `fm_rad` | 自由重量/惯性补偿 |
| `2` | EccentricOverload | `fm_mset`, `fm_kin`, `fm_bfr`, `fm_kecc`, `fm_vth`, Spotter 参数 | 离心超负荷 |
| `3` | Viscous | `fm_cdrv`, `fm_crec`, `fm_rad` | 粘滞/流体阻尼 |
| `4` | Elastic | `fm_k`, `fm_x0`, `fm_rad` | 弹性/弹簧 |
| `5` | IsokineticSpotting | `fm_mset`, `fm_vmax`, `fm_gwall`, Spotter 参数 | 等速速度墙 |
| `6` | Spotter | `fm_mset`, `fm_kin`, `fm_bfr`, Spotter 参数 | 保护模式 |
## 5. 示例
设置右侧设备为离心超负荷模式:
```json
{
"fm_mode": 2,
"fm_mset": 10.0,
"fm_vth": 0.3,
"fm_kecc": 1.5,
"fm_kin": 1.0,
"fm_bfr": 0.05,
"fm_rad": 0.04
}
```
对应写入帧:
```text
key = 0xAF
command = 0x01
json_string = '{"fm_mode":2,"fm_mset":10.0,"fm_vth":0.3,"fm_kecc":1.5,"fm_kin":1.0,"fm_bfr":0.05,"fm_rad":0.04}'
payload = [0x01] + UTF8(json_string)
frame = [0xAF, len(payload) + 3, 0x00] + payload
```
写入 TX characteristic UUID
```text
6e400002-b5a3-f393-e0a9-e50e24dcca9e
```
## 6. 查询当前力控参数
查询参数同样写 TX characteristic。
查询当前模式参数:
```text
frame = [key, 0x04, 0x00, 0x02]
```
查询指定模式参数,例如查询 `fm_mode = 2`
```text
payload = [0x02] + UTF8('{"fm_mode":2}')
frame = [key, len(payload) + 3, 0x00] + payload
```
设备会通过 RX characteristic notify 返回 JSON 参数。返回可能分包,需要按包序号拼接:
```text
[0] key
[1] length
[2] crc
[3] type = 0x02
[4] packet_index
[5] packet_count
[6...] utf8(json_fragment)
```
`packet_index == packet_count` 时,说明最后一包已收到,可以拼接所有 `json_fragment` 后解析 JSON。
## 7. 心跳包
当连接上设备之后,需要每隔2s发送心跳包给设备,维持和设备的连接
```text
[0] key
[1] length
[2] crc
[3] command = 0x00
```
## 8. 注意事项
- 写入前必须先连接设备并开启 RX notify。
- 写入 key 必须和设备侧别一致:左侧 `0x6F`,右侧 `0xAF`
- `crc` 当前固定填 `0x00`
- JSON 使用 UTF-8 编码。
+191
View File
@@ -0,0 +1,191 @@
# BLE 接入说明
本文档只说明客户实现“连接蓝牙”和“设置力控参数”所需的最小协议。
## 1. BLE 连接
设备使用 Nordic UART Service 风格的 BLE 服务。
| 用途 | UUID | 方向 |
| --- | --- | --- |
| Service | `6e400001-b5a3-f393-e0a9-e50e24dcca9e` | - |
| TX characteristic | `6e400002-b5a3-f393-e0a9-e50e24dcca9e` | 客户 App 写入设备 |
| RX characteristic | `6e400003-b5a3-f393-e0a9-e50e24dcca9e` | 设备 notify 给客户 App |
连接流程:
1. 扫描 BLE 设备,设备名通常包含 `YRobot`
2. 连接目标设备。
3. 对 RX characteristic 开启 notify。
4. 向 TX characteristic 写入力控参数帧。
单包最大长度建议不超过 `250 bytes`
## 2. 左右侧设备
力控参数帧的 `key` 需要区分左右侧。
| 侧别 | 写入 key |
| --- | --- |
| 左侧 | `0x6F` |
| 右侧 | `0xAF` |
| 不区分左右侧 | `0x2F` |
现有工具通过设备名判断左右侧:
- 右侧:设备名包含 `ZDR`, `ZDB`, `ZCR`, `ZCB`, `ARR`, `ARB`, `ASR`, `ASB`
- 左侧:设备名包含 `ZDL`, `ZCL`, `ARL`, `ASL`
如果设备名无法判断,客户 App 需要让用户手动选择左/右侧。
## 3. 力控参数帧格式
设置力控参数使用 JSON 字符串,通过 TX characteristic 写入。
帧格式:
```text
[0] key
[1] length
[2] crc
[3] command
[4...] utf8(json)
```
字段说明:
| 字段 | 说明 |
| --- | --- |
| `key` | 左侧 `0x6F`,右侧 `0xAF` |
| `length` | 整帧长度,即 `json_payload_len + 4` |
| `crc` | 固定填 `0x00` |
| `command` | 设置参数固定填 `0x01` |
| `json` | UTF-8 编码的 JSON 参数 |
也就是:
```text
payload = [0x01] + UTF8(json_string)
frame = [key, len(payload) + 3, 0x00] + payload
```
## 4. 设置力控模式和参数
### 力控参数表
所有 key 都定义在 `TuningParams::RegisterForceModeCtrl()` 中。
| JSON key | 默认值 | 单位 | 说明 |
| --- | ---: | --- | --- |
| `fm_mode` | `0.0` | - | 力控模式选择,四舍五入后映射到模式枚举 |
| `fm_mset` | `0.1` | kg | 用户设定重量 |
| `fm_kin` | `0.0` | - | 惯性比例系数,虚拟质量 = `fm_kin * fm_mset` |
| `fm_bfr` | `0.0` | N/(m/s) | 线性摩擦/阻尼系数 |
| `fm_kecc` | `0.1` | - | 离心倍率,离心力 = `fm_kecc * 向心力` |
| `fm_vth` | `0.3` | m/s | 离心/向心平滑切换速度阈值 |
| `fm_cdrv` | `0.1` | N/(m/s)^2 | 粘滞模式拉出方向平方阻尼系数 |
| `fm_crec` | `0.1` | N/(m/s) | 粘滞模式回收方向线性阻尼系数 |
| `fm_k` | `0.0` | N/m | 弹性刚度 |
| `fm_x0` | `0.0` | m | 弹性零点位置 |
| `fm_vmax` | `1.0` | m/s | 等速模式最大速度 |
| `fm_gwall` | `0.0` | N/(m/s) | 等速速度墙增益 |
| `fm_sp_v` | `0.1` | m/s | Spotter 触发速度阈值 |
| `fm_sp_t` | `5.0` | s | Spotter 触发时间阈值 |
| `fm_sp_d` | `5.0` | s | Spotter 减重衰减时长 |
| `fm_sp_home` | `0.0` | m | Spotter 参考初始位置 |
| `fm_sp_rng` | `-0.10` | m | Spotter 负重判定位置阈值 |
| `fm_sp_rec` | `1.0` | s | Spotter 恢复时长;当前实现中会被同步为 `fm_sp_t` |
| `fm_rad` | `0.2` | m | 滑轮半径,输出扭矩 = 输出力 * `fm_rad` |
### 力控模式
`fm_mode` 会先四舍五入,再限幅到 `0...6`
| `fm_mode` | 模式 | 主要参数 | 说明 |
| ---: | --- | --- | --- |
| `0` | None | - | 输出力为 0 |
| `1` | FreeWeight | `fm_mset`, `fm_kin`, `fm_bfr`, `fm_rad` | 自由重量/惯性补偿 |
| `2` | EccentricOverload | `fm_mset`, `fm_kin`, `fm_bfr`, `fm_kecc`, `fm_vth`, Spotter 参数 | 离心超负荷 |
| `3` | Viscous | `fm_cdrv`, `fm_crec`, `fm_rad` | 粘滞/流体阻尼 |
| `4` | Elastic | `fm_k`, `fm_x0`, `fm_rad` | 弹性/弹簧 |
| `5` | IsokineticSpotting | `fm_mset`, `fm_vmax`, `fm_gwall`, Spotter 参数 | 等速速度墙 |
| `6` | Spotter | `fm_mset`, `fm_kin`, `fm_bfr`, Spotter 参数 | 保护模式 |
## 5. 示例
设置右侧设备为离心超负荷模式:
```json
{
"fm_mode": 2,
"fm_mset": 10.0,
"fm_vth": 0.3,
"fm_kecc": 1.5,
"fm_kin": 1.0,
"fm_bfr": 0.05,
"fm_rad": 0.04
}
```
对应写入帧:
```text
key = 0xAF
command = 0x01
json_string = '{"fm_mode":2,"fm_mset":10.0,"fm_vth":0.3,"fm_kecc":1.5,"fm_kin":1.0,"fm_bfr":0.05,"fm_rad":0.04}'
payload = [0x01] + UTF8(json_string)
frame = [0xAF, len(payload) + 3, 0x00] + payload
```
写入 TX characteristic UUID
```text
6e400002-b5a3-f393-e0a9-e50e24dcca9e
```
## 6. 查询当前力控参数
查询参数同样写 TX characteristic。
查询当前模式参数:
```text
frame = [key, 0x04, 0x00, 0x02]
```
查询指定模式参数,例如查询 `fm_mode = 2`
```text
payload = [0x02] + UTF8('{"fm_mode":2}')
frame = [key, len(payload) + 3, 0x00] + payload
```
设备会通过 RX characteristic notify 返回 JSON 参数。返回可能分包,需要按包序号拼接:
```text
[0] key
[1] length
[2] crc
[3] type = 0x02
[4] packet_index
[5] packet_count
[6...] utf8(json_fragment)
```
`packet_index == packet_count` 时,说明最后一包已收到,可以拼接所有 `json_fragment` 后解析 JSON。
## 7. 心跳包
当连接上设备之后,需要每隔2s发送心跳包给设备,维持和设备的连接
```text
[0] key
[1] length
[2] crc
[3] command = 0x00
```
## 8. 注意事项
- 写入前必须先连接设备并开启 RX notify。
- 写入 key 必须和设备侧别一致:左侧 `0x6F`,右侧 `0xAF`
- `crc` 当前固定填 `0x00`
- JSON 使用 UTF-8 编码。
-7
View File
@@ -233,10 +233,3 @@ void comm_protocol_send_cop(uint8_t flags, int16_t cop_x, int16_t cop_y, int16_t
* @param data 8 字节响应数据。
*/
void comm_protocol_send_cal_resp(uint8_t status, uint8_t subcmd, const uint8_t data[8]);
/**
* @brief 获取下行消息队列指针,业务层通过 k_msgq_get() 消费。
*
* @return 指向内部 msgq 的指针。
*/
struct k_msgq *comm_protocol_get_msgq(void);
-4
View File
@@ -152,7 +152,3 @@ void comm_protocol_send_cal_resp(uint8_t status, uint8_t subcmd, const uint8_t d
pkt.frame.crc = frame_crc(pkt.bytes, sizeof(pkt.bytes));
ble_transport_send(pkt.bytes, sizeof(pkt.bytes));
}
struct k_msgq *comm_protocol_get_msgq(void) {
return &rx_msgq;
}