forked from maxshep/Exoboot_Code
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathconfig_util.py
More file actions
194 lines (164 loc) · 6.33 KB
/
config_util.py
File metadata and controls
194 lines (164 loc) · 6.33 KB
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
from typing import Type, List
from dataclasses import dataclass, field
import time
import csv
import sys
import importlib
from enum import Enum
import argparse
import constants
import os
class Task(Enum):
'''Used to determine gait_event_detector used and state machines used.'''
WALKING = 0
STANDINGPERTURBATION = 1
BILATERALSTANDINGPERTURBATION = 2
SLIPDETECTFROMSYNC = 3
WALKINGMLGAITPHASE = 4
class StanceCtrlStyle(Enum):
'''Used to determine behavior during stance.'''
FOURPOINTSPLINE = 0
GENERICSPLINE = 1
SAWICKIWICKI = 2
GENERICIMPEDANCE = 3
FIVEPOINTSPLINE = 4
@dataclass
class ConfigurableConstants():
'''Class that stores configuration-related constants.
These variables serve to allow 1) loadable configurations from files in /custom_constants/,
2) online updating of device behavior via parameter_passers.py, and 3) to store calibration
details. Below are the default config constants. DO NOT MODIFY DEFAULTS. Write your own short
script in /custom_constants/ (see default_config.py for example).
(see ) '''
# Set by functions... no need to change in config file
loop_time: float = 0
actual_time: float = time.time()
LEFT_STANDING_ANGLE: float = None # Deg
RIGHT_STANDING_ANGLE: float = None # Deg
TARGET_FREQ: float = 175 # Hz
ACTPACK_FREQ: float = 200 # Hz
DO_DEPHY_LOG: bool = False
DEPHY_LOG_LEVEL: int = 4
ONLY_LOG_IF_NEW: bool = True
TASK: Type[Task] = Task.WALKING
STANCE_CONTROL_STYLE: Type[
StanceCtrlStyle] = StanceCtrlStyle.FOURPOINTSPLINE
MAX_ALLOWABLE_CURRENT = 20000 # mA
# Gait State details
HS_GYRO_THRESHOLD: float = 100
HS_GYRO_FILTER_N: int = 2
HS_GYRO_FILTER_WN: float = 3
HS_GYRO_DELAY: float = 0.05
SWING_SLACK: int = 10000
TOE_OFF_FRACTION: float = 0.60
REEL_IN_MV: int = 1200
REEL_IN_SLACK_CUTOFF: int = 1200
REEL_IN_TIMEOUT: float = 0.2
NUM_STRIDES_REQUIRED: int = 2
SWING_ONLY: bool = False
# 4 point Spline
RISE_FRACTION: float = 0.2
PEAK_FRACTION: float = 0.53
FALL_FRACTION: float = 0.60
PEAK_TORQUE: float = 5
SPLINE_BIAS: float = 3 # Nm
# Impedance
K_VAL: int = 500
B_VAL: int = 0
B_RATIO: float = 0.5 # when B_VAL is a function of B_RATIO. 2.5 is approx. crit. damped
SET_POINT: float = 0 # Deg
READ_ONLY: bool = False # Does not require Lipos
DO_READ_FSRS: bool = False
DO_READ_SYNC: bool = False
PRINT_HS: bool = True # Print heel strikes
VARS_TO_PLOT: List = field(default_factory=lambda: [])
DO_DETECT_SLIP: bool = False
SLIP_DETECT_ACTIVE: bool = False
DO_INCLUDE_GEN_VARS: bool = False
SLIP_DETECT_DELAY: int = 0
EXPERIMENTER_NOTES: str = 'Experimenter notes go here'
#It is always zero untill the first generation
#When this variable is non zero it means the update function can be called
#It basically avoids any error caused by grpc call not being received due
#to server not running on the optimizer side
number_of_calls: int = 0
generation: int = 0
# DO NOT CHANGE THE DEFAULT VALUE
confirmed: bool = False
User_Ready = False
#Needed for the Exosekeleton (EB 45, EB 51)
resetting_time = 685 # the Exoboot typically stops updating after 731 seconds
controller_stop_time = 710
class ConfigSaver():
def __init__(self, file_ID: str, config: Type[ConfigurableConstants]):
'''file_ID is used as a custom file identifier after date.'''
self.file_ID = file_ID
self.config = config
subfolder_name = 'exo_data/'
filename = subfolder_name + \
time.strftime("%Y%m%d_%H%M_") + file_ID + \
'_CONFIG' + '.csv'
if os.path.exists(subfolder_name) and os.path.isdir(subfolder_name):
pass
else:
os.mkdir(subfolder_name)
self.my_file = open(filename, 'w', newline='')
self.writer = csv.DictWriter(self.my_file,
fieldnames=self.config.__dict__.keys())
self.writer.writeheader()
def write_data(self, loop_time):
'''Writes new row of Config data to Config file.'''
self.config.loop_time = loop_time
self.config.actual_time = time.time()
self.writer.writerow(self.config.__dict__)
def close_file(self):
if self.file_ID is not None:
self.my_file.close()
def load_config(config_filename) -> Type[ConfigurableConstants]:
try:
# strip extra parts off
config_filename = config_filename.lower()
if config_filename.endswith('_config'):
config_filename = config_filename[:-7]
elif config_filename.endswith('_config.py'):
config_filename = config_filename[:-11]
elif config_filename.endswith('.py'):
config_filename = config_filename[:-4]
config_filename = config_filename + '_config'
module = importlib.import_module('.' + config_filename,
package='custom_configs')
except:
error_str = 'Unable to find config file: ' + \
config_filename + ' in custom_constants'
raise ValueError(error_str)
config = module.config
print('Using ConfigurableConstants from: ', config_filename)
return config
def parse_args():
# Create the parser
my_parser = argparse.ArgumentParser(prog='Exoboot Code',
description='Run Exoboot Controllers',
epilog='Enjoy the program! :)')
# Add the arguments
my_parser.add_argument('-c',
'--config',
action='store',
type=str,
required=False,
default='default_config')
# Execute the parse_args() method
args = my_parser.parse_args()
return args
def load_config_from_args():
args = parse_args()
config = load_config(config_filename=args.config)
return config
def get_sync_detector(config: Type[ConfigurableConstants]):
if config.DO_READ_SYNC:
print('Creating sync detector')
import gpiozero # pylint: disable=import-error
sync_detector = gpiozero.InputDevice(pin=constants.SYNC_PIN,
pull_up=False)
return sync_detector
else:
return None