Code for the COVR project DROPSAW project test rig (previously used for the Heros testing).

Dependencies:   SPTE_10Bar_5V mbed AS5048 SDFileSystem MODSERIAL LCM101_DROPSAW LinearActuator

Committer:
cnckiwi31
Date:
Mon Oct 26 11:55:27 2020 +0000
Revision:
15:a84d54e25775
Parent:
11:fc82dd22a527
Code ready for inclusion in documentation (compiles, but no last check on runBenchmarkExperiment1() code done)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
cnckiwi31 15:a84d54e25775 1 /* Copyright 2020 Allan Joshua Veale
cnckiwi31 15:a84d54e25775 2
cnckiwi31 15:a84d54e25775 3 Licensed under the Apache License, Version 2.0 (the "License");
cnckiwi31 15:a84d54e25775 4 you may not use this file except in compliance with the License.
cnckiwi31 15:a84d54e25775 5 You may obtain a copy of the License at
cnckiwi31 15:a84d54e25775 6
cnckiwi31 15:a84d54e25775 7 http://www.apache.org/licenses/LICENSE-2.0
cnckiwi31 15:a84d54e25775 8
cnckiwi31 15:a84d54e25775 9 Unless required by applicable law or agreed to in writing, software
cnckiwi31 15:a84d54e25775 10 distributed under the License is distributed on an "AS IS" BASIS,
cnckiwi31 15:a84d54e25775 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
cnckiwi31 15:a84d54e25775 12 See the License for the specific language governing permissions and
cnckiwi31 15:a84d54e25775 13 limitations under the License.
cnckiwi31 15:a84d54e25775 14 */
cnckiwi31 15:a84d54e25775 15
megrootens 0:3855d4588f76 16 #include "bench.h"
megrootens 0:3855d4588f76 17
cnckiwi31 15:a84d54e25775 18 /** constructor
cnckiwi31 7:edb876c98565 19 * Create an object representing the test rig
cnckiwi31 7:edb876c98565 20 * @param mosi: mosi pin for sensor chain (SPI angle sensors)
cnckiwi31 7:edb876c98565 21 * @param miso: miso pin for sensor chain (SPI angle sensors)
cnckiwi31 7:edb876c98565 22 * @param sck: clock pin for sensor chain (SPI angle sensors)
cnckiwi31 7:edb876c98565 23 * @param cs: chip select pin for sensor chain (SPI angle sensors)
cnckiwi31 5:63063a9fa51c 24 * @param use5kNLoadCell: if 5kN load cell is used (if false, 1kN sensor is used)
cnckiwi31 4:1cdce6c6c94e 25 * @param p_lcm101: analog input pin for load cell
cnckiwi31 4:1cdce6c6c94e 26 * @param p_spte0: analog input pin for pressure sensor 0
cnckiwi31 4:1cdce6c6c94e 27 * @param p_spte1: analog input pin for pressure sensor 1
cnckiwi31 5:63063a9fa51c 28 * @param p_valve: digital output for valve (on/off) that inflates leg actuator
surajgiri 11:fc82dd22a527 29 * @param p_laDir: digital output for linear actuator direction (retract/extend)
surajgiri 11:fc82dd22a527 30 * @param p_laPwm: pwm output for linear actuator speed
cnckiwi31 5:63063a9fa51c 31 * @param mosi: mosi pin for sd card
cnckiwi31 5:63063a9fa51c 32 * @param miso: miso pin for sd card
cnckiwi31 5:63063a9fa51c 33 * @param sck: clock pin for sd card
cnckiwi31 5:63063a9fa51c 34 * @param cs: chip select pin for sd card
cnckiwi31 5:63063a9fa51c 35 * @param tx: serial transmission line
cnckiwi31 5:63063a9fa51c 36 * @param rx: serial receive line
megrootens 0:3855d4588f76 37 */
megrootens 0:3855d4588f76 38 Bench::Bench(PinName mosi, PinName miso, PinName sck, PinName cs,
surajgiri 11:fc82dd22a527 39 bool use5kNLoadCell,PinName p_lcm101, PinName p_spte0, PinName p_spte1, PinName p_valve,PinName p_laDir, PinName p_laPwm,
cnckiwi31 5:63063a9fa51c 40 PinName sd_mosi, PinName sd_miso, PinName sd_sck, PinName sd_cs,
surajgiri 11:fc82dd22a527 41 PinName tx, PinName rx) :
cnckiwi31 5:63063a9fa51c 42 pc(tx,rx),
megrootens 0:3855d4588f76 43 as5048_(mosi, miso, sck, cs, sensors::kNumJoints),
cnckiwi31 5:63063a9fa51c 44 loadCell5kN(p_lcm101, sensors::kGen5kNOffset, sensors::kGen5kNFactor),
cnckiwi31 5:63063a9fa51c 45 loadCell1kN(p_lcm101, sensors::kLcm101Offset, sensors::kLcm101Factor),
cnckiwi31 5:63063a9fa51c 46 use5kN(use5kNLoadCell),
cnckiwi31 4:1cdce6c6c94e 47 spte0(p_spte0, sensors::kSPTE0Offset, sensors::kSPTE0Factor),
cnckiwi31 5:63063a9fa51c 48 spte1(p_spte1, sensors::kSPTE1Offset, sensors::kSPTE1Factor),
cnckiwi31 5:63063a9fa51c 49 valveFesto(p_valve),
surajgiri 11:fc82dd22a527 50 LinAct(p_laDir,p_laPwm),
cnckiwi31 5:63063a9fa51c 51 sd(sd_mosi, sd_miso, sd_sck, sd_cs, "sd")
cnckiwi31 5:63063a9fa51c 52 {
cnckiwi31 5:63063a9fa51c 53 //init serial things
cnckiwi31 5:63063a9fa51c 54 pc.baud(timing::kSerialBaudrate);//set the serial rate
cnckiwi31 5:63063a9fa51c 55
cnckiwi31 15:a84d54e25775 56 sd_card_present = false;//have not checked for an sd card
cnckiwi31 15:a84d54e25775 57 fname_prepend = 0;//have not checked what is on the sd card
cnckiwi31 15:a84d54e25775 58 is_logging = false;//not datalogging
cnckiwi31 15:a84d54e25775 59 is_printing = false;//not printing anything
cnckiwi31 15:a84d54e25775 60 was_printing = false;//was not printing
cnckiwi31 5:63063a9fa51c 61
cnckiwi31 15:a84d54e25775 62 usedExtraCols = 0;//default
cnckiwi31 5:63063a9fa51c 63
cnckiwi31 5:63063a9fa51c 64 firstReadMS = 0; //first timer value read
cnckiwi31 15:a84d54e25775 65 startedLogging = false; //not in the middle of a logging cycle
cnckiwi31 5:63063a9fa51c 66
surajgiri 11:fc82dd22a527 67 keyIntOffset = timing::minKeyInt;//any right keypress is ok at the start
surajgiri 11:fc82dd22a527 68 k = '\0'; //keyboard value starts off as a null value
surajgiri 11:fc82dd22a527 69
cnckiwi31 5:63063a9fa51c 70 //set data logging frequency
cnckiwi31 5:63063a9fa51c 71 loggingUS = timing::kTimeLogDataUs;
cnckiwi31 5:63063a9fa51c 72 loggingHz = (int)(1000000/timing::kTimeLogDataUs);
cnckiwi31 5:63063a9fa51c 73
cnckiwi31 15:a84d54e25775 74 //set all angle sensor calibration data
megrootens 0:3855d4588f76 75 for (int i=0; i<sensors::kNumJoints; ++i) {
megrootens 0:3855d4588f76 76 as5048_.setOffsetDegrees(i,sensors::kOffsetsDegrees[i]);
megrootens 0:3855d4588f76 77 as5048_.setDirection(i,sensors::kDirections[i]);
cnckiwi31 5:63063a9fa51c 78 }
cnckiwi31 5:63063a9fa51c 79 }
cnckiwi31 5:63063a9fa51c 80
cnckiwi31 5:63063a9fa51c 81 /**
cnckiwi31 5:63063a9fa51c 82 * Initialises: timers, SD card
cnckiwi31 7:edb876c98565 83 * Prints a welcome message and information on the logging frequency and sensor
cnckiwi31 7:edb876c98565 84 * reading rate
cnckiwi31 5:63063a9fa51c 85 */
cnckiwi31 5:63063a9fa51c 86 void Bench::initialise()
cnckiwi31 5:63063a9fa51c 87 {
cnckiwi31 15:a84d54e25775 88 //setup the timing for the control loop (which only reads the angle sensors)
cnckiwi31 5:63063a9fa51c 89 tick_update.attach_us(this,&Bench::update,timing::kTimeControlUs);
cnckiwi31 7:edb876c98565 90
cnckiwi31 5:63063a9fa51c 91 // set rate at which data is printed
cnckiwi31 5:63063a9fa51c 92 tick_serial.attach_us(this,&Bench::PrintStatus,timing::kTimeSerialPrintUs);
cnckiwi31 5:63063a9fa51c 93
surajgiri 11:fc82dd22a527 94 //setup the timer to read key presses
surajgiri 11:fc82dd22a527 95 Bench::pc.attach(this,&Bench::ToggleState,MODSERIAL::RxIrq);
cnckiwi31 5:63063a9fa51c 96
cnckiwi31 5:63063a9fa51c 97 //display welcome message
cnckiwi31 5:63063a9fa51c 98 pc.printf("\r\n**Hello!**\r\n");
cnckiwi31 15:a84d54e25775 99 pc.printf("Version: V4\r\n\n");
cnckiwi31 5:63063a9fa51c 100
cnckiwi31 5:63063a9fa51c 101 Bench::pc.printf("5kN load cell? %s\r\n\n",sensors::use5kN?"Yes":"No");
cnckiwi31 5:63063a9fa51c 102
cnckiwi31 5:63063a9fa51c 103 pc.printf("Bench update rate (Hz): %i\r\n",timing::TimeControlHertz);
cnckiwi31 5:63063a9fa51c 104 pc.printf("Logging rate (Hz): %i\r\n\n",(int)loggingHz);
cnckiwi31 5:63063a9fa51c 105
cnckiwi31 5:63063a9fa51c 106 //startup the SD card
cnckiwi31 5:63063a9fa51c 107 InitSdCard();
cnckiwi31 5:63063a9fa51c 108
cnckiwi31 5:63063a9fa51c 109 //Display the menu
cnckiwi31 5:63063a9fa51c 110 PrintMenu();
cnckiwi31 5:63063a9fa51c 111 }
cnckiwi31 5:63063a9fa51c 112
cnckiwi31 5:63063a9fa51c 113 /**
cnckiwi31 15:a84d54e25775 114 * Sets the rate at which data is logged in an experiment - when automatic datalogging is used
cnckiwi31 5:63063a9fa51c 115 * @param hertz: logging frequency in Hz
cnckiwi31 5:63063a9fa51c 116 */
cnckiwi31 5:63063a9fa51c 117 void Bench::setLoggingFrequency(float hertz)
cnckiwi31 5:63063a9fa51c 118 {
cnckiwi31 5:63063a9fa51c 119 //set data logging frequency
cnckiwi31 5:63063a9fa51c 120 if (hertz > 0) {
cnckiwi31 5:63063a9fa51c 121 loggingUS = 1000000/hertz;
cnckiwi31 5:63063a9fa51c 122 loggingHz = hertz;
cnckiwi31 15:a84d54e25775 123 } else { //default if bad value supplied
cnckiwi31 5:63063a9fa51c 124 loggingUS = timing::kTimeLogDataUs;
cnckiwi31 5:63063a9fa51c 125 loggingHz = (int)(1000000/timing::kTimeLogDataUs);
megrootens 0:3855d4588f76 126 }
megrootens 0:3855d4588f76 127 }
megrootens 0:3855d4588f76 128
megrootens 0:3855d4588f76 129 /**
cnckiwi31 15:a84d54e25775 130 * Sets names of extra columns of data to be recorded (those more than maxCols are
cnckiwi31 15:a84d54e25775 131 * ignored)
cnckiwi31 5:63063a9fa51c 132 * @param extraColumnNames: string array of the column names
cnckiwi31 5:63063a9fa51c 133 * @param numCols: number of elements in the string array
cnckiwi31 5:63063a9fa51c 134 */
cnckiwi31 5:63063a9fa51c 135 void Bench::setExtraColumns(string extraColumnNames[], int numCols)
cnckiwi31 5:63063a9fa51c 136 {
cnckiwi31 5:63063a9fa51c 137 usedExtraCols = numCols;
cnckiwi31 5:63063a9fa51c 138 // save the names
cnckiwi31 5:63063a9fa51c 139 for(int i=0; i<maxCols; i++) {
cnckiwi31 5:63063a9fa51c 140 if (i<numCols) {
cnckiwi31 5:63063a9fa51c 141 extraColNames[i] = extraColumnNames[i];
cnckiwi31 5:63063a9fa51c 142 } else {
cnckiwi31 5:63063a9fa51c 143 extraColNames[i] = ""; //less columns than the max possible are filled with a null space
cnckiwi31 5:63063a9fa51c 144 }
cnckiwi31 5:63063a9fa51c 145 }
cnckiwi31 5:63063a9fa51c 146
cnckiwi31 5:63063a9fa51c 147 }
cnckiwi31 5:63063a9fa51c 148
cnckiwi31 5:63063a9fa51c 149 /**
cnckiwi31 5:63063a9fa51c 150 * Sets values of extra columns of data to be recorded
cnckiwi31 5:63063a9fa51c 151 * @param data: data to be logged with the extra columns
cnckiwi31 5:63063a9fa51c 152 */
cnckiwi31 5:63063a9fa51c 153 void Bench::setExtraData(float data[])
cnckiwi31 5:63063a9fa51c 154 {
cnckiwi31 5:63063a9fa51c 155 for (int i=0; i<usedExtraCols; i++) {
cnckiwi31 5:63063a9fa51c 156 extraColValues[i] = data[i];
cnckiwi31 15:a84d54e25775 157 }
cnckiwi31 5:63063a9fa51c 158 }
cnckiwi31 5:63063a9fa51c 159
cnckiwi31 6:02507d7a6f51 160 // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
cnckiwi31 6:02507d7a6f51 161 // IMPLEMENTATION HARDWARE INTERFACE
cnckiwi31 6:02507d7a6f51 162 // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
cnckiwi31 6:02507d7a6f51 163
cnckiwi31 5:63063a9fa51c 164 /**
cnckiwi31 7:edb876c98565 165 * Update routine for the test rig
megrootens 0:3855d4588f76 166 * - Updates the angle buffer of the sensor array
cnckiwi31 7:edb876c98565 167 * Note that angles lag one update() behind, due to the way the SPI
megrootens 0:3855d4588f76 168 * protocol works.
megrootens 0:3855d4588f76 169 */
cnckiwi31 5:63063a9fa51c 170 void Bench::update()
megrootens 0:3855d4588f76 171 {
megrootens 0:3855d4588f76 172 as5048_.UpdateAngleBuffer();
megrootens 0:3855d4588f76 173 }
megrootens 0:3855d4588f76 174
cnckiwi31 6:02507d7a6f51 175 /**
cnckiwi31 7:edb876c98565 176 * Obtain the joint angle in degrees
cnckiwi31 6:02507d7a6f51 177 * These are the angles at the time of two Update() calls back
cnckiwi31 6:02507d7a6f51 178 * @param joint: the joint for which the angle is requested (a number starting
cnckiwi31 6:02507d7a6f51 179 * from 0 indicating the position in the sensor daisy chain)
cnckiwi31 6:02507d7a6f51 180 * @return: joint angle
cnckiwi31 6:02507d7a6f51 181 */
megrootens 0:3855d4588f76 182 float Bench::getDegrees(int i_joint)
megrootens 0:3855d4588f76 183 {
megrootens 0:3855d4588f76 184 float ang = as5048_.getAngleDegrees(i_joint);
megrootens 0:3855d4588f76 185 if (ang>kCutOffDegrees) {
megrootens 0:3855d4588f76 186 return ang-As5048::kDegPerRev;
megrootens 0:3855d4588f76 187 }
megrootens 0:3855d4588f76 188 return ang;
megrootens 0:3855d4588f76 189 }
megrootens 0:3855d4588f76 190
cnckiwi31 6:02507d7a6f51 191 /**
cnckiwi31 6:02507d7a6f51 192 * @param joint: the joint for which the angle is requested (a number starting
cnckiwi31 6:02507d7a6f51 193 * from 0 indicating the position in the sensor daisy chain)
cnckiwi31 15:a84d54e25775 194 * @return the name of the joint number
cnckiwi31 6:02507d7a6f51 195 */
cnckiwi31 6:02507d7a6f51 196 const char* Bench::getJointName(int i_joint)
cnckiwi31 6:02507d7a6f51 197 {
cnckiwi31 6:02507d7a6f51 198 return sensors::kJointNames[i_joint];
cnckiwi31 6:02507d7a6f51 199 }
cnckiwi31 6:02507d7a6f51 200
cnckiwi31 15:a84d54e25775 201 /**
cnckiwi31 15:a84d54e25775 202 * @return the encoder object reference
cnckiwi31 15:a84d54e25775 203 */
cnckiwi31 6:02507d7a6f51 204 As5048* Bench::get_as5048()
cnckiwi31 6:02507d7a6f51 205 {
cnckiwi31 6:02507d7a6f51 206 return &as5048_;
cnckiwi31 6:02507d7a6f51 207 }
cnckiwi31 6:02507d7a6f51 208
cnckiwi31 6:02507d7a6f51 209 /**
cnckiwi31 7:edb876c98565 210 * The force applied vertically at the hip joint in N
cnckiwi31 6:02507d7a6f51 211 * @return: force
cnckiwi31 6:02507d7a6f51 212 */
cnckiwi31 6:02507d7a6f51 213 float Bench::getForce()
cnckiwi31 6:02507d7a6f51 214 {
cnckiwi31 6:02507d7a6f51 215 if (Bench::use5kN) {
cnckiwi31 6:02507d7a6f51 216 return loadCell5kN.getForce();
cnckiwi31 6:02507d7a6f51 217 } else {
cnckiwi31 6:02507d7a6f51 218 return loadCell1kN.getForce();
cnckiwi31 6:02507d7a6f51 219 }
cnckiwi31 6:02507d7a6f51 220
cnckiwi31 6:02507d7a6f51 221 }
cnckiwi31 6:02507d7a6f51 222
cnckiwi31 15:a84d54e25775 223 /**
cnckiwi31 15:a84d54e25775 224 * zero the force reading (like a tare function)
cnckiwi31 15:a84d54e25775 225 */
cnckiwi31 6:02507d7a6f51 226 void Bench::nullForce()
cnckiwi31 6:02507d7a6f51 227 {
cnckiwi31 6:02507d7a6f51 228 if (use5kN) {
cnckiwi31 6:02507d7a6f51 229 return loadCell5kN.nullForce();
cnckiwi31 6:02507d7a6f51 230 } else {
cnckiwi31 6:02507d7a6f51 231 return loadCell1kN.nullForce();
cnckiwi31 6:02507d7a6f51 232 }
cnckiwi31 6:02507d7a6f51 233 }
cnckiwi31 6:02507d7a6f51 234
cnckiwi31 6:02507d7a6f51 235 /**
cnckiwi31 6:02507d7a6f51 236 * The pressure measured by pressure sensor 0 in bar
cnckiwi31 6:02507d7a6f51 237 * @return: pressure
cnckiwi31 6:02507d7a6f51 238 */
cnckiwi31 6:02507d7a6f51 239 float Bench::getPressure0()
cnckiwi31 6:02507d7a6f51 240 {
cnckiwi31 6:02507d7a6f51 241 return spte0.getPressure();
cnckiwi31 6:02507d7a6f51 242 }
cnckiwi31 6:02507d7a6f51 243
cnckiwi31 15:a84d54e25775 244 /**
cnckiwi31 15:a84d54e25775 245 * zero the pressure reading (like a tare function)
cnckiwi31 15:a84d54e25775 246 */
cnckiwi31 6:02507d7a6f51 247 void Bench::nullPressure0()
cnckiwi31 6:02507d7a6f51 248 {
cnckiwi31 6:02507d7a6f51 249 return spte0.nullPressure();
cnckiwi31 6:02507d7a6f51 250 }
cnckiwi31 6:02507d7a6f51 251
cnckiwi31 15:a84d54e25775 252 /**
cnckiwi31 15:a84d54e25775 253 * The pressure measured by pressure sensor 0 in bar
cnckiwi31 15:a84d54e25775 254 * @return: pressure
cnckiwi31 15:a84d54e25775 255 */
cnckiwi31 6:02507d7a6f51 256 float Bench::getPressure1()
cnckiwi31 6:02507d7a6f51 257 {
cnckiwi31 6:02507d7a6f51 258 return spte1.getPressure();
cnckiwi31 6:02507d7a6f51 259 }
cnckiwi31 6:02507d7a6f51 260
cnckiwi31 15:a84d54e25775 261 /**
cnckiwi31 15:a84d54e25775 262 * zero the pressure reading (like a tare function)
cnckiwi31 15:a84d54e25775 263 */
cnckiwi31 6:02507d7a6f51 264 void Bench::nullPressure1()
cnckiwi31 6:02507d7a6f51 265 {
cnckiwi31 6:02507d7a6f51 266 return spte1.nullPressure();
cnckiwi31 6:02507d7a6f51 267 }
cnckiwi31 6:02507d7a6f51 268
cnckiwi31 6:02507d7a6f51 269 /**
cnckiwi31 6:02507d7a6f51 270 * Control the valve (true turns the valve on to pressurise, false turns
cnckiwi31 6:02507d7a6f51 271 * the valve off to depressurise)
cnckiwi31 6:02507d7a6f51 272 * @param set: valve state
cnckiwi31 6:02507d7a6f51 273 */
cnckiwi31 6:02507d7a6f51 274 void Bench::setValve(bool set)
cnckiwi31 6:02507d7a6f51 275 {
cnckiwi31 6:02507d7a6f51 276 valveFesto.setValve(set);
cnckiwi31 6:02507d7a6f51 277 }
cnckiwi31 6:02507d7a6f51 278
cnckiwi31 6:02507d7a6f51 279 /**
cnckiwi31 7:edb876c98565 280 * The valve state (true is on/pressurising and false is off/depressurising).
cnckiwi31 6:02507d7a6f51 281 * @return: valve state
cnckiwi31 6:02507d7a6f51 282 */
cnckiwi31 6:02507d7a6f51 283 bool Bench::getValve() {
cnckiwi31 6:02507d7a6f51 284 return valveFesto.getValve();
cnckiwi31 6:02507d7a6f51 285 }
cnckiwi31 6:02507d7a6f51 286
surajgiri 11:fc82dd22a527 287 /**
surajgiri 11:fc82dd22a527 288 * The linear actuator state (true is retracting and false is extending)
surajgiri 11:fc82dd22a527 289 * @return: linear actuator state
surajgiri 11:fc82dd22a527 290 */
surajgiri 11:fc82dd22a527 291 bool Bench::getDir() {
surajgiri 11:fc82dd22a527 292 return LinAct.getDirection();
surajgiri 11:fc82dd22a527 293 }
surajgiri 11:fc82dd22a527 294
surajgiri 11:fc82dd22a527 295 /**
surajgiri 11:fc82dd22a527 296 * Control the linear actuator direction (true retracts and false extends)
surajgiri 11:fc82dd22a527 297 * @param set: direction
surajgiri 11:fc82dd22a527 298 */
surajgiri 11:fc82dd22a527 299 void Bench::setDir(bool dir)
surajgiri 11:fc82dd22a527 300 {
surajgiri 11:fc82dd22a527 301 LinAct.setDirection(dir);
surajgiri 11:fc82dd22a527 302 }
surajgiri 11:fc82dd22a527 303
surajgiri 11:fc82dd22a527 304 /**
surajgiri 11:fc82dd22a527 305 * Control the linear actuator speed (0-100% integer of pwm. generally need
surajgiri 11:fc82dd22a527 306 * above 50% to get it moving)
surajgiri 11:fc82dd22a527 307 * @param pwm: pwm duty cycle percentage
surajgiri 11:fc82dd22a527 308 */
surajgiri 11:fc82dd22a527 309 void Bench::setPWM(int pwm)
surajgiri 11:fc82dd22a527 310 {
surajgiri 11:fc82dd22a527 311 LinAct.setPWM(pwm);
surajgiri 11:fc82dd22a527 312 }
cnckiwi31 15:a84d54e25775 313
cnckiwi31 5:63063a9fa51c 314 // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
cnckiwi31 5:63063a9fa51c 315 // IMPLEMENTATION DATA LOGGING
cnckiwi31 5:63063a9fa51c 316 // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
cnckiwi31 5:63063a9fa51c 317
cnckiwi31 5:63063a9fa51c 318 /**
cnckiwi31 5:63063a9fa51c 319 * Check contents of SD card and count files in order
cnckiwi31 7:edb876c98565 320 * to ensure unique file name for logging data.
cnckiwi31 5:63063a9fa51c 321 */
cnckiwi31 5:63063a9fa51c 322 void Bench::InitSdCard()
cnckiwi31 5:63063a9fa51c 323 {
cnckiwi31 5:63063a9fa51c 324 pc.printf("\r\nINITIALISING SD CARD\r\n");
cnckiwi31 5:63063a9fa51c 325
cnckiwi31 5:63063a9fa51c 326 int num_files = 0;
cnckiwi31 5:63063a9fa51c 327
cnckiwi31 5:63063a9fa51c 328 // scan dir
cnckiwi31 5:63063a9fa51c 329 DIR *d;
cnckiwi31 5:63063a9fa51c 330 struct dirent *p;
cnckiwi31 5:63063a9fa51c 331
cnckiwi31 5:63063a9fa51c 332 d = opendir("/sd");
cnckiwi31 15:a84d54e25775 333 if (d != NULL) {//if there is an SD card
cnckiwi31 5:63063a9fa51c 334 sd_card_present = true;
cnckiwi31 15:a84d54e25775 335
cnckiwi31 15:a84d54e25775 336 //print existing files
cnckiwi31 5:63063a9fa51c 337 pc.printf("\t> Contents of SD Card:\r\n");
cnckiwi31 5:63063a9fa51c 338 while ((p = readdir(d)) != NULL) {
cnckiwi31 5:63063a9fa51c 339 if (p->d_name[0] != '.') {
cnckiwi31 5:63063a9fa51c 340 // skip files starting with '.'
cnckiwi31 5:63063a9fa51c 341 pc.printf("\t %s",p->d_name);
cnckiwi31 5:63063a9fa51c 342 ++num_files;
cnckiwi31 5:63063a9fa51c 343 }
cnckiwi31 5:63063a9fa51c 344 }
cnckiwi31 5:63063a9fa51c 345 pc.printf("\r\n\t> Counted %d visible files.\r\n",num_files);
cnckiwi31 5:63063a9fa51c 346
cnckiwi31 5:63063a9fa51c 347 closedir(d);
cnckiwi31 5:63063a9fa51c 348 } else {
cnckiwi31 5:63063a9fa51c 349 sd_card_present = false;
cnckiwi31 5:63063a9fa51c 350
cnckiwi31 5:63063a9fa51c 351 pc.printf("\t> No SD Card present. Data cannot be logged.\r\n");
cnckiwi31 5:63063a9fa51c 352 }
cnckiwi31 5:63063a9fa51c 353
cnckiwi31 5:63063a9fa51c 354 // id to be appended to logged data files
cnckiwi31 5:63063a9fa51c 355 fname_prepend = num_files;
cnckiwi31 5:63063a9fa51c 356 }
cnckiwi31 5:63063a9fa51c 357
cnckiwi31 5:63063a9fa51c 358 /**
cnckiwi31 15:a84d54e25775 359 * Start logging data (now manual, meaning user has to call a method to record a datapoint
cnckiwi31 15:a84d54e25775 360 * but if tick_logging.attach...(...) is uncommmented
cnckiwi31 15:a84d54e25775 361 * then recording becomes automatic)
cnckiwi31 6:02507d7a6f51 362 * param fname_append: a string describing the name appended to each logged file
cnckiwi31 7:edb876c98565 363 * (along with its unique loggging number).
cnckiwi31 5:63063a9fa51c 364 */
cnckiwi31 5:63063a9fa51c 365 void Bench::StartLogging(const char * fname_append)
cnckiwi31 5:63063a9fa51c 366 {
cnckiwi31 5:63063a9fa51c 367 pc.printf("\r\nDATA LOGGING");
cnckiwi31 5:63063a9fa51c 368 if (sd_card_present) {
cnckiwi31 5:63063a9fa51c 369 // create unique file name
cnckiwi31 5:63063a9fa51c 370 ++fname_prepend;
cnckiwi31 5:63063a9fa51c 371 char fname[50];
cnckiwi31 5:63063a9fa51c 372 sprintf(fname, "/sd/%d_%s.csv",fname_prepend,fname_append);
cnckiwi31 5:63063a9fa51c 373
cnckiwi31 5:63063a9fa51c 374 pc.printf("\t> Opening data log file '%s'...\r\n",fname);
cnckiwi31 5:63063a9fa51c 375
cnckiwi31 5:63063a9fa51c 376 // open file for writing and start logging after success
cnckiwi31 5:63063a9fa51c 377 fp_data = fopen(fname,"w");
cnckiwi31 5:63063a9fa51c 378 if (fp_data==NULL) {
cnckiwi31 15:a84d54e25775 379 pc.printf("\t> ERROR: failed to open log file (t=%d ms)\r\n",timer.read_ms());
cnckiwi31 5:63063a9fa51c 380 } else {
cnckiwi31 15:a84d54e25775 381 string fHeader = "time (s),theta_knee (deg),force (N),pressure (kPa)";//default data points recorded
cnckiwi31 5:63063a9fa51c 382
cnckiwi31 5:63063a9fa51c 383 for (int i=0; i<usedExtraCols; i++) {
cnckiwi31 5:63063a9fa51c 384 if (extraColNames[i] != "") {
cnckiwi31 5:63063a9fa51c 385 fHeader = fHeader + "," + extraColNames[i];
cnckiwi31 5:63063a9fa51c 386 }
cnckiwi31 5:63063a9fa51c 387 }
cnckiwi31 5:63063a9fa51c 388 fprintf(fp_data, "%s", fHeader.c_str());
cnckiwi31 15:a84d54e25775 389 //tick_logging.attach_us(this,&Bench::LogData,loggingUS); - uncomment to automatically log data
cnckiwi31 15:a84d54e25775 390 timer.start();//enable a time stamp for the logging file
cnckiwi31 15:a84d54e25775 391 startedLogging = true;
cnckiwi31 5:63063a9fa51c 392 is_logging = true;
cnckiwi31 5:63063a9fa51c 393 }
cnckiwi31 5:63063a9fa51c 394 } else {
cnckiwi31 5:63063a9fa51c 395 pc.printf("\t> No SD Card; no data will be logged.\r\n");
cnckiwi31 5:63063a9fa51c 396 startedLogging = false;
cnckiwi31 5:63063a9fa51c 397 }
cnckiwi31 5:63063a9fa51c 398 }
cnckiwi31 5:63063a9fa51c 399
surajgiri 11:fc82dd22a527 400 /**
surajgiri 11:fc82dd22a527 401 * Restart logging data (opens data logging file)
surajgiri 11:fc82dd22a527 402 * @param fname_append: a string describing the name appended to each logged file
surajgiri 11:fc82dd22a527 403 * (along with its unique loggging number).
surajgiri 11:fc82dd22a527 404 */
surajgiri 11:fc82dd22a527 405 void Bench::RestartLogging(const char * fname_append)
surajgiri 11:fc82dd22a527 406 {
surajgiri 11:fc82dd22a527 407 if (sd_card_present) {
surajgiri 11:fc82dd22a527 408
surajgiri 11:fc82dd22a527 409 // file name carries on from what we last had
surajgiri 11:fc82dd22a527 410 char fname[50];
surajgiri 11:fc82dd22a527 411 sprintf(fname, "/sd/%d_%s.csv",fname_prepend,fname_append);
surajgiri 11:fc82dd22a527 412
surajgiri 11:fc82dd22a527 413 pc.printf("\t> Opening data log file '%s'...\r\n",fname);
surajgiri 11:fc82dd22a527 414
surajgiri 11:fc82dd22a527 415 // open file for writing and start logging after success
surajgiri 11:fc82dd22a527 416 fp_data = fopen(fname,"w");
surajgiri 11:fc82dd22a527 417 if (fp_data==NULL) {
cnckiwi31 15:a84d54e25775 418 pc.printf("\t> ERROR: failed to open log file (t=%d ms)\r\n",timer.read_ms());
surajgiri 11:fc82dd22a527 419 } else {
surajgiri 11:fc82dd22a527 420 timer.start();
surajgiri 11:fc82dd22a527 421 startedLogging = true;
surajgiri 11:fc82dd22a527 422
surajgiri 11:fc82dd22a527 423 pc.printf("\t> Logging file opened.\r\n");
surajgiri 11:fc82dd22a527 424
surajgiri 11:fc82dd22a527 425 is_logging = true;
surajgiri 11:fc82dd22a527 426 }
surajgiri 11:fc82dd22a527 427 } else {
surajgiri 11:fc82dd22a527 428 pc.printf("\t> No SD Card; no data will be logged.\r\n");
surajgiri 11:fc82dd22a527 429 startedLogging = false;
surajgiri 11:fc82dd22a527 430 }
surajgiri 11:fc82dd22a527 431 }
cnckiwi31 5:63063a9fa51c 432
cnckiwi31 5:63063a9fa51c 433 /**
cnckiwi31 15:a84d54e25775 434 * Stop automatically logging data.
cnckiwi31 5:63063a9fa51c 435 */
cnckiwi31 5:63063a9fa51c 436 void Bench::StopLogging()
cnckiwi31 5:63063a9fa51c 437 {
cnckiwi31 5:63063a9fa51c 438 Bench::pc.printf("\r\nDATA LOGGING:");
cnckiwi31 5:63063a9fa51c 439 if (sd_card_present) {
cnckiwi31 15:a84d54e25775 440 // close data file, stop logging, reset time stamp
cnckiwi31 5:63063a9fa51c 441 fclose(fp_data);
cnckiwi31 5:63063a9fa51c 442 tick_logging.detach();
cnckiwi31 5:63063a9fa51c 443 timer.stop();
cnckiwi31 5:63063a9fa51c 444 timer.reset();
cnckiwi31 5:63063a9fa51c 445 Bench::pc.printf("\r> Stopped.");
cnckiwi31 5:63063a9fa51c 446 } else {
cnckiwi31 5:63063a9fa51c 447 Bench::pc.printf("\t> No data was logged.");
cnckiwi31 15:a84d54e25775 448 }
cnckiwi31 5:63063a9fa51c 449 is_logging = false;
cnckiwi31 5:63063a9fa51c 450 }
cnckiwi31 5:63063a9fa51c 451
cnckiwi31 5:63063a9fa51c 452 /**
cnckiwi31 5:63063a9fa51c 453 * Stop logging data and print the menu
cnckiwi31 5:63063a9fa51c 454 */
cnckiwi31 5:63063a9fa51c 455 void Bench::stopLogging()
cnckiwi31 5:63063a9fa51c 456 {
cnckiwi31 5:63063a9fa51c 457 if(is_logging) {
cnckiwi31 5:63063a9fa51c 458 is_logging = false;
cnckiwi31 5:63063a9fa51c 459 StopLogging();
cnckiwi31 5:63063a9fa51c 460 PrintMenu();
cnckiwi31 5:63063a9fa51c 461 }
cnckiwi31 5:63063a9fa51c 462 }
cnckiwi31 5:63063a9fa51c 463
cnckiwi31 5:63063a9fa51c 464 /**
cnckiwi31 15:a84d54e25775 465 * Log data (record all the data points, default and custom with a timestamp)
cnckiwi31 5:63063a9fa51c 466 */
cnckiwi31 5:63063a9fa51c 467 void Bench::LogData()
cnckiwi31 5:63063a9fa51c 468 {
cnckiwi31 5:63063a9fa51c 469 int currTime = timer.read_ms();
cnckiwi31 15:a84d54e25775 470 if(startedLogging) {//the first time this is called, save the timer offset
cnckiwi31 5:63063a9fa51c 471 firstReadMS = currTime;
cnckiwi31 5:63063a9fa51c 472 startedLogging = false;
cnckiwi31 5:63063a9fa51c 473 }
cnckiwi31 15:a84d54e25775 474 double currTimeS = ((double)currTime - firstReadMS)/1000;//time stamp
cnckiwi31 5:63063a9fa51c 475
cnckiwi31 5:63063a9fa51c 476 // time
cnckiwi31 5:63063a9fa51c 477 fprintf(fp_data,"\n%f",currTimeS);
cnckiwi31 5:63063a9fa51c 478
cnckiwi31 15:a84d54e25775 479 // bench default datapoints: joint angles and force sensor and pressure sensor values
cnckiwi31 5:63063a9fa51c 480 fprintf(fp_data,",%f,%f,%f",
cnckiwi31 5:63063a9fa51c 481 getDegrees(0),
cnckiwi31 5:63063a9fa51c 482 getForce(),
cnckiwi31 5:63063a9fa51c 483 getPressure0()*100
cnckiwi31 5:63063a9fa51c 484 );
cnckiwi31 15:a84d54e25775 485 //custom datapoints
cnckiwi31 5:63063a9fa51c 486 for (int i=0; i<usedExtraCols; i++) {
cnckiwi31 5:63063a9fa51c 487 fprintf(fp_data,",%f",extraColValues[i]);
cnckiwi31 5:63063a9fa51c 488 }
cnckiwi31 5:63063a9fa51c 489 }
cnckiwi31 5:63063a9fa51c 490
cnckiwi31 5:63063a9fa51c 491 // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
cnckiwi31 5:63063a9fa51c 492 // IMPLEMENTATION SERIAL COM
cnckiwi31 5:63063a9fa51c 493 // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
cnckiwi31 5:63063a9fa51c 494 /**
cnckiwi31 5:63063a9fa51c 495 * Prints the values of the key measurements in the setup
cnckiwi31 5:63063a9fa51c 496 */
cnckiwi31 5:63063a9fa51c 497 void Bench::PrintStatus()
cnckiwi31 5:63063a9fa51c 498 {
cnckiwi31 5:63063a9fa51c 499 if (is_printing) {
cnckiwi31 5:63063a9fa51c 500 if(sd_card_present)
cnckiwi31 5:63063a9fa51c 501 {
cnckiwi31 15:a84d54e25775 502 //file name and whether logging is happening
cnckiwi31 5:63063a9fa51c 503 Bench::pc.printf("\tFile number %15i\r\n", fname_prepend);
cnckiwi31 5:63063a9fa51c 504 Bench::pc.printf("\tLogging? %18s\r\n",is_logging?"Yes":"No");
cnckiwi31 5:63063a9fa51c 505 }
cnckiwi31 5:63063a9fa51c 506
cnckiwi31 15:a84d54e25775 507 //angles printed
cnckiwi31 5:63063a9fa51c 508 for (int i=0; i<sensors::kNumJoints; ++i)
cnckiwi31 5:63063a9fa51c 509 {
cnckiwi31 5:63063a9fa51c 510 string jointName = sensors::kJointNames[i];
cnckiwi31 5:63063a9fa51c 511 jointName = jointName + " (deg)";
cnckiwi31 5:63063a9fa51c 512 Bench::pc.printf("\t%15s %7.2f\r\n",jointName, getDegrees(i));
cnckiwi31 5:63063a9fa51c 513 }
cnckiwi31 15:a84d54e25775 514 Bench::pc.printf("\t%15s %7.2f\r\n","Force (N)", getForce()); //force reading
cnckiwi31 15:a84d54e25775 515 Bench::pc.printf("\t%15s %7.2f\r\n","Pressure0 (kPa)", getPressure0()*100); //pressure reading
cnckiwi31 5:63063a9fa51c 516 }
cnckiwi31 5:63063a9fa51c 517 }
cnckiwi31 5:63063a9fa51c 518
cnckiwi31 5:63063a9fa51c 519 /**
cnckiwi31 5:63063a9fa51c 520 * Prints the user choices to be made
cnckiwi31 5:63063a9fa51c 521 */
cnckiwi31 5:63063a9fa51c 522 void Bench::PrintMenu()
cnckiwi31 5:63063a9fa51c 523 {
cnckiwi31 5:63063a9fa51c 524 Bench::pc.printf("\r\nMENU\r\n");
surajgiri 11:fc82dd22a527 525 Bench::pc.printf("\t> Press s to toggle printing leg status\r\n");
surajgiri 11:fc82dd22a527 526 Bench::pc.printf("\t> Press l to toggle data logging\r\n");
cnckiwi31 5:63063a9fa51c 527
cnckiwi31 5:63063a9fa51c 528 Bench::pc.printf("\tSD card detected? %9s\r\n",sd_card_present?"Yes":"No");
cnckiwi31 5:63063a9fa51c 529 if(sd_card_present)
cnckiwi31 5:63063a9fa51c 530 {
cnckiwi31 5:63063a9fa51c 531 Bench::pc.printf("\tFile number %15i\r\n", fname_prepend);
cnckiwi31 5:63063a9fa51c 532 Bench::pc.printf("\tLogging? %18s\r\n",is_logging?"Yes":"No");
cnckiwi31 5:63063a9fa51c 533 }
cnckiwi31 5:63063a9fa51c 534 }
cnckiwi31 5:63063a9fa51c 535
cnckiwi31 5:63063a9fa51c 536 /**
cnckiwi31 5:63063a9fa51c 537 * Stops the Bench class from printing data if it is
cnckiwi31 5:63063a9fa51c 538 */
cnckiwi31 5:63063a9fa51c 539 void Bench::pausePrint()
cnckiwi31 5:63063a9fa51c 540 {
cnckiwi31 5:63063a9fa51c 541 was_printing = is_printing;
cnckiwi31 5:63063a9fa51c 542 is_printing = false;
cnckiwi31 5:63063a9fa51c 543 }
cnckiwi31 5:63063a9fa51c 544
cnckiwi31 5:63063a9fa51c 545 /**
cnckiwi31 5:63063a9fa51c 546 * Resumes printing in the Bench class
cnckiwi31 5:63063a9fa51c 547 */
cnckiwi31 5:63063a9fa51c 548 void Bench::resumePrint()
cnckiwi31 5:63063a9fa51c 549 {
cnckiwi31 5:63063a9fa51c 550 is_printing = was_printing;
cnckiwi31 5:63063a9fa51c 551 }
cnckiwi31 5:63063a9fa51c 552
cnckiwi31 5:63063a9fa51c 553 // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
cnckiwi31 5:63063a9fa51c 554 // IMPLEMENTATION USER IO
cnckiwi31 5:63063a9fa51c 555 // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
cnckiwi31 5:63063a9fa51c 556
cnckiwi31 5:63063a9fa51c 557 /**
cnckiwi31 15:a84d54e25775 558 * s toggles printing state of sensors and l toggles logging of data
surajgiri 11:fc82dd22a527 559 * use the keyboard on the pc
cnckiwi31 15:a84d54e25775 560 * do not press longer than a minKeyInt or it will toggle back
surajgiri 11:fc82dd22a527 561 */
surajgiri 11:fc82dd22a527 562 void Bench::ToggleState(MODSERIAL_IRQ_INFO *q)
surajgiri 11:fc82dd22a527 563 {
surajgiri 11:fc82dd22a527 564 //if we have data and it was not too soon since the last data
surajgiri 11:fc82dd22a527 565 if(Bench::pc.readable() && (((Bench::keyIntT.read() + keyIntOffset) >= timing::minKeyInt))) {
cnckiwi31 15:a84d54e25775 566 k = Bench::pc.getc();//read the keystroke
cnckiwi31 15:a84d54e25775 567 Bench::pc.rxBufferFlush();//delete all recorded keystrokes
cnckiwi31 15:a84d54e25775 568
surajgiri 11:fc82dd22a527 569 if(k == 's') {//toggle printing of data
surajgiri 11:fc82dd22a527 570 Bench::pc.printf("\tInput: %c\r\n",k);
surajgiri 11:fc82dd22a527 571 TogglePrinting();
surajgiri 11:fc82dd22a527 572 keyIntT.reset();
surajgiri 11:fc82dd22a527 573 keyIntT.start();
surajgiri 11:fc82dd22a527 574 keyIntOffset = 0;
cnckiwi31 15:a84d54e25775 575 } else if (k == 'l') {//toggle status of logging
surajgiri 11:fc82dd22a527 576 Bench::pc.printf("\tInput: %c\r\n",k);
surajgiri 11:fc82dd22a527 577 ToggleLogging();
surajgiri 11:fc82dd22a527 578 keyIntT.reset();
surajgiri 11:fc82dd22a527 579 keyIntT.start();
surajgiri 11:fc82dd22a527 580 keyIntOffset = 0;
surajgiri 11:fc82dd22a527 581 }
surajgiri 11:fc82dd22a527 582 k = '\0';
surajgiri 11:fc82dd22a527 583 }
surajgiri 11:fc82dd22a527 584 }
surajgiri 11:fc82dd22a527 585
surajgiri 11:fc82dd22a527 586 /**
surajgiri 11:fc82dd22a527 587 * toggles printing of data
cnckiwi31 5:63063a9fa51c 588 */
cnckiwi31 5:63063a9fa51c 589 void Bench::TogglePrinting()
cnckiwi31 5:63063a9fa51c 590 {
cnckiwi31 5:63063a9fa51c 591 if (not is_printing) {
cnckiwi31 5:63063a9fa51c 592 is_printing = true;
cnckiwi31 5:63063a9fa51c 593 } else {
cnckiwi31 5:63063a9fa51c 594 is_printing = false;
cnckiwi31 15:a84d54e25775 595 PrintMenu();//data no longer printed, print home menu
cnckiwi31 5:63063a9fa51c 596 }
cnckiwi31 5:63063a9fa51c 597 was_printing = is_printing;
cnckiwi31 5:63063a9fa51c 598 }
cnckiwi31 5:63063a9fa51c 599
cnckiwi31 5:63063a9fa51c 600 /*
surajgiri 11:fc82dd22a527 601 * toggles logging of data
cnckiwi31 5:63063a9fa51c 602 */
cnckiwi31 5:63063a9fa51c 603 void Bench::ToggleLogging()
cnckiwi31 5:63063a9fa51c 604 {
cnckiwi31 5:63063a9fa51c 605 if (not is_logging) {
surajgiri 11:fc82dd22a527 606 is_logging = true;
cnckiwi31 5:63063a9fa51c 607 } else {
cnckiwi31 5:63063a9fa51c 608 is_logging = false;
cnckiwi31 5:63063a9fa51c 609 }
cnckiwi31 5:63063a9fa51c 610 }
cnckiwi31 5:63063a9fa51c 611
cnckiwi31 8:bc467f5fe7c3 612 /**
cnckiwi31 5:63063a9fa51c 613 * Indicates if we are now data logging
cnckiwi31 9:60760807834f 614 * @return: true if logging
cnckiwi31 5:63063a9fa51c 615 */
cnckiwi31 5:63063a9fa51c 616 bool Bench::isLogging()
cnckiwi31 5:63063a9fa51c 617 {
cnckiwi31 5:63063a9fa51c 618 return is_logging;
cnckiwi31 5:63063a9fa51c 619 }
cnckiwi31 5:63063a9fa51c 620