node-red-contrib-seeed-recamera
Version:
Node-RED nodes for reCamera
191 lines (168 loc) • 6.22 kB
HTML
<script type="text/html" data-template-name="can-to-angle">
<div class="form-row">
<label for="node-input-name">
<i class="fa fa-tag"></i>
<span>Name</span>
</label>
<input type="text" id="node-input-name" />
</div>
<div class="form-row">
<label for="node-input-name">
<i class="fa fa-arrow-circle-right"></i>
<span>Input</span>
</label>
<input type="text" id="node-input-input" />
<input type="hidden" id="node-input-input-type" />
</div>
<div class="form-row">
<label style="width: 100%;">
<i class="fa fa-arrow-circle-left"></i>
<span>Output as <b>motor angle</b></span>
</label>
</div>
<div class="form-row">
<label for="node-input-unit">
<i class="fa fa-pencil"></i>
<span>Unit</span>
</label>
</div>
<div class="form-row">
<div style="margin-left: 10px;">
<div>
<div style="display: flex; margin-bottom: 5px;">
<input style="width: auto; margin: 0 10px;" type="radio" name="node-input-unit" id="node-input-unit-decimal" value="0" />
<span>Output in decimal (e.g 180.23 as 180.23 degrees)</span>
</div>
<div style="display: flex;">
<input style="width: auto; margin: 0 10px;" type="radio" name="node-input-unit" id="node-input-unit-integer" value="1" />
<span>Output in integer (e.g 18023 as 180.23 degrees)</span>
</div>
</div>
</div>
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType("can-to-angle", {
category: "reCamera gimbal",
color: "#C6D09C",
defaults: {
name: { value: "" },
input: { value: "payload", required: true },
"input-type": { value: "msg" },
unit: { value: "0" }
},
inputs: 1,
outputs: 1,
icon: "font-awesome/fa-exchange",
paletteLabel: "CAN to angle",
label: function () {
return this.name || "CAN to angle";
},
oneditprepare: function () {
const node = this;
$("#node-input-input").typedInput({
type: "msg",
types: ["msg", "flow", "global"],
typeField: "#node-input-input-type",
});
$(`input[name="node-input-unit"][value="${node.unit || "0"}"]`).prop("checked", true);
},
oneditsave: function () {
this.unit = $('input[name="node-input-unit"]:checked').val();
this.input = $("#node-input-input").typedInput("value");
},
});
</script>
<script type="text/markdown" data-help-name="can-to-angle">
# CAN to angle
This node decodes and converts the raw data read from CANbus to decimal angular values.
## Overview
The node takes a CAN message object as input and extracts the motor ID, command type, and angle/offset value. It supports absolute position commands (A4), relative offset commands (A8), and status query commands (94).
## Input Configuration
The Input field allows you to specify the message property, flow context, or global context variable that contains the CAN message object. By default, it uses `msg.payload`.
## Input Format
The input should be a CAN message object with the following structure:
```json
{
"id": 0x141, // Motor ID in hex format (0x141 for Yaw, 0x142 for Pitch)
"data": [...] // Byte array containing the command data (8 bytes)
}
```
Example:
```json
{
"id": 0x141,
"data": [0xA4, 0x00, 0x5A, 0x00, 0x10, 0x27, 0x00, 0x00]
}
```
## Command Validation
The node includes advanced validation to ensure only meaningful data commands are processed:
- **94 commands**: Must NOT have all remaining bytes as zero (which would indicate a query, not a response)
- **A4/A6 commands**: The second byte must be 0x00 or 0x01 to be considered valid (excludes ACK responses like 0x2F)
- **A8 commands**: The second byte must be 0x00 to be considered valid
These validation rules prevent processing ACK responses and query commands that would result in incorrect angle calculations.
## Unit
- **Output in decimal**: Outputs angle values in decimal degrees (e.g., 180.23°)
- **Output in integer**: Outputs angle values in integer format representing hundredths of degrees (e.g., 18023 = 180.23°)
## Output
The node outputs a JSON object with the decoded information:
For absolute position commands (A4) with "Output in decimal" selected:
```json
{
"payload": {
"motorId": 0x141,
"angle": 90.5
}
}
```
For absolute position commands (A4) with "Output in integer" selected:
```json
{
"payload": {
"motorId": 0x141,
"angle": 9050
}
}
```
For relative offset commands (A8) with "Output in decimal" selected:
```json
{
"payload": {
"motorId": 0x142,
"offset": 5.0
}
}
```
For status query commands (94) with "Output in decimal" selected:
```json
{
"payload": {
"motorId": 0x141,
"status": true,
"angle": 90.5
}
}
```
## Motor IDs
- Yaw motor (horizontal): `0x141`
- Pitch motor (vertical): `0x142`
## Command Types
- `0xA4`: Absolute position command
- `0xA8`: Relative offset command
- `0x94`: Status query command
## Angle Units
- **Raw Value**: Motor units (hundredths of degrees)
- **Converted Value**: Degrees
## Notes
- The node handles the byte order conversion (little-endian format)
- Error messages are displayed if the input format is invalid
- When "Output in decimal" is selected, the values are more human-readable
- When "Output in integer" is selected, the values match the motor's internal units
- Invalid commands and ACK responses are filtered out with a yellow status indicator
## Technical Notes
- Motor units are in hundredths of degrees (0.01 degree/LSB)
- The raw value is useful for high-precision applications
- The converted value is more human-readable
- Status commands (94) return the current angle of the motor
- ACK responses with second byte 0x2F are automatically filtered
</script>