-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsensors.c
executable file
·149 lines (121 loc) · 5.13 KB
/
sensors.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/*******************************************************************************
* File: sensors.c
* Version 0.1
* Author: Francisco Rascón
José González
* Implements all the transformations routines necessary for the sensors.
******************************************************************************/
#include "sensors.h"
#include "constants.h"
#include <math.h>
#include <xc.h>
// extern int16_t flag_init; //GAP: flag to detect initilialization of the
// optical encoder angle and start applying the mech stop supervisor
extern void __attribute__((interrupt, auto_psv)) _QEIInterrupt(void) {
_LATF5 ^= 1;
_LATB8 = ~_LATF5;
POSCNT = 0;
// Clear QEI interrupt flag
_QEIIF = 0;
// GAP:
// for the mechanical stop supervisor, I wait for the first time I detect
// where the zero is, to start applying the supervisor (otherwise, I do not
// know where I really am, and could try to block the control before the
// mechanical stop))
// if (flag_init == 0) flag_init=1;
}
void sensors_qei_init(int16_t encoder_max_counts) {
// BIOMOT project is using an incremental optical encoder with multiplying
// factor of 4
// Configure QEI's pins as inputs.
_TRISB3 = 0b1; // INDX
_TRISB4 = 0b1; // QEA
_TRISB5 = 0b1; // QEB
// Configure QEI's pins as inputs of digital type, not analog type.
_PCFG3 = 0b1; // INDX
_PCFG4 = 0b1; // QEA
_PCFG5 = 0b1; // QEB
// Configure QEI Control Register
// UDSRC (QEICON<0>). Position Counter Direction Selection Control bit. This
// bit is only useful when QEI module is configured as a timer.
// TQCS (QEICON<1>). Timer Clock Source Select bit. This bit is only useful
// when QEI module is configured as a timer.
_POSRES = 0b1; // Index pulse resets position counter.
// TQCKPS (QEICON<4:3>). Timer Input Clock Prescale Select bit. These bits are
// only useful when QEI module is configured as a timer.
// TQGATE (QEICON<5>). Timer Gated Time Accumulation Enable bit. These bits
// are only useful when QEI module is configured as a timer gate.
_PCDOUT = 0b0; // Position counter direction status output disabled (normal
// i/o pin operation)
#if SWAP_INC_OPT_ENC == 1
_SWPAB = 0b1; // Phase A and Phase B inputs swapped
#else
_SWPAB = 0b0; // Phase A and Phase B inputs not swapped
#endif
//_QEIM = 0b111; // Quadrature encoder interface enabled (x4 mode) with
// position counter reset by match (MAXCNT)
_QEIM = 0b110; // Quadrature encoder interface enabled (x4 mode) with index
// pulse reset of position counter
//_UPDN (QEICON<11>) Read only bit when QEIM = 1XX
// INDEX (QEICON<12>) Index pin state status bit (read only)
_QEISIDL = 0b0; // Continue module operation in idle mode
_CNTERR = 0b0; // Clean position count
// Configure Digital Filter Control Register
_QECK = 0b011; // QEA/QEB/INDX digital filter clock divide select bits. 1:16
// clook divide
_QEOUT = 0b1; // QEA/QEB/INDX digital filter output enabled
_CEID = 0b1; // Interrupts due to count errors are disabled.
_IMV0 = 0;
_IMV1 = 0;
POSCNT = 0;
// Example
// encoder_max_counts = 2000 cpr
// encoder_max_counts * 4 = 8000 cpr ==> from 0 to 7999 (last registrable
// count index)
// 8000 counts is equivalent to 360 degrees or 0 degrees.
// 7999 corresponds to 7999/8000 = 359.955 degrees
// Resolution 360 * (1/8000) = 0.045 degrees
MAXCNT = (4 * encoder_max_counts) - 1;
_QEIIP = 0b111; // Priority 1
_QEIIF = 0b0;
}
int16_t sensors_get_incremental_encoder_angle(void) { return POSCNT; }
// CURRENT TRANSFORMATIONS ROUTINES
/* Read the value of the filtered current in amps [A]
* 0 A ==> 2.5 V ==> 512 (For an ADC with Vref- = 0 V, Vref+ = 5 V and 10 bits)
* 5 A ==> 3.5 V ==> 512 * (3.5 / 2.5) = 716.8
*/
float sensors_get_current_amps(int16_t current_digital) {
// y = m * (x - 512)
// m = 5/(716.8 - 512) = 5 / (((3.5/2.5)*512) - 512) = 5 / (512 * ((3.5/2.5) -
// 1))
// = (5 * 2.5) / 512 = 25 / 1024
// y = m * (x - 512) = (25/1024) * (x - 512) = ((25/1024) * x) - 12.5
return (((25.0f / 1024) * current_digital) - 12.5f);
}
// LOAD CELL TRANSFORMATIONS ROUTINES
float sensors_get_external_load_cell_force_newtons(
int16_t external_load_cell_force_digital) {
return ((0.8f * external_load_cell_force_digital) + 7.522f);
}
// TEMPERATURE TRANSFORMATIONS ROUTINES
/* Read the value of the filtered temperature in celsius */
int16_t sensors_get_temperature_celsius(int16_t temperature_digital) {
if (temperature_digital < 102)
return 0;
else
return (temperature_digital - 102) / 2;
}
// TORQUE TRANSFORMATIONS ROUTINE
void sensors_get_theoretical_torque_newtons(
float *alpha_angle_rad, float *precompression,
float *internal_load_cell_force, float *alpha_torque_Nm,
float *internal_load_cell_torque_Nm) {
// BIOMOT
float A_term = sqrtf(0.003725f - (0.003500f * cos(*alpha_angle_rad)));
*alpha_torque_Nm = 92.75f * (1.0f + ((*precompression - 0.015f) / A_term)) *
sin(*alpha_angle_rad);
*internal_load_cell_torque_Nm = 0;
//*theoretical_torque_by_internal_load_cell = (internal_load_cell_force *
//(0.0026152f / A_term) * sin(alpha_angle_rad));
}