UNPKG

pololu-jrk

Version:

Drive motors with the Pololu JRK motor controller

347 lines (330 loc) 9.74 kB
/** * Module dependencies. */ const { exec } = require('child_process'); const { format, createLogger, transports } = require('winston') const logger = createLogger({ transports: [ new transports.Console({ level: 'info', silent: false, format: format.combine( format.colorize(), format.simple() ) }) ] }) /** * jrk2cmd commands */ const device_type = 'Jrk G2'; const jrk_cmd = { prefix: 'jrk2cmd', general: { status: '--status', full: '--full', dev: '-d', list: '--list', cmd_port: '--cmd-port', ttl_port: '--ttl-port', pause: '--pause', pause_on_error: '--pause-on-error', help: '--help' }, ctrl: { target: '--target', target_relative: '--target-relative', speed: '--speed', stop: '--stop', run: '--run', clear_errors: '--clear-errors', force_duty_cycle: '--force-duty-cycle', force_duty_cycle_target: '--force-duty-cycle-target' }, eeprom: { restore_defaults: '--restore-defaults', settings: '--settings', get_settings: '--get-settings', fix_settings: '--fix-settings' }, ram: { get_ram_settings: '--get-ram-settings', ram_settings: '--ram-settings', reinitialize: '--reinitialize', proportional: '--proportional', integral: '--integral', derivative: '--derivative', max_duty_cycle: '--max-duty-cycle', max_duty_cycle_fwd: '--max-duty-cycle-fwd', max_duty_cycle_rev: '--max-duty-cycle-rev', current_limit: '--current-limit', current_limit_fwd: '--current-limit-fwd', current_limit_rev: '--current-limit-rev' }, encoded: { current_table: '--current-table', current_decode: '--current-decode', current_encode: '--current-encode' } } const limits = { max_target: 4096, min_target: 0, max_duty: 600 } const properties = { name: { key: "Name", type: String }, serial: { key: "Serial number", type: String }, firmware: { key: "Firmware version", type: String }, cmd_port: { key: "Command port", type: String }, ttl_port: { key: "TTL port", type: String }, last_reset: { key: "Last reset", type: String }, // TODO: update matching regex to handle uptime results // uptime: { // key: "Up time", // type: String // }, input: { key: "Input", type: Number }, target: { key: "Target", type: Number }, fb: { key: "Feedback", type: Number }, scaled_fb: { key: "Scaled feedback", type: Number }, error: { key: "Error", type: String }, integral: { key: "Integral", type: Number }, duty_cycle_target: { key: "Duty cycle target", type: Number }, duty_cycle: { key: "Duty cycle", type: Number }, current: { key: "Current", type: String }, vin: { key: "VIN voltage", type: String }, pid_period_exceeded: { key: "PID period exceeded", type: String }, pid_period_count: { key: "PID period count", type: Number }, } function getDeviceList() { return new Promise(async(resolve, reject) => { let cmd = `${jrk_cmd.prefix} ${jrk_cmd.general.list}`; exec(cmd, (error, stdout, stderr) => { if (error) { logger.error(`Command: ${cmd} error: ${error.message}`); reject(error); } if (stderr) { logger.warn(`Command: ${cmd} stderr: ${stderr}`); reject(stderr); } logger.debug(`Command: ${cmd} stdout: ${stdout}`); let jrk_list = []; stdout.trim().split('\n').forEach(element => { jrk_list.push(element.split(',').map(s => s.trim())); }); logger.debug('Extracted Jrk list: ' + jrk_list); resolve(jrk_list); }); }); } function getVersion() { return new Promise(async(resolve, reject) => { let cmd = `${jrk_cmd.prefix}`; exec(cmd, (error, stdout, stderr) => { if (error) { logger.error(`Command: ${cmd} error: ${error.message}`); reject(error); } if (stderr) { logger.warn(`Command: ${cmd} stderr: ${stderr}`); reject(stderr); } logger.debug(`Command: ${cmd} stdout: ${stdout}`); version = stdout.trim().split('\n')[1].split(' ')[1]; logger.debug(`Extracted version: ${version}`); resolve(version); }); }); } class Jrk { constructor(id = null) { // default to first device if (id == null) { getDeviceList().then((dev_list) => { try { this.id = dev_list[0][0]; logger.debug(`New Jrk object with ID ${this.id} created`); } catch (err) { if (err instanceof TypeError) { logger.error("No JRK devices found"); } else { logger.error("Unexpected Error"); } logger.error(err); process.exit(1); } }).catch((err) => { logger.error('Error initializing Jrk object'); process.exit(1); }); } else { this.id = id } } stop() { let cmd = `${jrk_cmd.prefix} ${jrk_cmd.ctrl.stop} ${jrk_cmd.general.dev} ${this.id}`; exec(cmd, (error, stdout, stderr) => { if (error) { logger.error(`Command: ${cmd} error: ${error.message}`); reject(error); } if (stderr) { logger.warn(`Command: ${cmd} stderr: ${stderr}`); reject(stderr); } logger.debug(`Command: ${cmd} stdout: ${stdout}`); }); } run() { let cmd = `${jrk_cmd.prefix} ${jrk_cmd.ctrl.run} ${jrk_cmd.general.dev} ${this.id}`; exec(cmd, (error, stdout, stderr) => { if (error) { logger.error(`Command: ${cmd} error: ${error.message}`); reject(error); } if (stderr) { logger.warn(`Command: ${cmd} stderr: ${stderr}`); reject(stderr); } logger.debug(`Command: ${cmd} stdout: ${stdout}`); }); } setTarget(val) { let cmd = `${jrk_cmd.prefix} ${jrk_cmd.ctrl.target} ${val} ${jrk_cmd.general.dev} ${this.id}`; exec(cmd, (error, stdout, stderr) => { if (error) { logger.error(`Command: ${cmd} error: ${error.message}`); reject(error); } if (stderr) { logger.warn(`Command: ${cmd} stderr: ${stderr}`); reject(stderr); } logger.debug(`Command: ${cmd} stdout: ${stdout}`); }); } SetTargetRel(val) { let cmd = `${jrk_cmd.prefix} ${jrk_cmd.ctrl.target_relative} ${val} ${jrk_cmd.general.dev} ${this.id}`; exec(cmd, (error, stdout, stderr) => { if (error) { logger.error(`Command: ${cmd} error: ${error.message}`); reject(error); } if (stderr) { logger.warn(`Command: ${cmd} stderr: ${stderr}`); reject(stderr); } logger.debug(`Command: ${cmd} stdout: ${stdout}`); }); } getProperty(name) { return new Promise(async(resolve, reject) => { const prop = properties[name]; if (typeof(prop) == 'undefined') { reject(`Invalid property: ${name}`); } else { let cmd = `${jrk_cmd.prefix} ${jrk_cmd.general.status} ${jrk_cmd.general.dev} ${this.id}`; exec(cmd, (error, stdout, stderr) => { if (error) { logger.error(`Command: ${cmd} error: ${error.message}`); reject(error); } if (stderr) { logger.warn(`Command: ${cmd} stderr: ${stderr}`); reject(stderr); } logger.debug(`Command: ${cmd} stdout: ${stdout}`); const regex = new RegExp(`${prop.key}:\\s+([\\w\\s\./^\\\n]+)\\n`); const match = stdout.match(regex); const prop_val = prop.type(match[1]); logger.debug(`${prop.key}: ${prop_val}`); resolve(prop_val); }); } }); } } // Exports module.exports.getDeviceList = getDeviceList; module.exports.getVersion = getVersion; module.exports.limits = limits; module.exports.Jrk = Jrk; // Testing and debugging async function test() { let ver = await getVersion().catch((err) => { console.error(err); process.exit(1); }); let mot = new Jrk(); setTimeout(async () => { mot.setTarget(500); let prop = await mot.getProperty('name').catch((err) => { logger.error(err); }); console.log(prop); }, 500); } // test();