curves now sending/receiving correctly. Y values are now converted to Int16 values to allow handles to dip below 0

node_mode
realrobots 2025-10-10 23:11:10 +08:00
parent d67cba4c6f
commit 55b2c178e6
3 changed files with 56 additions and 26 deletions

View File

@ -8,6 +8,8 @@ export class CurveEditor {
this.offset = { x: 0, y: 0 };
this.pixelsPerSecond = 48;
this.exportRange = [0, 4095];
this.currentTime = timelineLength * this.pixelsPerSecond / 2;
this.motorButtons = {
@ -40,15 +42,15 @@ export class CurveEditor {
this.panStart = { x: 0, y: 0 };
// Default curve
// this.setCurves([
// {
// startPoint: { x: this.valueToX(0), y: this.valueToY(0) },
// startPointHandle: { x: this.valueToX(timelineLength / 2), y: this.valueToY(0.5) },
// endPointHandle: { x: this.valueToX(timelineLength / 2), y: this.valueToY(-0.5) },
// endPoint: { x: this.valueToX(timelineLength), y: this.valueToY(0) }
// }
// ]);
// this.curveSets[this.selectedMotorID] = this.curves;
this.setCurves([
{
startPoint: { x: this.valueToX(0), y: this.valueToY(0) },
startPointHandle: { x: this.valueToX(timelineLength / 2), y: this.valueToY(0.5) },
endPointHandle: { x: this.valueToX(timelineLength / 2), y: this.valueToY(-0.5) },
endPoint: { x: this.valueToX(timelineLength), y: this.valueToY(0) }
}
]);
this.curveSets[this.selectedMotorID] = this.curves;
// let othercurves = [
// {
@ -71,14 +73,14 @@ export class CurveEditor {
// this.curveSets[7] = othercurves;
// this.setSelectedMotor(5);
this.setSelectedMotor(4);
this.initEvents();
this.draw();
console.log(this.curveSets);
}
setLength(endTime){
setLength(endTime) {
this.timelineLength = endTime / this.pixelsPerSecond;
console.log("new endtime: " + endTime);
//this.currentTime = this.timelineLength * this.pixelsPerSecond / 2;
@ -115,10 +117,31 @@ export class CurveEditor {
return (this.canvas.height / 2 - v * (this.canvas.height / 2)) * this.scale + this.offset.y;
}
// Maps pixel value of y axis to -1 to 1 normalised value
yToValue(y) {
return ((this.canvas.height / 2 - (y - this.offset.y) / this.scale) / (this.canvas.height / 2));
}
// Maps normalised -1 to 1 value to motor range (0, 4095)
yToExportRange(y) {
const [minOut, maxOut] = this.exportRange;
// Normalize y from [-1, 1] to [0, 1]
const normalized = (this.yToValue(y) + 1) / 2;
// Scale to export range
return Math.round(normalized * (maxOut - minOut) + minOut);
}
exportRangeToY(value) {
const [minOut, maxOut] = this.exportRange;
// Reverse the scaling
const normalized = (value - minOut) / (maxOut - minOut);
// Convert from [0, 1] back to [-1, 1]
const yValue = normalized * 2 - 1;
// Apply inverse mapping from value space to editor Y
return this.valueToY(yValue);
}
valueToX(t) {
return t * this.pixelsPerSecond * this.scale + this.offset.x;
}
@ -635,6 +658,8 @@ export class CurveEditor {
curve.startPointHandle.y += deltaY;
this.dragControlPoint(curve, 'startPointHandle', curve.startPointHandle.x, curve.startPointHandle.y, index);
console.log(this.yToExportRange(curve.startPoint.y));
} else if (key === 'endPoint') {
const oldX = curve.endPoint.x;
const oldY = curve.endPoint.y;
@ -660,6 +685,7 @@ export class CurveEditor {
this.dragControlPoint(curve, 'endPointHandle', curve.endPointHandle.x, curve.endPointHandle.y, index);
const nextCurve = this.curves[index + 1];
console.log(curve.endPoint.y);
if (nextCurve) {
nextCurve.startPoint.x = curve.endPoint.x;
nextCurve.startPoint.y = curve.endPoint.y;

View File

@ -155,7 +155,7 @@
<div class="tab-pane fade" id="animation" role="tabpanel" aria-labelledby="animation-tab">
<canvas id="curveCanvas" width="900" height="300"></canvas>
<canvas id="curveCanvas" width="900" height="600"></canvas>
<div style="margin-top: 10px; text-align: center;">
<input type="range" id="timeSlider" min="0" step="1" style="width: 80%;">
</div>

View File

@ -424,34 +424,34 @@ window.onload = () => {
offset += 1;
const startTime = view.getUint16(offset, true); offset += 2;
const endTime = view.getUint16(offset, true); offset += 2;
const startPointY = view.getUint16(offset, true); offset += 2;
const startPointY = view.getInt16(offset, true); offset += 2;
const startHandleX = view.getUint16(offset, true); offset += 2;
const startHandleY = view.getUint16(offset, true); offset += 2;
const startHandleY = view.getInt16(offset, true); offset += 2;
const endHandleX = view.getUint16(offset, true); offset += 2;
const endHandleY = view.getUint16(offset, true); offset += 2;
const endPointY = view.getUint16(offset, true); offset += 2;
const endHandleY = view.getInt16(offset, true); offset += 2;
const endPointY = view.getInt16(offset, true); offset += 2;
console.log("RECEIVED VALUES RAW:");
console.log(startTime, endTime);
console.log(startTime, endTime, startPointY, endPointY);
const toFloat = v => (v / 65535) * 2 - 1;
const curve = {
startPoint: {
x: startTime,
y: curveEditor.valueToY(toFloat(startPointY))
y: curveEditor.exportRangeToY(startPointY)
},
startPointHandle: {
x: startHandleX,
y: curveEditor.valueToY(toFloat(startHandleY))
y: curveEditor.exportRangeToY(startHandleY)
},
endPointHandle: {
x: endHandleX,
y: curveEditor.valueToY(toFloat(endHandleY))
y: curveEditor.exportRangeToY(endHandleY)
},
endPoint: {
x: endTime,
y: curveEditor.valueToY(toFloat(endPointY))
y: curveEditor.exportRangeToY(endPointY)
}
};
@ -561,23 +561,27 @@ window.onload = () => {
view.setUint16(offset, curveCount, true); offset += 2;
// 🔹 Curve segments
curveSegments.forEach(seg => {
view.setUint8(offset++, seg.motorID);
view.setUint16(offset, seg.startTime, true); offset += 2;
view.setUint16(offset, seg.endTime, true); offset += 2;
view.setUint16(offset, seg.startPointY, true); offset += 2;
view.setInt16(offset, curveEditor.yToExportRange(seg.startPointY), true); offset += 2;
console.log(curveEditor.yToExportRange(seg.startPointY));
view.setUint16(offset, seg.startHandleX, true); offset += 2;
view.setUint16(offset, seg.startHandleY, true); offset += 2;
console.log("STARTHANDLEY: " + seg.startHandleY);
view.setInt16(offset, curveEditor.yToExportRange(seg.startHandleY), true); offset += 2;
view.setUint16(offset, seg.endHandleX, true); offset += 2;
view.setUint16(offset, seg.endHandleY, true); offset += 2;
view.setUint16(offset, seg.endPointY, true); offset += 2;
view.setInt16(offset, curveEditor.yToExportRange(seg.endHandleY), true); offset += 2;
view.setInt16(offset, curveEditor.yToExportRange(seg.endPointY), true); offset += 2;
});
console.log("🧵 Curve segments packed:", curveSegments.length);
console.log(curveSegments);
// 🔹 Send to ESP32
const payload = new Uint8Array(buffer);
console.log()
console.log(payload);
serial.saveFile(payload); // CMD_SAVE_ANIMATION
}