sane-project-backends/backend/genesys/motor.h

199 wiersze
6.3 KiB
C++

/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BACKEND_GENESYS_MOTOR_H
#define BACKEND_GENESYS_MOTOR_H
#include <algorithm>
#include <cstdint>
#include <vector>
#include "enums.h"
#include "sensor.h"
#include "value_filter.h"
namespace genesys {
/* Describes a motor acceleration curve.
Definitions:
v - speed in steps per pixeltime
w - speed in pixel times per step. w = 1 / v
a - acceleration in steps per pixeltime squared
s - distance travelled in steps
t - time in pixeltime
The physical mode defines the curve in physical quantities. We assume that the scanner head
accelerates from standstill to the target speed uniformly. Then:
v(t) = v(0) + a * t (2)
Where `a` is acceleration, `t` is time. Also we can calculate the travelled distance `s`:
s(t) = v(0) * t + a * t^2 / 2 (3)
The actual motor slope is defined as the duration of each motor step. That means we need to
define speed in terms of travelled distance.
Solving (3) for `t` gives:
sqrt( v(0)^2 + 2 * a * s ) - v(0)
t(s) = --------------------------------- (4)
a
Combining (4) and (2) will yield:
v(s) = sqrt( v(0)^2 + 2 * a * s ) (5)
The data in the slope struct MotorSlope corresponds to the above in the following way:
maximum_start_speed is `w(0) = 1/v(0)`
maximum_speed is defines maximum speed which should not be exceeded
minimum_steps is not used
g is `a`
Given the start and target speeds on a known motor curve, `a` can be computed as follows:
v(t1)^2 - v(t0)^2
a = ----------------- (6)
2 * s
Here `v(t0)` and `v(t1)` are the start and target speeds and `s` is the number of step required
to reach the target speeds.
*/
struct MotorSlope
{
// initial speed in pixeltime per step
unsigned initial_speed_w = 0;
// max speed in pixeltime per step
unsigned max_speed_w = 0;
// maximum number of steps in the table
unsigned max_step_count;
// acceleration in steps per pixeltime squared.
float acceleration = 0;
unsigned get_table_step_shifted(unsigned step, StepType step_type) const;
static MotorSlope create_from_steps(unsigned initial_w, unsigned max_w,
unsigned steps);
};
struct MotorSlopeTable
{
std::vector<std::uint16_t> table;
void slice_steps(unsigned count, unsigned step_multiplier);
// expands the table by the given number of steps
void expand_table(unsigned count, unsigned step_multiplier);
std::uint64_t pixeltime_sum() const { return pixeltime_sum_; }
void generate_pixeltime_sum();
private:
std::uint64_t pixeltime_sum_ = 0;
};
unsigned get_slope_table_max_size(AsicType asic_type);
MotorSlopeTable create_slope_table_for_speed(const MotorSlope& slope, unsigned target_speed_w,
StepType step_type, unsigned steps_alignment,
unsigned min_size, unsigned max_size);
std::ostream& operator<<(std::ostream& out, const MotorSlope& slope);
struct MotorProfile
{
MotorProfile() = default;
MotorProfile(const MotorSlope& a_slope, StepType a_step_type, unsigned a_max_exposure) :
slope{a_slope}, step_type{a_step_type}, max_exposure{a_max_exposure}
{}
MotorSlope slope;
StepType step_type = StepType::FULL;
int motor_vref = -1;
// the resolutions this profile is good for
ValueFilterAny<unsigned> resolutions = VALUE_FILTER_ANY;
// the scan method this profile is good for. If the list is empty, good for any method.
ValueFilterAny<ScanMethod> scan_methods = VALUE_FILTER_ANY;
unsigned max_exposure = 0; // 0 - any exposure
};
std::ostream& operator<<(std::ostream& out, const MotorProfile& profile);
struct Genesys_Motor
{
Genesys_Motor() = default;
// id of the motor description
MotorId id = MotorId::UNKNOWN;
// motor base steps. Unit: 1/inch
int base_ydpi = 0;
// slopes to derive individual slopes from
std::vector<MotorProfile> profiles;
// slopes to derive individual slopes from for fast moving
std::vector<MotorProfile> fast_profiles;
MotorSlope& get_slope_with_step_type(StepType step_type)
{
for (auto& p : profiles) {
if (p.step_type == step_type)
return p.slope;
}
throw SaneException("No motor profile with step type");
}
const MotorSlope& get_slope_with_step_type(StepType step_type) const
{
for (const auto& p : profiles) {
if (p.step_type == step_type)
return p.slope;
}
throw SaneException("No motor profile with step type");
}
StepType max_step_type() const
{
if (profiles.empty()) {
throw std::runtime_error("Profiles table is empty");
}
StepType step_type = StepType::FULL;
for (const auto& p : profiles) {
step_type = static_cast<StepType>(
std::max(static_cast<unsigned>(step_type),
static_cast<unsigned>(p.step_type)));
}
return step_type;
}
};
std::ostream& operator<<(std::ostream& out, const Genesys_Motor& motor);
} // namespace genesys
#endif // BACKEND_GENESYS_MOTOR_H