HansonServo/animation.cpp

168 lines
3.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "animation.h"
Animation::Animation() {
clear();
memcpy(header.magic, "ANIM", 4);
header.version = 1;
header.frameRate = FRAMES_PER_SECOND;
header.frameCount = MAX_FRAMES;
memset(header.reserved, 0, sizeof(header.reserved));
}
void Animation::addCurveSegment(const CurveSegment& segment) {
if (segment.motorID < NUM_CHANNELS) {
curves[segment.motorID].push_back(segment);
}
}
void Animation::clearCurves(uint8_t motorID) {
if (motorID < NUM_CHANNELS) {
curves[motorID].clear();
}
}
void Animation::clearAllCurves() {
for (int i = 0; i < NUM_CHANNELS; ++i) {
curves[i].clear();
}
}
uint16_t Animation::getMotorPosition(uint8_t motorID, uint16_t timeCS) {
if (motorID >= NUM_CHANNELS) return 0;
for (const auto& seg : curves[motorID]) {
if (timeCS >= seg.startTime && timeCS <= seg.endTime) {
float t = float(timeCS - seg.startTime) / (seg.endTime - seg.startTime);
// Convert uint16_t to float in range -1 to 1
auto toFloat = [](uint16_t v) {
return (float(v) / 65535.0f) * 2.0f - 1.0f;
};
float p0 = toFloat(seg.startPoint);
float p1 = toFloat(seg.startHandle);
float p2 = toFloat(seg.endHandle);
float p3 = toFloat(seg.endPoint);
float u = 1.0f - t;
float value = u*u*u*p0 + 3*u*u*t*p1 + 3*u*t*t*p2 + t*t*t*p3;
// Remap back to 04095 for PWM
return constrain((value + 1.0f) * 2047.5f, 0, 4095);
}
}
return 2048; // Default center if no segment matches
}
void Animation::clear() {
memset(data, 0, sizeof(data));
}
uint16_t* Animation::getRawData() {
return &data[0][0];
}
size_t Animation::getSize() const {
return sizeof(data);
}
uint16_t Animation::getFrameCount() const {
return header.frameCount;
}
bool Animation::saveToFile(const char* filename) {
// Auto-detect actual frame count
uint16_t lastFrame = 0;
for (uint16_t frame = 0; frame < MAX_FRAMES; frame++) {
for (uint8_t ch = 0; ch < NUM_CHANNELS; ch++) {
if (data[frame][ch] != 0) {
lastFrame = frame;
break;
}
}
}
header.frameCount = lastFrame + 1;
File file = FFat.open(filename, FILE_WRITE);
if (!file) return false;
// Write header and motion data
file.write((uint8_t*)&header, sizeof(header));
file.write((uint8_t*)data, sizeof(data));
// Count total curve segments
uint16_t curveCount = 0;
for (uint8_t ch = 0; ch < NUM_CHANNELS; ch++) {
curveCount += curves[ch].size();
}
// Write curve count
file.write((uint8_t*)&curveCount, sizeof(curveCount));
// Write all curve segments
for (uint8_t ch = 0; ch < NUM_CHANNELS; ch++) {
for (const CurveSegment& seg : curves[ch]) {
file.write((uint8_t*)&seg, sizeof(CurveSegment));
}
}
file.close();
return true;
}
bool Animation::loadFromFile(const char* filename) {
File file = FFat.open(filename, FILE_READ);
if (!file) return false;
// Read and validate header
AnimationHeader tempHeader;
if (file.read((uint8_t*)&tempHeader, sizeof(tempHeader)) != sizeof(tempHeader)) {
file.close();
return false;
}
if (strncmp(tempHeader.magic, "ANIM", 4) != 0 || tempHeader.version != 1) {
file.close();
return false;
}
header = tempHeader;
// Read motion data
size_t expectedSize = sizeof(data);
if (file.read((uint8_t*)data, expectedSize) != expectedSize) {
file.close();
return false;
}
// Read curve count
uint16_t curveCount;
if (file.read((uint8_t*)&curveCount, sizeof(curveCount)) != sizeof(curveCount)) {
file.close();
return false;
}
// Clear existing curves
clearAllCurves();
// Read curve segments
for (uint16_t i = 0; i < curveCount; i++) {
CurveSegment seg;
if (file.read((uint8_t*)&seg, sizeof(CurveSegment)) != sizeof(CurveSegment)) {
file.close();
return false;
}
if (seg.motorID < NUM_CHANNELS) {
curves[seg.motorID].push_back(seg);
}
}
file.close();
return true;
}