UNPKG

@robotical/roboticaljs

Version:

Javascript/TS library for Robotical products

370 lines (338 loc) 12.4 kB
///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // RICJS // Communications Library // // Rob Dobson & Chris Greening 2020-2022 // (C) 2020-2022 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// import { RaftOKFail, RaftReportMsg, RaftMsgHandler, RaftLog } from "@robotical/raftjs"; import { RICConfiguredAddOns } from "./RICAddOn"; import RICAddOnManager from "./RICAddOnManager"; import { RICHWElem, RICHWElemList, RICHWElemList_Str } from "./RICHWElem"; import { RICCalibInfo } from "./RICTypes"; export default class RICSystemUtils { // Message handler private _msgHandler: RaftMsgHandler; // Add-on manager private _addOnManager: RICAddOnManager; // HWElems (connected to RIC) - excluding AddOns private _hwElemsExcludingAddOns: Array<RICHWElem> = new Array<RICHWElem>(); private _connectedAddOns: Array<RICHWElem> = new Array<RICHWElem>(); // Calibration info private _calibInfo: RICCalibInfo | null = null; /** * constructor * @param raftMsgHandler * @param addOnManager */ constructor(msgHandler: RaftMsgHandler, addOnManager: RICAddOnManager) { this._msgHandler = msgHandler; this._addOnManager = addOnManager; } /** * invalidate */ invalidate() { // Invalidate system info this._hwElemsExcludingAddOns = new Array<RICHWElem>(); this._connectedAddOns = new Array<RICHWElem>(); this._addOnManager.clear(); this._calibInfo = null; RaftLog.debug("RICSystem information invalidated"); } /** * getSystemInfo - get system info * @returns Promise<RICSystemInfo> * */ async retrieveInfo(): Promise<boolean> { // Get HWElems (connected to RIC) try { await this.getHWElemList(); } catch (error) { RaftLog.warn("retrieveInfo - failed to get HWElems " + error); return false; } // Get calibration info try { await this.getRICCalibInfo(true); } catch (error) { RaftLog.warn("retrieveInfo - failed to get calib info " + error); return false; } // Get HWElems (connected to RIC) try { await this.getHWElemList(); } catch (error) { RaftLog.warn("retrieveInfo - failed to get HWElems " + error); return false; } return true; } /** * Get information Marty system * * @return void * */ async retrieveMartySystemInfo(): Promise<boolean> { // Retrieve system info try { const retrieveResult = await this.retrieveInfo(); return retrieveResult; } catch (err) { RaftLog.error(`retrieveMartySystemInfo: error ${err}`); } return false; } // Mark: Calibration ----------------------------------------------------------------------------------------- async calibrate( cmd: string, jointList: Array<string>, jointNames: { [key: string]: string } ) { let overallResult = true; if (cmd === "set") { // Set calibration for (const jnt of jointList) { try { // Set calibration on joint const cmdUrl = "calibrate/set/" + jnt; const rsl = await this._msgHandler.sendRICRESTURL<RaftOKFail>( cmdUrl ); // saving the calibration... (For the new servo boards it is necessary // to send a "save" command after the calibration ones or any servo // parameter changes in order to save any changes made into nonvolatile storage) const saveCalibCmd = `elem/${jnt}/saveparams`; await this._msgHandler.sendRICRESTURL<RaftOKFail>(saveCalibCmd); if (rsl.rslt != "ok") overallResult = false; } catch (error) { console.log(`calibrate failed on joint ${jnt}`, error); } // Wait as writing to flash blocks servo access // as of v0.0.113 of firmware, the pause is no longer required //await new Promise(resolve => setTimeout(resolve, 3000)); } // ensure all joints are enabled for (const jnt in jointNames) { try { // enable joint const cmdUrl = "servo/" + jnt + "/enable/1"; const rsl = await this._msgHandler.sendRICRESTURL<RaftOKFail>( cmdUrl ); if (rsl.rslt != "ok") overallResult = false; } catch (error) { console.log(`enable failed on joint ${jnt}`, error); } } // Result console.log("Set calibration flag to true"); const rslt = new RaftOKFail(); rslt.rslt = overallResult ? "ok" : "fail"; return rslt; } return false; } /** * * getRICCalibInfo * @returns Promise<RICCalibInfo> * */ async getRICCalibInfo(forceGetFromRIC = false): Promise<RICCalibInfo> { if (!forceGetFromRIC && this._calibInfo) { return this._calibInfo; } try { this._calibInfo = await this._msgHandler.sendRICRESTURL<RICCalibInfo>( "calibrate" ); RaftLog.debug("getRICCalibInfo returned " + this._calibInfo); this._calibInfo.validMs = Date.now(); return this._calibInfo; } catch (error) { RaftLog.debug(`getRICCalibInfo Failed to get version ${error}`); return new RICCalibInfo(); } } /** * * getHWElemList - get the list of hardware elements connected to the robot * - the result (if successful) is processed as follows: * = if no filter is applied then all non-add-ons found are stored in * this._hwElemsExcludingAddOns and all addons are stored in this._connectedAddOns * = if a filter is applied and this filter is RSAddOns then this._connectedAddOns is * updated with the new list of addons * = in all cases the discovered list is returned * * @returns Promise<RICHWElemList> * */ async getHWElemList(filterByType?: string): Promise<Array<RICHWElem>> { // Form a list of the requests to make const reqList: Array<string> = []; let addToNonAddOnsList = false; if (!filterByType) { reqList.push("SmartServo"); reqList.push("RSAddOn"); reqList.push("BusPixels"); reqList.push("!SmartServo,RSAddOn,BusPixels"); // not SmartServo or RSAddOn or BusPixels this._hwElemsExcludingAddOns = new Array<RICHWElem>(); addToNonAddOnsList = true; } else if (filterByType === "RSAddOn") { // we treat BusPixels as an RSAddOn // (batch 4 led eye add-ons have type BusPixels) reqList.push("RSAddOn"); reqList.push("BusPixels"); this._connectedAddOns = new Array<RICHWElem>(); } else { reqList.push(filterByType); } // Make the requests const fullListOfElems = new Array<RICHWElem>(); this._connectedAddOns = []; for (const reqType of reqList) { try { const hwElemList_Str = await this._msgHandler.sendRICRESTURL< RICHWElemList_Str >(`hwstatus/strstat?filterByType=${reqType}`); // if the results of hwElem indicates that we are on an older fw version // send the old hwstatus command and don't expand() // the logic behind deciding if we are on a fw version that // supports strstat is: given that hwElemList_Str.hw === object[] // if we get back string[], then we know we are on an older version // if hw === empty array, then we don't have any hw elems in which // case we can stop at that point const hwElems = hwElemList_Str.hw; let hwElemList; if (hwElems.length) { if (typeof hwElems[0] !== "object") { // we are on an older version hwElemList = await this._msgHandler.sendRICRESTURL< RICHWElemList >(`hwstatus?filterByType=${reqType}`); } else { // we are on the fw version that supports strstat hwElemList = RICHWElemList_Str.expand(hwElemList_Str); } } if (hwElemList && hwElemList.rslt && hwElemList.rslt === "ok") { fullListOfElems.push(...hwElemList.hw); if (reqType === "RSAddOn") { this._connectedAddOns = hwElemList.hw; this._addOnManager.setHWElems(this._connectedAddOns); // Debug RaftLog.debug( `getHWElemList: found ${hwElemList.hw.length} addons/buspixels` ); } else if (reqType === "BusPixels") { // BusPixels are treated as an RSAddOn this._connectedAddOns.push(...hwElemList.hw); this._addOnManager.setHWElems(this._connectedAddOns); // Debug RaftLog.debug( `getHWElemList: found ${hwElemList.hw.length} addons/buspixels` ); } else if (addToNonAddOnsList) { this._hwElemsExcludingAddOns.push(...hwElemList.hw); // Debug RaftLog.debug( `getHWElemList: found ${hwElemList.hw.length} elems matching ${reqType}` ); } } } catch (error) { RaftLog.debug(`getHWElemList failed to get ${reqType} ${error}`); return new Array<RICHWElem>(); } } // Handle any callbacks try { const reports: Array<RaftReportMsg> = []; // add callback to subscribe to report messages this._msgHandler.reportMsgCallbacksSet("getHWElemCB", async function ( report: RaftReportMsg ) { reports.push(report); RaftLog.debug(`getHWElemCB Report callback ${JSON.stringify(report)}`); }); // run any required initialisation for the addons const initCmds = this._addOnManager.getInitCmds(); // send init commands to the robot const timeInitStart = Date.now(); for (let i = 0; i < initCmds.length; i++) { this.runCommand(initCmds[i], {}); } // wait a couple of seconds for any report messages to be received await new Promise((resolve) => setTimeout(resolve, 2000)); // pass report messages to add on manager for processing this._addOnManager.processReportMsg(reports, timeInitStart); // clean up callback this._msgHandler.reportMsgCallbacksDelete("getHWElemCB"); } catch (error) { RaftLog.debug(`getHWElemList failed processing callback reports ${error}`); return new Array<RICHWElem>(); } // return the full list of elements return fullListOfElems; } /** * * getAddOnConfigs - get list of add-ons configured on the robot * @returns Promise<RICConfiguredAddOns> * */ async getAddOnConfigs(): Promise<RICConfiguredAddOns> { try { const addOnList = await this._msgHandler.sendRICRESTURL< RICConfiguredAddOns >("addon/list"); RaftLog.debug("getAddOnConfigs returned " + addOnList); return addOnList; } catch (error) { RaftLog.debug(`getAddOnConfigs Failed to get list of add-ons ${error}`); return new RICConfiguredAddOns(); } } /** * * runCommand * @param commandName command API string * @param params parameters (simple name value pairs only) to parameterize trajectory * @returns Promise<RaftOKFail> * */ async runCommand(commandName: string, params: object): Promise<RaftOKFail> { try { // Format the paramList as query string const paramEntries = Object.entries(params); let paramQueryStr = ""; for (const param of paramEntries) { if (paramQueryStr.length > 0) paramQueryStr += "&"; paramQueryStr += param[0] + "=" + param[1]; } // Format the url to send if (paramQueryStr.length > 0) commandName += "?" + paramQueryStr; return await this._msgHandler.sendRICRESTURL<RaftOKFail>(commandName); } catch (error) { RaftLog.debug(`RaftSystemUtils runCommand failed ${error}`); return new RaftOKFail(); } } getCachedAddOnList(): Array<RICHWElem> { return this._connectedAddOns; } getCachedAllHWElems(): Array<RICHWElem> { const allHWElems = new Array<RICHWElem>(); allHWElems.push(...this._connectedAddOns); allHWElems.push(...this._hwElemsExcludingAddOns); return allHWElems; } getCachedCalibInfo(): RICCalibInfo | null { return this._calibInfo; } }