mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-07-02 15:22:06 +08:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e0a5c99588 | |||
| 31dc4d8e52 | |||
| da6313dbe9 | |||
| 01a843e0ac |
@@ -2,6 +2,5 @@ Wen
|
||||
REGIST
|
||||
PullRequest
|
||||
cancelled
|
||||
indeces
|
||||
FOF
|
||||
NoO
|
||||
|
||||
@@ -35,18 +35,36 @@ jobs:
|
||||
- name: Init sunnypilot opendbc submodule
|
||||
run: git submodule update --init --depth 1 opendbc_repo
|
||||
|
||||
- name: Checkout upstream openpilot cereal
|
||||
- name: Checkout upstream openpilot
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: 'commaai/openpilot'
|
||||
path: upstream_openpilot
|
||||
sparse-checkout: cereal
|
||||
ref: "refs/heads/master"
|
||||
|
||||
- name: Init upstream opendbc submodule
|
||||
working-directory: upstream_openpilot
|
||||
run: git submodule update --init --depth 1 opendbc_repo
|
||||
|
||||
- name: Locate upstream capnp paths
|
||||
id: locate-capnp
|
||||
run: |
|
||||
CEREAL_DIR=$(find upstream_openpilot -maxdepth 4 -name log.capnp -path '*/cereal/log.capnp' -printf '%h\n' -quit)
|
||||
if [ -z "$CEREAL_DIR" ]; then
|
||||
echo "::error::Could not locate cereal/log.capnp in upstream openpilot"
|
||||
exit 1
|
||||
fi
|
||||
echo "cereal_dir=$CEREAL_DIR" >> "$GITHUB_OUTPUT"
|
||||
echo "Found upstream cereal at: $CEREAL_DIR"
|
||||
|
||||
IMPORT_ARGS=""
|
||||
CAR_CAPNP=$(find upstream_openpilot -maxdepth 5 -name car.capnp -path '*/opendbc/car/car.capnp' -printf '%h\n' -quit)
|
||||
if [ -n "$CAR_CAPNP" ]; then
|
||||
IMPORT_ARGS="-I $CAR_CAPNP"
|
||||
echo "Found car.capnp at: $CAR_CAPNP"
|
||||
fi
|
||||
echo "import_args=$IMPORT_ARGS" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Install uv
|
||||
run: pip install uv
|
||||
|
||||
@@ -62,4 +80,5 @@ jobs:
|
||||
PYCAPNP_VER=$(python3 -c "import re; m=re.search(r'name = \"pycapnp\"\nversion = \"([^\"]+)\"', open('uv.lock').read()); print(m.group(1))")
|
||||
uv run --isolated --with "pycapnp==${PYCAPNP_VER}" \
|
||||
python3 cereal/messaging/tests/validate_sp_cereal_upstream.py \
|
||||
-r -f /tmp/sp_schema.json --cereal-dir upstream_openpilot/cereal
|
||||
-r -f /tmp/sp_schema.json --cereal-dir ${{ steps.locate-capnp.outputs.cereal_dir }} \
|
||||
${{ steps.locate-capnp.outputs.import_args }}
|
||||
|
||||
Generated
-7
@@ -21,12 +21,5 @@
|
||||
</clean>
|
||||
</configuration>
|
||||
</target>
|
||||
<target id="f2590b2b-9b93-49f9-8510-da3f3724a2ae" name="replay" defaultType="TOOL">
|
||||
<configuration id="d475264f-6f4c-4092-9b4e-6773309f38b7" name="replay" toolchainName="Default">
|
||||
<build type="TOOL">
|
||||
<tool actionId="Tool_External Tools_uv build tools replay" />
|
||||
</build>
|
||||
</configuration>
|
||||
</target>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-7
@@ -20,11 +20,4 @@
|
||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
||||
</exec>
|
||||
</tool>
|
||||
<tool name="uv build tools replay" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
||||
<exec>
|
||||
<option name="COMMAND" value="bash" />
|
||||
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc) tools/replay/"" />
|
||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
||||
</exec>
|
||||
</tool>
|
||||
</toolSet>
|
||||
@@ -1,5 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Build Debug" type="CLionExternalRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/selfdrive/ui" PASS_PARENT_ENVS_2="true" PROJECT_NAME="openpilot-special" TARGET_NAME="uv Scons Build Debug" CONFIG_NAME="uv Scons Build Debug" RUN_PATH="ui">
|
||||
<configuration default="false" name="Build Debug" type="CLionExternalRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/selfdrive/ui" PASS_PARENT_ENVS_2="true" PROJECT_NAME="sunnypilot" TARGET_NAME="uv Scons Build Debug" CONFIG_NAME="uv Scons Build Debug" RUN_PATH="ui">
|
||||
<envs>
|
||||
<env name="QT_DBL_CLICK_DIST" value="150" />
|
||||
</envs>
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Debug Route Controls" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="openpilot-special" />
|
||||
<option name="ENV_FILES" value="" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
<env name="FINGERPRINT" value="KIA_EV9" />
|
||||
<env name="SKIP_FW_QUERY" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/selfdrive/car" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/selfdrive/car/card.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,7 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Replay for controls + ui" type="Multirun" separateTabs="false" reuseTabsWithFailures="false" startOneByOne="true" markFailedProcess="true" hideSuccessProcess="false" delayTime="0.0">
|
||||
<runConfiguration name="replay for controls" type="Native Application" />
|
||||
<runConfiguration name="Build Debug" type="Custom Build Application" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,7 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="replay for controls" type="CLionNativeAppRunConfigurationType" focusToolWindowBeforeRun="true" PROGRAM_PARAMS=""$Prompt$" --block "sendcan,carState,carParams,carOutput,liveTracks,carParamsSP,carStateSP,bookmarkButton"" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="true" WORKING_DIR="file://$ProjectFileDir$/tools/replay" PASS_PARENT_ENVS_2="true" PROJECT_NAME="openpilot-special" TARGET_NAME="replay" CONFIG_NAME="replay" version="1" RUN_PATH="replay">
|
||||
<method v="2">
|
||||
<option name="CLION.COMPOUND.BUILD" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
+30
-1
@@ -1,5 +1,34 @@
|
||||
sunnypilot Version 2026.002.000 (2026-xx-xx)
|
||||
sunnypilot Version 2026.002.000 (2026-06-28)
|
||||
========================
|
||||
* What's Changed (sunnypilot/sunnypilot)
|
||||
* ui: update gates for certain toggles by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1830
|
||||
* release: ignore upstream IsReleaseBranch by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1831
|
||||
* manager: disable DEVELOPMENT_ONLY reset by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1833
|
||||
* sunnylink: fix max time offroad values by @nayan8teen in https://github.com/sunnypilot/sunnypilot/pull/1835
|
||||
* ui: show default model name by @nayan8teen in https://github.com/sunnypilot/sunnypilot/pull/1837
|
||||
* sunnylink: add CarParams fallback for brand-specific capabilities by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1839
|
||||
* sunnylink SDUI: tweak DisableUpdate param for clarity by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1842
|
||||
* Revert "DM: Lancia Delta HF Integrale model" by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1849
|
||||
* modeld_v2: safe model validation by @Discountchubbs in https://github.com/sunnypilot/sunnypilot/pull/1855
|
||||
* Revert "deprecate `carState.brake`" for Honda Gas Interceptor by @mvl-boston in https://github.com/sunnypilot/sunnypilot/pull/1860
|
||||
* sunnylink: deprecate legacy params metadata by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1862
|
||||
* ui: reset Enforce Torque Control and NNLC if both are enabled by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1863
|
||||
* What's Changed (sunnypilot/opendbc)
|
||||
* Rivian: suppress ACM hold-the-wheel warning during MADS-only lateral by @lukasloetkolben in https://github.com/sunnypilot/opendbc/pull/465
|
||||
* Sync: `commaai/opendbc:master` → `sunnypilot/opendbc:master` by @sunnyhaibin in https://github.com/sunnypilot/opendbc/pull/479
|
||||
* safety: add option to ignore frequency check for RX checks by @sunnyhaibin in https://github.com/sunnypilot/opendbc/pull/480
|
||||
* Revert "deprecate carState.brake" for Honda Gas Interceptor by @mvl-boston in https://github.com/sunnypilot/opendbc/pull/481
|
||||
* New Contributors (sunnypilot/sunnypilot)
|
||||
* @mvl-boston made their first contribution in https://github.com/sunnypilot/sunnypilot/pull/1860
|
||||
* Full Changelog: https://github.com/sunnypilot/sunnypilot/compare/v2026.001.007...v2026.002.000
|
||||
************************
|
||||
* Synced with commaai's openpilot (v0.11.1)
|
||||
* master commit 69e2c321e49760e52f7983eaa0a5f77cb95de637 (June 02, 2026)
|
||||
* New driver monitoring model
|
||||
* Improved image processing pipeline for driver camera
|
||||
* Improved thermal policy for comma four
|
||||
* Acura MDX 2022-24 support thanks to mvl-boston!
|
||||
* Rivian R1S and R1T 2025 support thanks to lukasloetkolben!
|
||||
|
||||
sunnypilot Version 2026.001.000 (2026-05-06)
|
||||
========================
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Schema-level cereal compat check between sunnypilot and upstream openpilot.
|
||||
"""Validate sunnypilot routes are parseable by stock commaai/openpilot.
|
||||
|
||||
Rules (per struct matched across sides by typeId):
|
||||
R1 shared ordinal must reference the same type.
|
||||
R2 sunnypilot-only ordinal in a union -> FAIL (unknown discriminant upstream).
|
||||
R3 sunnypilot-only ordinal on a regular field -> OK (additive struct evolution).
|
||||
R4 upstream-only ordinal -> OK.
|
||||
R5 sunnypilot-only struct referenced via an upstream-shared field -> FAIL.
|
||||
Cap'n Proto is wire-compatible across renames, type relocations, and
|
||||
additive fields. The only breaking change is a union variant that
|
||||
upstream doesn't recognize — an unknown discriminant makes the entire
|
||||
union unreadable.
|
||||
|
||||
This script checks: for every struct with a union that exists in both
|
||||
schemas, does sunnypilot introduce union variants upstream doesn't have?
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -24,46 +25,19 @@ def hex_id(value: int) -> str:
|
||||
return f"0x{value:016x}"
|
||||
|
||||
|
||||
def encode_type(type_node: Any) -> dict:
|
||||
which = type_node.which()
|
||||
if which == "struct":
|
||||
return {"kind": "struct", "typeId": hex_id(type_node.struct.typeId)}
|
||||
if which == "enum":
|
||||
return {"kind": "enum", "typeId": hex_id(type_node.enum.typeId)}
|
||||
if which == "interface":
|
||||
return {"kind": "interface", "typeId": hex_id(type_node.interface.typeId)}
|
||||
if which == "list":
|
||||
return {"kind": "list", "element": encode_type(type_node.list.elementType)}
|
||||
if which == "anyPointer":
|
||||
return {"kind": "anyPointer"}
|
||||
return {"kind": which}
|
||||
|
||||
|
||||
def encode_field(name: str, field: Any) -> dict:
|
||||
proto = field.proto
|
||||
ordinal = proto.ordinal.explicit if proto.ordinal.which() == "explicit" else None
|
||||
discriminant = proto.discriminantValue if proto.discriminantValue != NO_DISCRIMINANT else None
|
||||
|
||||
if proto.which() == "group":
|
||||
type_desc = {"kind": "group", "typeId": hex_id(proto.group.typeId)}
|
||||
else:
|
||||
type_desc = encode_type(proto.slot.type)
|
||||
|
||||
return {
|
||||
"name": name,
|
||||
"ordinal": ordinal,
|
||||
"discriminant": discriminant,
|
||||
"type": type_desc,
|
||||
}
|
||||
|
||||
|
||||
def encode_struct(schema: Any) -> dict:
|
||||
node = schema.node
|
||||
fields = []
|
||||
for name, field in schema.fields.items():
|
||||
proto = field.proto
|
||||
ordinal = proto.ordinal.explicit if proto.ordinal.which() == "explicit" else None
|
||||
discriminant = proto.discriminantValue if proto.discriminantValue != NO_DISCRIMINANT else None
|
||||
fields.append({"name": name, "ordinal": ordinal, "discriminant": discriminant})
|
||||
return {
|
||||
"typeId": hex_id(node.id),
|
||||
"displayName": node.displayName,
|
||||
"hasUnion": node.struct.discriminantCount > 0,
|
||||
"fields": [encode_field(name, field) for name, field in schema.fields.items()],
|
||||
"fields": fields,
|
||||
}
|
||||
|
||||
|
||||
@@ -105,15 +79,16 @@ def collect_schema(root: Any) -> dict[str, dict]:
|
||||
return structs
|
||||
|
||||
|
||||
def load_log(cereal_dir: str) -> Any:
|
||||
def load_log(cereal_dir: str, extra_imports: list[str] | None = None) -> Any:
|
||||
import capnp
|
||||
cereal_dir = os.path.abspath(cereal_dir)
|
||||
capnp.remove_import_hook()
|
||||
return capnp.load(os.path.join(cereal_dir, "log.capnp"), imports=[cereal_dir])
|
||||
imports = [cereal_dir] + [os.path.abspath(p) for p in (extra_imports or [])]
|
||||
return capnp.load(os.path.join(cereal_dir, "log.capnp"), imports=imports)
|
||||
|
||||
|
||||
def dump_schema(cereal_dir: str, path: str) -> None:
|
||||
log = load_log(cereal_dir)
|
||||
def dump_schema(cereal_dir: str, path: str, extra_imports: list[str] | None = None) -> None:
|
||||
log = load_log(cereal_dir, extra_imports)
|
||||
payload = {
|
||||
"root": hex_id(log.Event.schema.node.id),
|
||||
"structs": collect_schema(log.Event.schema),
|
||||
@@ -123,100 +98,37 @@ def dump_schema(cereal_dir: str, path: str) -> None:
|
||||
print(f"wrote schema dump with {len(payload['structs'])} structs to {path}")
|
||||
|
||||
|
||||
def types_equal(a: dict, b: dict) -> bool:
|
||||
if a.get("kind") != b.get("kind"):
|
||||
return False
|
||||
kind = a["kind"]
|
||||
if kind in ("struct", "enum", "interface", "group"):
|
||||
return a.get("typeId") == b.get("typeId")
|
||||
if kind == "list":
|
||||
return types_equal(a["element"], b["element"])
|
||||
return True
|
||||
|
||||
|
||||
def type_repr(t: dict) -> str:
|
||||
kind = t.get("kind", "?")
|
||||
if kind in ("struct", "enum", "interface", "group"):
|
||||
return f"{kind}({t.get('typeId')})"
|
||||
if kind == "list":
|
||||
return f"list<{type_repr(t['element'])}>"
|
||||
return kind
|
||||
|
||||
|
||||
def field_is_union_variant(field: dict) -> bool:
|
||||
return field.get("discriminant") is not None
|
||||
|
||||
|
||||
def index_fields_by_ordinal(struct: dict) -> dict[int, dict]:
|
||||
indexed: dict[int, dict] = {}
|
||||
for field in struct["fields"]:
|
||||
ordinal = field.get("ordinal")
|
||||
if ordinal is None:
|
||||
continue
|
||||
indexed[ordinal] = field
|
||||
return indexed
|
||||
|
||||
|
||||
def compare(sunnypilot_dump: dict, upstream_dump: dict) -> list[str]:
|
||||
violations: list[str] = []
|
||||
sunnypilot_structs: dict[str, dict] = sunnypilot_dump["structs"]
|
||||
upstream_structs: dict[str, dict] = upstream_dump["structs"]
|
||||
sunnypilot_structs = sunnypilot_dump["structs"]
|
||||
upstream_structs = upstream_dump["structs"]
|
||||
|
||||
sunnypilot_struct_referenced_from_shared: set[str] = set()
|
||||
|
||||
for type_id, sunnypilot_struct in sunnypilot_structs.items():
|
||||
upstream_struct = upstream_structs.get(type_id)
|
||||
if upstream_struct is None:
|
||||
for type_id, sp_struct in sunnypilot_structs.items():
|
||||
if not sp_struct["hasUnion"]:
|
||||
continue
|
||||
up_struct = upstream_structs.get(type_id)
|
||||
if up_struct is None:
|
||||
continue
|
||||
|
||||
sunnypilot_fields = index_fields_by_ordinal(sunnypilot_struct)
|
||||
upstream_fields = index_fields_by_ordinal(upstream_struct)
|
||||
display = sunnypilot_struct["displayName"]
|
||||
up_ordinals = {f["ordinal"] for f in up_struct["fields"] if f.get("discriminant") is not None}
|
||||
display = sp_struct["displayName"]
|
||||
|
||||
for ordinal, sunnypilot_field in sunnypilot_fields.items():
|
||||
upstream_field = upstream_fields.get(ordinal)
|
||||
if upstream_field is None:
|
||||
if field_is_union_variant(sunnypilot_field):
|
||||
violations.append(
|
||||
f"[R2] {display} @{ordinal} ('{sunnypilot_field['name']}', {type_repr(sunnypilot_field['type'])}): "
|
||||
f"union variant not present upstream. upstream cannot parse this discriminant."
|
||||
)
|
||||
for field in sp_struct["fields"]:
|
||||
if field.get("discriminant") is None:
|
||||
continue
|
||||
|
||||
if not types_equal(sunnypilot_field["type"], upstream_field["type"]):
|
||||
if field["ordinal"] not in up_ordinals:
|
||||
violations.append(
|
||||
f"[R1] {display} @{ordinal}: type mismatch. "
|
||||
f"sunnypilot='{sunnypilot_field['name']}' {type_repr(sunnypilot_field['type'])} vs "
|
||||
f"upstream='{upstream_field['name']}' {type_repr(upstream_field['type'])}."
|
||||
f"{display} @{field['ordinal']} '{field['name']}': "
|
||||
f"union variant not present upstream (discriminant={field['discriminant']})"
|
||||
)
|
||||
continue
|
||||
|
||||
cursor = sunnypilot_field["type"]
|
||||
while cursor.get("kind") == "list":
|
||||
cursor = cursor["element"]
|
||||
if cursor.get("kind") in ("struct", "group", "interface") and cursor.get("typeId"):
|
||||
sunnypilot_struct_referenced_from_shared.add(cursor["typeId"])
|
||||
|
||||
for type_id, sunnypilot_struct in sunnypilot_structs.items():
|
||||
if type_id in upstream_structs:
|
||||
continue
|
||||
if type_id in sunnypilot_struct_referenced_from_shared:
|
||||
violations.append(
|
||||
f"[R5] struct {sunnypilot_struct['displayName']} ({type_id}) exists only on sunnypilot "
|
||||
f"but is referenced from an upstream-shared field. upstream cannot resolve this type."
|
||||
)
|
||||
|
||||
return violations
|
||||
|
||||
|
||||
def load_peer(path: str) -> dict:
|
||||
with open(path, "r", encoding="utf-8") as handle:
|
||||
return json.load(handle)
|
||||
|
||||
|
||||
def run_read(cereal_dir: str, peer_path: str) -> int:
|
||||
log = load_log(cereal_dir)
|
||||
peer_dump = load_peer(peer_path)
|
||||
def run_read(cereal_dir: str, peer_path: str, extra_imports: list[str] | None = None) -> int:
|
||||
log = load_log(cereal_dir, extra_imports)
|
||||
with open(peer_path, "r", encoding="utf-8") as f:
|
||||
peer_dump = json.load(f)
|
||||
local_dump = {
|
||||
"root": hex_id(log.Event.schema.node.id),
|
||||
"structs": collect_schema(log.Event.schema),
|
||||
@@ -224,32 +136,29 @@ def run_read(cereal_dir: str, peer_path: str) -> int:
|
||||
violations = compare(sunnypilot_dump=peer_dump, upstream_dump=local_dump)
|
||||
|
||||
if not violations:
|
||||
print("cereal compat OK: upstream openpilot can parse sunnypilot routes "
|
||||
"(no leaked structs, no ordinal collisions).")
|
||||
print("cereal compat OK: upstream can parse sunnypilot routes.")
|
||||
return 0
|
||||
|
||||
print(f"cereal compat FAIL: upstream openpilot would misparse sunnypilot routes "
|
||||
f"({len(violations)} violation(s)):")
|
||||
print(f"cereal compat FAIL ({len(violations)} leaked union variant(s)):")
|
||||
for v in violations:
|
||||
print(f" {v}")
|
||||
return 1
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="sunnypilot <-> upstream cereal compatibility validator (schema-level)."
|
||||
)
|
||||
parser = argparse.ArgumentParser(description="sunnypilot cereal upstream compat check")
|
||||
mode = parser.add_mutually_exclusive_group(required=True)
|
||||
mode.add_argument("-g", "--generate", action="store_true", help="dump local schema to JSON")
|
||||
mode.add_argument("-r", "--read", action="store_true", help="load peer JSON and diff against local")
|
||||
parser.add_argument("-f", "--file", default="schema.json", help="JSON file path (default: schema.json)")
|
||||
parser.add_argument("--cereal-dir", required=True, help="path to cereal directory containing log.capnp")
|
||||
mode.add_argument("-r", "--read", action="store_true", help="validate against peer schema")
|
||||
parser.add_argument("-f", "--file", default="schema.json", help="JSON file path")
|
||||
parser.add_argument("--cereal-dir", required=True, help="path to cereal directory")
|
||||
parser.add_argument("-I", "--import-path", action="append", default=[], help="extra capnp import paths")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.generate:
|
||||
dump_schema(args.cereal_dir, args.file)
|
||||
dump_schema(args.cereal_dir, args.file, args.import_path)
|
||||
return 0
|
||||
return run_read(args.cereal_dir, args.file)
|
||||
return run_read(args.cereal_dir, args.file, args.import_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+1
-1
Submodule opendbc_repo updated: 0b5dacee34...bb51a59e53
@@ -226,7 +226,6 @@ exclude = [
|
||||
"teleoprtc/",
|
||||
"teleoprtc_repo/",
|
||||
"third_party/",
|
||||
"**/*.ipynb",
|
||||
]
|
||||
|
||||
[tool.ty.rules]
|
||||
|
||||
@@ -13,7 +13,7 @@ cd $ROOT
|
||||
|
||||
FAILED=0
|
||||
|
||||
IGNORED_FILES="uv\.lock|docs\/CARS.md|LICENSE\.md|layouts\/.*\.xml|.*\.ipynb"
|
||||
IGNORED_FILES="uv\.lock|docs\/CARS.md|LICENSE\.md"
|
||||
IGNORED_DIRS="^msgq.*|^msgq_repo.*|^opendbc.*|^opendbc_repo.*|^cereal.*|^panda.*|^rednose.*|^rednose_repo.*|^tinygrad.*|^tinygrad_repo.*|^teleoprtc.*|^teleoprtc_repo.*|^third_party.*"
|
||||
|
||||
function run() {
|
||||
|
||||
@@ -134,6 +134,11 @@ class SteeringLayout(Widget):
|
||||
|
||||
enforce_torque_enabled = self._torque_control_toggle.action_item.get_state()
|
||||
nnlc_enabled = self._nnlc_toggle.action_item.get_state()
|
||||
if enforce_torque_enabled and nnlc_enabled:
|
||||
self._torque_control_toggle.action_item.set_state(False)
|
||||
self._nnlc_toggle.action_item.set_state(False)
|
||||
enforce_torque_enabled = False
|
||||
nnlc_enabled = False
|
||||
self._nnlc_toggle.action_item.set_enabled(ui_state.is_offroad() and torque_allowed and not enforce_torque_enabled)
|
||||
self._torque_control_toggle.action_item.set_enabled(ui_state.is_offroad() and torque_allowed and not nnlc_enabled)
|
||||
self._torque_customization_button.action_item.set_enabled(self._torque_control_toggle.action_item.get_state())
|
||||
|
||||
@@ -179,6 +179,10 @@ class UIStateSP:
|
||||
CP = self.CP
|
||||
|
||||
if CP is not None:
|
||||
if self.params.get_bool("EnforceTorqueControl") and self.params.get_bool("NeuralNetworkLateralControl"):
|
||||
self.params.put_bool("EnforceTorqueControl", False, block=True)
|
||||
self.params.put_bool("NeuralNetworkLateralControl", False, block=True)
|
||||
|
||||
# Angle steering: no torque-based lateral controls
|
||||
if CP.steerControlType == car.CarParams.SteerControlType.angle:
|
||||
self.params.remove("EnforceTorqueControl")
|
||||
|
||||
@@ -28,8 +28,6 @@ SP_BRANCH_MIGRATIONS = {
|
||||
("tizi", "release3-staging"): "release-tizi-staging",
|
||||
("mici", "release3"): "release-mici",
|
||||
("mici", "release3-staging"): "release-mici-staging",
|
||||
("tici", "hkg-angle-steering-2025"): "hkg-angle-steering-2025-tici",
|
||||
("tici", "hkg-angle-steering-2025-prebuilt"): "hkg-angle-steering-2025-tici-prebuilt"
|
||||
}
|
||||
|
||||
BUILD_METADATA_FILENAME = "build.json"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,183 +0,0 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<root>
|
||||
<tabbed_widget parent="main_window" name="Main Window">
|
||||
<Tab containers="1" tab_name="actuator data">
|
||||
<Container>
|
||||
<DockSplitter orientation="-" sizes="0.25;0.25;0.25;0.25" count="4">
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="-0.100000" left="301.990881" top="0.100000" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/carControl/actuators/torque" color="#17becf"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="-130.920132" left="301.990881" top="103.993176" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/carControl/actuators/steeringAngleDeg" color="#1f77b4"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="-0.604818" left="301.990881" top="24.797527" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/carState/vEgoRaw" color="#ff7f0e"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="-0.037812" left="301.990881" top="0.047261" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/carControl/actuators/curvature" color="#f14cc1"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
</DockSplitter>
|
||||
</Container>
|
||||
</Tab>
|
||||
<Tab containers="1" tab_name="steering messages (CAN)">
|
||||
<Container>
|
||||
<DockSplitter orientation="-" sizes="0.142857;0.142857;0.142857;0.142857;0.142857;0.142857;0.142857" count="7">
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="-0.025000" left="301.990881" top="1.025000" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/can/128/LKAS_ALT/ADAS_ACIAnglTqRedcGainVal" color="#1f77b4"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="-128.740000" left="301.990881" top="103.940000" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/can/128/LKAS_ALT/ADAS_StrAnglReqVal" color="#29d627"/>
|
||||
<curve name="/can/192/LKAS_ALT/ADAS_StrAnglReqVal" color="#b41f32"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="-0.025000" left="301.990881" top="1.025000" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/carState/steeringPressed" color="#d62728"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="0.975000" left="301.990881" top="2.025000" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/sendcan/0/LKAS_ALT/LKAS_ANGLE_ACTIVE" color="#1f77b4"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="-0.025000" left="301.990881" top="1.025000" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/carState/steerFaultTemporary" color="#d62728"/>
|
||||
<curve name="/carControl/latActive" color="#1ac938"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="-0.025000" left="301.990881" top="1.025000" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/can/1/CCNC_0x161/DAW_ICON" color="#f14cc1"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="-14.375000" left="301.990881" top="589.375000" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/pandaStates/0/safetyTxBlocked" color="#1f77b4"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
</DockSplitter>
|
||||
</Container>
|
||||
</Tab>
|
||||
<Tab containers="1" tab_name="Understanding Torque">
|
||||
<Container>
|
||||
<DockSplitter orientation="-" sizes="0.5;0.5" count="2">
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="-6.175000" left="429.901019" top="253.175000" right="590.696728"/>
|
||||
<limitY/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="-24.190000" left="301.990881" top="21.590000" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/carState/steeringTorqueEps" color="#1ac938"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
</DockSplitter>
|
||||
</Container>
|
||||
</Tab>
|
||||
<Tab containers="1" tab_name="tab2">
|
||||
<Container>
|
||||
<DockSplitter orientation="-" sizes="0.25;0.25;0.25;0.25" count="4">
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Dots">
|
||||
<range bottom="-0.025000" left="301.990881" top="1.025000" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/sendcan/0/LKAS_ALT/ADAS_ACIAnglTqRedcGainVal" color="#9467bd"/>
|
||||
<curve name="/can/1/LFA_ALT/ADAS_ACIAnglTqRedcGainVal" color="#17becf"/>
|
||||
<curve name="/can/128/LKAS_ALT/ADAS_ACIAnglTqRedcGainVal" color="#1f77b4"/>
|
||||
<curve name="/can/192/LKAS_ALT/ADAS_ACIAnglTqRedcGainVal" color="#d62728"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Dots">
|
||||
<range bottom="0.975000" left="301.990881" top="2.025000" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/can/128/LKAS_ALT/LKAS_ANGLE_ACTIVE" color="#b8c91a"/>
|
||||
<curve name="/can/192/LKAS_ALT/LKAS_ANGLE_ACTIVE" color="#ff7f0e"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range bottom="-0.025000" left="301.990881" top="1.025000" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/can/1/CCNC_0x161/DAW_ICON" color="#f14cc1"/>
|
||||
<curve name="/carState/steerFaultTemporary" color="#1f77b4"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Dots">
|
||||
<range bottom="-14.375000" left="301.990881" top="589.375000" right="462.962504"/>
|
||||
<limitY/>
|
||||
<curve name="/pandaStates/0/safetyTxBlocked" color="#bcbd22"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
</DockSplitter>
|
||||
</Container>
|
||||
</Tab>
|
||||
<currentTabIndex index="3"/>
|
||||
</tabbed_widget>
|
||||
<use_relative_time_offset enabled="1"/>
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<Plugins>
|
||||
<plugin ID="DataLoad CSV">
|
||||
<default time_axis="" delimiter="0"/>
|
||||
</plugin>
|
||||
<plugin ID="DataLoad MCAP"/>
|
||||
<plugin ID="DataLoad Rlog"/>
|
||||
<plugin ID="DataLoad ULog"/>
|
||||
<plugin ID="Cereal Subscriber"/>
|
||||
<plugin ID="UDP Server"/>
|
||||
<plugin ID="WebSocket Server"/>
|
||||
<plugin ID="ZMQ Subscriber"/>
|
||||
<plugin ID="Fast Fourier Transform"/>
|
||||
<plugin ID="Quaternion to RPY"/>
|
||||
<plugin ID="Reactive Script Editor">
|
||||
<library code="--[[ Helper function to create a series from arrays

 new_series: a series previously created with ScatterXY.new(name)
 prefix: prefix of the timeseries, before the index of the array
 suffix_X: suffix to complete the name of the series containing the X value. If [nil], use the index of the array.
 suffix_Y: suffix to complete the name of the series containing the Y value
 timestamp: usually the tracker_time variable
 
 Example:
 
 Assuming we have multiple series in the form:
 
 /trajectory/node.{X}/position/x
 /trajectory/node.{X}/position/y
 
 where {N} is the index of the array (integer). We can create a reactive series from the array with:
 
 new_series = ScatterXY.new("my_trajectory") 
 CreateSeriesFromArray( new_series, "/trajectory/node", "position/x", "position/y", tracker_time );
--]]

function CreateSeriesFromArray( new_series, prefix, suffix_X, suffix_Y, timestamp )
 
 --- clear previous values
 new_series:clear()
 
 --- Append points to new_series
 index = 0
 while(true) do

 x = index;
 -- if not nil, get the X coordinate from a series
 if suffix_X ~= nil then 
 series_x = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_X) )
 if series_x == nil then break end
 x = series_x:atTime(timestamp)	 
 end
 
 series_y = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_Y) )
 if series_y == nil then break end 
 y = series_y:atTime(timestamp)
 
 new_series:push_back(x,y)
 index = index+1
 end
end

--[[ Similar to the built-in function GetSeriesNames(), but select only the names with a give prefix. --]]

function GetSeriesNamesByPrefix(prefix)
 -- GetSeriesNames(9 is a built-in function
 all_names = GetSeriesNames()
 filtered_names = {}
 for i, name in ipairs(all_names) do
 -- check the prefix
 if name:find(prefix, 1, #prefix) then
 table.insert(filtered_names, name);
 end
 end
 return filtered_names
end

--[[ Modify an existing series, applying offsets to all their X and Y values

 series: an existing timeseries, obtained with TimeseriesView.find(name)
 delta_x: offset to apply to each x value
 delta_y: offset to apply to each y value 
 
--]]

function ApplyOffsetInPlace(series, delta_x, delta_y)
 -- use C++ indeces, not Lua indeces
 for index=0, series:size()-1 do
 x,y = series:at(index)
 series:set(index, x + delta_x, y + delta_y)
 end
end
"/>
|
||||
<scripts/>
|
||||
</plugin>
|
||||
<plugin ID="CSV Exporter"/>
|
||||
</Plugins>
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<customMathEquations/>
|
||||
<snippets/>
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
</root>
|
||||
|
||||
@@ -1,702 +0,0 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<root>
|
||||
<tabbed_widget name="Main Window" parent="main_window">
|
||||
<Tab containers="1" tab_name="actuator data">
|
||||
<Container>
|
||||
<DockSplitter sizes="0.25;0.25;0.25;0.25" count="4" orientation="-">
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="0.100000" bottom="-0.100000" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="/carControl/actuators/torque" color="#17becf"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="21.512506" bottom="-143.133163" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="/carControl/actuators/steeringAngleDeg" color="#1f77b4"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="17.919758" bottom="7.125814" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="/carState/vEgoRaw" color="#ff7f0e"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="0.055486" bottom="-0.008455" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="/carControl/actuators/curvature" color="#f14cc1"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
</DockSplitter>
|
||||
</Container>
|
||||
</Tab>
|
||||
<Tab containers="1" tab_name="steering messages (CAN)">
|
||||
<Container>
|
||||
<DockSplitter sizes="0.25;0.25;0.25;0.25" count="4" orientation="-">
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="1.020200" bottom="0.171800" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="/sendcan/0/LKAS_ALT/ADAS_ACIAnglTqRedcGainVal" color="#1f77b4"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="3.417986" bottom="-1.676466" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="IMU_LatAccelVal_ms^2_roll_compensated" color="#ff7f0e"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="1.025000" bottom="-0.025000" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="/carState/steeringPressed" color="#d62728"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="0.100000" bottom="-0.100000" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="/can/1/CCNC_0x161/DAW_ICON" color="#f14cc1"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
</DockSplitter>
|
||||
</Container>
|
||||
</Tab>
|
||||
<Tab containers="1" tab_name="Understanding Torque">
|
||||
<Container>
|
||||
<DockSplitter sizes="0.5;0.5" count="2" orientation="-">
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="378.825000" bottom="-1125.825000" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="/carState/steeringTorque" color="#1f77b4"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="17.092500" bottom="-32.992499" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="/carState/steeringTorqueEps" color="#1ac938"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
</DockSplitter>
|
||||
</Container>
|
||||
</Tab>
|
||||
<Tab containers="1" tab_name="Angle Error and Saturation TQ">
|
||||
<Container>
|
||||
<DockSplitter sizes="0.166667;0.166667;0.166667;0.166667;0.166667;0.166667" count="6" orientation="-">
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="21.512506" bottom="-143.133163" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="/carControl/actuators/steeringAngleDeg" color="#d62728"/>
|
||||
<curve name="/carState/steeringAngleDeg" color="#1ac938"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="48.052530" bottom="-34.508142" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="Angle Error" color="#ff7f0e"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="1.020200" bottom="0.171800" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="/sendcan/0/LKAS_ALT/ADAS_ACIAnglTqRedcGainVal" color="#1f77b4"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="1.025000" bottom="-0.025000" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="Angle Staturation" color="#f14cc1"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="1.025000" bottom="-0.025000" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="/carControl/latActive" color="#9467bd"/>
|
||||
<curve name="/carState/steeringPressed" color="#17becf"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="64.446359" bottom="25.681587" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="carState.vEgo kmh" color="#1f77b4"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
</DockSplitter>
|
||||
</Container>
|
||||
</Tab>
|
||||
<Tab containers="1" tab_name="Smoothing and Torque celings">
|
||||
<Container>
|
||||
<DockSplitter sizes="0.5;0.5" count="2" orientation="-">
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="4.075000" bottom="0.925000" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="subject_to_angle_smoothing" color="#d62728"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot mode="TimeSeries" flip_x="false" flip_y="false" style="Lines">
|
||||
<range top="3.025000" bottom="1.975000" left="256.448992" right="302.818689"/>
|
||||
<limitY/>
|
||||
<curve name="base_ceiling_bracket" color="#1f77b4"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
</DockSplitter>
|
||||
</Container>
|
||||
</Tab>
|
||||
<currentTabIndex index="4"/>
|
||||
</tabbed_widget>
|
||||
<use_relative_time_offset enabled="1"/>
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<Plugins>
|
||||
<plugin ID="DataLoad CSV">
|
||||
<default time_axis="" delimiter="0"/>
|
||||
</plugin>
|
||||
<plugin ID="DataLoad MCAP"/>
|
||||
<plugin ID="DataLoad Rlog"/>
|
||||
<plugin ID="DataLoad ULog"/>
|
||||
<plugin ID="Cereal Subscriber"/>
|
||||
<plugin ID="UDP Server"/>
|
||||
<plugin ID="WebSocket Server"/>
|
||||
<plugin ID="ZMQ Subscriber"/>
|
||||
<plugin ID="Fast Fourier Transform"/>
|
||||
<plugin ID="Quaternion to RPY"/>
|
||||
<plugin ID="Reactive Script Editor">
|
||||
<library code="--[[ Helper function to create a series from arrays

 new_series: a series previously created with ScatterXY.new(name)
 prefix: prefix of the timeseries, before the index of the array
 suffix_X: suffix to complete the name of the series containing the X value. If [nil], use the index of the array.
 suffix_Y: suffix to complete the name of the series containing the Y value
 timestamp: usually the tracker_time variable
 
 Example:
 
 Assuming we have multiple series in the form:
 
 /trajectory/node.{X}/position/x
 /trajectory/node.{X}/position/y
 
 where {N} is the index of the array (integer). We can create a reactive series from the array with:
 
 new_series = ScatterXY.new("my_trajectory") 
 CreateSeriesFromArray( new_series, "/trajectory/node", "position/x", "position/y", tracker_time );
--]]

function CreateSeriesFromArray( new_series, prefix, suffix_X, suffix_Y, timestamp )
 
 --- clear previous values
 new_series:clear()
 
 --- Append points to new_series
 index = 0
 while(true) do

 x = index;
 -- if not nil, get the X coordinate from a series
 if suffix_X ~= nil then 
 series_x = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_X) )
 if series_x == nil then break end
 x = series_x:atTime(timestamp)	 
 end
 
 series_y = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_Y) )
 if series_y == nil then break end 
 y = series_y:atTime(timestamp)
 
 new_series:push_back(x,y)
 index = index+1
 end
end

--[[ Similar to the built-in function GetSeriesNames(), but select only the names with a give prefix. --]]

function GetSeriesNamesByPrefix(prefix)
 -- GetSeriesNames(9 is a built-in function
 all_names = GetSeriesNames()
 filtered_names = {}
 for i, name in ipairs(all_names) do
 -- check the prefix
 if name:find(prefix, 1, #prefix) then
 table.insert(filtered_names, name);
 end
 end
 return filtered_names
end

--[[ Modify an existing series, applying offsets to all their X and Y values

 series: an existing timeseries, obtained with TimeseriesView.find(name)
 delta_x: offset to apply to each x value
 delta_y: offset to apply to each y value 
 
--]]

function ApplyOffsetInPlace(series, delta_x, delta_y)
 -- use C++ indeces, not Lua indeces
 for index=0, series:size()-1 do
 x,y = series:at(index)
 series:set(index, x + delta_x, y + delta_y)
 end
end
"/>
|
||||
<scripts/>
|
||||
</plugin>
|
||||
<plugin ID="CSV Exporter"/>
|
||||
</Plugins>
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<customMathEquations>
|
||||
<snippet name="subject_to_angle_smoothing">
|
||||
<global></global>
|
||||
<function>if v1 == 0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
if value < 8.5 then
|
||||
return 1
|
||||
elseif value < 11 then
|
||||
return 2
|
||||
elseif value <= 13.8 then
|
||||
return 3
|
||||
elseif value <= 18 then
|
||||
return 4
|
||||
end
|
||||
|
||||
return 0</function>
|
||||
<linked_source>/carState/vEgo</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carControl/latActive</v1>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="base_ceiling_bracket">
|
||||
<global></global>
|
||||
<function>if v1 == 0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
if value < 20 then
|
||||
return 1
|
||||
elseif value < 40 then
|
||||
return 2
|
||||
elseif value <= 120 then
|
||||
return 3
|
||||
end
|
||||
|
||||
|
||||
return 0</function>
|
||||
<linked_source>carState.vEgo kmh</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carControl/latActive</v1>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="max torque lj adj">
|
||||
<global>min=0
|
||||
max=250
|
||||
max_from_speed=96
|
||||
|
||||
k1=200
|
||||
k2=30
|
||||
k3=1
|
||||
k4=1
|
||||
k5=10
|
||||
|
||||
function sign(number)
|
||||
return number > 0 and 1 or (number == 0 and 0 or -1)
|
||||
end</global>
|
||||
<function>return 250 - value * 20</function>
|
||||
<linked_source>desired lateral jark</linked_source>
|
||||
</snippet>
|
||||
<snippet name="Angle Staturation">
|
||||
<global></global>
|
||||
<function>if value > .3 then
|
||||
return 1
|
||||
end
|
||||
|
||||
return 0</function>
|
||||
<linked_source>Angle Error</linked_source>
|
||||
</snippet>
|
||||
<snippet name="ang_cmd rate">
|
||||
<global>firstX = 0
|
||||
firstY = 0
|
||||
is_first = true
|
||||
secondX = 0
|
||||
secondY = 0
|
||||
is_second = false</global>
|
||||
<function>-- Wait for initial values
|
||||
if (is_first) then
|
||||
is_first = false
|
||||
is_second = true
|
||||
firstX = time
|
||||
firstY = value
|
||||
end
|
||||
|
||||
if (is_second) then
|
||||
is_second = false
|
||||
secondX = time
|
||||
secondY = value
|
||||
end
|
||||
|
||||
-- Central derivative: dy/dx ~= f(x+delta_x)-f(x-delta_x)/(2*delta_x)
|
||||
dx = time - firstX
|
||||
dy = value - firstY
|
||||
-- Increment
|
||||
firstX = secondX
|
||||
firstY = secondY
|
||||
secondX = time
|
||||
secondY = value
|
||||
|
||||
return dy/dx</function>
|
||||
<linked_source>/can/1/LFA_ALT/LKAS_ANGLE_CMD</linked_source>
|
||||
</snippet>
|
||||
<snippet name="IMU_LatAccelVal_Ms^3">
|
||||
<global></global>
|
||||
<function>return value * -9.8</function>
|
||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/steeringPressed</v1>
|
||||
<v2>/carControl/latActive</v2>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="IMU_LatAccelVal_Ms^2">
|
||||
<global></global>
|
||||
<function>if (v1 == 0 and v2 == 1) then
|
||||
return value * -9.8
|
||||
end
|
||||
return 0</function>
|
||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/steeringPressed</v1>
|
||||
<v2>/carControl/latActive</v2>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="IMU_LatAccelVal_ms^2_roll_compensated">
|
||||
<global></global>
|
||||
<function>if (v1 == 0 and v2 == 1) then
|
||||
return (value * -9.8) - (v3 * 9.81)
|
||||
end
|
||||
--return 0
|
||||
return (value * -9.8) - (v3 * 9.81)</function>
|
||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/steeringPressed</v1>
|
||||
<v2>/carControl/latActive</v2>
|
||||
<v3>/liveParameters/roll</v3>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="abs(ang_cmd)">
|
||||
<global></global>
|
||||
<function>return math.abs(value)</function>
|
||||
<linked_source>/can/1/LFA_ALT/LKAS_ANGLE_CMD</linked_source>
|
||||
</snippet>
|
||||
<snippet name="zero">
|
||||
<global>min=0
|
||||
max=250
|
||||
max_from_speed=96
|
||||
|
||||
rate_lim = 500
|
||||
|
||||
la_deadzone = 0.38
|
||||
|
||||
k1=200
|
||||
k2=20
|
||||
k3=1.0
|
||||
k4=1
|
||||
k5=10
|
||||
|
||||
old = 0
|
||||
|
||||
function sign(number)
|
||||
return number > 0 and 1 or (number == 0 and 0 or -1)
|
||||
end
|
||||
|
||||
function apply_rate_limit(old, new, limit)
|
||||
return math.min(math.max(new, old - limit), old + limit)
|
||||
end
|
||||
|
||||
function apply_deadzone(val, deadzone)
|
||||
if math.abs(val) <= deadzone then
|
||||
return 0.0
|
||||
elseif val < 0.0 then
|
||||
return val + deadzone
|
||||
else
|
||||
return val - deadzone
|
||||
end
|
||||
end</global>
|
||||
<function>return 0</function>
|
||||
<linked_source>/carState/aEgo</linked_source>
|
||||
</snippet>
|
||||
<snippet name="engaged curvature vehicle model">
|
||||
<global>engage_delay = 5
|
||||
last_bad_time = -engage_delay</global>
|
||||
<function>curvature = value
|
||||
pressed = v1
|
||||
enabled = v2
|
||||
|
||||
if (pressed == 1 or enabled == 0) then
|
||||
last_bad_time = time
|
||||
end
|
||||
|
||||
if (time > last_bad_time + engage_delay) then
|
||||
return value
|
||||
else
|
||||
return 0
|
||||
end</function>
|
||||
<linked_source>/controlsState/curvature</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/steeringPressed</v1>
|
||||
<v2>/carControl/enabled</v2>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="engaged curvature plan">
|
||||
<global>engage_delay = 5
|
||||
last_bad_time = -engage_delay</global>
|
||||
<function>curvature = value
|
||||
pressed = v1
|
||||
enabled = v2
|
||||
|
||||
if (pressed == 1 or enabled == 0) then
|
||||
last_bad_time = time
|
||||
end
|
||||
|
||||
if (time > last_bad_time + engage_delay) then
|
||||
return value
|
||||
else
|
||||
return 0
|
||||
end</function>
|
||||
<linked_source>/lateralPlan/curvatures/0</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/steeringPressed</v1>
|
||||
<v2>/carControl/enabled</v2>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="desired lateral jark">
|
||||
<global>firstX = 0
|
||||
firstY = 0
|
||||
is_first = true
|
||||
secondX = 0
|
||||
secondY = 0
|
||||
is_second = false</global>
|
||||
<function>-- Wait for initial values
|
||||
if (is_first) then
|
||||
is_first = false
|
||||
is_second = true
|
||||
firstX = time
|
||||
firstY = value
|
||||
end
|
||||
|
||||
if (is_second) then
|
||||
is_second = false
|
||||
secondX = time
|
||||
secondY = value
|
||||
end
|
||||
|
||||
-- Central derivative: dy/dx ~= f(x+delta_x)-f(x-delta_x)/(2*delta_x)
|
||||
dx = time - firstX
|
||||
dy = value - firstY
|
||||
-- Increment
|
||||
firstX = secondX
|
||||
firstY = secondY
|
||||
secondX = time
|
||||
secondY = value
|
||||
|
||||
return dy/dx</function>
|
||||
<linked_source>desired lat accel</linked_source>
|
||||
</snippet>
|
||||
<snippet name="carState.vEgo kmh">
|
||||
<global></global>
|
||||
<function>return value * 3.6</function>
|
||||
<linked_source>/carState/vEgo</linked_source>
|
||||
</snippet>
|
||||
<snippet name="engaged_accel_plan">
|
||||
<global>engage_delay = 5
|
||||
last_bad_time = -engage_delay</global>
|
||||
<function>accel = value
|
||||
brake = v1
|
||||
gas = v2
|
||||
enabled = v3
|
||||
|
||||
if (brake ~= 0 or gas ~= 0 or enabled == 0) then
|
||||
last_bad_time = time
|
||||
end
|
||||
|
||||
if (time > last_bad_time + engage_delay) then
|
||||
return value
|
||||
else
|
||||
return 0
|
||||
end</function>
|
||||
<linked_source>/longitudinalPlan/accels/0</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/brakePressed</v1>
|
||||
<v2>/carState/gasPressed</v2>
|
||||
<v3>/carControl/enabled</v3>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="Angle Error">
|
||||
<global>last_angle_requested = 0</global>
|
||||
<function>angle_error = last_angle_requested - v1
|
||||
|
||||
|
||||
last_angle_requested = value
|
||||
return angle_error</function>
|
||||
<linked_source>/carControl/actuators/steeringAngleDeg</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/steeringAngleDeg</v1>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="IMU_LatAccelVal_ms^2">
|
||||
<global></global>
|
||||
<function>return value * -9.8</function>
|
||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/steeringPressed</v1>
|
||||
<v2>/carControl/latActive</v2>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="desired lat accel">
|
||||
<global></global>
|
||||
<function>return value * v1^2</function>
|
||||
<linked_source>/controlsState/desiredCurvature</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/vEgo</v1>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="engaged_accel_actuator">
|
||||
<global>engage_delay = 5
|
||||
last_bad_time = -engage_delay</global>
|
||||
<function>accel = value
|
||||
brake = v1
|
||||
gas = v2
|
||||
enabled = v3
|
||||
|
||||
if (brake ~= 0 or gas ~= 0 or enabled == 0) then
|
||||
last_bad_time = time
|
||||
end
|
||||
|
||||
if (time > last_bad_time + engage_delay) then
|
||||
return value
|
||||
else
|
||||
return 0
|
||||
end</function>
|
||||
<linked_source>/carControl/actuators/accel</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/brakePressed</v1>
|
||||
<v2>/carState/gasPressed</v2>
|
||||
<v3>/carControl/enabled</v3>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="engaged_accel_actual">
|
||||
<global>engage_delay = 5
|
||||
last_bad_time = -engage_delay</global>
|
||||
<function>accel = value
|
||||
brake = v1
|
||||
gas = v2
|
||||
enabled = v3
|
||||
|
||||
if (brake ~= 0 or gas ~= 0 or enabled == 0) then
|
||||
last_bad_time = time
|
||||
end
|
||||
|
||||
if (time > last_bad_time + engage_delay) then
|
||||
return value
|
||||
else
|
||||
return 0
|
||||
end</function>
|
||||
<linked_source>/carState/aEgo</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/brakePressed</v1>
|
||||
<v2>/carState/gasPressed</v2>
|
||||
<v3>/carControl/enabled</v3>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="roll compensated lateral acceleration">
|
||||
<global></global>
|
||||
<function>if (v3 == 0 and v4 == 1) then
|
||||
return (value * v1 ^ 2) - (v2 * 9.81)
|
||||
end
|
||||
return 0</function>
|
||||
<linked_source>/controlsState/curvature</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/vEgo</v1>
|
||||
<v2>/liveParameters/roll</v2>
|
||||
<v3>/carState/steeringPressed</v3>
|
||||
<v4>/carControl/latActive</v4>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="Zero">
|
||||
<global></global>
|
||||
<function>return (0)</function>
|
||||
<linked_source>/carState/canValid</linked_source>
|
||||
</snippet>
|
||||
<snippet name="abs(des la accel)">
|
||||
<global></global>
|
||||
<function>return math.abs(value)</function>
|
||||
<linked_source>desired lat accel</linked_source>
|
||||
</snippet>
|
||||
<snippet name="Desired lateral accel (roll compensated)">
|
||||
<global></global>
|
||||
<function>return (value * v1 ^ 2) - (v2 * 9.81)</function>
|
||||
<linked_source>/controlsState/desiredCurvature</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/vEgo</v1>
|
||||
<v2>/liveParameters/roll</v2>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="Actual lateral accel (roll compensated)">
|
||||
<global></global>
|
||||
<function>return (value * v1 ^ 2) - (v2 * 9.81)</function>
|
||||
<linked_source>/controlsState/curvature</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/vEgo</v1>
|
||||
<v2>/liveParameters/roll</v2>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="max torque(calc)">
|
||||
<global>min=0
|
||||
max=250
|
||||
max_from_speed=96
|
||||
|
||||
rate_lim = 500
|
||||
|
||||
la_deadzone = 0.38
|
||||
|
||||
k1=200
|
||||
k2=20
|
||||
k3=1.0
|
||||
k4=1
|
||||
k5=10
|
||||
|
||||
old = 0
|
||||
|
||||
function sign(number)
|
||||
return number > 0 and 1 or (number == 0 and 0 or -1)
|
||||
end
|
||||
|
||||
function apply_rate_limit(old, new, limit)
|
||||
return math.min(math.max(new, old - limit), old + limit)
|
||||
end
|
||||
|
||||
function apply_deadzone(val, deadzone)
|
||||
if math.abs(val) <= deadzone then
|
||||
return 0.0
|
||||
elseif val < 0.0 then
|
||||
return val + deadzone
|
||||
else
|
||||
return val - deadzone
|
||||
end
|
||||
end</global>
|
||||
<function>la = apply_deadzone(v2, la_deadzone)
|
||||
lj = v3
|
||||
|
||||
if la == 0.0 then
|
||||
lj = 0.0
|
||||
end
|
||||
|
||||
fla = math.min(math.abs(k1 * la)^k3, max)
|
||||
flj = math.min(math.abs(k2 * lj)^k4, max)
|
||||
|
||||
out = fla
|
||||
|
||||
flv = math.min(max_from_speed, k5 * v4)
|
||||
|
||||
out = out + flv
|
||||
|
||||
out = math.max(math.min(out, max), min)
|
||||
|
||||
if sign(la) == sign(lj) then
|
||||
out = out - flj
|
||||
else
|
||||
out = out + flj
|
||||
end
|
||||
|
||||
|
||||
if v5 == 1.0 then
|
||||
out = 0.0
|
||||
end
|
||||
|
||||
out = math.max(math.min(out, max), min)
|
||||
out = apply_rate_limit(old, out, rate_lim)
|
||||
old = out
|
||||
|
||||
return out</function>
|
||||
<linked_source>/can/1/LFA_ALT/LKAS_ANGLE_CMD</linked_source>
|
||||
<additional_sources>
|
||||
<v1>ang_cmd rate</v1>
|
||||
<v2>desired lat accel</v2>
|
||||
<v3>desired lateral jark</v3>
|
||||
<v4>/carState/vEgo</v4>
|
||||
<v5>/can/1/LFA_ALT/LKAS_ANGLE_ACTIVE</v5>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="carState.vEgo mph">
|
||||
<global></global>
|
||||
<function>return value * 2.23694</function>
|
||||
<linked_source>/carState/vEgo</linked_source>
|
||||
</snippet>
|
||||
<snippet name="engaged curvature yaw">
|
||||
<global>engage_delay = 5
|
||||
last_bad_time = -engage_delay</global>
|
||||
<function>curvature = value / v3
|
||||
pressed = v1
|
||||
enabled = v2
|
||||
|
||||
if (pressed == 1 or enabled == 0) then
|
||||
last_bad_time = time
|
||||
end
|
||||
|
||||
if (time > last_bad_time + engage_delay) then
|
||||
return curvature
|
||||
else
|
||||
return 0
|
||||
end</function>
|
||||
<linked_source>/liveLocationKalman/angularVelocityCalibrated/value/2</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/steeringPressed</v1>
|
||||
<v2>/carControl/enabled</v2>
|
||||
<v3>/liveLocationKalman/velocityCalibrated/value/0</v3>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
</customMathEquations>
|
||||
<snippets/>
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
</root>
|
||||
|
||||
@@ -1,274 +0,0 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<root>
|
||||
<tabbed_widget name="Main Window" parent="main_window">
|
||||
<Tab containers="1" tab_name="tab1">
|
||||
<Container>
|
||||
<DockSplitter sizes="0.500397;0.499603" count="2" orientation="-">
|
||||
<DockArea name="...">
|
||||
<plot flip_x="false" flip_y="false" mode="TimeSeries" style="Lines">
|
||||
<range top="256.250000" left="0.000000" right="421.102293" bottom="-6.250000"/>
|
||||
<limitY/>
|
||||
<curve color="#1ac938" name="/can/1/LFA_ALT/LKAS_ANGLE_MAX_TORQUE"/>
|
||||
<curve color="#17becf" name="max torque(calc)">
|
||||
<transform name="Moving Average" alias="max torque(calc)[Moving Average]">
|
||||
<options compensate_offset="true" value="10"/>
|
||||
</transform>
|
||||
</curve>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot flip_x="false" flip_y="false" mode="TimeSeries" style="Lines">
|
||||
<range top="2.776497" left="0.000000" right="421.102293" bottom="-2.918548"/>
|
||||
<limitY/>
|
||||
<curve color="#f14cc1" name="desired lat accel"/>
|
||||
<curve color="#888888" name="zero"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
</DockSplitter>
|
||||
</Container>
|
||||
</Tab>
|
||||
<currentTabIndex index="0"/>
|
||||
</tabbed_widget>
|
||||
<use_relative_time_offset enabled="1"/>
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<Plugins>
|
||||
<plugin ID="DataLoad CSV">
|
||||
<default time_axis="" delimiter="0"/>
|
||||
</plugin>
|
||||
<plugin ID="DataLoad MCAP"/>
|
||||
<plugin ID="DataLoad Rlog"/>
|
||||
<plugin ID="DataLoad ULog"/>
|
||||
<plugin ID="Cereal Subscriber"/>
|
||||
<plugin ID="UDP Server"/>
|
||||
<plugin ID="WebSocket Server"/>
|
||||
<plugin ID="ZMQ Subscriber"/>
|
||||
<plugin ID="Fast Fourier Transform"/>
|
||||
<plugin ID="Quaternion to RPY"/>
|
||||
<plugin ID="Reactive Script Editor">
|
||||
<library code="--[[ Helper function to create a series from arrays

 new_series: a series previously created with ScatterXY.new(name)
 prefix: prefix of the timeseries, before the index of the array
 suffix_X: suffix to complete the name of the series containing the X value. If [nil], use the index of the array.
 suffix_Y: suffix to complete the name of the series containing the Y value
 timestamp: usually the tracker_time variable
 
 Example:
 
 Assuming we have multiple series in the form:
 
 /trajectory/node.{X}/position/x
 /trajectory/node.{X}/position/y
 
 where {N} is the index of the array (integer). We can create a reactive series from the array with:
 
 new_series = ScatterXY.new("my_trajectory") 
 CreateSeriesFromArray( new_series, "/trajectory/node", "position/x", "position/y", tracker_time );
--]]

function CreateSeriesFromArray( new_series, prefix, suffix_X, suffix_Y, timestamp )
 
 --- clear previous values
 new_series:clear()
 
 --- Append points to new_series
 index = 0
 while(true) do

 x = index;
 -- if not nil, get the X coordinate from a series
 if suffix_X ~= nil then 
 series_x = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_X) )
 if series_x == nil then break end
 x = series_x:atTime(timestamp)	 
 end
 
 series_y = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_Y) )
 if series_y == nil then break end 
 y = series_y:atTime(timestamp)
 
 new_series:push_back(x,y)
 index = index+1
 end
end

--[[ Similar to the built-in function GetSeriesNames(), but select only the names with a give prefix. --]]

function GetSeriesNamesByPrefix(prefix)
 -- GetSeriesNames(9 is a built-in function
 all_names = GetSeriesNames()
 filtered_names = {}
 for i, name in ipairs(all_names) do
 -- check the prefix
 if name:find(prefix, 1, #prefix) then
 table.insert(filtered_names, name);
 end
 end
 return filtered_names
end

--[[ Modify an existing series, applying offsets to all their X and Y values

 series: an existing timeseries, obtained with TimeseriesView.find(name)
 delta_x: offset to apply to each x value
 delta_y: offset to apply to each y value 
 
--]]

function ApplyOffsetInPlace(series, delta_x, delta_y)
 -- use C++ indeces, not Lua indeces
 for index=0, series:size()-1 do
 x,y = series:at(index)
 series:set(index, x + delta_x, y + delta_y)
 end
end
"/>
|
||||
<scripts/>
|
||||
</plugin>
|
||||
<plugin ID="CSV Exporter"/>
|
||||
</Plugins>
|
||||
<customMathEquations>
|
||||
<snippet name="zero">
|
||||
<global>min=0
|
||||
max=250
|
||||
max_from_speed=96
|
||||
|
||||
rate_lim = 500
|
||||
|
||||
la_deadzone = 0.38
|
||||
|
||||
k1=200
|
||||
k2=20
|
||||
k3=1.0
|
||||
k4=1
|
||||
k5=10
|
||||
|
||||
old = 0
|
||||
|
||||
function sign(number)
|
||||
return number > 0 and 1 or (number == 0 and 0 or -1)
|
||||
end
|
||||
|
||||
function apply_rate_limit(old, new, limit)
|
||||
return math.min(math.max(new, old - limit), old + limit)
|
||||
end
|
||||
|
||||
function apply_deadzone(val, deadzone)
|
||||
if math.abs(val) <= deadzone then
|
||||
return 0.0
|
||||
elseif val < 0.0 then
|
||||
return val + deadzone
|
||||
else
|
||||
return val - deadzone
|
||||
end
|
||||
end</global>
|
||||
<function>return 0</function>
|
||||
<linked_source>/carState/aEgo</linked_source>
|
||||
</snippet>
|
||||
<snippet name="max torque lj adj">
|
||||
<global>min=0
|
||||
max=250
|
||||
max_from_speed=96
|
||||
|
||||
k1=200
|
||||
k2=30
|
||||
k3=1
|
||||
k4=1
|
||||
k5=10
|
||||
|
||||
function sign(number)
|
||||
return number > 0 and 1 or (number == 0 and 0 or -1)
|
||||
end</global>
|
||||
<function>return 250 - value * 20</function>
|
||||
<linked_source>desired lateral jark</linked_source>
|
||||
</snippet>
|
||||
<snippet name="ang_cmd rate">
|
||||
<global>firstX = 0
|
||||
firstY = 0
|
||||
is_first = true
|
||||
secondX = 0
|
||||
secondY = 0
|
||||
is_second = false</global>
|
||||
<function>-- Wait for initial values
|
||||
if (is_first) then
|
||||
is_first = false
|
||||
is_second = true
|
||||
firstX = time
|
||||
firstY = value
|
||||
end
|
||||
|
||||
if (is_second) then
|
||||
is_second = false
|
||||
secondX = time
|
||||
secondY = value
|
||||
end
|
||||
|
||||
-- Central derivative: dy/dx ~= f(x+delta_x)-f(x-delta_x)/(2*delta_x)
|
||||
dx = time - firstX
|
||||
dy = value - firstY
|
||||
-- Increment
|
||||
firstX = secondX
|
||||
firstY = secondY
|
||||
secondX = time
|
||||
secondY = value
|
||||
|
||||
return dy/dx</function>
|
||||
<linked_source>/can/1/LFA_ALT/LKAS_ANGLE_CMD</linked_source>
|
||||
</snippet>
|
||||
<snippet name="max torque(calc)">
|
||||
<global>min=0
|
||||
max=250
|
||||
max_from_speed=96
|
||||
|
||||
rate_lim = 500
|
||||
|
||||
la_deadzone = 0.38
|
||||
|
||||
k1=200
|
||||
k2=20
|
||||
k3=1.0
|
||||
k4=1
|
||||
k5=10
|
||||
|
||||
old = 0
|
||||
|
||||
function sign(number)
|
||||
return number > 0 and 1 or (number == 0 and 0 or -1)
|
||||
end
|
||||
|
||||
function apply_rate_limit(old, new, limit)
|
||||
return math.min(math.max(new, old - limit), old + limit)
|
||||
end
|
||||
|
||||
function apply_deadzone(val, deadzone)
|
||||
if math.abs(val) <= deadzone then
|
||||
return 0.0
|
||||
elseif val < 0.0 then
|
||||
return val + deadzone
|
||||
else
|
||||
return val - deadzone
|
||||
end
|
||||
end</global>
|
||||
<function>la = apply_deadzone(v2, la_deadzone)
|
||||
lj = v3
|
||||
|
||||
if la == 0.0 then
|
||||
lj = 0.0
|
||||
end
|
||||
|
||||
fla = math.min(math.abs(k1 * la)^k3, max)
|
||||
flj = math.min(math.abs(k2 * lj)^k4, max)
|
||||
|
||||
out = fla
|
||||
|
||||
flv = math.min(max_from_speed, k5 * v4)
|
||||
|
||||
out = out + flv
|
||||
|
||||
out = math.max(math.min(out, max), min)
|
||||
|
||||
if sign(la) == sign(lj) then
|
||||
out = out - flj
|
||||
else
|
||||
out = out + flj
|
||||
end
|
||||
|
||||
|
||||
if v5 == 1.0 then
|
||||
out = 0.0
|
||||
end
|
||||
|
||||
out = math.max(math.min(out, max), min)
|
||||
out = apply_rate_limit(old, out, rate_lim)
|
||||
old = out
|
||||
|
||||
return out</function>
|
||||
<linked_source>/can/1/LFA_ALT/LKAS_ANGLE_CMD</linked_source>
|
||||
<additional_sources>
|
||||
<v1>ang_cmd rate</v1>
|
||||
<v2>desired lat accel</v2>
|
||||
<v3>desired lateral jark</v3>
|
||||
<v4>/carState/vEgo</v4>
|
||||
<v5>/can/1/LFA_ALT/LKAS_ANGLE_ACTIVE</v5>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="desired lateral jark">
|
||||
<global>firstX = 0
|
||||
firstY = 0
|
||||
is_first = true
|
||||
secondX = 0
|
||||
secondY = 0
|
||||
is_second = false</global>
|
||||
<function>-- Wait for initial values
|
||||
if (is_first) then
|
||||
is_first = false
|
||||
is_second = true
|
||||
firstX = time
|
||||
firstY = value
|
||||
end
|
||||
|
||||
if (is_second) then
|
||||
is_second = false
|
||||
secondX = time
|
||||
secondY = value
|
||||
end
|
||||
|
||||
-- Central derivative: dy/dx ~= f(x+delta_x)-f(x-delta_x)/(2*delta_x)
|
||||
dx = time - firstX
|
||||
dy = value - firstY
|
||||
-- Increment
|
||||
firstX = secondX
|
||||
firstY = secondY
|
||||
secondX = time
|
||||
secondY = value
|
||||
|
||||
return dy/dx</function>
|
||||
<linked_source>desired lat accel</linked_source>
|
||||
</snippet>
|
||||
<snippet name="abs(des la accel)">
|
||||
<global></global>
|
||||
<function>return math.abs(value)</function>
|
||||
<linked_source>desired lat accel</linked_source>
|
||||
</snippet>
|
||||
<snippet name="desired lat accel">
|
||||
<global></global>
|
||||
<function>return value * v1^2</function>
|
||||
<linked_source>/controlsState/desiredCurvature</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/vEgo</v1>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="abs(ang_cmd)">
|
||||
<global></global>
|
||||
<function>return math.abs(value)</function>
|
||||
<linked_source>/can/1/LFA_ALT/LKAS_ANGLE_CMD</linked_source>
|
||||
</snippet>
|
||||
</customMathEquations>
|
||||
<snippets/>
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
</root>
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<root>
|
||||
<tabbed_widget parent="main_window" name="Main Window">
|
||||
<Tab tab_name="tab1" containers="1">
|
||||
<Container>
|
||||
<DockSplitter sizes="0.25;0.25;0.25;0.25" count="4" orientation="-">
|
||||
<DockArea name="...">
|
||||
<plot flip_x="false" style="Lines" flip_y="false" mode="TimeSeries">
|
||||
<range bottom="-3.582051" right="1431.113121" top="5.314632" left="5.322399"/>
|
||||
<limitY/>
|
||||
<curve name="Actual lateral accel (roll compensated)" color="#1ac938"/>
|
||||
<curve name="Desired lateral accel (roll compensated)" color="#ff7f0e"/>
|
||||
<curve name="IMU_LatAccelVal_ms^2" color="#f14cc1"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot flip_x="false" style="Lines" flip_y="false" mode="TimeSeries">
|
||||
<range bottom="-3.741271" right="1431.113121" top="3.756006" left="5.322399"/>
|
||||
<limitY/>
|
||||
<curve name="roll compensated lateral acceleration" color="#ff7f0e"/>
|
||||
<curve name="IMU_LatAccelVal_Ms^2" color="#1ac938"/>
|
||||
<curve name="IMU_LatAccelVal_ms^2_roll_compensated" color="#9467bd"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot flip_x="false" style="Lines" flip_y="false" mode="TimeSeries">
|
||||
<range bottom="-0.025000" right="1431.113121" top="1.025000" left="5.322399"/>
|
||||
<limitY/>
|
||||
<curve name="/carState/steeringPressed" color="#0097ff"/>
|
||||
<curve name="/carOutput/actuatorsOutput/torque" color="#d62728"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot flip_x="false" style="Lines" flip_y="false" mode="TimeSeries">
|
||||
<range bottom="-1.660728" right="1431.113121" top="67.942958" left="5.322399"/>
|
||||
<limitY/>
|
||||
<curve name="/carState/vEgo" color="#f14cc1">
|
||||
<transform name="Scale/Offset" alias="/carState/vEgo[Scale/Offset]">
|
||||
<options value_scale="2.23694" time_offset="0" value_offset="0"/>
|
||||
</transform>
|
||||
</curve>
|
||||
</plot>
|
||||
</DockArea>
|
||||
</DockSplitter>
|
||||
</Container>
|
||||
</Tab>
|
||||
<Tab tab_name="tab2" containers="1">
|
||||
<Container>
|
||||
<DockSplitter sizes="0.5;0.5" count="2" orientation="-">
|
||||
<DockArea name="...">
|
||||
<plot flip_x="false" style="Lines" flip_y="false" mode="TimeSeries">
|
||||
<range bottom="30595.900000" right="1431.113121" top="34884.100000" left="5.322399"/>
|
||||
<limitY/>
|
||||
<curve name="/can/1/IMU_01_10ms/IMU_RollRtVal" color="#17becf"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
<DockArea name="...">
|
||||
<plot flip_x="false" style="Lines" flip_y="false" mode="TimeSeries">
|
||||
<range bottom="-0.058795" right="1431.113121" top="0.072448" left="5.322399"/>
|
||||
<limitY/>
|
||||
<curve name="/liveParameters/roll" color="#bcbd22"/>
|
||||
</plot>
|
||||
</DockArea>
|
||||
</DockSplitter>
|
||||
</Container>
|
||||
</Tab>
|
||||
<currentTabIndex index="1"/>
|
||||
</tabbed_widget>
|
||||
<use_relative_time_offset enabled="1"/>
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<Plugins>
|
||||
<plugin ID="DataLoad CSV">
|
||||
<default time_axis="" delimiter="0"/>
|
||||
</plugin>
|
||||
<plugin ID="DataLoad MCAP"/>
|
||||
<plugin ID="DataLoad Rlog"/>
|
||||
<plugin ID="DataLoad ULog"/>
|
||||
<plugin ID="Cereal Subscriber"/>
|
||||
<plugin ID="UDP Server"/>
|
||||
<plugin ID="WebSocket Server"/>
|
||||
<plugin ID="ZMQ Subscriber"/>
|
||||
<plugin ID="Fast Fourier Transform"/>
|
||||
<plugin ID="Quaternion to RPY"/>
|
||||
<plugin ID="Reactive Script Editor">
|
||||
<library code="--[[ Helper function to create a series from arrays

 new_series: a series previously created with ScatterXY.new(name)
 prefix: prefix of the timeseries, before the index of the array
 suffix_X: suffix to complete the name of the series containing the X value. If [nil], use the index of the array.
 suffix_Y: suffix to complete the name of the series containing the Y value
 timestamp: usually the tracker_time variable
 
 Example:
 
 Assuming we have multiple series in the form:
 
 /trajectory/node.{X}/position/x
 /trajectory/node.{X}/position/y
 
 where {N} is the index of the array (integer). We can create a reactive series from the array with:
 
 new_series = ScatterXY.new("my_trajectory") 
 CreateSeriesFromArray( new_series, "/trajectory/node", "position/x", "position/y", tracker_time );
--]]

function CreateSeriesFromArray( new_series, prefix, suffix_X, suffix_Y, timestamp )
 
 --- clear previous values
 new_series:clear()
 
 --- Append points to new_series
 index = 0
 while(true) do

 x = index;
 -- if not nil, get the X coordinate from a series
 if suffix_X ~= nil then 
 series_x = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_X) )
 if series_x == nil then break end
 x = series_x:atTime(timestamp)	 
 end
 
 series_y = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_Y) )
 if series_y == nil then break end 
 y = series_y:atTime(timestamp)
 
 new_series:push_back(x,y)
 index = index+1
 end
end

--[[ Similar to the built-in function GetSeriesNames(), but select only the names with a give prefix. --]]

function GetSeriesNamesByPrefix(prefix)
 -- GetSeriesNames(9 is a built-in function
 all_names = GetSeriesNames()
 filtered_names = {}
 for i, name in ipairs(all_names) do
 -- check the prefix
 if name:find(prefix, 1, #prefix) then
 table.insert(filtered_names, name);
 end
 end
 return filtered_names
end

--[[ Modify an existing series, applying offsets to all their X and Y values

 series: an existing timeseries, obtained with TimeseriesView.find(name)
 delta_x: offset to apply to each x value
 delta_y: offset to apply to each y value 
 
--]]

function ApplyOffsetInPlace(series, delta_x, delta_y)
 -- use C++ indeces, not Lua indeces
 for index=0, series:size()-1 do
 x,y = series:at(index)
 series:set(index, x + delta_x, y + delta_y)
 end
end
"/>
|
||||
<scripts/>
|
||||
</plugin>
|
||||
<plugin ID="CSV Exporter"/>
|
||||
</Plugins>
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
<customMathEquations>
|
||||
<snippet name="IMU_LatAccelVal_ms^2">
|
||||
<global></global>
|
||||
<function>return value * -9.8</function>
|
||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/steeringPressed</v1>
|
||||
<v2>/carControl/latActive</v2>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="roll compensated lateral acceleration">
|
||||
<global></global>
|
||||
<function>if (v3 == 0 and v4 == 1) then
|
||||
return (value * v1 ^ 2) - (v2 * 9.81)
|
||||
end
|
||||
return 0</function>
|
||||
<linked_source>/controlsState/curvature</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/vEgo</v1>
|
||||
<v2>/liveParameters/roll</v2>
|
||||
<v3>/carState/steeringPressed</v3>
|
||||
<v4>/carControl/latActive</v4>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="IMU_LatAccelVal_Ms^2">
|
||||
<global></global>
|
||||
<function>if (v1 == 0 and v2 == 1) then
|
||||
return value * -9.8
|
||||
end
|
||||
return 0</function>
|
||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/steeringPressed</v1>
|
||||
<v2>/carControl/latActive</v2>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="IMU_LatAccelVal_Ms^3">
|
||||
<global></global>
|
||||
<function>return value * -9.8</function>
|
||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/steeringPressed</v1>
|
||||
<v2>/carControl/latActive</v2>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="IMU_LatAccelVal_ms^2_roll_compensated">
|
||||
<global></global>
|
||||
<function>
|
||||
|
||||
if (v1 == 0 and v2 == 1) then
|
||||
return (value * -9.8) - (v3 * 9.81)
|
||||
end
|
||||
return 0</function>
|
||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/steeringPressed</v1>
|
||||
<v2>/carControl/latActive</v2>
|
||||
<v3>/liveParameters/roll</v3>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="Actual lateral accel (roll compensated)">
|
||||
<global></global>
|
||||
<function>return (value * v1 ^ 2) - (v2 * 9.81)</function>
|
||||
<linked_source>/controlsState/curvature</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/vEgo</v1>
|
||||
<v2>/liveParameters/roll</v2>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
<snippet name="Desired lateral accel (roll compensated)">
|
||||
<global></global>
|
||||
<function>return (value * v1 ^ 2) - (v2 * 9.81)</function>
|
||||
<linked_source>/controlsState/desiredCurvature</linked_source>
|
||||
<additional_sources>
|
||||
<v1>/carState/vEgo</v1>
|
||||
<v2>/liveParameters/roll</v2>
|
||||
</additional_sources>
|
||||
</snippet>
|
||||
</customMathEquations>
|
||||
<snippets/>
|
||||
<!-- - - - - - - - - - - - - - - -->
|
||||
</root>
|
||||
|
||||
Reference in New Issue
Block a user