id changes through motor panel work now (was sending new id as target
parent
9036014e21
commit
5a9eee688b
|
|
@ -143,7 +143,7 @@ export class CurveEditor {
|
||||||
endPoint: { x: this.timelineLength * this.pixelsPerSecond, y: this.canvas.height / 2 }
|
endPoint: { x: this.timelineLength * this.pixelsPerSecond, y: this.canvas.height / 2 }
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
console.log("TL LENGTH: " + this.timelineLength);
|
//console.log("TL LENGTH: " + this.timelineLength);
|
||||||
this.curveSets[motorID] = this.curves;
|
this.curveSets[motorID] = this.curves;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ export class ServoMotor {
|
||||||
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 used by robot config loader
|
||||||
this.CHANNEL = arg1;
|
this.CHANNEL = arg1;
|
||||||
this.ID = arg2;
|
this.ID = arg2;
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@ export class ServoMotor {
|
||||||
|
|
||||||
|
|
||||||
// Takes Motor object and updates simulated value, returns packet for real device
|
// Takes Motor object and updates simulated value, returns packet for real device
|
||||||
export function writeData(motor, key) {
|
export function writeData(targetID, motor, key) {
|
||||||
const entry = DataMap[key];
|
const entry = DataMap[key];
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
throw new Error(`Invalid data key: ${key}`);
|
throw new Error(`Invalid data key: ${key}`);
|
||||||
|
|
@ -68,7 +68,7 @@ export function writeData(motor, key) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const packet = [motor.CHANNEL, motor.ID, address, length]; // channel, id, address, value
|
const packet = [motor.CHANNEL, targetID, address, length]; // channel, id, address, value
|
||||||
|
|
||||||
if (length === 2) {
|
if (length === 2) {
|
||||||
packet.push(value & 0xFF);
|
packet.push(value & 0xFF);
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ export class NodeEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
generateDefaultNodes(curveSets, motorIDs) {
|
generateDefaultNodes(curveSets, motorIDs) {
|
||||||
console.log("Generating Default Nodes");
|
//console.log("Generating Default Nodes");
|
||||||
console.log(curveSets, motorIDs);
|
//console.log(curveSets, motorIDs);
|
||||||
|
|
||||||
for (var i = 0; i < motorIDs.length; i++) {
|
for (var i = 0; i < motorIDs.length; i++) {
|
||||||
let inputNode = this.addCurveNode(200, 20 + i * 140, "Curve", motorIDs[i]);
|
let inputNode = this.addCurveNode(200, 20 + i * 140, "Curve", motorIDs[i]);
|
||||||
|
|
|
||||||
52
robot.js
52
robot.js
|
|
@ -1,4 +1,4 @@
|
||||||
import { ServoMotor } from './feetechDefinitions.js';
|
import { getModelType, ServoMotor } from './feetechDefinitions.js';
|
||||||
|
|
||||||
export class Robot {
|
export class Robot {
|
||||||
constructor(name, firmwareVersionId) {
|
constructor(name, firmwareVersionId) {
|
||||||
|
|
@ -6,7 +6,8 @@ export class Robot {
|
||||||
this.firmwareVersion = { major: 0, minor: 0 };
|
this.firmwareVersion = { major: 0, minor: 0 };
|
||||||
|
|
||||||
// Map of position ID → ServoMotor
|
// Map of position ID → ServoMotor
|
||||||
this.positionMap = new Map();
|
//this.positionMap = new Map();
|
||||||
|
this.motors = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign a motor to a position
|
// Assign a motor to a position
|
||||||
|
|
@ -14,39 +15,38 @@ export class Robot {
|
||||||
if (!(motor instanceof ServoMotor)) {
|
if (!(motor instanceof ServoMotor)) {
|
||||||
throw new Error('Assigned motor must be a ServoMotor instance');
|
throw new Error('Assigned motor must be a ServoMotor instance');
|
||||||
}
|
}
|
||||||
this.positionMap.set(positionId, motor);
|
//this.positionMap.set(positionId, motor);
|
||||||
|
this.motors.push(motor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get motor assigned to a position
|
getMotor(motorID) {
|
||||||
getMotor(positionId) {
|
for (let i = 0; i < this.motors.length; i++) {
|
||||||
return this.positionMap.get(positionId);
|
console.log(motorID, this.motors[i].ID);
|
||||||
|
if (String(this.motors[i].ID) === String(motorID)) {
|
||||||
|
return this.motors[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Remove motor from a position
|
// Remove motor from a position
|
||||||
removeMotor(positionId) {
|
removeMotor(motorID) {
|
||||||
this.positionMap.delete(positionId);
|
this.motors = this.motors.filter(motor => motor.ID !== motorID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all position assignments
|
|
||||||
getAllAssignments() {
|
|
||||||
const assignments = [];
|
|
||||||
for (const [position, motor] of this.positionMap.entries()) {
|
|
||||||
assignments.push({ position, motor });
|
|
||||||
}
|
|
||||||
return assignments;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optional: Find position by motor ID
|
// Optional: Find position by motor ID
|
||||||
findPositionByMotorId(id) {
|
// findPositionByMotorId(id) {
|
||||||
for (const [position, motor] of this.positionMap.entries()) {
|
// for (const [position, motor] of this.positionMap.entries()) {
|
||||||
if (motor.ID === id) return position;
|
// if (motor.ID === id) return position;
|
||||||
}
|
// }
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
static fromBytes(bytes) {
|
static fromBytes(bytes) {
|
||||||
console.log("Loading Robot from:");
|
console.log("Loading Robot from:");
|
||||||
console.log(bytes);
|
//console.log(bytes);
|
||||||
const data = bytes instanceof Uint8Array ? bytes : Uint8Array.from(bytes);
|
const data = bytes instanceof Uint8Array ? bytes : Uint8Array.from(bytes);
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
|
|
||||||
|
|
@ -73,8 +73,12 @@ export class Robot {
|
||||||
const name = String.fromCharCode(...data.slice(offset, offset + nameLen));
|
const name = String.fromCharCode(...data.slice(offset, offset + nameLen));
|
||||||
offset += nameLen;
|
offset += nameLen;
|
||||||
|
|
||||||
|
const modelMajor = data[offset++];
|
||||||
|
const modelMinor = data[offset++];
|
||||||
|
const modelType = getModelType(modelMajor, modelMinor);
|
||||||
|
|
||||||
const position = (data[offset++] << 8) | data[offset++];
|
const position = (data[offset++] << 8) | data[offset++];
|
||||||
const motor = new ServoMotor(0, motorID, null, name);
|
const motor = new ServoMotor(0, motorID, modelType, name);
|
||||||
robot.assignMotor(motorID, motor); // motorID used as position ID
|
robot.assignMotor(motorID, motor); // motorID used as position ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
86
script.js
86
script.js
|
|
@ -34,7 +34,42 @@ window.onload = () => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const dialColors = ['red', 'green', 'blue', 'orange', 'purple'];
|
const dialColors = [
|
||||||
|
'#F50057', // Raspberry
|
||||||
|
'#6200EA', // Deep Violet
|
||||||
|
'#FFB400', // Bright Amber
|
||||||
|
'#2979FF', // Royal Blue
|
||||||
|
'#FF5252', // Coral Red
|
||||||
|
'#00C853', // Vivid Green
|
||||||
|
'#FF80AB', // Bubblegum
|
||||||
|
'#00B8D4', // Sky Cyan
|
||||||
|
'#FF9100', // Neon Orange
|
||||||
|
'#651FFF', // Electric Indigo
|
||||||
|
'#FF4F81', // Vibrant Pink
|
||||||
|
'#AEEA00', // Chartreuse
|
||||||
|
'#FFAB40', // Sunset Orange
|
||||||
|
'#00E5FF', // Aqua
|
||||||
|
'#FF6F00', // Vivid Orange
|
||||||
|
'#64DD17', // Leaf Green
|
||||||
|
'#FFEA00', // Vivid Yellow
|
||||||
|
'#C51162', // Deep Rose
|
||||||
|
'#40C4FF', // Sky Blue
|
||||||
|
'#D500F9', // Vivid Purple
|
||||||
|
'#76FF03', // Lime Green
|
||||||
|
'#FF4081', // Hot Pink
|
||||||
|
'#00B0FF', // Electric Blue
|
||||||
|
'#FF1744', // Crimson
|
||||||
|
'#B388FF', // Soft Violet
|
||||||
|
'#1DE9B6', // Minty Teal
|
||||||
|
'#AA00FF', // Vivid Lavender
|
||||||
|
'#FFB347', // Pastel Orange
|
||||||
|
'#00C1D4', // Bright Cyan
|
||||||
|
'#7C4DFF' // Neon Purple
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let dials = [];
|
let dials = [];
|
||||||
const frameSlider = document.getElementById('frameSlider');
|
const frameSlider = document.getElementById('frameSlider');
|
||||||
|
|
@ -44,7 +79,7 @@ window.onload = () => {
|
||||||
|
|
||||||
|
|
||||||
const curveCanvas = document.getElementById('curveCanvas');
|
const curveCanvas = document.getElementById('curveCanvas');
|
||||||
const curveEditor = new CurveEditor(curveCanvas, 6, frameSlider);
|
const curveEditor = new CurveEditor(curveCanvas, 10, frameSlider);
|
||||||
|
|
||||||
|
|
||||||
// Animation File List
|
// Animation File List
|
||||||
|
|
@ -77,13 +112,14 @@ window.onload = () => {
|
||||||
console.log(connectedRobot);
|
console.log(connectedRobot);
|
||||||
let motorIDList = []
|
let motorIDList = []
|
||||||
clearDials();
|
clearDials();
|
||||||
for (const [position, motor] of connectedRobot.positionMap.entries()) {
|
for (const motor of connectedRobot.motors) {
|
||||||
console.log(`Assigning ${position} motor with ID ${motor.ID}`);
|
|
||||||
curveEditor.addChannel(motor.ID);
|
curveEditor.addChannel(motor.ID);
|
||||||
motorIDList.push(motor.ID);
|
motorIDList.push(motor.ID);
|
||||||
addDial(motor.ID, motor.NAME);
|
addDial(motor.ID, motor.NAME);
|
||||||
}
|
}
|
||||||
setSelectedMotor(10);
|
if (connectedRobot.motors.length > 0){
|
||||||
|
setSelectedMotor(connectedRobot.motors[0].ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
nodeEditor = new NodeEditor(nodeCanvas, {
|
nodeEditor = new NodeEditor(nodeCanvas, {
|
||||||
|
|
@ -95,7 +131,7 @@ window.onload = () => {
|
||||||
|
|
||||||
|
|
||||||
function setSelectedMotor(motorID) {
|
function setSelectedMotor(motorID) {
|
||||||
console.log(motorID);
|
//console.log(motorID);
|
||||||
curveEditor.selectMotor(motorID);
|
curveEditor.selectMotor(motorID);
|
||||||
selectedDial = motorID;
|
selectedDial = motorID;
|
||||||
|
|
||||||
|
|
@ -109,7 +145,7 @@ window.onload = () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Selected motor:", motorID);
|
//console.log("Selected motor:", motorID);
|
||||||
// Any other logic you want to run
|
// Any other logic you want to run
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -134,8 +170,7 @@ window.onload = () => {
|
||||||
// Retrieve motor by position
|
// Retrieve motor by position
|
||||||
//console.log(robot.getMotor('eyelids'));
|
//console.log(robot.getMotor('eyelids'));
|
||||||
|
|
||||||
// List all assignments
|
|
||||||
console.log(robot.getAllAssignments());
|
|
||||||
return robot;
|
return robot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,12 +452,15 @@ window.onload = () => {
|
||||||
|
|
||||||
case 0x06: // CMD_MESSAGE
|
case 0x06: // CMD_MESSAGE
|
||||||
|
|
||||||
console.log(`Message Recieved`);
|
//console.log(`Message Recieved`);
|
||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
console.log(payload);
|
//console.log(payload);
|
||||||
const stringPayload = decoder.decode(new Uint8Array(payload));
|
const stringPayload = decoder.decode(new Uint8Array(payload));
|
||||||
console.log(stringPayload);
|
//console.log(stringPayload);
|
||||||
document.getElementById('log').value += "MSG: " + stringPayload + `\n`;
|
document.getElementById('log').value += "MSG: " + stringPayload + `\n`;
|
||||||
|
const logBox = document.getElementById('log');
|
||||||
|
logBox.value += "MSG: " + stringPayload + `\n`;
|
||||||
|
logBox.scrollTop = logBox.scrollHeight;
|
||||||
// 🔹 Do something with the file
|
// 🔹 Do something with the file
|
||||||
//handleLoadedFile(fileData);
|
//handleLoadedFile(fileData);
|
||||||
break;
|
break;
|
||||||
|
|
@ -479,15 +517,21 @@ window.onload = () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function handlePositionStreamPacket(data) {
|
function handlePositionStreamPacket(data) {
|
||||||
for (let i = 0; i < 5; i++) {
|
const motorCount = Math.floor(data.length / 2); // Each motor uses 2 bytes
|
||||||
const high = data[i * 2]; // High byte
|
|
||||||
const low = data[i * 2 + 1]; // Low byte
|
|
||||||
const value = (high << 8) | low; // Combine into uint16_t
|
|
||||||
|
|
||||||
|
for (let i = 0; i < motorCount; i++) {
|
||||||
|
const high = data[i * 2]; // High byte
|
||||||
|
const low = data[i * 2 + 1]; // Low byte
|
||||||
|
const value = (high << 8) | low; // Combine into uint16_t
|
||||||
|
|
||||||
|
if (dials[i]) {
|
||||||
dials[i].value = value;
|
dials[i].value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
|
||||||
function handleLoadedFile(data) {
|
function handleLoadedFile(data) {
|
||||||
const raw = new Uint8Array(data);
|
const raw = new Uint8Array(data);
|
||||||
const view = new DataView(raw.buffer);
|
const view = new DataView(raw.buffer);
|
||||||
|
|
@ -1033,7 +1077,9 @@ window.onload = () => {
|
||||||
let dataKey = packets[i].title;
|
let dataKey = packets[i].title;
|
||||||
let value = packets[i].value;
|
let value = packets[i].value;
|
||||||
servoMotor[dataKey] = value;
|
servoMotor[dataKey] = value;
|
||||||
let dataPacket = writeData(servoMotor, dataKey);
|
let dataPacket = writeData(packets[i].id, servoMotor, dataKey);
|
||||||
|
//dataPacket[1] = packets[i].id;
|
||||||
|
console.log(dataPacket);
|
||||||
serial.requestWriteData(dataPacket);
|
serial.requestWriteData(dataPacket);
|
||||||
}
|
}
|
||||||
console.log(servoMotors);
|
console.log(servoMotors);
|
||||||
|
|
@ -1073,6 +1119,12 @@ window.onload = () => {
|
||||||
console.log(motor.MODEL, motor.POSITION, motor.CURRENT_SPEED);
|
console.log(motor.MODEL, motor.POSITION, motor.CURRENT_SPEED);
|
||||||
servoMotors[motor.CHANNEL].push(motor);
|
servoMotors[motor.CHANNEL].push(motor);
|
||||||
|
|
||||||
|
// If motor is in robot config already, grab the name
|
||||||
|
let configMotor = connectedRobot.getMotor(motor.ID);
|
||||||
|
if (configMotor != null){
|
||||||
|
motor.NAME = configMotor.NAME;
|
||||||
|
}
|
||||||
|
|
||||||
insertTableRow(motor);
|
insertTableRow(motor);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue