/
FingerLib.h
268 lines (206 loc) · 9.34 KB
/
FingerLib.h
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/*
* FingerLib.h
*
* Created: 02/11/2015 11:12:48
* Author: Olly McBride
*
* This work is licensed under the Creative Commons Attribution 4.0 International License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/.
*
*/
#ifndef FINGERLIB_H_
#define FINGERLIB_H_
#include <inttypes.h>
#include <Arduino.h>
// CHANGE SETTINGS
// Uncomment out the following to use PID pos control instead of custom P control
#define USE_PID
//// Uncomment the following to enable force/current sensing (Arduino Zero & Chestnut PCB Only)
//#define FORCE_SENSE
// GENERIC LIBRARIES
#include "timers/timer_and_delay.h"
// BOARD SPECIFIC LIBRARIES
#if defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_AVR_UNO)
//#define MYSERIAL Serial
#include "timers/avr_FingerTimer.h"
#elif defined(ARDUINO_ARCH_SAMD)
//#define MYSERIAL SerialUSB
#include "timers/samd_FingerTimer.h"
// Uncomment the following to enable force/current sensing (Arduino Zero & Chestnut PCB Only)
#define FORCE_SENSE
#else
#error FingerLib only supports boards using an Arduino Mega 2560, Arduino UNO, Arduino Zero, Almond PCB or Chestnut PCB.
#endif
// SETTING SPECIFIC LIBRARIES
#if defined(USE_PID)
#include "pid/pid_controller.h"
#endif
#if defined(FORCE_SENSE)
#if defined(ARDUINO_ARCH_SAMD)
#include "current_sense/samd_CurrentSense.h"
#else
#error Force sensing is only available on the Arduino Zero or Chestnut PCB.
#endif
#endif
// BOOLEANS
#define OPEN 0
#define CLOSE 1
#define RIGHT 1 // HAND TYPE
#define LEFT 2 // HAND TYPE
// LIMITS
#define MAX_FINGERS 6 // maximum number of _fingers
#define MAX_FINGER_SPEED 255 // maximum motor speed
#if defined(ARDUINO_AVR_MEGA2560)
#define MIN_FINGER_SPEED 180 // minimum motor speed
#else
#define MIN_FINGER_SPEED 0 // minimum motor speed
#endif
#define MAX_FINGER_POS 973 // maximum motor position
#define MIN_FINGER_POS 50 // minimum motor position
#define POS_REACHED_TOLERANCE 50 // tolerance for posReached()
#if defined(FORCE_SENSE)
#define CURR_SPIKE_DUR_US (double) 50000 // us - duration of peak to discard
// force and current conversion values
#define MOTOR_DRIVER_CURRENT_LIMIT (float) 425 // mA
#define CURRENT_SENSE_SATURATION_VAL (float) 950 // max ADC value
#define ADC_VALS_PER_MA_DRAW (float) (CURRENT_SENSE_SATURATION_VAL/MOTOR_DRIVER_CURRENT_LIMIT) // number of ADC values per mA draw of motor
// Y = MX + C, where Y = force, X = current draw
#define CURRENT_SENSE_CONST_M (float) 7.4833 // generated from the equation of the line from the force-current graph
#define CURRENT_SENSE_CONST_C (float) 46.444 // generated from the equation of the line from the force-current graph
#endif
// FINGER PINS
typedef struct _FingerPin
{
uint8_t dir[2];
uint8_t posSns;
#ifdef FORCE_SENSE
uint8_t forceSns;
#endif
} FingerPin;
// VECTOR PROPERTIES
typedef struct _LimitProperties
{
double min;
double max;
bool reached;
} LimitProperties;
typedef struct _VectorProperties
{
double prev;
double curr;
double targ;
double error;
LimitProperties limit;
} VectorProperties;
// FINGER CLASS
class Finger
{
public:
// CONSTRUCTOR
Finger();
// INITIALISATION
uint8_t attach(uint8_t dir0, uint8_t dir1, uint8_t posSns); // attach pins to a finger using only position control
uint8_t attach(uint8_t dir0, uint8_t dir1, uint8_t posSns, bool inv); // attach pins to a finger using only position control, but allow the direction to be inverted
uint8_t attach(uint8_t dir0, uint8_t dir1, uint8_t posSns, uint8_t forceSns, bool inv); // attach pins to a finger using position control and force control, and allow the direction to be inverted
void detach(void); // deactivate the finger
bool attached(void); // return true if the current finger is attached and initialised correctly
void invertFingerDir(void); // set the motor to be inverted
// LIMITS
void setPosLimits(int min, int max); // set the maximum and minimum position limits
void setSpeedLimits(int min, int max); // set the maximum and minimum speed limits
#ifdef FORCE_SENSE
void setForceLimits(int min, int max); // set the maximum and minimum force limits
#endif
// POS
void writePos(int value); // write a target position to the finger
void movePos(int value); // write a change in position to the finger
int16_t readPos(void); // return the current position
int16_t readPosError(void); // return the error between the current position and the target position
uint16_t readTargetPos(void); // return the target position
bool reachedPos(void); // returns true if position reached
bool reachedPos(uint16_t posErr); // returns true if position reached
// DIR
void writeDir(int value); // write a target direction to the finger
uint8_t readDir(void); // return the current direction
void open(void); // open the finger
void close(void); // close the finger
void open_close(void); // toggle finger between open/closed
void open_close(boolean dir); // set finger to open/close
// SPEED
void writeSpeed(int value); // write a target speed to the finger
uint8_t readSpeed(void); // return the current speed being written to the finger
uint8_t readTargetSpeed(void); // return the target speed
#ifdef FORCE_SENSE
// FORCE
void writeForce(float value, int dir); // write a target force in a particular direction (0.0 - 54.95N, OPEN - CLOSE)
float readForce(void); // return the current force value. If force sense is not enabled, return blank (-1)
uint16_t readCurrent(void); // return the latest force sense ADC value
bool reachedForceLimit(void); // return true if the force limit has been reached
void readCurrentSns(void); // read the current force and discount the current spike (called via interrupt)
float convertADCToForce(int ADCVal); // convert ADC current sense value to force value (float)
int convertForceToADC(float force); // convert force value to ADC current sense value (int)
#endif
// STOP/START
void stopMotor(void); // stop the motor and hold position
void disableMotor(void); // disable the motor by setting the speed to 0
void enableMotor(void); // re-enable the motor
void motorEnable(bool motorEn); // set motor to be enabled/disabled
void enableInterrupt(void); // enable timer interrupt for motor control
void disableInterrupt(void); // disable timer interrupt for motor control
#ifdef FORCE_SENSE
void enableForceSense(void); // enable force sensing
void disableForceSense(void); // disable force sensing
#endif
//// PRINT
//void printPos(void); // print the current position (no new line)
//void printPos(bool newL); // print the current position (new line)
//void printPosError(void); // print the current position error (no new line)
//void printPosError(bool newL); // print the current position error (new line)
//void printDir(void); // print the current direction (no new line)
//void printDir(bool newL); // print the current direction (new line)
//void printReached(void); // print whether the target position has been reached (no new line)
//void printReached(bool newL); // print whether the target position has been reached (new line)
//void printSpeed(void); // print the current speed (no new line)
//void printSpeed(bool newL); // print the current speed (new line)
//
//void printDetails(void); // print current position, direction, speed and whether the target position has been reached
//void printConfig(void); // print finger number, pins and limits
// CONTROL
void control(void); // run position (and force) controller (called via interrupt)
private:
#if defined(USE_PID)
PID_CONTROLLER _PID;
#endif
uint8_t fingerIndex; // current finger number
FingerPin _pin; // finger pin struct (dir, pos, force)
bool _isActive = false; // flag to indicate if finger is enabled
bool _invert; // finger inversion flag
bool _motorEn; // motor enable flag
bool _interruptEn; // flag to set whether to use the timer interrupt for motor control
#ifdef FORCE_SENSE
bool _forceSenseEn = false; // force sense is enable flag
#endif
// PROPERTIES
VectorProperties _pos; // position properties (prev, curr, targ, error, limit)
VectorProperties _dir; // direction properties (curr)
VectorProperties _speed; // speed properties (prev, curr, targ, error, limit)
#ifdef FORCE_SENSE
VectorProperties _force; // force properties (prev, curr, targ, error, limit) (all stored as ADC values instead of N)
#endif
void positionController(void); // position controller (either PID or custom P)
void motorControl(int motorSpeed); // split the vectorised motor speed into direction and speed values and write to the motor
#ifdef FORCE_SENSE
void forceController(void); // stop the finger if the force limit is reached, or move to reach a target force
US_NB_DELAY currentSpikeTimer; // current spike rejection timer
#endif
};
// INTERRUPT HANDLERS
void _fingerControlCallback(void); // runs the control() function of a Finger instance at each call by the timer interrupt
#ifdef FORCE_SENSE
void _currentSenseCallback(void); // runs the readCurrentSns() function of a Finger instance at each call
#endif
// HARDWARE SPECIFIC FUNCTIONS
#ifdef ARDUINO_AVR_MEGA2560
void setPWMFreq(uint8_t pin, uint8_t value); // change the PWM timer frequency to be out of the audible range
#endif
#endif /* FINGERLIB_H_ */