amiro-os / components / Lidar.cpp @ 3f899f5d
History | View | Annotate | Download (9.527 KB)
| 1 | 58fe0e0b | Thomas Schöpping | #include <amiro/Lidar.h> |
|---|---|---|---|
| 2 | |||
| 3 | using namespace chibios_rt; |
||
| 4 | using namespace amiro; |
||
| 5 | |||
| 6 | uint8_t Lidar::scannedData[NUMBER_OF_CHARACTERS + 1] = {};
|
||
| 7 | |||
| 8 | Lidar::Lidar(const uint8_t boardId, Lidar::SETUP setup)
|
||
| 9 | : BaseStaticThread<256>(),
|
||
| 10 | boardId(boardId), |
||
| 11 | setup(setup) {
|
||
| 12 | |||
| 13 | } |
||
| 14 | |||
| 15 | Lidar:: |
||
| 16 | ~Lidar() {
|
||
| 17 | |||
| 18 | // Power down the LIDAR
|
||
| 19 | // TODO Is it correct anyway
|
||
| 20 | switch (boardId) {
|
||
| 21 | case(CAN::LIGHT_RING_ID):
|
||
| 22 | palWritePad(GPIOB, GPIOB_LASER_EN, PAL_LOW); |
||
| 23 | break;
|
||
| 24 | default:
|
||
| 25 | break;
|
||
| 26 | } |
||
| 27 | this->isReady = false; |
||
| 28 | }; |
||
| 29 | |||
| 30 | void Lidar::flushSD2InputQueue() {
|
||
| 31 | chSysLock(); |
||
| 32 | chIQResetI(&SD2.iqueue); |
||
| 33 | chSysUnlock(); |
||
| 34 | } |
||
| 35 | |||
| 36 | msg_t Lidar::main(void) {
|
||
| 37 | |||
| 38 | |||
| 39 | switch (this->boardId) { |
||
| 40 | case(CAN::LIGHT_RING_ID): {
|
||
| 41 | |||
| 42 | // Power up the LIDAR
|
||
| 43 | palWritePad(GPIOB, GPIOB_LASER_EN, PAL_HIGH); |
||
| 44 | BaseThread::sleep(MS2ST(5000));
|
||
| 45 | |||
| 46 | // Setup the driver and lidar, if we want to communicate with it
|
||
| 47 | if (setup != SETUP::POWER_ONLY) {
|
||
| 48 | // Flush the queue because there is a "0" in it
|
||
| 49 | flushSD2InputQueue(); |
||
| 50 | |||
| 51 | // Configure LIDAR serial interface speed
|
||
| 52 | // chprintf((BaseSequentialStream*) &SD1, "Speed switch to " STR(SD_SPEED) "\n");
|
||
| 53 | chprintf((BaseSequentialStream*) &SD2, "SS" STR(SD_SPEED_PREFIX) STR(SD_SPEED) LF);
|
||
| 54 | |||
| 55 | // Check if the switch went well, otherwise terminate the thread
|
||
| 56 | if (checkDataString("SS" STR(SD_SPEED_PREFIX) STR(SD_SPEED) "\n00P\n\n")) { |
||
| 57 | chprintf((BaseSequentialStream*) &SD1, "Lidar speed switch OK\n");
|
||
| 58 | // Configure serial interface of STM32
|
||
| 59 | sdStop(&SD2); |
||
| 60 | SerialConfig sdLidarconf = { SD_SPEED, 0, 0, 0 };
|
||
| 61 | sdStart(&SD2, &sdLidarconf); |
||
| 62 | } else {
|
||
| 63 | chprintf((BaseSequentialStream*) &SD1, "Lidar speed switch NOT OK: Terminating Lidar \n");
|
||
| 64 | palWritePad(GPIOB, GPIOB_LASER_EN, PAL_LOW); |
||
| 65 | return -1; |
||
| 66 | } |
||
| 67 | } |
||
| 68 | break;
|
||
| 69 | } |
||
| 70 | default:
|
||
| 71 | break;
|
||
| 72 | } |
||
| 73 | |||
| 74 | evtInit(&this->evtimer, UPDATE_LIDAR_PERIOD_MSEC);
|
||
| 75 | |||
| 76 | EvtSource *eventTimerEvtSource = reinterpret_cast<EvtSource *>(&this->evtimer.et_es); |
||
| 77 | |||
| 78 | EvtListener eventTimerEvtListener; |
||
| 79 | |||
| 80 | // TODO Does PERIODIC_TIMER_ID has something to do with ControllerAreNetwork.h ?
|
||
| 81 | eventTimerEvtSource->registerOne(&eventTimerEvtListener, CAN::PERIODIC_TIMER_ID); |
||
| 82 | |||
| 83 | evtStart(&this->evtimer);
|
||
| 84 | |||
| 85 | this->setName("Lidar"); |
||
| 86 | |||
| 87 | while (!this->shouldTerminate()) { |
||
| 88 | |||
| 89 | eventmask_t eventMask = this->waitOneEvent(ALL_EVENTS);
|
||
| 90 | switch (eventMask) {
|
||
| 91 | case EVENT_MASK(CAN::PERIODIC_TIMER_ID):
|
||
| 92 | // printDetails();
|
||
| 93 | if (setup != SETUP::POWER_ONLY) {
|
||
| 94 | updateSensorVal(); |
||
| 95 | } |
||
| 96 | break;
|
||
| 97 | } |
||
| 98 | } |
||
| 99 | |||
| 100 | evtStop(&this->evtimer);
|
||
| 101 | eventTimerEvtSource->unregister(&eventTimerEvtListener); |
||
| 102 | |||
| 103 | return RDY_OK;
|
||
| 104 | } |
||
| 105 | |||
| 106 | bool_t Lidar::getScan(uint16_t (&scannedData)[NUMBER_OF_STEPS]) {
|
||
| 107 | if (this->isReady && !this->isFail) { |
||
| 108 | chSysLock(); |
||
| 109 | memcpy(&scannedData, &(Lidar::scannedData[0]), NUMBER_OF_CHARACTERS);
|
||
| 110 | this->isReady = false; |
||
| 111 | chSysUnlock(); |
||
| 112 | return true; |
||
| 113 | } else {
|
||
| 114 | return false; |
||
| 115 | } |
||
| 116 | } |
||
| 117 | |||
| 118 | uint16_t Lidar::getNumberOfValues() {
|
||
| 119 | return NUMBER_OF_STEPS;
|
||
| 120 | } |
||
| 121 | |||
| 122 | uint16_t Lidar::twoCharacterEncoding(uint8_t &char1, uint8_t &char2) {
|
||
| 123 | return uint16_t((((char1 - 0x30) & 0b00111111) << 6) | ((char2 - 0x30) & 0b00111111)); |
||
| 124 | } |
||
| 125 | |||
| 126 | bool_t Lidar::getData(uint8_t &data, uint32_t timeoutMs) {
|
||
| 127 | |||
| 128 | // data = sdGet(&SD2);
|
||
| 129 | msg_t dataTmp = chIQGetTimeout(&SD2.iqueue, MS2ST(timeoutMs)); |
||
| 130 | if (dataTmp == Q_TIMEOUT || dataTmp == Q_RESET) {
|
||
| 131 | return false; |
||
| 132 | } else {
|
||
| 133 | data = uint8_t(dataTmp); |
||
| 134 | ++this->dataCounter;
|
||
| 135 | return true; |
||
| 136 | } |
||
| 137 | } |
||
| 138 | |||
| 139 | msg_t Lidar::updateSensorVal() {
|
||
| 140 | |||
| 141 | chSysLock(); |
||
| 142 | // Set this flag so that the everyone knows, that scannedData will be filed right now
|
||
| 143 | this->isReady = false; |
||
| 144 | // Reset the FAIL flag
|
||
| 145 | this->isFail = false; |
||
| 146 | chSysUnlock(); |
||
| 147 | |||
| 148 | while (!this->isReady) { |
||
| 149 | switch(step) {
|
||
| 150 | case SEND_SCAN_CMD:
|
||
| 151 | flushSD2InputQueue(); |
||
| 152 | // Read (725-(44-1))=682 values with two-character encoding what makes 1364 datapoints
|
||
| 153 | // 1456 in total:
|
||
| 154 | // 16 (Cmd-Echo) + ? (Remaining Scans) + 1 (LF) + ? (String Characters) + 1 (LF) + 2 (Status) + 1 (Sum) + 1 (LF) + ? (Timestamp) + 1 (LF) + 1364 (Data for a certain setup) + 1 (Sum) + 1 (LF) + 1 (LF)
|
||
| 155 | chprintf((BaseSequentialStream*) &SD2,DATA_ACQ_CODE STR(STARTING_STEP_PREFIX) STR(STARTING_STEP) STR(END_STEP_PREFIX) STR(END_STEP) STR(CLUSTER_COUNT) STR(SCAN_INTERVALL) STR(NUMBER_OF_INTERVALL) LF); |
||
| 156 | step = DATA_VALID_CHECK; |
||
| 157 | this->dataCounter = 0; |
||
| 158 | break;
|
||
| 159 | case DATA_VALID_CHECK:
|
||
| 160 | if(getData(this->newInput, 200)) { |
||
| 161 | // TODO check for last data, if scan has a few errors
|
||
| 162 | // HACK The timeout fix this issue at least, because after a while there
|
||
| 163 | // wont be any transmitts
|
||
| 164 | if (this->newInput == validScanTag[this->checkStatusIdx]) { |
||
| 165 | if (++this->checkStatusIdx == 5) { |
||
| 166 | // scan_data is without error: Found the sting "\n99b\n"
|
||
| 167 | step = DATA_START_CHECK; |
||
| 168 | this->checkStatusIdx = 0; |
||
| 169 | } |
||
| 170 | } else {
|
||
| 171 | this->checkStatusIdx = 0; |
||
| 172 | } |
||
| 173 | } else {
|
||
| 174 | step = FAIL; |
||
| 175 | } |
||
| 176 | break;
|
||
| 177 | case DATA_START_CHECK:
|
||
| 178 | // Check for the next linefeed to start the record
|
||
| 179 | if(getData(this->newInput, 200)) { |
||
| 180 | if (this->newInput == 10) { |
||
| 181 | step = DATA_RECORD; |
||
| 182 | this->dataIdx = 0; |
||
| 183 | } |
||
| 184 | } else {
|
||
| 185 | step = FAIL; |
||
| 186 | } |
||
| 187 | break;
|
||
| 188 | case DATA_RECORD:
|
||
| 189 | if(getData(this->newInput, 200)) { |
||
| 190 | if (this->lastInput == 10 && this->newInput == 10) { |
||
| 191 | // end of data
|
||
| 192 | this->lastInput = 0x0; // Just to delete this->lastInput value |
||
| 193 | step = DATA_DECODE; |
||
| 194 | } else if (this->newInput != 10) { |
||
| 195 | Lidar::scannedData[this->dataIdx++] = this->newInput; |
||
| 196 | this->lastInput = this->newInput; |
||
| 197 | } else { // this->lastInput != 10 && this->newInput == 10 |
||
| 198 | // This is the case, where we know that the last character was the checksum.
|
||
| 199 | // Therefore, we need to decrement the counter
|
||
| 200 | --this->dataIdx;
|
||
| 201 | this->lastInput = this->newInput; |
||
| 202 | } |
||
| 203 | //chprintf((BaseSequentialStream*) &SD1, "%d ", this->newInput);
|
||
| 204 | } else {
|
||
| 205 | step = FAIL; |
||
| 206 | } |
||
| 207 | break;
|
||
| 208 | case DATA_DECODE:
|
||
| 209 | // Decode the recorded data
|
||
| 210 | for (uint16_t idx=0; idx < NUMBER_OF_CHARACTERS; idx += 2) { |
||
| 211 | //TODO Check if +1 is right
|
||
| 212 | *((uint16_t*) &(Lidar::scannedData[idx])) = twoCharacterEncoding(Lidar::scannedData[idx],Lidar::scannedData[idx+1]);
|
||
| 213 | } |
||
| 214 | // To print out the data in this thread, choose "step = DATA_SHOW"
|
||
| 215 | step = FINISH; |
||
| 216 | break;
|
||
| 217 | case DATA_SHOW:
|
||
| 218 | // Show the decoded data
|
||
| 219 | chprintf((BaseSequentialStream*) &SD1, "\n%d", this->dataCounter); |
||
| 220 | for (uint32_t idx=0; idx < this->dataIdx; idx+=2) { |
||
| 221 | chprintf((BaseSequentialStream*) &SD1, "\n%d", *((uint16_t*) &(Lidar::scannedData[idx])));
|
||
| 222 | } |
||
| 223 | step = FINISH; |
||
| 224 | break;
|
||
| 225 | case FAIL:
|
||
| 226 | // Set the FAIL flag
|
||
| 227 | chSysLock(); |
||
| 228 | // Set this flag so that the everyone knows, that scannedData holds wrong information
|
||
| 229 | this->isFail = true; |
||
| 230 | chSysUnlock(); |
||
| 231 | break;
|
||
| 232 | case FINISH:
|
||
| 233 | // Clean up
|
||
| 234 | this->step = SEND_SCAN_CMD;
|
||
| 235 | chSysLock(); |
||
| 236 | // Set this flag so that the everyone knows, that scannedData holds the actual data
|
||
| 237 | this->isReady = true; |
||
| 238 | chSysUnlock(); |
||
| 239 | break;
|
||
| 240 | default:
|
||
| 241 | break;
|
||
| 242 | } |
||
| 243 | } |
||
| 244 | |||
| 245 | return RDY_OK;
|
||
| 246 | } |
||
| 247 | |||
| 248 | void Lidar::printData() {
|
||
| 249 | uint8_t lastInput = 0xFF, newInput = 0xFF; |
||
| 250 | while (true) { |
||
| 251 | if(getData(newInput, 200)) { |
||
| 252 | if (lastInput == 10 && newInput == 10) { |
||
| 253 | return;
|
||
| 254 | } else {
|
||
| 255 | chprintf((BaseSequentialStream*) &SD1, "%c", newInput);
|
||
| 256 | } |
||
| 257 | lastInput = newInput; |
||
| 258 | } else {
|
||
| 259 | chprintf((BaseSequentialStream*) &SD1, "TIMEOUT\n", newInput);
|
||
| 260 | return;
|
||
| 261 | } |
||
| 262 | } |
||
| 263 | } |
||
| 264 | |||
| 265 | bool_t Lidar::checkDataString(const char compareString[]) { |
||
| 266 | uint8_t lastInput = 0xFF, newInput = 0xFF, recIdx = 0; |
||
| 267 | bool_t dataOk = true, processFlag = true; |
||
| 268 | while (processFlag) {
|
||
| 269 | if (getData(newInput, 200)) { |
||
| 270 | // End of data received, quit processing
|
||
| 271 | if (lastInput == 10 && newInput == 10) { |
||
| 272 | processFlag = false;
|
||
| 273 | } |
||
| 274 | // Compare data if the characters before have been ok
|
||
| 275 | // Otherwise do not compare anymore, because of possible
|
||
| 276 | // segmentation fault
|
||
| 277 | if (dataOk) {
|
||
| 278 | if (newInput != compareString[recIdx++]) {
|
||
| 279 | dataOk = false;
|
||
| 280 | } |
||
| 281 | } |
||
| 282 | // Save the received character
|
||
| 283 | lastInput = newInput; |
||
| 284 | } else {
|
||
| 285 | processFlag = false;
|
||
| 286 | dataOk = false;
|
||
| 287 | } |
||
| 288 | } |
||
| 289 | return dataOk;
|
||
| 290 | } |
||
| 291 | |||
| 292 | void Lidar::printDetails() {
|
||
| 293 | |||
| 294 | chprintf((BaseSequentialStream*) &SD1, "Print sensor details:\n");
|
||
| 295 | |||
| 296 | // Tell the sensor to transmit its details
|
||
| 297 | chprintf((BaseSequentialStream*) &SD2, "VV\n");
|
||
| 298 | |||
| 299 | // Print the transmitted data
|
||
| 300 | printData(); |
||
| 301 | } |
||
| 302 | |||
| 303 | void Lidar::printSpecification() {
|
||
| 304 | |||
| 305 | chprintf((BaseSequentialStream*) &SD1, "Print sensor specification:\n");
|
||
| 306 | |||
| 307 | // Tell the sensor to transmit its specifications
|
||
| 308 | chprintf((BaseSequentialStream*) &SD2, "PP\n");
|
||
| 309 | |||
| 310 | // Print the transmitted data
|
||
| 311 | printData(); |
||
| 312 | } |
||
| 313 | |||
| 314 | void Lidar::printInformation() {
|
||
| 315 | chprintf((BaseSequentialStream*) &SD1, "Print sensor information:\n");
|
||
| 316 | |||
| 317 | // Tell the sensor to transmit its information
|
||
| 318 | chprintf((BaseSequentialStream*) &SD2, "II\n");
|
||
| 319 | |||
| 320 | // Print the transmitted data
|
||
| 321 | printData(); |
||
| 322 | } |
||
| 323 | |||
| 324 | bool_t Lidar::getIsReady() {
|
||
| 325 | return this->isReady; |
||
| 326 | } |