mirror of
https://github.com/synthetos/g2.git
synced 2026-08-18 17:08:38 +08:00
138 lines
6.5 KiB
C
138 lines
6.5 KiB
C
/*
|
|
* encoder.h - encoder interface
|
|
* This file is part of g2core project
|
|
*
|
|
* Copyright (c) 2013 - 2018 Alden S. Hart, Jr.
|
|
*
|
|
* This file ("the software") is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License, version 2 as published by the
|
|
* Free Software Foundation. You should have received a copy of the GNU General Public
|
|
* License, version 2 along with the software. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* As a special exception, you may use this file as part of a software library without
|
|
* restriction. Specifically, if other files instantiate templates or use macros or
|
|
* inline functions from this file, or you compile this file and link it with other
|
|
* files to produce an executable, this file does not by itself cause the resulting
|
|
* executable to be covered by the GNU General Public License. This exception does not
|
|
* however invalidate any other reasons why the executable file might be covered by the
|
|
* GNU General Public License.
|
|
*
|
|
* THE SOFTWARE IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY
|
|
* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
|
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
|
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
/*
|
|
* ENCODERS
|
|
*
|
|
* Calling this file "encoders" is kind of a lie, at least for now. There are no encoders.
|
|
* Instead the steppers count steps to provide a "truth" reference for position. In the
|
|
* future when we have real encoders we'll stop counting steps and actually measure the
|
|
* position. Which should be a lot easier than how this module currently works.
|
|
*
|
|
* *** Measuring position ***
|
|
*
|
|
* The challenge is that you can't just measure the position at any arbitrary point
|
|
* because the system is so heavily queued (pipelined) by the planner queue and the stepper
|
|
* sequencing.
|
|
*
|
|
* You only know where the machine should be at known "targets", which are at the end of
|
|
* each move section (end of head, body, and tail). You need to take encoder readings at
|
|
* these points. This synchronization is taken care of by the Target, Position, Position_delayed
|
|
* sequence in plan_exec. Referring to ASCII art in stepper.h and reproduced here:
|
|
*
|
|
* LOAD/STEP (~5000uSec) [L1][Segment1][L2][Segment2][L3][Segment3][L4][Segment4][Lb1][Segmentb1]
|
|
* PREP (100 uSec) [P1] [P2] [P3] [P4] [Pb1] [Pb2]
|
|
* EXEC (400 uSec) [EXEC1] [EXEC2] [EXEC3] [EXEC4] [EXECb1] [EXECb2]
|
|
* PLAN (<4ms) [PLANmoveA][PLANmoveB][PLANmoveC][PLANmoveD][PLANmoveE] etc.
|
|
*
|
|
* You can collect the target for moveA as early as the end of [PLANmoveA]. The system will
|
|
* not reach that target position until the end of [Segment4]. Data from Segment4 can only be
|
|
* processed during the EXECb2 or Pb2 interval as it's the first time that is not time-critical
|
|
* and you actually have enough cycles to calculate the position and error terms. We use Pb2.
|
|
*
|
|
* Additionally, by this time the target in Gcode model knows about has advanced quite a bit,
|
|
* so the moveA target needs to be saved somewhere. Targets are propagated downward to the planner
|
|
* runtime (the EXEC), but the exec will have moved on to moveB by the time we need it. So moveA's
|
|
* target needs to be saved somewhere.
|
|
*/
|
|
/*
|
|
* ERROR CORRECTION
|
|
*
|
|
* The purpose of this module is to calculate an error term between the programmed
|
|
* position (target) and the actual measured position (position). The error term is
|
|
* used during move execution (exec) to adjust the move to compensate for accumulated
|
|
* positional errors. It's also the basis of closed-loop (servoed) systems.
|
|
*
|
|
* Positional error occurs due to floating point numerical inaccuracies. g2core uses
|
|
* 32 bit floating point (GCC 32 bit, which is NOT IEEE 32 bit). Errors creep in
|
|
* during planning, move execution, and stepper output phases. Care has been taken
|
|
* to minimize introducing errors throughout the process, but they still occur.
|
|
* In most cases errors are not noticeable as they fall below the step resolution
|
|
* for most jobs. For jobs that run > 1 hour the errors can accumulate and send
|
|
* results off by as much as a millimeter if not corrected.
|
|
*
|
|
* Note: Going to doubles (from floats) would reduce the errors but not eliminate
|
|
* them altogether.
|
|
*
|
|
* *** Applying the error term for error correction ***
|
|
*
|
|
* So if you want to use the error from moveA to correct moveB it has to be done in a region that
|
|
* is not already running (i.e. the head, body, or tail) as moveB is already 2 segments into run.
|
|
* Since most moves in very short line Gcode files are body only, for practical purposes the
|
|
* correction will be applied to moveC. (It's possible to recompute the body of moveB, but it may
|
|
* not be worth the trouble).
|
|
*/
|
|
|
|
#include "hardware.h" // for MOTORS
|
|
|
|
#ifndef ENCODER_H_ONCE
|
|
#define ENCODER_H_ONCE
|
|
|
|
/**** Configs and Constants ****/
|
|
|
|
/**** Macros ****/
|
|
// used to abstract the encoder code out of the stepper so it can be managed in one place
|
|
|
|
#define SET_ENCODER_STEP_SIGN(m, s) en.en[m].step_sign = s;
|
|
#define INCREMENT_ENCODER(m) en.en[m].steps_run += en.en[m].step_sign;
|
|
#define ACCUMULATE_ENCODER(m) \
|
|
en.en[m].encoder_steps += en.en[m].steps_run; \
|
|
en.en[m].steps_run = 0;
|
|
|
|
/**** Structures ****/
|
|
|
|
typedef struct enEncoder { // one real or virtual encoder per controlled motor
|
|
int8_t step_sign; // set to +1 or -1
|
|
int16_t steps_run; // + or - steps counted during stepper interrupt
|
|
int32_t encoder_steps; // counted encoder position in steps
|
|
} enEncoder_t;
|
|
|
|
typedef struct enEncoders {
|
|
magic_t magic_start;
|
|
enEncoder_t en[MOTORS]; // runtime encoder structures
|
|
float snapshot[MOTORS]; // snapshot vector
|
|
magic_t magic_end;
|
|
} enEncoders_t;
|
|
|
|
extern enEncoders_t en;
|
|
|
|
|
|
/**** FUNCTION PROTOTYPES ****/
|
|
|
|
void encoder_init(void);
|
|
void encoder_reset(void);
|
|
void encoder_init_assertions(void);
|
|
stat_t encoder_test_assertions(void);
|
|
|
|
void en_set_encoder_steps(uint8_t motor, float steps);
|
|
float en_read_encoder(uint8_t motor);
|
|
|
|
void en_take_encoder_snapshot();
|
|
float en_get_encoder_snapshot_steps(uint8_t motor);
|
|
float* en_get_encoder_snapshot_vector();
|
|
|
|
#endif // End of include guard: ENCODER_H_ONCE
|