RoboidControl-cpp/ServoMotor.cpp
2024-03-05 09:13:46 +01:00

97 lines
2.8 KiB
C++

#include "ServoMotor.h"
#include "LinearAlgebra/FloatSingle.h"
ServoMotor::ServoMotor() {
this->type = Thing::ServoType;
this->controlMode = ControlMode::Position;
this->targetAngle = 0;
this->hasTargetAngle = false;
}
void ServoMotor::SetTargetAngle(float angle) {
angle = Float::Clamp(angle, minAngle, maxAngle);
if (maxVelocity == 0.0F || hasTargetAngle == false) {
SetAngle(angle);
this->limitedTargetAngle = angle;
} else if (angle != this->targetAngle) {
// if the new target is the same, the limited angle is not overwritten
this->limitedTargetAngle = this->targetAngle;
}
this->controlMode = ControlMode::Position;
this->targetAngle = angle;
this->hasTargetAngle = true;
}
float ServoMotor::GetTargetAngle() { return this->targetAngle; }
void ServoMotor::SetMaximumVelocity(float maxVelocity) {
this->maxVelocity = maxVelocity;
}
void ServoMotor::SetTargetVelocity(float targetVelocity) {
targetVelocity =
Float::Clamp(targetVelocity, -this->maxVelocity, maxVelocity);
this->controlMode = ControlMode::Velocity;
this->targetVelocity = targetVelocity;
this->hasTargetAngle = false; // can't we use the controlMode for this?
}
float ServoMotor::GetTargetVelocity() { return this->targetVelocity; }
void ServoMotor::Update(float currentTimeMs) {
for (unsigned char childIx = 0; childIx < this->childCount; childIx++) {
Thing *child = this->GetChild(childIx);
if (child != nullptr && child->type == Thing::ServoType) {
ServoMotor *servo = (ServoMotor *)child;
servo->Update(currentTimeMs);
}
}
if (this->lastUpdateTimeMs == 0 || currentTimeMs < this->lastUpdateTimeMs) {
this->lastUpdateTimeMs = currentTimeMs;
return;
}
float deltaTime = (currentTimeMs - this->lastUpdateTimeMs) / 1000.0F;
// Position control
if (controlMode == ControlMode::Position) {
if (maxVelocity == 0.0F || hasTargetAngle == false) {
this->lastUpdateTimeMs = currentTimeMs;
return;
} else {
float angleStep = maxVelocity * deltaTime;
float deltaAngle = this->targetAngle - this->limitedTargetAngle;
float absDeltaAngle = (deltaAngle < 0) ? -deltaAngle : deltaAngle;
if (absDeltaAngle < angleStep) {
this->limitedTargetAngle = this->targetAngle;
SetAngle(targetAngle);
} else {
if (deltaAngle < 0)
limitedTargetAngle -= angleStep;
else
limitedTargetAngle += angleStep;
}
SetAngle(limitedTargetAngle);
this->lastUpdateTimeMs = currentTimeMs;
return;
}
// Velocity control
} else {
float newAngle = this->targetAngle + targetVelocity * deltaTime;
newAngle = Float::Clamp(newAngle, minAngle, maxAngle);
ServoMotor::SetTargetAngle(newAngle);
SetAngle(newAngle);
this->lastUpdateTimeMs = currentTimeMs;
}
}