implemented minimal config (motors) updating
parent
0fa8e04493
commit
9036014e21
|
|
@ -1,45 +1,45 @@
|
||||||
export class ServoMotor {
|
export class ServoMotor {
|
||||||
constructor(arg1, arg2, arg3, arg4) {
|
constructor(arg1, arg2, arg3, arg4) {
|
||||||
if (Array.isArray(arg1)) {
|
if (Array.isArray(arg1)) {
|
||||||
// Full payload constructor
|
// Full payload constructor
|
||||||
const payload = arg1;
|
const payload = arg1;
|
||||||
|
|
||||||
this.CHANNEL = payload[0];
|
this.CHANNEL = payload[0];
|
||||||
this.ID = payload[1];
|
this.ID = payload[1];
|
||||||
this.MODEL = getModelType(payload[3], payload[2]);
|
this.MODEL = getModelType(payload[3], payload[2]);
|
||||||
|
|
||||||
this.MIN_ANGLE_LIMIT = (payload[4] << 8) | payload[5];
|
this.MIN_ANGLE_LIMIT = (payload[4] << 8) | payload[5];
|
||||||
this.MAX_ANGLE_LIMIT = (payload[6] << 8) | payload[7];
|
this.MAX_ANGLE_LIMIT = (payload[6] << 8) | payload[7];
|
||||||
this.POSITION = (payload[8] << 8) | payload[9];
|
this.POSITION = (payload[8] << 8) | payload[9];
|
||||||
this.CW_DEAD_ZONE = payload[10];
|
this.CW_DEAD_ZONE = payload[10];
|
||||||
this.CCW_DEAD_ZONE = payload[11];
|
this.CCW_DEAD_ZONE = payload[11];
|
||||||
this.OFFSET = (payload[12] << 8) | payload[13];
|
this.OFFSET = (payload[12] << 8) | payload[13];
|
||||||
this.MODE = payload[14];
|
this.MODE = payload[14];
|
||||||
this.TORQUE_ENABLE = payload[15];
|
this.TORQUE_ENABLE = payload[15];
|
||||||
this.ACCELERATION = payload[16];
|
this.ACCELERATION = payload[16];
|
||||||
this.GOAL_POSITION = (payload[17] << 8) | payload[18];
|
this.GOAL_POSITION = (payload[17] << 8) | payload[18];
|
||||||
this.GOAL_TIME = (payload[19] << 8) | payload[20];
|
this.GOAL_TIME = (payload[19] << 8) | payload[20];
|
||||||
this.GOAL_SPEED = (payload[21] << 8) | payload[22];
|
this.GOAL_SPEED = (payload[21] << 8) | payload[22];
|
||||||
this.LOCK = payload[23];
|
this.LOCK = payload[23];
|
||||||
|
|
||||||
const rawSpeed = (payload[24] << 8) | payload[25];
|
const rawSpeed = (payload[24] << 8) | payload[25];
|
||||||
this.CURRENT_SPEED = rawSpeed > 0x7FFF ? rawSpeed - 0x10000 : rawSpeed;
|
this.CURRENT_SPEED = rawSpeed > 0x7FFF ? rawSpeed - 0x10000 : rawSpeed;
|
||||||
|
|
||||||
this.CURRENT_LOAD = (payload[26] << 8) | payload[27];
|
this.CURRENT_LOAD = (payload[26] << 8) | payload[27];
|
||||||
this.TEMPERATURE = payload[28];
|
this.TEMPERATURE = payload[28];
|
||||||
this.MOVING = payload[29];
|
this.MOVING = payload[29];
|
||||||
this.CURRENT_CURRENT = (payload[30] << 8) | payload[31];
|
this.CURRENT_CURRENT = (payload[30] << 8) | payload[31];
|
||||||
this.VOLTAGE = payload[32];
|
this.VOLTAGE = payload[32];
|
||||||
} else {
|
} else {
|
||||||
// Simplified constructor
|
// Simplified constructor
|
||||||
this.CHANNEL = arg1;
|
this.CHANNEL = arg1;
|
||||||
this.ID = arg2;
|
this.ID = arg2;
|
||||||
|
|
||||||
this.MODEL = arg3 || 'Unknown Model';
|
|
||||||
|
|
||||||
this.NAME = arg4 || "UNKNOWN";
|
this.MODEL = arg3 || 'Unknown Model';
|
||||||
|
|
||||||
|
this.NAME = arg4 || "UNKNOWN";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -57,11 +57,11 @@ export function writeData(motor, key) {
|
||||||
throw new Error(`Motor does not contain value for key: ${key}`);
|
throw new Error(`Motor does not contain value for key: ${key}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// HANDLE DIFFERENT ADDRESS FOR LOCK ON SMS_STS
|
// HANDLE DIFFERENT ADDRESS FOR LOCK ON SMS_STS
|
||||||
if (key == 'LOCK') {
|
if (key == 'LOCK') {
|
||||||
if (motor.MODEL && (motor.MODEL.includes("SMS") || motor.MODEL.includes("STS"))) {
|
if (motor.MODEL && (motor.MODEL.includes("SMS") || motor.MODEL.includes("STS"))) {
|
||||||
address = DataMap.LOCK_SMS_STS.address;
|
address = DataMap.LOCK_SMS_STS.address;
|
||||||
} else {
|
} else {
|
||||||
address = DataMap.LOCK.address;
|
address = DataMap.LOCK.address;
|
||||||
|
|
@ -112,71 +112,80 @@ const DataMap = Object.freeze({
|
||||||
|
|
||||||
|
|
||||||
export function getModelType(major, minor) {
|
export function getModelType(major, minor) {
|
||||||
const modelList = new Map([
|
|
||||||
[combine(5, 0), "SCSXX"],
|
|
||||||
[combine(5, 4), "SCS009"],
|
|
||||||
[combine(5, 8), "SCS2332"],
|
|
||||||
[combine(5, 12), "SCS45"],
|
|
||||||
[combine(5, 15), "SCS15"],
|
|
||||||
[combine(5, 16), "SCS315"],
|
|
||||||
[combine(5, 25), "SCS115"],
|
|
||||||
[combine(5, 35), "SCS215"],
|
|
||||||
[combine(5, 40), "SCS40"],
|
|
||||||
[combine(5, 60), "SCS6560"],
|
|
||||||
[combine(5, 240), "SCDZZ"],
|
|
||||||
[combine(6, 0), "SMXX-360M"],
|
|
||||||
[combine(6, 3), "SM30-360M"],
|
|
||||||
[combine(6, 8), "SM60-360M"],
|
|
||||||
[combine(6, 12), "SM80-360M"],
|
|
||||||
[combine(6, 16), "SM100-360M"],
|
|
||||||
[combine(6, 20), "SM150-360M"],
|
|
||||||
[combine(6, 24), "SM85-360M"],
|
|
||||||
[combine(6, 26), "SM60-360M"],
|
|
||||||
[combine(8, 0), "SM30BL"],
|
|
||||||
[combine(8, 1), "SM30BL"],
|
|
||||||
[combine(8, 2), "SM30BL"],
|
|
||||||
[combine(8, 3), "SM30BL"],
|
|
||||||
[combine(8, 4), "SM30BL"],
|
|
||||||
[combine(8, 5), "SM30BL"],
|
|
||||||
[combine(8, 6), "SM30BL"],
|
|
||||||
[combine(8, 7), "SM30BL"],
|
|
||||||
[combine(8, 8), "SM30BL"],
|
|
||||||
[combine(8, 9), "SM30BL"],
|
|
||||||
[combine(8, 10), "SM30BL"],
|
|
||||||
[combine(8, 11), "SM30BL"],
|
|
||||||
[combine(8, 12), "SM30BL"],
|
|
||||||
[combine(8, 13), "SM30BL"],
|
|
||||||
[combine(8, 14), "SM30BL"],
|
|
||||||
[combine(8, 15), "SM30BL"],
|
|
||||||
[combine(8, 16), "SM30BL"],
|
|
||||||
[combine(8, 17), "SM30BL"],
|
|
||||||
[combine(8, 18), "SM30BL"],
|
|
||||||
[combine(8, 19), "SM30BL"],
|
|
||||||
[combine(8, 25), "SM29BL(LJ)"],
|
|
||||||
[combine(8, 29), "SM29BL(FT)"],
|
|
||||||
[combine(8, 30), "SM30BL(FT)"],
|
|
||||||
[combine(8, 20), "SM30BL(LJ)"],
|
|
||||||
[combine(8, 40), "SM40BLHV"],
|
|
||||||
[combine(8, 42), "SM45BLHV"],
|
|
||||||
[combine(8, 44), "SM85BLHV"],
|
|
||||||
[combine(8, 120), "SM120BLHV"],
|
|
||||||
[combine(8, 220), "SM200BLHV"],
|
|
||||||
[combine(9, 0), "STSXX"],
|
|
||||||
[combine(9, 2), "STS3032"],
|
|
||||||
[combine(9, 3), "STS3215"],
|
|
||||||
[combine(9, 4), "STS3040"],
|
|
||||||
[combine(9, 5), "STS3020"],
|
|
||||||
[combine(9, 6), "STS3046"],
|
|
||||||
[combine(9, 20), "SCSXX-2"],
|
|
||||||
[combine(9, 15), "SCS15-2"],
|
|
||||||
[combine(9, 35), "SCS225"],
|
|
||||||
[combine(9, 40), "SCS40-2"]
|
|
||||||
]);
|
|
||||||
|
|
||||||
const id = combine(major, minor);
|
const id = combine(major, minor);
|
||||||
return modelList.get(id) || "Unknown Model";
|
return modelList.get(id) || "Unknown Model";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const modelList = new Map([
|
||||||
|
[combine(5, 0), "SCSXX"],
|
||||||
|
[combine(5, 4), "SCS009"],
|
||||||
|
[combine(5, 8), "SCS2332"],
|
||||||
|
[combine(5, 12), "SCS45"],
|
||||||
|
[combine(5, 15), "SCS15"],
|
||||||
|
[combine(5, 16), "SCS315"],
|
||||||
|
[combine(5, 25), "SCS115"],
|
||||||
|
[combine(5, 35), "SCS215"],
|
||||||
|
[combine(5, 40), "SCS40"],
|
||||||
|
[combine(5, 60), "SCS6560"],
|
||||||
|
[combine(5, 240), "SCDZZ"],
|
||||||
|
[combine(6, 0), "SMXX-360M"],
|
||||||
|
[combine(6, 3), "SM30-360M"],
|
||||||
|
[combine(6, 8), "SM60-360M"],
|
||||||
|
[combine(6, 12), "SM80-360M"],
|
||||||
|
[combine(6, 16), "SM100-360M"],
|
||||||
|
[combine(6, 20), "SM150-360M"],
|
||||||
|
[combine(6, 24), "SM85-360M"],
|
||||||
|
[combine(6, 26), "SM60-360M"],
|
||||||
|
[combine(8, 0), "SM30BL"],
|
||||||
|
[combine(8, 1), "SM30BL"],
|
||||||
|
[combine(8, 2), "SM30BL"],
|
||||||
|
[combine(8, 3), "SM30BL"],
|
||||||
|
[combine(8, 4), "SM30BL"],
|
||||||
|
[combine(8, 5), "SM30BL"],
|
||||||
|
[combine(8, 6), "SM30BL"],
|
||||||
|
[combine(8, 7), "SM30BL"],
|
||||||
|
[combine(8, 8), "SM30BL"],
|
||||||
|
[combine(8, 9), "SM30BL"],
|
||||||
|
[combine(8, 10), "SM30BL"],
|
||||||
|
[combine(8, 11), "SM30BL"],
|
||||||
|
[combine(8, 12), "SM30BL"],
|
||||||
|
[combine(8, 13), "SM30BL"],
|
||||||
|
[combine(8, 14), "SM30BL"],
|
||||||
|
[combine(8, 15), "SM30BL"],
|
||||||
|
[combine(8, 16), "SM30BL"],
|
||||||
|
[combine(8, 17), "SM30BL"],
|
||||||
|
[combine(8, 18), "SM30BL"],
|
||||||
|
[combine(8, 19), "SM30BL"],
|
||||||
|
[combine(8, 25), "SM29BL(LJ)"],
|
||||||
|
[combine(8, 29), "SM29BL(FT)"],
|
||||||
|
[combine(8, 30), "SM30BL(FT)"],
|
||||||
|
[combine(8, 20), "SM30BL(LJ)"],
|
||||||
|
[combine(8, 40), "SM40BLHV"],
|
||||||
|
[combine(8, 42), "SM45BLHV"],
|
||||||
|
[combine(8, 44), "SM85BLHV"],
|
||||||
|
[combine(8, 120), "SM120BLHV"],
|
||||||
|
[combine(8, 220), "SM200BLHV"],
|
||||||
|
[combine(9, 0), "STSXX"],
|
||||||
|
[combine(9, 2), "STS3032"],
|
||||||
|
[combine(9, 3), "STS3215"],
|
||||||
|
[combine(9, 4), "STS3040"],
|
||||||
|
[combine(9, 5), "STS3020"],
|
||||||
|
[combine(9, 6), "STS3046"],
|
||||||
|
[combine(9, 20), "SCSXX-2"],
|
||||||
|
[combine(9, 15), "SCS15-2"],
|
||||||
|
[combine(9, 35), "SCS225"],
|
||||||
|
[combine(9, 40), "SCS40-2"]
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const reverseModelMap = new Map();
|
||||||
|
for (const [combined, model] of modelList.entries()) {
|
||||||
|
const minor = combined >> 8;
|
||||||
|
const major = combined & 0xFF;
|
||||||
|
reverseModelMap.set(model, { major, minor });
|
||||||
|
}
|
||||||
|
|
||||||
function combine(major, minor) {
|
function combine(major, minor) {
|
||||||
return (minor << 8) | major;
|
return (minor << 8) | major;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
16
index.html
16
index.html
|
|
@ -50,16 +50,19 @@
|
||||||
<div class="channel-box mb-5">
|
<div class="channel-box mb-5">
|
||||||
<label class="form-label">Channel 0</label>
|
<label class="form-label">Channel 0</label>
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<div class="col-9">
|
<!-- <div class="col-9">
|
||||||
<select class="form-select">
|
<select class="form-select">
|
||||||
<option selected>SCS</option>
|
<option selected>SCS</option>
|
||||||
<option>STS</option>
|
<option>STS</option>
|
||||||
<option>SM</option>
|
<option>SM</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div> -->
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<button id="btn_scan_channel_0" class="btn btn-primary w-100">Scan</button>
|
<button id="btn_scan_channel_0" class="btn btn-primary w-100">Scan</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
<button id="btn_apply_config_channel_0" class="btn btn-primary w-100">Apply To Config</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table id="channel0-motor-table" class="table table-bordered">
|
<table id="channel0-motor-table" class="table table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
@ -85,6 +88,7 @@
|
||||||
<th data-key="MOVING">MOVING</th>
|
<th data-key="MOVING">MOVING</th>
|
||||||
<th data-key="CURRENT_CURRENT">CURRENT</th>
|
<th data-key="CURRENT_CURRENT">CURRENT</th>
|
||||||
<th data-key="VOLTAGE">VOLTAGE</th>
|
<th data-key="VOLTAGE">VOLTAGE</th>
|
||||||
|
<th data-key="NAME">NAME</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -97,16 +101,19 @@
|
||||||
<div class="channel-box mb-5">
|
<div class="channel-box mb-5">
|
||||||
<label class="form-label">Channel 1</label>
|
<label class="form-label">Channel 1</label>
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<div class="col-9">
|
<!-- <div class="col-9">
|
||||||
<select class="form-select">
|
<select class="form-select">
|
||||||
<option selected>SCS</option>
|
<option selected>SCS</option>
|
||||||
<option>STS</option>
|
<option>STS</option>
|
||||||
<option>SM</option>
|
<option>SM</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div> -->
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<button id="btn_scan_channel_1" class="btn btn-primary w-100">Scan</button>
|
<button id="btn_scan_channel_1" class="btn btn-primary w-100">Scan</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
<button id="btn_apply_config_channel_1" class="btn btn-primary w-100">Apply</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table id="channel1-motor-table" class="table table-bordered">
|
<table id="channel1-motor-table" class="table table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
@ -132,6 +139,7 @@
|
||||||
<th data-key="MOVING">MOVING</th>
|
<th data-key="MOVING">MOVING</th>
|
||||||
<th data-key="CURRENT_CURRENT">CURRENT</th>
|
<th data-key="CURRENT_CURRENT">CURRENT</th>
|
||||||
<th data-key="VOLTAGE">VOLTAGE</th>
|
<th data-key="VOLTAGE">VOLTAGE</th>
|
||||||
|
<th data-key="NAME">NAME</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</thead>
|
</thead>
|
||||||
|
|
|
||||||
122
script.js
122
script.js
|
|
@ -1,5 +1,5 @@
|
||||||
import { SerialManager } from './serial.js';
|
import { SerialManager } from './serial.js';
|
||||||
import { ServoMotor, getModelType, writeData } from './feetechDefinitions.js';
|
import { ServoMotor, getModelType, reverseModelMap, writeData } from './feetechDefinitions.js';
|
||||||
import { CurveEditor } from './curveEditor.js';
|
import { CurveEditor } from './curveEditor.js';
|
||||||
import { Robot } from './robot.js';
|
import { Robot } from './robot.js';
|
||||||
import { NodeEditor } from './nodeeditor/NodeEditor.js';
|
import { NodeEditor } from './nodeeditor/NodeEditor.js';
|
||||||
|
|
@ -249,7 +249,7 @@ window.onload = () => {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function clearDials(){
|
function clearDials() {
|
||||||
const dialArea = document.getElementById('dialArea');
|
const dialArea = document.getElementById('dialArea');
|
||||||
dialArea.innerHTML = ''; // Remove all child elements
|
dialArea.innerHTML = ''; // Remove all child elements
|
||||||
dials = [];
|
dials = [];
|
||||||
|
|
@ -315,7 +315,7 @@ window.onload = () => {
|
||||||
dials[ch].value = curveEditor.getMotorPositionAtTime(dials[ch].motorID, currentFrame);
|
dials[ch].value = curveEditor.getMotorPositionAtTime(dials[ch].motorID, currentFrame);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -330,7 +330,7 @@ window.onload = () => {
|
||||||
|
|
||||||
for (let ch = 0; ch < dials.length; ch++) {
|
for (let ch = 0; ch < dials.length; ch++) {
|
||||||
const value = dials[ch].value;
|
const value = dials[ch].value;
|
||||||
motorPayloads.push({ motorId: ch, position: value });
|
motorPayloads.push({ motorId: dials[ch].motorID, position: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
const buffer = new ArrayBuffer(motorPayloads.length * 3);
|
const buffer = new ArrayBuffer(motorPayloads.length * 3);
|
||||||
|
|
@ -343,6 +343,8 @@ window.onload = () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const payload = new Uint8Array(buffer);
|
const payload = new Uint8Array(buffer);
|
||||||
|
console.log("SENDING POSITIONTS");
|
||||||
|
console.log(payload);
|
||||||
serial.sendSetPositions(payload);
|
serial.sendSetPositions(payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -732,6 +734,92 @@ window.onload = () => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('btn_apply_config_channel_0').onclick = async () => {
|
||||||
|
const table = document.querySelector('#channel0-motor-table tbody');
|
||||||
|
const rows = table.querySelectorAll('tr');
|
||||||
|
const motors = [];
|
||||||
|
|
||||||
|
rows.forEach(row => {
|
||||||
|
const cells = row.querySelectorAll('td');
|
||||||
|
const motor = {
|
||||||
|
MODEL: reverseModelMap.get(cells[0].textContent.trim()),
|
||||||
|
ID: parseInt(cells[1].textContent.trim()),
|
||||||
|
// MIN_ANGLE_LIMIT: parseInt(cells[2].textContent.trim()),
|
||||||
|
// MAX_ANGLE_LIMIT: parseInt(cells[3].textContent.trim()),
|
||||||
|
// POSITION: parseInt(cells[4].textContent.trim()),
|
||||||
|
// CW_DEAD_ZONE: parseInt(cells[5].textContent.trim()),
|
||||||
|
// CCW_DEAD_ZONE: parseInt(cells[6].textContent.trim()),
|
||||||
|
// OFFSET: parseInt(cells[7].textContent.trim()),
|
||||||
|
// MODE: parseInt(cells[8].textContent.trim()),
|
||||||
|
// TORQUE_ENABLE: parseInt(cells[9].textContent.trim()),
|
||||||
|
// ACCELERATION: parseInt(cells[10].textContent.trim()),
|
||||||
|
// GOAL_POSITION: parseInt(cells[11].textContent.trim()),
|
||||||
|
// GOAL_TIME: parseInt(cells[12].textContent.trim()),
|
||||||
|
// GOAL_SPEED: parseInt(cells[13].textContent.trim()),
|
||||||
|
// LOCK: parseInt(cells[14].textContent.trim()),
|
||||||
|
// CURRENT_SPEED: parseInt(cells[15].textContent.trim()),
|
||||||
|
// CURRENT_LOAD: parseInt(cells[16].textContent.trim()),
|
||||||
|
// TEMPERATURE: parseInt(cells[17].textContent.trim()),
|
||||||
|
// MOVING: parseInt(cells[18].textContent.trim()),
|
||||||
|
// CURRENT_CURRENT: parseInt(cells[19].textContent.trim()),
|
||||||
|
// VOLTAGE: parseInt(cells[20].textContent.trim()),
|
||||||
|
NAME: cells[21].textContent.trim()
|
||||||
|
};
|
||||||
|
|
||||||
|
motors.push(motor);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Compiled motor list:", motors);
|
||||||
|
|
||||||
|
await serial.sendConfigUpdate(encodeMotorConfig(motors));
|
||||||
|
// You can now use this list for saving, sending, or applying config
|
||||||
|
};
|
||||||
|
|
||||||
|
function encodeMotorConfig(motors) {
|
||||||
|
const robotName = "Mr Roboto";
|
||||||
|
const firmwareVersion = 1;
|
||||||
|
|
||||||
|
const bufferSize = 1024; // adjust as needed
|
||||||
|
const buffer = new ArrayBuffer(bufferSize);
|
||||||
|
const view = new DataView(buffer);
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
const nameBytes = encoder.encode(robotName);
|
||||||
|
const nameLength = Math.min(nameBytes.length, 255); // max 255 bytes
|
||||||
|
|
||||||
|
// 🔹 Encode robotName (length + bytes)
|
||||||
|
view.setUint8(offset++, nameLength);
|
||||||
|
for (let i = 0; i < nameLength; i++) {
|
||||||
|
view.setUint8(offset++, nameBytes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔹 Encode firmwareVersion (2 bytes)
|
||||||
|
view.setUint16(offset, firmwareVersion, true); offset += 2;
|
||||||
|
|
||||||
|
// 🔹 Encode motor count (1 byte)
|
||||||
|
view.setUint8(offset++, motors.length);
|
||||||
|
|
||||||
|
// 🔹 Encode motor entries
|
||||||
|
motors.forEach(motor => {
|
||||||
|
const { major, minor } = motor.MODEL;
|
||||||
|
const modelValue = (minor << 8) | major;
|
||||||
|
|
||||||
|
view.setUint16(offset, modelValue, true); offset += 2; // MODEL
|
||||||
|
view.setUint16(offset, motor.ID, true); offset += 2; // ID
|
||||||
|
|
||||||
|
const motorNameBytes = encoder.encode(motor.NAME);
|
||||||
|
const motorNameLength = Math.min(motorNameBytes.length, 255);
|
||||||
|
|
||||||
|
view.setUint8(offset++, motorNameLength);
|
||||||
|
for (let i = 0; i < motorNameLength; i++) {
|
||||||
|
view.setUint8(offset++, motorNameBytes[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Uint8Array(buffer.slice(0, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -771,7 +859,8 @@ window.onload = () => {
|
||||||
motor.TEMPERATURE,
|
motor.TEMPERATURE,
|
||||||
motor.MOVING,
|
motor.MOVING,
|
||||||
motor.CURRENT_CURRENT,
|
motor.CURRENT_CURRENT,
|
||||||
motor.VOLTAGE
|
motor.VOLTAGE,
|
||||||
|
motor.NAME
|
||||||
];
|
];
|
||||||
|
|
||||||
const modelType = motor.MODEL.startsWith('SCS') ? 'SCS' :
|
const modelType = motor.MODEL.startsWith('SCS') ? 'SCS' :
|
||||||
|
|
@ -792,18 +881,23 @@ window.onload = () => {
|
||||||
td.setAttribute('contenteditable', 'true');
|
td.setAttribute('contenteditable', 'true');
|
||||||
td.setAttribute('data-type', 'number');
|
td.setAttribute('data-type', 'number');
|
||||||
|
|
||||||
if (index === 1) {
|
if (index === 21) {
|
||||||
td.setAttribute('data-min', '0');
|
td.setAttribute('data-type', 'text');
|
||||||
td.setAttribute('data-max', '255');
|
|
||||||
} else if (index === 9) { // TORQUE ENABLE
|
|
||||||
td.setAttribute('data-min', '0');
|
|
||||||
td.setAttribute('data-max', '1');
|
|
||||||
} else if (index === 14) { // EEPROM LOCK
|
|
||||||
td.setAttribute('data-min', '0');
|
|
||||||
td.setAttribute('data-max', '1');
|
|
||||||
} else {
|
} else {
|
||||||
|
td.setAttribute('data-type', 'number');
|
||||||
td.setAttribute('data-min', rangeMin.toString());
|
td.setAttribute('data-min', rangeMin.toString());
|
||||||
td.setAttribute('data-max', rangeMax.toString());
|
td.setAttribute('data-max', rangeMax.toString());
|
||||||
|
|
||||||
|
if (index === 1) {
|
||||||
|
td.setAttribute('data-min', '0');
|
||||||
|
td.setAttribute('data-max', '255');
|
||||||
|
} else if (index === 9) {
|
||||||
|
td.setAttribute('data-min', '0');
|
||||||
|
td.setAttribute('data-max', '1');
|
||||||
|
} else if (index === 14) {
|
||||||
|
td.setAttribute('data-min', '0');
|
||||||
|
td.setAttribute('data-max', '1');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
td.addEventListener('input', function () {
|
td.addEventListener('input', function () {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ const CMD_PLAY_FILE = 0x08;
|
||||||
const CMD_SCAN_CHANNEL = 0x09;
|
const CMD_SCAN_CHANNEL = 0x09;
|
||||||
const CMD_WRITE_DATA = 0x10;
|
const CMD_WRITE_DATA = 0x10;
|
||||||
const CMD_READ_DATA = 0x11;
|
const CMD_READ_DATA = 0x11;
|
||||||
|
const CMD_WRITE_CONFIG_UPDATE = 0x12;
|
||||||
const CMD_START_POSITION_STREAM = 0x14;
|
const CMD_START_POSITION_STREAM = 0x14;
|
||||||
const POSITION_STREAM = 0x15;
|
const POSITION_STREAM = 0x15;
|
||||||
|
|
||||||
|
|
@ -96,6 +97,11 @@ export class SerialManager {
|
||||||
await this.send(CMD_WRITE_DATA, payload);
|
await this.send(CMD_WRITE_DATA, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async sendConfigUpdate(payload) {
|
||||||
|
console.log(payload);
|
||||||
|
await this.send(CMD_WRITE_CONFIG_UPDATE, payload);
|
||||||
|
}
|
||||||
|
|
||||||
async requestPositionStreaming(stream) { //stream true/false
|
async requestPositionStreaming(stream) { //stream true/false
|
||||||
await this.send(CMD_START_POSITION_STREAM, new Uint8Array([stream]));
|
await this.send(CMD_START_POSITION_STREAM, new Uint8Array([stream]));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue