CAN Bus Output » History » Version 1
Adam Klama, 06/21/2026 03:29 PM
| 1 | 1 | Adam Klama | # CAN Bus Output |
|---|---|---|---|
| 2 | |||
| 3 | ## Overview |
||
| 4 | A **CAN Bus Output** packs a single **CANbus signal** into a raw outgoing CAN |
||
| 5 | frame, using a byte/bit layout you define by hand. Use it when you know the frame |
||
| 6 | layout (e.g. from a DBC) for an arbitrary or custom device and there is no |
||
| 7 | [CAN Preset](Working_with_the_CAN_Bus#can-presets) for it. |
||
| 8 | |||
| 9 | This is the **raw frame signal** approach: you give the message ID, say how the |
||
| 10 | bits are encoded and where they sit, then scale your source value into the raw |
||
| 11 | signal. To write a named object on a supported device instead, use a |
||
| 12 | [CAN Object Output](CAN_Object_Output). |
||
| 13 | |||
| 14 | ## Prerequisites & hardware |
||
| 15 | - A **defined CAN bus** for the channel the frame is sent on — see |
||
| 16 | [Working with the CAN Bus](Working_with_the_CAN_Bus). |
||
| 17 | - The frame's **message ID** and **bit layout** for the signal you want to write |
||
| 18 | (length, offset, encoding). |
||
| 19 | - A source value (a map, driver or input) to drive the signal. |
||
| 20 | |||
| 21 | ## Add it in the app |
||
| 22 | 1. Add a new output and choose **CAN Bus Output** as the type. |
||
| 23 | 2. Give it a clear **alias** (e.g. `Requested Torque`). |
||
| 24 | 3. Enter the **Message ID** and its **ID type**, then the **encoding type**, |
||
| 25 | **length** and **offset** that place the signal in the frame. |
||
| 26 | 4. Set the **in → raw** scaling and a **default value**, then drive it from a |
||
| 27 | map/driver. |
||
| 28 | |||
| 29 | ## Settings reference |
||
| 30 | > Schema: `config/CanbusOutputConfiguration.proto`. |
||
| 31 | |||
| 32 | | Setting | Meaning | Unit | Range / values | Notes | |
||
| 33 | |---|---|---|---|---| |
||
| 34 | | **Message ID** | CAN frame identifier to send | hex | fixed32 | The arbitration ID of the outgoing frame. | |
||
| 35 | | **Message ID type** | Identifier width | — | `Extended (29-bit)`, `Standard (11-bit)` | Must match what the receiving device expects. | |
||
| 36 | | **Encoding type** | How the value is packed into the bits | — | `UnsignedBigEndian`, `UnsignedLittleEndian`, `SignedBigEndian`, `SignedLittleEndian`, `BitField`, `CounterField`, `BitCounterField` | Selects signedness/endianness/bitfield. `CounterField` / `BitCounterField` auto-generate a rolling message counter. | |
||
| 37 | | **Length** | Signal length | bytes / bits | uint32 | In **bytes** for the integer types and `CounterField`; in **bits** for the bitfield types (`BitField`, `BitCounterField`). | |
||
| 38 | | **Offset** | Position of the signal in the frame | bytes / bits | uint32 | Same units as Length: **bytes** for integer/`CounterField` types, **bits** for bitfield types. | |
||
| 39 | | **In min / In max** | Input (engineering) range to scale **from** | source unit | sint32 | The source low/high points. | |
||
| 40 | | **Raw min / Raw max** | Raw signal range to scale **to** | — | sint32 | The packed value at In min / In max. | |
||
| 41 | | **Default value** | Value packed before a source value is available | source unit | sint32 | Sent until the source provides a value. | |
||
| 42 | |||
| 43 | **Scaling:** the source value is mapped from `In min…In max` to `Raw min…Raw max` |
||
| 44 | using [two-point interpolation](Scaling_and_Maps#two-point-interpolation). |
||
| 45 | |||
| 46 | **Rolling counter:** choose `CounterField` or `BitCounterField` for keep-alive / |
||
| 47 | rolling-counter bytes — the controller increments the value each frame for you, so |
||
| 48 | no source is needed. |
||
| 49 | |||
| 50 | ## Common settings |
||
| 51 | CAN Bus Output also uses the shared settings — alias and pin. See [Common IO Settings](Common_IO_Settings). |
||
| 52 | |||
| 53 | ## Example — requested torque to an inverter |
||
| 54 | 1. Type **CAN Bus Output**, alias `Requested Torque`. |
||
| 55 | 2. **Message ID** `0x100`, **ID type** `Standard (11-bit)`. |
||
| 56 | 3. **Encoding type** `UnsignedLittleEndian`, **Length** `2` (bytes), **Offset** `1` |
||
| 57 | (starts at byte 1) — a 16-bit value. (A bitfield type would use bits here.) |
||
| 58 | 4. **In min/max** `0`/`500` (Nm) → **Raw min/max** `0`/`5000` (0.1 Nm/bit). |
||
| 59 | 5. **Default value** `0` so no torque is requested until the strategy drives it. |
||
| 60 | 6. Add a second output on the same ID with **Encoding type** `CounterField` for the |
||
| 61 | inverter's rolling-counter byte. |
||
| 62 | |||
| 63 | ## Troubleshooting |
||
| 64 | - **Receiver ignores the frame:** check the **Message ID** and **ID type**, and the |
||
| 65 | CAN bus baud rate. |
||
| 66 | - **Value lands wrong / sign flipped:** check the **encoding type**, **Length** and |
||
| 67 | **Offset** — they are in **bytes** for integer/`CounterField` types and **bits** |
||
| 68 | for bitfield types. |
||
| 69 | - **Receiver reports a counter/checksum fault:** add a `CounterField` / |
||
| 70 | `BitCounterField` output for the rolling-counter byte. |
||
| 71 | - **Sends an unexpected value at start-up:** set a sensible **Default value**. |
||
| 72 | |||
| 73 | ## Related |
||
| 74 | - [CAN Object Output](CAN_Object_Output) — write a named object to a CAN Preset |
||
| 75 | instead of packing bytes by hand. |
||
| 76 | - [CAN Bus Input](CAN_Bus_Input) — decode a signal from an incoming |
||
| 77 | frame. |
||
| 78 | - [Working with the CAN Bus](Working_with_the_CAN_Bus) |