OpenMicroManipulator/firmware/MotionControllerRP/src/servo_control/actuator_calibration.cpp
0x23 d9888ef369 Version v1.0.1:
* Improved homing (parallel homing support, better repeatability, better geometric reference point)
 * Improved joint calibration procedure
 * Calibration data can now be stored persistently on the flash memory (no repeated calibration required)
 * Improved logging
 * added PythonAPI to control device easily

New G-Code commands:
 * Enable/Disable motors command, including pose recovery from current position on motor enable
 * Dedicated joint calibration command with save to flash option
 * Set pose command to directly set a target pose for the servo loops, bypassing the motion controller (good for real-time control)
2025-09-19 09:24:56 +02:00

84 lines
3.2 KiB
C++

// --------------------------------------------------------------------------------------
// Project: MicroManipulatorStepper
// License: MIT (see LICENSE file for full description)
// All text in here must be included in any redistribution.
// Author: M. S. (diffraction limited)
// --------------------------------------------------------------------------------------
#include <algorithm>
#include "servo_controller.h"
#include "utilities/logging.h"
#include "utilities/math_constants.h"
#include "actuator_calibration.h"
//*** FUNCTION ***********************************************************************************/
bool measure_calibration_data(
LookupTable& encoder_raw_to_motor_pos_lut,
LookupTable& motor_pos_to_field_angle_lut,
ServoController& servo_controller,
float calibration_range,
float field_velocity,
size_t table_size)
{
LOG_INFO("Measuring motor to encoder angle lookup table...");
int sample_count = table_size*4;
// get required values
std::vector<std::pair<float, float>> motor_pos_and_field_angle;
std::vector<std::pair<float, float>> encoder_angle_and_motor_pos;
auto& motor_driver = servo_controller.get_motor_driver();
float pole_pair_count = servo_controller.get_pole_pair_count();
float start_field_angle = motor_driver.get_field_angle();
float field_angle_step = calibration_range*pole_pair_count/(sample_count-1);
auto run_measurement = [&](int sample_count, float field_angle_step) {
// Measure in increasing direction
for (size_t i = 0; i < sample_count; ++i) {
if(i>0)
motor_driver.rotate_field(field_angle_step, field_velocity, nullptr);
float encoder_angle_raw = servo_controller.get_encoder().read_abs_angle_raw();
float field_angle = motor_driver.get_field_angle();
float motor_pos = (field_angle-start_field_angle)/pole_pair_count;
// TODO: read motor_pos from precise reference encoder
encoder_angle_and_motor_pos.push_back({encoder_angle_raw, motor_pos});
motor_pos_and_field_angle.push_back({motor_pos, field_angle});
}
};
// Measure in increasing direction
LOG_DEBUG("Running foreward pass...");
run_measurement(sample_count, field_angle_step);
LOG_DEBUG("Running backward pass...");
run_measurement(sample_count, -field_angle_step);
// rotate back to start position
motor_driver.rotate_field(start_field_angle-motor_driver.get_field_angle(),
Constants::TWO_PI_F*40.0f, [&servo_controller]() {
servo_controller.get_encoder().read_abs_angle_raw();
});
// build lookup tables
bool ok = encoder_raw_to_motor_pos_lut.init_interpolating(encoder_angle_and_motor_pos, table_size, true);
encoder_raw_to_motor_pos_lut.optimize_lut(encoder_angle_and_motor_pos);
if(ok == false) {
LOG_ERROR("Creating lookup table encoder_raw_angle -> motor_pos failed.");
return false;
}
ok = motor_pos_to_field_angle_lut.init_interpolating(motor_pos_and_field_angle, table_size/2, true);
motor_pos_to_field_angle_lut.optimize_lut(motor_pos_and_field_angle);
if(ok == false) {
LOG_ERROR("Creating lookup table motor_pos -> field_angle failed.");
return false;
}
LOG_INFO("finished");
return true;
}