UNPKG

yoctolib-esm

Version:

Yoctopuce library for TypeScript/JavaScript, as an ECMAScript 2015 module

1,064 lines 43.2 kB
/********************************************************************* * * $Id: svn_id $ * * Implements the high-level API for RefFrame functions * * - - - - - - - - - License information: - - - - - - - - - * * Copyright (C) 2011 and beyond by Yoctopuce Sarl, Switzerland. * * Yoctopuce Sarl (hereafter Licensor) grants to you a perpetual * non-exclusive license to use, modify, copy and integrate this * file into your software for the sole purpose of interfacing * with Yoctopuce products. * * You may reproduce and distribute copies of this file in * source or object form, as long as the sole purpose of this * code is to interface with Yoctopuce products. You must retain * this notice in the distributed source file. * * You should refer to Yoctopuce General Terms and Conditions * for additional information regarding your rights and * obligations. * * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED 'AS IS' WITHOUT * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING * WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO * EVENT SHALL LICENSOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, * COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR * SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT * LIMITED TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR * CONTRIBUTION, OR OTHER SIMILAR COSTS, WHETHER ASSERTED ON THE * BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF * WARRANTY, OR OTHERWISE. * *********************************************************************/ import { YAPI, YAPIContext, YFunction } from './yocto_api.js'; //--- (YRefFrame class start) /** * YRefFrame Class: 3D reference frame configuration interface, available for instance in the * Yocto-3D-V2 or the Yocto-Inclinometer * * The YRefFrame class is used to set up the base orientation of the Yoctopuce inertial * sensors. Thanks to this, orientation functions relative to the earth surface plane * can use the proper reference frame. For some devices, the class also implements a * tridimensional sensor calibration process, which can compensate for local variations * of standard gravity and improve the precision of the tilt sensors. */ //--- (end of YRefFrame class start) export class YRefFrame extends YFunction { //--- (end of YRefFrame attributes declaration) constructor(yapi, func) { //--- (YRefFrame constructor) super(yapi, func); this._mountPos = YRefFrame.MOUNTPOS_INVALID; this._bearing = YRefFrame.BEARING_INVALID; this._calibrationParam = YRefFrame.CALIBRATIONPARAM_INVALID; this._fusionMode = YRefFrame.FUSIONMODE_INVALID; this._valueCallbackRefFrame = null; this._calibV2 = false; this._calibStage = 0; this._calibStageHint = ''; this._calibStageProgress = 0; this._calibProgress = 0; this._calibLogMsg = ''; this._calibSavedParams = ''; this._calibCount = 0; this._calibInternalPos = 0; this._calibPrevTick = 0; this._calibOrient = []; this._calibDataAccX = []; this._calibDataAccY = []; this._calibDataAccZ = []; this._calibDataAcc = []; this._calibAccXOfs = 0; this._calibAccYOfs = 0; this._calibAccZOfs = 0; this._calibAccXScale = 0; this._calibAccYScale = 0; this._calibAccZScale = 0; // API symbols as object properties this.MOUNTPOS_INVALID = YAPI.INVALID_UINT; this.BEARING_INVALID = YAPI.INVALID_DOUBLE; this.CALIBRATIONPARAM_INVALID = YAPI.INVALID_STRING; this.FUSIONMODE_NDOF = 0; this.FUSIONMODE_NDOF_FMC_OFF = 1; this.FUSIONMODE_M4G = 2; this.FUSIONMODE_COMPASS = 3; this.FUSIONMODE_IMU = 4; this.FUSIONMODE_INCLIN_90DEG_1G8 = 5; this.FUSIONMODE_INCLIN_90DEG_3G6 = 6; this.FUSIONMODE_INCLIN_10DEG = 7; this.FUSIONMODE_INVALID = -1; this.MOUNTPOSITION_BOTTOM = 0; this.MOUNTPOSITION_TOP = 1; this.MOUNTPOSITION_FRONT = 2; this.MOUNTPOSITION_REAR = 3; this.MOUNTPOSITION_RIGHT = 4; this.MOUNTPOSITION_LEFT = 5; this.MOUNTPOSITION_INVALID = 6; this.MOUNTORIENTATION_TWELVE = 0; this.MOUNTORIENTATION_THREE = 1; this.MOUNTORIENTATION_SIX = 2; this.MOUNTORIENTATION_NINE = 3; this.MOUNTORIENTATION_INVALID = 4; this._className = 'RefFrame'; //--- (end of YRefFrame constructor) } //--- (YRefFrame implementation) imm_parseAttr(name, val) { switch (name) { case 'mountPos': this._mountPos = val; return 1; case 'bearing': this._bearing = Math.round(val / 65.536) / 1000.0; return 1; case 'calibrationParam': this._calibrationParam = val; return 1; case 'fusionMode': this._fusionMode = val; return 1; } return super.imm_parseAttr(name, val); } async get_mountPos() { let res; if (this._cacheExpiration <= this._yapi.GetTickCount()) { if (await this.load(this._yapi.defaultCacheValidity) != this._yapi.SUCCESS) { return YRefFrame.MOUNTPOS_INVALID; } } res = this._mountPos; return res; } async set_mountPos(newval) { let rest_val; rest_val = String(newval); return await this._setAttr('mountPos', rest_val); } /** * Changes the reference bearing used by the compass. The relative bearing * indicated by the compass is the difference between the measured magnetic * heading and the reference bearing indicated here. * * For instance, if you set up as reference bearing the value of the earth * magnetic declination, the compass will provide the orientation relative * to the geographic North. * * Similarly, when the sensor is not mounted along the standard directions * because it has an additional yaw angle, you can set this angle in the reference * bearing so that the compass provides the expected natural direction. * * Remember to call the saveToFlash() * method of the module if the modification must be kept. * * @param newval : a floating point number corresponding to the reference bearing used by the compass * * @return YAPI.SUCCESS if the call succeeds. * * On failure, throws an exception or returns a negative error code. */ async set_bearing(newval) { let rest_val; rest_val = String(Math.round(newval * 65536.0)); return await this._setAttr('bearing', rest_val); } /** * Returns the reference bearing used by the compass. The relative bearing * indicated by the compass is the difference between the measured magnetic * heading and the reference bearing indicated here. * * @return a floating point number corresponding to the reference bearing used by the compass * * On failure, throws an exception or returns YRefFrame.BEARING_INVALID. */ async get_bearing() { let res; if (this._cacheExpiration <= this._yapi.GetTickCount()) { if (await this.load(this._yapi.defaultCacheValidity) != this._yapi.SUCCESS) { return YRefFrame.BEARING_INVALID; } } res = this._bearing; return res; } async get_calibrationParam() { let res; if (this._cacheExpiration <= this._yapi.GetTickCount()) { if (await this.load(this._yapi.defaultCacheValidity) != this._yapi.SUCCESS) { return YRefFrame.CALIBRATIONPARAM_INVALID; } } res = this._calibrationParam; return res; } async set_calibrationParam(newval) { let rest_val; rest_val = String(newval); return await this._setAttr('calibrationParam', rest_val); } /** * Returns the sensor fusion mode. Note that available sensor fusion modes depend on the sensor type. * * @return a value among YRefFrame.FUSIONMODE_NDOF, YRefFrame.FUSIONMODE_NDOF_FMC_OFF, * YRefFrame.FUSIONMODE_M4G, YRefFrame.FUSIONMODE_COMPASS, YRefFrame.FUSIONMODE_IMU, * YRefFrame.FUSIONMODE_INCLIN_90DEG_1G8, YRefFrame.FUSIONMODE_INCLIN_90DEG_3G6 and * YRefFrame.FUSIONMODE_INCLIN_10DEG corresponding to the sensor fusion mode * * On failure, throws an exception or returns YRefFrame.FUSIONMODE_INVALID. */ async get_fusionMode() { let res; if (this._cacheExpiration <= this._yapi.GetTickCount()) { if (await this.load(this._yapi.defaultCacheValidity) != this._yapi.SUCCESS) { return YRefFrame.FUSIONMODE_INVALID; } } res = this._fusionMode; return res; } /** * Change the sensor fusion mode. Note that available sensor fusion modes depend on the sensor type. * Remember to call the matching module saveToFlash() method to save the setting permanently. * * @param newval : a value among YRefFrame.FUSIONMODE_NDOF, YRefFrame.FUSIONMODE_NDOF_FMC_OFF, * YRefFrame.FUSIONMODE_M4G, YRefFrame.FUSIONMODE_COMPASS, YRefFrame.FUSIONMODE_IMU, * YRefFrame.FUSIONMODE_INCLIN_90DEG_1G8, YRefFrame.FUSIONMODE_INCLIN_90DEG_3G6 and * YRefFrame.FUSIONMODE_INCLIN_10DEG * * @return YAPI.SUCCESS if the call succeeds. * * On failure, throws an exception or returns a negative error code. */ async set_fusionMode(newval) { let rest_val; rest_val = String(newval); return await this._setAttr('fusionMode', rest_val); } /** * Retrieves a reference frame for a given identifier. * The identifier can be specified using several formats: * * - FunctionLogicalName * - ModuleSerialNumber.FunctionIdentifier * - ModuleSerialNumber.FunctionLogicalName * - ModuleLogicalName.FunctionIdentifier * - ModuleLogicalName.FunctionLogicalName * * * This function does not require that the reference frame is online at the time * it is invoked. The returned object is nevertheless valid. * Use the method YRefFrame.isOnline() to test if the reference frame is * indeed online at a given time. In case of ambiguity when looking for * a reference frame by logical name, no error is notified: the first instance * found is returned. The search is performed first by hardware name, * then by logical name. * * If a call to this object's is_online() method returns FALSE although * you are certain that the matching device is plugged, make sure that you did * call registerHub() at application initialization time. * * @param func : a string that uniquely characterizes the reference frame, for instance * Y3DMK002.refFrame. * * @return a YRefFrame object allowing you to drive the reference frame. */ static FindRefFrame(func) { let obj; obj = YFunction._FindFromCache('RefFrame', func); if (obj == null) { obj = new YRefFrame(YAPI, func); YFunction._AddToCache('RefFrame', func, obj); } return obj; } /** * Retrieves a reference frame for a given identifier in a YAPI context. * The identifier can be specified using several formats: * * - FunctionLogicalName * - ModuleSerialNumber.FunctionIdentifier * - ModuleSerialNumber.FunctionLogicalName * - ModuleLogicalName.FunctionIdentifier * - ModuleLogicalName.FunctionLogicalName * * * This function does not require that the reference frame is online at the time * it is invoked. The returned object is nevertheless valid. * Use the method YRefFrame.isOnline() to test if the reference frame is * indeed online at a given time. In case of ambiguity when looking for * a reference frame by logical name, no error is notified: the first instance * found is returned. The search is performed first by hardware name, * then by logical name. * * @param yctx : a YAPI context * @param func : a string that uniquely characterizes the reference frame, for instance * Y3DMK002.refFrame. * * @return a YRefFrame object allowing you to drive the reference frame. */ static FindRefFrameInContext(yctx, func) { let obj; obj = YFunction._FindFromCacheInContext(yctx, 'RefFrame', func); if (obj == null) { obj = new YRefFrame(yctx, func); YFunction._AddToCache('RefFrame', func, obj); } return obj; } /** * Registers the callback function that is invoked on every change of advertised value. * The callback is then invoked only during the execution of ySleep or yHandleEvents. * This provides control over the time when the callback is triggered. For good responsiveness, * remember to call one of these two functions periodically. The callback is called once juste after beeing * registered, passing the current advertised value of the function, provided that it is not an empty string. * To unregister a callback, pass a null pointer as argument. * * @param callback : the callback function to call, or a null pointer. The callback function should take two * arguments: the function object of which the value has changed, and the character string describing * the new advertised value. * @noreturn */ async registerValueCallback(callback) { let val; if (callback != null) { await YFunction._UpdateValueCallbackList(this, true); } else { await YFunction._UpdateValueCallbackList(this, false); } this._valueCallbackRefFrame = callback; // Immediately invoke value callback with current value if (callback != null && await this.isOnline()) { val = this._advertisedValue; if (!(val == '')) { await this._invokeValueCallback(val); } } return 0; } async _invokeValueCallback(value) { if (this._valueCallbackRefFrame != null) { try { await this._valueCallbackRefFrame(this, value); } catch (e) { this._yapi.imm_log('Exception in valueCallback:', e); } } else { await super._invokeValueCallback(value); } return 0; } /** * Returns the installation position of the device, as configured * in order to define the reference frame for the compass and the * pitch/roll tilt sensors. * * @return a value among the YRefFrame.MOUNTPOSITION enumeration * (YRefFrame.MOUNTPOSITION_BOTTOM, YRefFrame.MOUNTPOSITION_TOP, * YRefFrame.MOUNTPOSITION_FRONT, YRefFrame.MOUNTPOSITION_RIGHT, * YRefFrame.MOUNTPOSITION_REAR, YRefFrame.MOUNTPOSITION_LEFT), * corresponding to the installation in a box, on one of the six faces. * * On failure, throws an exception or returns YRefFrame.MOUNTPOSITION_INVALID. */ async get_mountPosition() { let position; position = await this.get_mountPos(); if (position < 0) { return YRefFrame.MOUNTPOSITION_INVALID; } return (position >> 2); } /** * Returns the installation orientation of the device, as configured * in order to define the reference frame for the compass and the * pitch/roll tilt sensors. * * @return a value among the enumeration YRefFrame.MOUNTORIENTATION * (YRefFrame.MOUNTORIENTATION_TWELVE, YRefFrame.MOUNTORIENTATION_THREE, * YRefFrame.MOUNTORIENTATION_SIX, YRefFrame.MOUNTORIENTATION_NINE) * corresponding to the orientation of the "X" arrow on the device, * as on a clock dial seen from an observer in the center of the box. * On the bottom face, the 12H orientation points to the front, while * on the top face, the 12H orientation points to the rear. * * On failure, throws an exception or returns YRefFrame.MOUNTORIENTATION_INVALID. */ async get_mountOrientation() { let position; position = await this.get_mountPos(); if (position < 0) { return YRefFrame.MOUNTORIENTATION_INVALID; } return (position & 3); } /** * Changes the compass and tilt sensor frame of reference. The magnetic compass * and the tilt sensors (pitch and roll) naturally work in the plane * parallel to the earth surface. In case the device is not installed upright * and horizontally, you must select its reference orientation (parallel to * the earth surface) so that the measures are made relative to this position. * * @param position : a value among the YRefFrame.MOUNTPOSITION enumeration * (YRefFrame.MOUNTPOSITION_BOTTOM, YRefFrame.MOUNTPOSITION_TOP, * YRefFrame.MOUNTPOSITION_FRONT, YRefFrame.MOUNTPOSITION_RIGHT, * YRefFrame.MOUNTPOSITION_REAR, YRefFrame.MOUNTPOSITION_LEFT), * corresponding to the installation in a box, on one of the six faces. * @param orientation : a value among the enumeration YRefFrame.MOUNTORIENTATION * (YRefFrame.MOUNTORIENTATION_TWELVE, YRefFrame.MOUNTORIENTATION_THREE, * YRefFrame.MOUNTORIENTATION_SIX, YRefFrame.MOUNTORIENTATION_NINE) * corresponding to the orientation of the "X" arrow on the device, * as on a clock dial seen from an observer in the center of the box. * On the bottom face, the 12H orientation points to the front, while * on the top face, the 12H orientation points to the rear. * * Remember to call the saveToFlash() * method of the module if the modification must be kept. * * On failure, throws an exception or returns a negative error code. */ async set_mountPosition(position, orientation) { let mixedPos; mixedPos = (position << 2) + orientation; return await this.set_mountPos(mixedPos); } /** * Returns the 3D sensor calibration state (Yocto-3D-V2 only). This function returns * an integer representing the calibration state of the 3 inertial sensors of * the BNO055 chip, found in the Yocto-3D-V2. Hundredths show the calibration state * of the accelerometer, tenths show the calibration state of the magnetometer while * units show the calibration state of the gyroscope. For each sensor, the value 0 * means no calibration and the value 3 means full calibration. * * @return an integer representing the calibration state of Yocto-3D-V2: * 333 when fully calibrated, 0 when not calibrated at all. * * On failure, throws an exception or returns a negative error code. * For the Yocto-3D (V1), this function always return -3 (unsupported function). */ async get_calibrationState() { let calibParam; let iCalib = []; let caltyp; let res; calibParam = await this.get_calibrationParam(); iCalib = this._yapi.imm_decodeFloats(calibParam); caltyp = ((iCalib[0] / 1000) >> 0); if (caltyp != 33) { return this._yapi.NOT_SUPPORTED; } res = ((iCalib[1] / 1000) >> 0); return res; } /** * Returns estimated quality of the orientation (Yocto-3D-V2 only). This function returns * an integer between 0 and 3 representing the degree of confidence of the position * estimate. When the value is 3, the estimation is reliable. Below 3, one should * expect sudden corrections, in particular for heading (compass function). * The most frequent causes for values below 3 are magnetic interferences, and * accelerations or rotations beyond the sensor range. * * @return an integer between 0 and 3 (3 when the measure is reliable) * * On failure, throws an exception or returns a negative error code. * For the Yocto-3D (V1), this function always return -3 (unsupported function). */ async get_measureQuality() { let calibParam; let iCalib = []; let caltyp; let res; calibParam = await this.get_calibrationParam(); iCalib = this._yapi.imm_decodeFloats(calibParam); caltyp = ((iCalib[0] / 1000) >> 0); if (caltyp != 33) { return this._yapi.NOT_SUPPORTED; } res = ((iCalib[2] / 1000) >> 0); return res; } async _calibSort(start, stopidx) { let idx; let changed; let a; let b; let xa; let xb; // bubble sort is good since we will re-sort again after offset adjustment changed = 1; while (changed > 0) { changed = 0; a = this._calibDataAcc[start]; idx = start + 1; while (idx < stopidx) { b = this._calibDataAcc[idx]; if (a > b) { this._calibDataAcc[idx - 1] = b; this._calibDataAcc[idx] = a; xa = this._calibDataAccX[idx - 1]; xb = this._calibDataAccX[idx]; this._calibDataAccX[idx - 1] = xb; this._calibDataAccX[idx] = xa; xa = this._calibDataAccY[idx - 1]; xb = this._calibDataAccY[idx]; this._calibDataAccY[idx - 1] = xb; this._calibDataAccY[idx] = xa; xa = this._calibDataAccZ[idx - 1]; xb = this._calibDataAccZ[idx]; this._calibDataAccZ[idx - 1] = xb; this._calibDataAccZ[idx] = xa; changed = changed + 1; } else { a = b; } idx = idx + 1; } } return 0; } /** * Initiates the sensors tridimensional calibration process. * This calibration is used at low level for inertial position estimation * and to enhance the precision of the tilt sensors. * * After calling this method, the device should be moved according to the * instructions provided by method get_3DCalibrationHint, * and more3DCalibration should be invoked about 5 times per second. * The calibration procedure is completed when the method * get_3DCalibrationProgress returns 100. At this point, * the computed calibration parameters can be applied using method * save3DCalibration. The calibration process can be cancelled * at any time using method cancel3DCalibration. * * On failure, throws an exception or returns a negative error code. */ async start3DCalibration() { if (!(await this.isOnline())) { return this._yapi.DEVICE_NOT_FOUND; } if (this._calibStage != 0) { await this.cancel3DCalibration(); } this._calibSavedParams = await this.get_calibrationParam(); this._calibV2 = (YAPIContext.imm_atoi(this._calibSavedParams) == 33); await this.set_calibrationParam('0'); this._calibCount = 50; this._calibStage = 1; this._calibStageHint = 'Set down the device on a steady horizontal surface'; this._calibStageProgress = 0; this._calibProgress = 1; this._calibInternalPos = 0; this._calibPrevTick = (this._yapi.GetTickCount() & 0x7FFFFFFF); this._calibOrient.length = 0; this._calibDataAccX.length = 0; this._calibDataAccY.length = 0; this._calibDataAccZ.length = 0; this._calibDataAcc.length = 0; return this._yapi.SUCCESS; } /** * Continues the sensors tridimensional calibration process previously * initiated using method start3DCalibration. * This method should be called approximately 5 times per second, while * positioning the device according to the instructions provided by method * get_3DCalibrationHint. Note that the instructions change during * the calibration process. * * On failure, throws an exception or returns a negative error code. */ async more3DCalibration() { if (this._calibV2) { return await this.more3DCalibrationV2(); } return await this.more3DCalibrationV1(); } async more3DCalibrationV1() { let currTick; let jsonData; let xVal; let yVal; let zVal; let xSq; let ySq; let zSq; let norm; let orient; let idx; let intpos; let err; // make sure calibration has been started if (this._calibStage == 0) { return this._yapi.INVALID_ARGUMENT; } if (this._calibProgress == 100) { return this._yapi.SUCCESS; } // make sure we leave at least 160 ms between samples currTick = (this._yapi.GetTickCount() & 0x7FFFFFFF); if (((currTick - this._calibPrevTick) & 0x7FFFFFFF) < 160) { return this._yapi.SUCCESS; } // load current accelerometer values, make sure we are on a straight angle // (default timeout to 0,5 sec without reading measure when out of range) this._calibStageHint = 'Set down the device on a steady horizontal surface'; this._calibPrevTick = ((currTick + 500) & 0x7FFFFFFF); jsonData = await this._download('api/accelerometer.json'); xVal = YAPIContext.imm_atoi(this.imm_json_get_key(jsonData, 'xValue')) / 65536.0; yVal = YAPIContext.imm_atoi(this.imm_json_get_key(jsonData, 'yValue')) / 65536.0; zVal = YAPIContext.imm_atoi(this.imm_json_get_key(jsonData, 'zValue')) / 65536.0; xSq = xVal * xVal; if (xSq >= 0.04 && xSq < 0.64) { return this._yapi.SUCCESS; } if (xSq >= 1.44) { return this._yapi.SUCCESS; } ySq = yVal * yVal; if (ySq >= 0.04 && ySq < 0.64) { return this._yapi.SUCCESS; } if (ySq >= 1.44) { return this._yapi.SUCCESS; } zSq = zVal * zVal; if (zSq >= 0.04 && zSq < 0.64) { return this._yapi.SUCCESS; } if (zSq >= 1.44) { return this._yapi.SUCCESS; } norm = Math.sqrt(xSq + ySq + zSq); if (norm < 0.8 || norm > 1.2) { return this._yapi.SUCCESS; } this._calibPrevTick = currTick; // Determine the device orientation index orient = 0; if (zSq > 0.5) { if (zVal > 0) { orient = 0; } else { orient = 1; } } if (xSq > 0.5) { if (xVal > 0) { orient = 2; } else { orient = 3; } } if (ySq > 0.5) { if (yVal > 0) { orient = 4; } else { orient = 5; } } // Discard measures that are not in the proper orientation if (this._calibStageProgress == 0) { // New stage, check that this orientation is not yet done idx = 0; err = 0; while (idx + 1 < this._calibStage) { if (this._calibOrient[idx] == orient) { err = 1; } idx = idx + 1; } if (err != 0) { this._calibStageHint = 'Turn the device on another face'; return this._yapi.SUCCESS; } this._calibOrient.push(orient); } else { // Make sure device is not turned before stage is completed if (orient != this._calibOrient[this._calibStage - 1]) { this._calibStageHint = 'Not yet done, please move back to the previous face'; return this._yapi.SUCCESS; } } // Save measure this._calibStageHint = 'calibrating..'; this._calibDataAccX.push(xVal); this._calibDataAccY.push(yVal); this._calibDataAccZ.push(zVal); this._calibDataAcc.push(norm); this._calibInternalPos = this._calibInternalPos + 1; this._calibProgress = 1 + 16 * (this._calibStage - 1) + (((16 * this._calibInternalPos) / this._calibCount) >> 0); if (this._calibInternalPos < this._calibCount) { this._calibStageProgress = 1 + (((99 * this._calibInternalPos) / this._calibCount) >> 0); return this._yapi.SUCCESS; } // Stage done, compute preliminary result intpos = (this._calibStage - 1) * this._calibCount; await this._calibSort(intpos, intpos + this._calibCount); intpos = intpos + ((this._calibCount / 2) >> 0); this._calibLogMsg = 'Stage ' + String(Math.round(this._calibStage)) + ': median is ' + String(Math.round(Math.round(1000 * this._calibDataAccX[intpos]))) + ',' + String(Math.round(Math.round(1000 * this._calibDataAccY[intpos]))) + ',' + String(Math.round(Math.round(1000 * this._calibDataAccZ[intpos]))); // move to next stage this._calibStage = this._calibStage + 1; if (this._calibStage < 7) { this._calibStageHint = 'Turn the device on another face'; this._calibPrevTick = ((currTick + 500) & 0x7FFFFFFF); this._calibStageProgress = 0; this._calibInternalPos = 0; return this._yapi.SUCCESS; } // Data collection completed, compute accelerometer shift xVal = 0; yVal = 0; zVal = 0; idx = 0; while (idx < 6) { intpos = idx * this._calibCount + ((this._calibCount / 2) >> 0); orient = this._calibOrient[idx]; if (orient == 0 || orient == 1) { zVal = zVal + this._calibDataAccZ[intpos]; } if (orient == 2 || orient == 3) { xVal = xVal + this._calibDataAccX[intpos]; } if (orient == 4 || orient == 5) { yVal = yVal + this._calibDataAccY[intpos]; } idx = idx + 1; } this._calibAccXOfs = xVal / 2.0; this._calibAccYOfs = yVal / 2.0; this._calibAccZOfs = zVal / 2.0; // Recompute all norms, taking into account the computed shift, and re-sort intpos = 0; while (intpos < this._calibDataAcc.length) { xVal = this._calibDataAccX[intpos] - this._calibAccXOfs; yVal = this._calibDataAccY[intpos] - this._calibAccYOfs; zVal = this._calibDataAccZ[intpos] - this._calibAccZOfs; norm = Math.sqrt(xVal * xVal + yVal * yVal + zVal * zVal); this._calibDataAcc[intpos] = norm; intpos = intpos + 1; } idx = 0; while (idx < 6) { intpos = idx * this._calibCount; await this._calibSort(intpos, intpos + this._calibCount); idx = idx + 1; } // Compute the scaling factor for each axis xVal = 0; yVal = 0; zVal = 0; idx = 0; while (idx < 6) { intpos = idx * this._calibCount + ((this._calibCount / 2) >> 0); orient = this._calibOrient[idx]; if (orient == 0 || orient == 1) { zVal = zVal + this._calibDataAcc[intpos]; } if (orient == 2 || orient == 3) { xVal = xVal + this._calibDataAcc[intpos]; } if (orient == 4 || orient == 5) { yVal = yVal + this._calibDataAcc[intpos]; } idx = idx + 1; } this._calibAccXScale = xVal / 2.0; this._calibAccYScale = yVal / 2.0; this._calibAccZScale = zVal / 2.0; // Report completion this._calibProgress = 100; this._calibStageHint = 'Calibration data ready for saving'; return this._yapi.SUCCESS; } async more3DCalibrationV2() { let currTick; let calibParam; let iCalib = []; let cal3; let calAcc; let calMag; let calGyr; // make sure calibration has been started if (this._calibStage == 0) { return this._yapi.INVALID_ARGUMENT; } if (this._calibProgress == 100) { return this._yapi.SUCCESS; } // make sure we don't start before previous calibration is cleared if (this._calibStage == 1) { currTick = (this._yapi.GetTickCount() & 0x7FFFFFFF); currTick = ((currTick - this._calibPrevTick) & 0x7FFFFFFF); if (currTick < 1600) { this._calibStageHint = 'Set down the device on a steady horizontal surface'; this._calibStageProgress = ((currTick / 40) >> 0); this._calibProgress = 1; return this._yapi.SUCCESS; } } calibParam = await this._download('api/refFrame/calibrationParam.txt'); iCalib = this._yapi.imm_decodeFloats(this._yapi.imm_bin2str(calibParam)); cal3 = ((iCalib[1] / 1000) >> 0); calAcc = ((cal3 / 100) >> 0); calMag = ((cal3 / 10) >> 0) - 10 * calAcc; calGyr = ((cal3) % (10)); if (calGyr < 3) { this._calibStageHint = 'Set down the device on a steady horizontal surface'; this._calibStageProgress = 40 + calGyr * 20; this._calibProgress = 4 + calGyr * 2; } else { this._calibStage = 2; if (calMag < 3) { this._calibStageHint = 'Slowly draw \'8\' shapes along the 3 axis'; this._calibStageProgress = 1 + calMag * 33; this._calibProgress = 10 + calMag * 5; } else { this._calibStage = 3; if (calAcc < 3) { this._calibStageHint = 'Slowly turn the device, stopping at each 90 degrees'; this._calibStageProgress = 1 + calAcc * 33; this._calibProgress = 25 + calAcc * 25; } else { this._calibStageProgress = 99; this._calibProgress = 100; } } } return this._yapi.SUCCESS; } /** * Returns instructions to proceed to the tridimensional calibration initiated with * method start3DCalibration. * * @return a character string. */ async get_3DCalibrationHint() { return this._calibStageHint; } /** * Returns the global process indicator for the tridimensional calibration * initiated with method start3DCalibration. * * @return an integer between 0 (not started) and 100 (stage completed). */ async get_3DCalibrationProgress() { return this._calibProgress; } /** * Returns index of the current stage of the calibration * initiated with method start3DCalibration. * * @return an integer, growing each time a calibration stage is completed. */ async get_3DCalibrationStage() { return this._calibStage; } /** * Returns the process indicator for the current stage of the calibration * initiated with method start3DCalibration. * * @return an integer between 0 (not started) and 100 (stage completed). */ async get_3DCalibrationStageProgress() { return this._calibStageProgress; } /** * Returns the latest log message from the calibration process. * When no new message is available, returns an empty string. * * @return a character string. */ async get_3DCalibrationLogMsg() { let msg; msg = this._calibLogMsg; this._calibLogMsg = ''; return msg; } /** * Applies the sensors tridimensional calibration parameters that have just been computed. * Remember to call the saveToFlash() method of the module if the changes * must be kept when the device is restarted. * * On failure, throws an exception or returns a negative error code. */ async save3DCalibration() { if (this._calibV2) { return await this.save3DCalibrationV2(); } return await this.save3DCalibrationV1(); } async save3DCalibrationV1() { let shiftX; let shiftY; let shiftZ; let scaleExp; let scaleX; let scaleY; let scaleZ; let scaleLo; let scaleHi; let newcalib; if (this._calibProgress != 100) { return this._yapi.INVALID_ARGUMENT; } // Compute integer values (correction unit is 732ug/count) shiftX = -Math.round(this._calibAccXOfs / 0.000732); if (shiftX < 0) { shiftX = shiftX + 65536; } shiftY = -Math.round(this._calibAccYOfs / 0.000732); if (shiftY < 0) { shiftY = shiftY + 65536; } shiftZ = -Math.round(this._calibAccZOfs / 0.000732); if (shiftZ < 0) { shiftZ = shiftZ + 65536; } scaleX = Math.round(2048.0 / this._calibAccXScale) - 2048; scaleY = Math.round(2048.0 / this._calibAccYScale) - 2048; scaleZ = Math.round(2048.0 / this._calibAccZScale) - 2048; if (scaleX < -2048 || scaleX >= 2048 || scaleY < -2048 || scaleY >= 2048 || scaleZ < -2048 || scaleZ >= 2048) { scaleExp = 3; } else { if (scaleX < -1024 || scaleX >= 1024 || scaleY < -1024 || scaleY >= 1024 || scaleZ < -1024 || scaleZ >= 1024) { scaleExp = 2; } else { if (scaleX < -512 || scaleX >= 512 || scaleY < -512 || scaleY >= 512 || scaleZ < -512 || scaleZ >= 512) { scaleExp = 1; } else { scaleExp = 0; } } } if (scaleExp > 0) { scaleX = (scaleX >> scaleExp); scaleY = (scaleY >> scaleExp); scaleZ = (scaleZ >> scaleExp); } if (scaleX < 0) { scaleX = scaleX + 1024; } if (scaleY < 0) { scaleY = scaleY + 1024; } if (scaleZ < 0) { scaleZ = scaleZ + 1024; } scaleLo = ((scaleY & 15) << 12) + (scaleX << 2) + scaleExp; scaleHi = (scaleZ << 6) + (scaleY >> 4); // Save calibration parameters newcalib = '5,' + String(Math.round(shiftX)) + ',' + String(Math.round(shiftY)) + ',' + String(Math.round(shiftZ)) + ',' + String(Math.round(scaleLo)) + ',' + String(Math.round(scaleHi)); this._calibStage = 0; return await this.set_calibrationParam(newcalib); } async save3DCalibrationV2() { return await this.set_calibrationParam('5,5,5,5,5,5'); } /** * Aborts the sensors tridimensional calibration process et restores normal settings. * * On failure, throws an exception or returns a negative error code. */ async cancel3DCalibration() { if (this._calibStage == 0) { return this._yapi.SUCCESS; } this._calibStage = 0; return await this.set_calibrationParam(this._calibSavedParams); } /** * Continues the enumeration of reference frames started using yFirstRefFrame(). * Caution: You can't make any assumption about the returned reference frames order. * If you want to find a specific a reference frame, use RefFrame.findRefFrame() * and a hardwareID or a logical name. * * @return a pointer to a YRefFrame object, corresponding to * a reference frame currently online, or a null pointer * if there are no more reference frames to enumerate. */ nextRefFrame() { let resolve = this._yapi.imm_resolveFunction(this._className, this._func); if (resolve.errorType != YAPI.SUCCESS) return null; let next_hwid = this._yapi.imm_getNextHardwareId(this._className, resolve.result); if (next_hwid == null) return null; return YRefFrame.FindRefFrameInContext(this._yapi, next_hwid); } /** * Starts the enumeration of reference frames currently accessible. * Use the method YRefFrame.nextRefFrame() to iterate on * next reference frames. * * @return a pointer to a YRefFrame object, corresponding to * the first reference frame currently online, or a null pointer * if there are none. */ static FirstRefFrame() { let next_hwid = YAPI.imm_getFirstHardwareId('RefFrame'); if (next_hwid == null) return null; return YRefFrame.FindRefFrame(next_hwid); } /** * Starts the enumeration of reference frames currently accessible. * Use the method YRefFrame.nextRefFrame() to iterate on * next reference frames. * * @param yctx : a YAPI context. * * @return a pointer to a YRefFrame object, corresponding to * the first reference frame currently online, or a null pointer * if there are none. */ static FirstRefFrameInContext(yctx) { let next_hwid = yctx.imm_getFirstHardwareId('RefFrame'); if (next_hwid == null) return null; return YRefFrame.FindRefFrameInContext(yctx, next_hwid); } } // API symbols as static members YRefFrame.MOUNTPOS_INVALID = YAPI.INVALID_UINT; YRefFrame.BEARING_INVALID = YAPI.INVALID_DOUBLE; YRefFrame.CALIBRATIONPARAM_INVALID = YAPI.INVALID_STRING; YRefFrame.FUSIONMODE_NDOF = 0; YRefFrame.FUSIONMODE_NDOF_FMC_OFF = 1; YRefFrame.FUSIONMODE_M4G = 2; YRefFrame.FUSIONMODE_COMPASS = 3; YRefFrame.FUSIONMODE_IMU = 4; YRefFrame.FUSIONMODE_INCLIN_90DEG_1G8 = 5; YRefFrame.FUSIONMODE_INCLIN_90DEG_3G6 = 6; YRefFrame.FUSIONMODE_INCLIN_10DEG = 7; YRefFrame.FUSIONMODE_INVALID = -1; YRefFrame.MOUNTPOSITION_BOTTOM = 0; YRefFrame.MOUNTPOSITION_TOP = 1; YRefFrame.MOUNTPOSITION_FRONT = 2; YRefFrame.MOUNTPOSITION_REAR = 3; YRefFrame.MOUNTPOSITION_RIGHT = 4; YRefFrame.MOUNTPOSITION_LEFT = 5; YRefFrame.MOUNTPOSITION_INVALID = 6; YRefFrame.MOUNTORIENTATION_TWELVE = 0; YRefFrame.MOUNTORIENTATION_THREE = 1; YRefFrame.MOUNTORIENTATION_SIX = 2; YRefFrame.MOUNTORIENTATION_NINE = 3; YRefFrame.MOUNTORIENTATION_INVALID = 4; //# sourceMappingURL=yocto_refframe.js.map