motion-master-client 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/lib/motion-master-req-res-client.ts +380 -15
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ const clientId = v4();
|
|
|
20
20
|
reqResSocket.open(`ws://oblac-drives-7dc95497.local:63524?clientId=${clientId}`);
|
|
21
21
|
pubSubSocket.open(`ws://oblac-drives-7dc95497.local:63525?clientId=${clientId}`);
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
client.request.getDeviceInfo().subscribe(console.log);
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
## Communication
|
package/package.json
CHANGED
|
@@ -13,19 +13,22 @@ import { decodeTextContent, valueTypeToParameterTypeValueKeyMap, getParameterVal
|
|
|
13
13
|
/**
|
|
14
14
|
* This class contains methods for making requests to Motion Master using the injected request/response socket.
|
|
15
15
|
*
|
|
16
|
-
* Each request message defined in the proto file has two corresponding request methods in this class.
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* Each request message defined in the proto file has two corresponding request methods in this class.
|
|
17
|
+
* One method supports Reactive and the other Promise-based API. Reactive API is the default one.
|
|
18
|
+
* Unlike promises which resolve to a single value, observables can emit multiple values over time.
|
|
19
|
+
* For some requests like firmware installation, Motion Master will send progress messages until the firmware installation is done.
|
|
19
20
|
* Reactive request methods are named like `getDeviceInfo` and Promise-based are named like `getDeviceInfoAsync` (notice the `Async` suffix).
|
|
20
21
|
*
|
|
21
22
|
* Reactive and Promise-based request methods have the same set of input parameters, but they differ in the return values.
|
|
22
23
|
* Call to Reactive request methods will return an Observable of (1) corresponding status message, for example call to `getDeviceInfo`
|
|
23
24
|
* will return an instance of `MotionMasterMessage.Status.DeviceInfo`, (2) request status, and (3) request message id.
|
|
24
|
-
* Promise-based request methods can only return (resolve to) a single value.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
25
|
+
* Promise-based request methods can only return (resolve to) a single value.
|
|
26
|
+
* These methods call the corresponding Reactive request method and return data from the last emmited status message.
|
|
27
|
+
* For example `getDeviceInfoAsync` calls `getDeviceInfo` and returns a list of devices from the last emmited status message.
|
|
28
|
+
* If the request fails on Motion Master the function will throw an error. It can also throw an error if the request times out.
|
|
27
29
|
*
|
|
28
|
-
* Request methods have optional `messageId` input parameter.
|
|
30
|
+
* Request methods have optional `messageId` input parameter.
|
|
31
|
+
* If `messageId` is not provided, one will be generated before sending the request message to Motion Master.
|
|
29
32
|
* Status messages (responses) received from Motion Master that correspond to the previous request will have the same `messageId` as the one in the request.
|
|
30
33
|
* This is how we match request with response messages in the full-duplex asynchronous communication (WebSockets, ZeroMQ).
|
|
31
34
|
* Matching request/response by message id is inspired by [JSON-RPC 2.0 Specification](https://www.jsonrpc.org/specification).
|
|
@@ -70,7 +73,7 @@ import { decodeTextContent, valueTypeToParameterTypeValueKeyMap, getParameterVal
|
|
|
70
73
|
* Beside device address and device serial number, devices can be referenced by position (sequence number in the network).
|
|
71
74
|
*
|
|
72
75
|
* It is ensured that Observable returned from a call to Reactive request method will eventually complete, so a call to unsubscribe is not required.
|
|
73
|
-
* Observable will complete when request status is either "succeeded" or "failed",
|
|
76
|
+
* Observable will complete when request status is either "succeeded" or "failed", or it will complete (error) due to timeout.
|
|
74
77
|
* Finding out if a request has completed, failed or is it still on-going is different for each request - it dependends on the status messages, see {@link requestStatusResolver}.
|
|
75
78
|
* Reactive request methods handle this and for each request they will emit status messages with one of "succeeded", "failed", or "running" request status.
|
|
76
79
|
*
|
|
@@ -98,7 +101,7 @@ export class MotionMasterReqResClient {
|
|
|
98
101
|
* When device parameter info is fetched this map gets updated by mapping device parameters type to oneof proto type, e.g. `INTEGER32 -> intValue`.
|
|
99
102
|
*
|
|
100
103
|
* This map helps in simplifying the API by allowing users to set parameter values without specifying the type value field.
|
|
101
|
-
* One can simply call `
|
|
104
|
+
* One can simply call `setParameterValue(2045285448, 0x2004, 0x03, 2500)` and the correct type value field on the proto message will be set, `uintValue` in this example.
|
|
102
105
|
*/
|
|
103
106
|
readonly parameterTypeValueKeyMap = new Map<number, Map<string, ParameterTypeValueKey>>();
|
|
104
107
|
|
|
@@ -117,8 +120,8 @@ export class MotionMasterReqResClient {
|
|
|
117
120
|
* For scripts and applications that use this library, having a permanent device identifier is a better option.
|
|
118
121
|
* Device serial number read from the hardware description file (.hardware_description) stored on a device is a permanent identifier.
|
|
119
122
|
*
|
|
120
|
-
* This map helps in making all request
|
|
121
|
-
* Device reference can be one of: device address, device serial number, or device position.
|
|
123
|
+
* This map helps in making all request methods related to a device accept device reference instead of just device address as an identifier.
|
|
124
|
+
* Device reference {@link DeviceRefObj} can be one of: device address, device serial number, or device position.
|
|
122
125
|
* Prior to sending a request message to Motion Master, device address is resolved from device reference and this map is used for that.
|
|
123
126
|
*/
|
|
124
127
|
readonly deviceAddressMap = new Map<string, number>();
|
|
@@ -180,8 +183,12 @@ export class MotionMasterReqResClient {
|
|
|
180
183
|
/**
|
|
181
184
|
* Get device info.
|
|
182
185
|
*
|
|
183
|
-
* Device info includes a list of devices on network.
|
|
184
|
-
*
|
|
186
|
+
* Device info includes a list of devices on the network. Each device has a type, position in the network, and device address.
|
|
187
|
+
*
|
|
188
|
+
* Motion Master will assign a unique device address to each device in the list.
|
|
189
|
+
* Device address is what the client libraries use to make requests like `getDeviceParameter` from a particular device.
|
|
190
|
+
* Device address is only valid for the duration of the session, that is until the list of devices is read again, for example
|
|
191
|
+
* when devices are power cycled or Motion Master process is restarted.
|
|
185
192
|
*/
|
|
186
193
|
getDeviceInfo(requestTimeout: number, messageId?: string) {
|
|
187
194
|
const getDeviceInfo = MotionMasterMessage.Request.GetDeviceInfo.create();
|
|
@@ -204,6 +211,22 @@ export class MotionMasterReqResClient {
|
|
|
204
211
|
throw new Error('Get device info request failed.');
|
|
205
212
|
}
|
|
206
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Get device parameter info.
|
|
216
|
+
*
|
|
217
|
+
* Device parameter info includes a list of all parameters for the requested device, but without the parameter values.
|
|
218
|
+
* Getting device parameter values can take more than 20ms per parameter using the IgH EtherCAT Master library.
|
|
219
|
+
* Not all clients require all the parameter values at once like OBLAC Drives, so this method is good for getting
|
|
220
|
+
* the list of available parameters and then getting the values of only some parameters.
|
|
221
|
+
*
|
|
222
|
+
* The returned list of device parameters will include some basic data for each parameter: index, subindex,
|
|
223
|
+
* name, unit, group (ARRAY or RECORD name for subitems), read and write access, min and max, and value type.
|
|
224
|
+
* The same info and more can be read from the "SOMANET_CiA_402.xml" file, but getting info from ESI file is more complicated.
|
|
225
|
+
* It requires an XML parsing library and knowing how to read objects info from a dictionary and assigned modules.
|
|
226
|
+
*
|
|
227
|
+
* In addition to fetching device parameter info, this method will map parameter base data type (ETG.1020) to proto3 types.
|
|
228
|
+
* The map removes the need to specify proto3 type field when setting a parameter value {@link parameterTypeValueKeyMap}.
|
|
229
|
+
*/
|
|
207
230
|
getDeviceParameterInfo(props: MotionMasterMessage.Request.IGetDeviceParameterInfo & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
208
231
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
209
232
|
mergeMap((deviceAddress) => {
|
|
@@ -231,6 +254,9 @@ export class MotionMasterReqResClient {
|
|
|
231
254
|
);
|
|
232
255
|
}
|
|
233
256
|
|
|
257
|
+
/**
|
|
258
|
+
* {@inheritDoc getDeviceParameterInfo}
|
|
259
|
+
*/
|
|
234
260
|
async getDeviceParameterInfoAsync(props: MotionMasterMessage.Request.IGetDeviceParameterInfo & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<MotionMasterMessage.Status.DeviceParameterInfo.IParameter[]> {
|
|
235
261
|
const status = await lastValueFrom(this.getDeviceParameterInfo(props, requestTimeout, messageId));
|
|
236
262
|
|
|
@@ -241,6 +267,9 @@ export class MotionMasterReqResClient {
|
|
|
241
267
|
throw new Error('Get device parameter info request failed.');
|
|
242
268
|
}
|
|
243
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Get device parameter values.
|
|
272
|
+
*/
|
|
244
273
|
getDeviceParameterValues(props: MotionMasterMessage.Request.IGetDeviceParameterValues & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
245
274
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
246
275
|
mergeMap((deviceAddress) => {
|
|
@@ -250,15 +279,21 @@ export class MotionMasterReqResClient {
|
|
|
250
279
|
transformMotionMasterMessageToStatus<MotionMasterMessage.Status.DeviceParameterValues>('deviceParameterValues', requestTimeout, id),
|
|
251
280
|
);
|
|
252
281
|
}),
|
|
253
|
-
)
|
|
282
|
+
);
|
|
254
283
|
}
|
|
255
284
|
|
|
285
|
+
/**
|
|
286
|
+
* {@inheritDoc getDeviceParameterValues}
|
|
287
|
+
*/
|
|
256
288
|
async getDeviceParameterValuesAsync(props: MotionMasterMessage.Request.IGetDeviceParameterValues & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<MotionMasterMessage.Status.DeviceParameterValues.IParameterValue[]> {
|
|
257
289
|
const status = await lastValueFrom(this.getDeviceParameterValues(props, requestTimeout, messageId));
|
|
258
290
|
|
|
259
291
|
return status.parameterValues;
|
|
260
292
|
}
|
|
261
293
|
|
|
294
|
+
/**
|
|
295
|
+
* Get multi device parameter values.
|
|
296
|
+
*/
|
|
262
297
|
getMultiDeviceParameterValues(props: MotionMasterMessage.Request.IGetMultiDeviceParameterValues, requestTimeout: number, messageId?: string) {
|
|
263
298
|
const getMultiDeviceParameterValues = MotionMasterMessage.Request.GetMultiDeviceParameterValues.create(props);
|
|
264
299
|
const id = this.sendRequest({ getMultiDeviceParameterValues }, messageId);
|
|
@@ -267,12 +302,18 @@ export class MotionMasterReqResClient {
|
|
|
267
302
|
);
|
|
268
303
|
}
|
|
269
304
|
|
|
305
|
+
/**
|
|
306
|
+
* {@inheritDoc getMultiDeviceParameterValues}
|
|
307
|
+
*/
|
|
270
308
|
async getMultiDeviceParameterValuesAsync(props: MotionMasterMessage.Request.IGetMultiDeviceParameterValues, requestTimeout: number, messageId?: string): Promise<MotionMasterMessage.Status.IDeviceParameterValues[]> {
|
|
271
309
|
const status = await lastValueFrom(this.getMultiDeviceParameterValues(props, requestTimeout, messageId));
|
|
272
310
|
|
|
273
311
|
return status.collection;
|
|
274
312
|
}
|
|
275
313
|
|
|
314
|
+
/**
|
|
315
|
+
* Set device parameter values.
|
|
316
|
+
*/
|
|
276
317
|
setDeviceParameterValues(props: MotionMasterMessage.Request.ISetDeviceParameterValues & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
277
318
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
278
319
|
mergeMap((deviceAddress) => {
|
|
@@ -285,12 +326,18 @@ export class MotionMasterReqResClient {
|
|
|
285
326
|
);
|
|
286
327
|
}
|
|
287
328
|
|
|
329
|
+
/**
|
|
330
|
+
* {@inheritDoc setDeviceParameterValues}
|
|
331
|
+
*/
|
|
288
332
|
async setDeviceParameterValuesAsync(props: MotionMasterMessage.Request.ISetDeviceParameterValues & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<MotionMasterMessage.Status.DeviceParameterValues.IParameterValue[]> {
|
|
289
333
|
const status = await lastValueFrom(this.setDeviceParameterValues(props, requestTimeout, messageId));
|
|
290
334
|
|
|
291
335
|
return status.parameterValues;
|
|
292
336
|
}
|
|
293
337
|
|
|
338
|
+
/**
|
|
339
|
+
* Set multi device parameter values.
|
|
340
|
+
*/
|
|
294
341
|
setMultiDeviceParameterValues(props: MotionMasterMessage.Request.ISetMultiDeviceParameterValues, requestTimeout: number, messageId?: string) {
|
|
295
342
|
const setMultiDeviceParameterValues = MotionMasterMessage.Request.SetMultiDeviceParameterValues.create(props);
|
|
296
343
|
const id = this.sendRequest({ setMultiDeviceParameterValues }, messageId);
|
|
@@ -299,6 +346,9 @@ export class MotionMasterReqResClient {
|
|
|
299
346
|
);
|
|
300
347
|
}
|
|
301
348
|
|
|
349
|
+
/**
|
|
350
|
+
* {@inheritDoc setMultiDeviceParameterValues}
|
|
351
|
+
*/
|
|
302
352
|
async setMultiDeviceParameterValuesAsync(props: MotionMasterMessage.Request.ISetMultiDeviceParameterValues, requestTimeout: number, messageId?: string): Promise<MotionMasterMessage.Status.IDeviceParameterValues[]> {
|
|
303
353
|
const status = await lastValueFrom(this.setMultiDeviceParameterValues(props, requestTimeout, messageId));
|
|
304
354
|
|
|
@@ -350,7 +400,7 @@ export class MotionMasterReqResClient {
|
|
|
350
400
|
/**
|
|
351
401
|
* Get device file.
|
|
352
402
|
*
|
|
353
|
-
* Motion Master uses the Filetransfer over EtherCAT (FoE) to read and send back
|
|
403
|
+
* Motion Master uses the Filetransfer over EtherCAT (FoE) to read and send back content of a file from device flash memory.
|
|
354
404
|
*
|
|
355
405
|
* The IgH EtherCAT Master library used by Motion Master limits the file read buffer to 9KB, so any file written to flash that is larger than 9KB
|
|
356
406
|
* needs to be split into parts of max 9KB. Motion Master does this automatically on request to {@link setDeviceFile}.
|
|
@@ -428,6 +478,15 @@ export class MotionMasterReqResClient {
|
|
|
428
478
|
throw new Error(`Failed to set device file. ${status.error?.message} ${JSON.stringify(props)}`);
|
|
429
479
|
}
|
|
430
480
|
|
|
481
|
+
/**
|
|
482
|
+
* Delete device file.
|
|
483
|
+
*
|
|
484
|
+
* Motion Master uses the Filetransfer over EtherCAT (FoE) to delete files from device flash memory.
|
|
485
|
+
*
|
|
486
|
+
* If the file to delete is written in parts, Motion Master will ensure that all parts are deleted.
|
|
487
|
+
* It does that by reading the list of files on a device, see {@link getDeviceFileList}. It will remove all parts from the list and then
|
|
488
|
+
* it will re-read the list again to ensure that there are no left overs if there were more than 32 files in the list.
|
|
489
|
+
*/
|
|
431
490
|
deleteDeviceFile(props: MotionMasterMessage.Request.IDeleteDeviceFile & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
432
491
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
433
492
|
mergeMap((deviceAddress) => {
|
|
@@ -440,6 +499,9 @@ export class MotionMasterReqResClient {
|
|
|
440
499
|
);
|
|
441
500
|
}
|
|
442
501
|
|
|
502
|
+
/**
|
|
503
|
+
* {@inheritDoc deleteDeviceFile}
|
|
504
|
+
*/
|
|
443
505
|
async deleteDeviceFileAsync(props: MotionMasterMessage.Request.IDeleteDeviceFile & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<void> {
|
|
444
506
|
const status = await lastValueFrom(this.deleteDeviceFile(props, requestTimeout, messageId));
|
|
445
507
|
|
|
@@ -525,6 +587,19 @@ export class MotionMasterReqResClient {
|
|
|
525
587
|
throw new Error(`Failed to stop device. ${status.error?.message} ${JSON.stringify(props)}`);
|
|
526
588
|
}
|
|
527
589
|
|
|
590
|
+
/**
|
|
591
|
+
* Start device firmware installation.
|
|
592
|
+
*
|
|
593
|
+
* When Motion Master receives this request it will do the following:
|
|
594
|
+
* - switch device to BOOT EtherCAT state, device will then run the bootloader instead of the firmware
|
|
595
|
+
* - delete files from device that it finds in the provided package (SOMANET_CiA_402.xml and stack_image.svg)
|
|
596
|
+
* - write files other than firmware binaries and SII from package to device (SOMANET_CiA_402.xml and stack_image.svg)
|
|
597
|
+
* - optionally install the SII file using the IgH EtherCAT Master library write SII function
|
|
598
|
+
* - write firmware binaries to device using the predefined names like app_firmware.bin
|
|
599
|
+
*
|
|
600
|
+
* During the firmware installation Motion Master will send progress messages back to clients.
|
|
601
|
+
* If Motion Master fails in any step other than SII write it will send error. If SII write fails only warning will be sent.
|
|
602
|
+
*/
|
|
528
603
|
startDeviceFirmwareInstallation(props: MotionMasterMessage.Request.IStartDeviceFirmwareInstallation & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
529
604
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
530
605
|
mergeMap((deviceAddress) => {
|
|
@@ -537,6 +612,9 @@ export class MotionMasterReqResClient {
|
|
|
537
612
|
);
|
|
538
613
|
}
|
|
539
614
|
|
|
615
|
+
/**
|
|
616
|
+
* {@inheritDoc startDeviceFirmwareInstallation}
|
|
617
|
+
*/
|
|
540
618
|
async startDeviceFirmwareInstallationAsync(props: MotionMasterMessage.Request.IStartDeviceFirmwareInstallation & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<void> {
|
|
541
619
|
const status = await lastValueFrom(this.startDeviceFirmwareInstallation(props, requestTimeout, messageId));
|
|
542
620
|
|
|
@@ -547,6 +625,13 @@ export class MotionMasterReqResClient {
|
|
|
547
625
|
throw new Error(`Failed to start device firmware installation. ${status.error?.code}: ${status.error?.message} ${JSON.stringify(props)}`);
|
|
548
626
|
}
|
|
549
627
|
|
|
628
|
+
/**
|
|
629
|
+
* Get device log.
|
|
630
|
+
*
|
|
631
|
+
* Device log is stored in two files due to IgH EtherCAT Master library 9KB file size limitation, see {@link getDeviceFile}.
|
|
632
|
+
* Device automatically writes log to logging_curr.log and copies that file to logging_prev.log once it reaches 9KB.
|
|
633
|
+
* When Motion Master receives this request it will read the both files and return their combined contents.
|
|
634
|
+
*/
|
|
550
635
|
getDeviceLog(props: MotionMasterMessage.Request.IGetDeviceLog & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
551
636
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
552
637
|
mergeMap((deviceAddress) => {
|
|
@@ -559,6 +644,9 @@ export class MotionMasterReqResClient {
|
|
|
559
644
|
);
|
|
560
645
|
}
|
|
561
646
|
|
|
647
|
+
/**
|
|
648
|
+
* {@inheritDoc getDeviceLog}
|
|
649
|
+
*/
|
|
562
650
|
async getDeviceLogAsync(props: MotionMasterMessage.Request.IGetDeviceLog & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<string | null | undefined> {
|
|
563
651
|
const status = await lastValueFrom(this.getDeviceLog(props, requestTimeout, messageId));
|
|
564
652
|
|
|
@@ -569,6 +657,33 @@ export class MotionMasterReqResClient {
|
|
|
569
657
|
throw new Error(`Failed to get device log. ${status.error?.code}: ${status.error?.message} ${JSON.stringify(props)}`);
|
|
570
658
|
}
|
|
571
659
|
|
|
660
|
+
/**
|
|
661
|
+
* Start cogging torque recording.
|
|
662
|
+
*
|
|
663
|
+
* Cogging torque recording (CTC) can be started with or without auto-config.
|
|
664
|
+
* In the proto file skipping the auto-config is currently named skip_auto_tuning. The field name is deprecated and will be renamed.
|
|
665
|
+
*
|
|
666
|
+
* If CTC is started without auto-config then users must ensure that encoder on the motor shaft is used for all functions: commutation, position, and velocity.
|
|
667
|
+
* If this is not the case, then Motion Master will return invalid encoder configuration error.
|
|
668
|
+
* Recording can also fail if the position controller is not tuned.
|
|
669
|
+
*
|
|
670
|
+
* If CTC is started with auto-config then Motion Master will:
|
|
671
|
+
* - change the encoder configuration to have all functions on the motor shaft
|
|
672
|
+
* - disabled CTC
|
|
673
|
+
* - change the velocity feed forward value
|
|
674
|
+
* - change the position and velocity filter types and cutoff frequencies
|
|
675
|
+
* - run iterative sharpening position auto-tuning in order to compute the optimal PID values (gains) using the auto tuning
|
|
676
|
+
*
|
|
677
|
+
* All parameter values that Motion Master changes as part of the auto-config are first stored in memory and once the CTC recording is done are reverted back.
|
|
678
|
+
*
|
|
679
|
+
* CTC recording is started by changing the Modes of operation (0x6060) parameter value to -1 (Cogging compensation recording mode).
|
|
680
|
+
* During the operation Motion Master will monitor the Cogging torque compensation state parameter (0x2008:01) to know when the recording is in progress and when it's done.
|
|
681
|
+
*
|
|
682
|
+
* The result of recording CTC is the cogging_torque.bin file written to device flash memory. Size of this file is 2048 bytes.
|
|
683
|
+
* Each pair of bytes represents a 16-bit signed integer value in mNm (milli newton meter).
|
|
684
|
+
*
|
|
685
|
+
* This request will turn the motor.
|
|
686
|
+
*/
|
|
572
687
|
startCoggingTorqueRecording(props: MotionMasterMessage.Request.IStartCoggingTorqueRecording & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
573
688
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
574
689
|
mergeMap((deviceAddress) => {
|
|
@@ -581,6 +696,9 @@ export class MotionMasterReqResClient {
|
|
|
581
696
|
);
|
|
582
697
|
}
|
|
583
698
|
|
|
699
|
+
/**
|
|
700
|
+
* {@inheritDoc startCoggingTorqueRecording}
|
|
701
|
+
*/
|
|
584
702
|
async startCoggingTorqueRecordingAsync(props: MotionMasterMessage.Request.IStartCoggingTorqueRecording & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<void> {
|
|
585
703
|
const status = await lastValueFrom(this.startCoggingTorqueRecording(props, requestTimeout, messageId));
|
|
586
704
|
|
|
@@ -591,6 +709,14 @@ export class MotionMasterReqResClient {
|
|
|
591
709
|
throw new Error(`Failed to start cogging torque recording. ${status.error?.code}: ${status.error?.message} ${JSON.stringify(props)}`);
|
|
592
710
|
}
|
|
593
711
|
|
|
712
|
+
/**
|
|
713
|
+
* Get cogging torque data.
|
|
714
|
+
*
|
|
715
|
+
* The cogging_torque.bin file is the result of recording cogging torque compensation, see {@link startCoggingTorqueRecording}.
|
|
716
|
+
* The size of this file is 2048 bytes where each pair of bytes represents a 16-bit signed integer value in mNm (milli newton meter).
|
|
717
|
+
*
|
|
718
|
+
* Motion Master will read the cogging_torque.bin file, convert bytes to 16-bit signed integer values and return that as an array.
|
|
719
|
+
*/
|
|
594
720
|
getCoggingTorqueData(props: MotionMasterMessage.Request.IGetCoggingTorqueData & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
595
721
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
596
722
|
mergeMap((deviceAddress) => {
|
|
@@ -603,6 +729,9 @@ export class MotionMasterReqResClient {
|
|
|
603
729
|
);
|
|
604
730
|
}
|
|
605
731
|
|
|
732
|
+
/**
|
|
733
|
+
* {@inheritDoc getCoggingTorqueData}
|
|
734
|
+
*/
|
|
606
735
|
async getCoggingTorqueDataAsync(props: MotionMasterMessage.Request.IGetCoggingTorqueData & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<number[]> {
|
|
607
736
|
const status = await lastValueFrom(this.getCoggingTorqueData(props, requestTimeout, messageId));
|
|
608
737
|
|
|
@@ -613,6 +742,34 @@ export class MotionMasterReqResClient {
|
|
|
613
742
|
throw new Error(`Failed to get cogging torque data. ${status.error?.code}: ${status.error?.message} ${JSON.stringify(props)}`);
|
|
614
743
|
}
|
|
615
744
|
|
|
745
|
+
/**
|
|
746
|
+
* Start offset detection.
|
|
747
|
+
*
|
|
748
|
+
* Running offset detection is different in firmwares <v5 and >=v5.
|
|
749
|
+
*
|
|
750
|
+
* For devices that run firmware >=v5 Motion Master will run multiple OS commands.
|
|
751
|
+
* Before starting any command device is switched to Modes of operation -2 (Diagnostics mode) and
|
|
752
|
+
* it's put into operation enabled CiA402 state. The OS commands are run in the following order:
|
|
753
|
+
* - open phase detection
|
|
754
|
+
* - phase resistance measurement
|
|
755
|
+
* - phase inductance measurement
|
|
756
|
+
* - pole pair detection
|
|
757
|
+
* - motor phase order detection
|
|
758
|
+
* - commutation offset measurement
|
|
759
|
+
*
|
|
760
|
+
* Motion Master will return error if any of the following OS commands fail: open phase detection,
|
|
761
|
+
* phase order detection, commutation offset measurement.
|
|
762
|
+
* If other OS commands fail Motion Master will continue with the procedure and only return warning.
|
|
763
|
+
*
|
|
764
|
+
* Once the commutation offset measurement command completes it will update:
|
|
765
|
+
* - 0x2001:00 Commutation angle offset to the computed offset value
|
|
766
|
+
* - 0x2009:01 Commutation offset State to 2 (OFFSET_VALID)
|
|
767
|
+
*
|
|
768
|
+
* For devices that run firmware <5 the same Modes of operation -2 is used, but it's named Commutation offset detection mode.
|
|
769
|
+
* The end result is the same, the procedure will update 0x2001:00 and 0x2009:01 parameter values.
|
|
770
|
+
*
|
|
771
|
+
* This request will turn the motor.
|
|
772
|
+
*/
|
|
616
773
|
startOffsetDetection(props: MotionMasterMessage.Request.IStartOffsetDetection & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
617
774
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
618
775
|
mergeMap((deviceAddress) => {
|
|
@@ -625,6 +782,9 @@ export class MotionMasterReqResClient {
|
|
|
625
782
|
);
|
|
626
783
|
}
|
|
627
784
|
|
|
785
|
+
/**
|
|
786
|
+
* {@inheritDoc startOffsetDetection}
|
|
787
|
+
*/
|
|
628
788
|
async startOffsetDetectionAsync(props: MotionMasterMessage.Request.IStartOffsetDetection & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<void> {
|
|
629
789
|
const status = await lastValueFrom(this.startOffsetDetection(props, requestTimeout, messageId));
|
|
630
790
|
|
|
@@ -663,6 +823,21 @@ export class MotionMasterReqResClient {
|
|
|
663
823
|
throw new Error(`Failed start plant identification. ${status.error?.code}: ${status.error?.message} ${JSON.stringify(props)}`);
|
|
664
824
|
}
|
|
665
825
|
|
|
826
|
+
/**
|
|
827
|
+
* Compute auto tuning gains.
|
|
828
|
+
*
|
|
829
|
+
* Auto tuning gains can be computed for position or velocity controller.
|
|
830
|
+
*
|
|
831
|
+
* Prerequisites for running this procedure are the configured motor and the existence of
|
|
832
|
+
* plant_model.csv file created by a previous run of the system identification {@link startSystemIdentification}.
|
|
833
|
+
* Motion Master will return error if the plant_model.csv file is not found.
|
|
834
|
+
*
|
|
835
|
+
* In OBLAC Drives this request is called when the tuning sliders (damping ratio, bandwidth) are moved and
|
|
836
|
+
* during the CTC recording {@link startCoggingTorqueRecording} when auto config is not skipped.
|
|
837
|
+
*
|
|
838
|
+
* Motion Master will compute the PID gains using the Python scripts and it will
|
|
839
|
+
* update the Kp, Ki, Kd values of 0x2011 and 0x2012 parameters.
|
|
840
|
+
*/
|
|
666
841
|
computeAutoTuningGains(props: MotionMasterMessage.Request.IComputeAutoTuningGains & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
667
842
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
668
843
|
mergeMap((deviceAddress) => {
|
|
@@ -675,6 +850,9 @@ export class MotionMasterReqResClient {
|
|
|
675
850
|
);
|
|
676
851
|
}
|
|
677
852
|
|
|
853
|
+
/**
|
|
854
|
+
* {@inheritDoc computeAutoTuningGains}
|
|
855
|
+
*/
|
|
678
856
|
async computeAutoTuningGainsAsync(props: MotionMasterMessage.Request.IComputeAutoTuningGains & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
679
857
|
const status = await lastValueFrom(this.computeAutoTuningGains(props, requestTimeout, messageId));
|
|
680
858
|
|
|
@@ -685,6 +863,13 @@ export class MotionMasterReqResClient {
|
|
|
685
863
|
throw new Error(`Failed to compute auto tuning gains. ${status.error?.code}: ${status.error?.message} ${JSON.stringify(props)}`);
|
|
686
864
|
}
|
|
687
865
|
|
|
866
|
+
/**
|
|
867
|
+
* Set motion controller parameters.
|
|
868
|
+
*
|
|
869
|
+
* This request sets the target value for a device on Motion Master.
|
|
870
|
+
*
|
|
871
|
+
* A previous call to {@link enableMotionController} will set the mode of operation to CSP, CSV, or CST and optionally enable filtering.
|
|
872
|
+
*/
|
|
688
873
|
setMotionControllerParameters(props: MotionMasterMessage.Request.ISetMotionControllerParameters & DeviceRefObj, messageId?: string) {
|
|
689
874
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
690
875
|
mergeMap((deviceAddress) => {
|
|
@@ -695,10 +880,23 @@ export class MotionMasterReqResClient {
|
|
|
695
880
|
);
|
|
696
881
|
}
|
|
697
882
|
|
|
883
|
+
/**
|
|
884
|
+
* {@inheritDoc setMotionControllerParameters}
|
|
885
|
+
*/
|
|
698
886
|
async setMotionControllerParametersAsync(props: MotionMasterMessage.Request.ISetMotionControllerParameters & DeviceRefObj, messageId?: string): Promise<void> {
|
|
699
887
|
return await lastValueFrom(this.setMotionControllerParameters(props, messageId), { defaultValue: undefined });
|
|
700
888
|
}
|
|
701
889
|
|
|
890
|
+
/**
|
|
891
|
+
* Enable motion controller.
|
|
892
|
+
*
|
|
893
|
+
* This request will set the mode of operation to CSP, CSV, or CST and optionally enable filtering.
|
|
894
|
+
*
|
|
895
|
+
* If filtering is enabled Motion Master will compute an intermediate target value in each cycle, and depending on the active mode of operation
|
|
896
|
+
* set the value of one of 0x607A Target position, 0x60FF Target velocity, 0x6071 Target torque to that value.
|
|
897
|
+
*
|
|
898
|
+
* Target value can be updated with {@link setMotionControllerParameters}.
|
|
899
|
+
*/
|
|
702
900
|
enableMotionController(props: MotionMasterMessage.Request.IEnableMotionController & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
703
901
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
704
902
|
mergeMap((deviceAddress) => {
|
|
@@ -711,6 +909,9 @@ export class MotionMasterReqResClient {
|
|
|
711
909
|
);
|
|
712
910
|
}
|
|
713
911
|
|
|
912
|
+
/**
|
|
913
|
+
* {@inheritDoc enableMotionController}
|
|
914
|
+
*/
|
|
714
915
|
async enableMotionControllerAsync(props: MotionMasterMessage.Request.IEnableMotionController & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<{ controllerType: MotionMasterMessage.Request.EnableMotionController.ControllerType, enabled: boolean, filter: boolean }> {
|
|
715
916
|
const status = await lastValueFrom(this.enableMotionController(props, requestTimeout, messageId));
|
|
716
917
|
|
|
@@ -721,6 +922,13 @@ export class MotionMasterReqResClient {
|
|
|
721
922
|
throw new Error(`Failed to enable motion controller. ${status.error?.code}: ${status.error?.message} ${JSON.stringify(props)}`);
|
|
722
923
|
}
|
|
723
924
|
|
|
925
|
+
/**
|
|
926
|
+
* Disable motion controller.
|
|
927
|
+
*
|
|
928
|
+
* Depending on the current CiA402 state this request will do the following:
|
|
929
|
+
* - if device is in Quick stop active it will transition to Switch on disabled state
|
|
930
|
+
* - if device is in Operation enabled it will transition to Switched on state
|
|
931
|
+
*/
|
|
724
932
|
disableMotionController(props: MotionMasterMessage.Request.IDisableMotionController & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
725
933
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
726
934
|
mergeMap((deviceAddress) => {
|
|
@@ -733,6 +941,9 @@ export class MotionMasterReqResClient {
|
|
|
733
941
|
);
|
|
734
942
|
}
|
|
735
943
|
|
|
944
|
+
/**
|
|
945
|
+
* {@inheritDoc disableMotionController}
|
|
946
|
+
*/
|
|
736
947
|
async disableMotionControllerAsync(props: MotionMasterMessage.Request.IDisableMotionController & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<{ controllerType: MotionMasterMessage.Request.EnableMotionController.ControllerType, enabled: boolean, filter: boolean }> {
|
|
737
948
|
const status = await lastValueFrom(this.disableMotionController(props, requestTimeout, messageId));
|
|
738
949
|
|
|
@@ -743,6 +954,13 @@ export class MotionMasterReqResClient {
|
|
|
743
954
|
throw new Error(`Failed to disable motion controller. ${status.error?.code}: ${status.error?.message} ${JSON.stringify(props)}`);
|
|
744
955
|
}
|
|
745
956
|
|
|
957
|
+
/**
|
|
958
|
+
* Set signal generator parameters.
|
|
959
|
+
*
|
|
960
|
+
* This request will update the signal generator parameters for a device on Motion Master.
|
|
961
|
+
* The selected signal generator is then started by {@link startSignalGenerator}.
|
|
962
|
+
* Signal generator must be started in the next 60 seconds before Motion Master invalidates the previously set parameters.
|
|
963
|
+
*/
|
|
746
964
|
setSignalGeneratorParameters(props: MotionMasterMessage.Request.ISetSignalGeneratorParameters & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
747
965
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
748
966
|
mergeMap((deviceAddress) => {
|
|
@@ -755,6 +973,9 @@ export class MotionMasterReqResClient {
|
|
|
755
973
|
);
|
|
756
974
|
}
|
|
757
975
|
|
|
976
|
+
/**
|
|
977
|
+
* {@inheritDoc setSignalGeneratorParameters}
|
|
978
|
+
*/
|
|
758
979
|
async setSignalGeneratorParametersAsync(props: MotionMasterMessage.Request.ISetSignalGeneratorParameters & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<void> {
|
|
759
980
|
const status = await lastValueFrom(this.setSignalGeneratorParameters(props, requestTimeout, messageId));
|
|
760
981
|
|
|
@@ -765,6 +986,47 @@ export class MotionMasterReqResClient {
|
|
|
765
986
|
throw new Error(`Failed to set signal generator parameters. ${status.error?.code}: ${status.error?.message} ${JSON.stringify(props)}`);
|
|
766
987
|
}
|
|
767
988
|
|
|
989
|
+
/**
|
|
990
|
+
* Start signal generator.
|
|
991
|
+
*
|
|
992
|
+
* This request will start one of the signal generators based on the
|
|
993
|
+
* previously set parameters with {@link setSignalGeneratorParameters}.
|
|
994
|
+
*
|
|
995
|
+
* Signal generators are started by changing the mode of operation, putting device into Operation enabled CiA402 state,
|
|
996
|
+
* and setting the target value. What mode of operation is set depends on the type of signal generator and controller:
|
|
997
|
+
* - For the simple & advanced step response and sine wave one of CSP, CSV, or CST is set.
|
|
998
|
+
* - For ramp, trapezoidal, and bidirectional signal generators, also called profiles, one of PP, PV, TQ is set.
|
|
999
|
+
*
|
|
1000
|
+
* Currently the only profile type that firmware supports is ramp.
|
|
1001
|
+
* Motion Master uses this profile type to run the following signal generators: ramp, trapezoidal, and bidirectional.
|
|
1002
|
+
* Sine wave is also a profile but it is currently generated on Motion Master.
|
|
1003
|
+
* Firmwares >=5.2 will support generating and running sine wave profiles on devices. This will enable lossless profile
|
|
1004
|
+
* execution on possibly higher frequencies. Future Motion Master versions will switch to this method.
|
|
1005
|
+
*
|
|
1006
|
+
* For the simple step response Motion Master will only set the target value,
|
|
1007
|
+
* wait for the specified holding duration, and then send Quick Stop.
|
|
1008
|
+
*
|
|
1009
|
+
* The advanced step response is similar to simple, but after the holding duration it will set the new target
|
|
1010
|
+
* multiple times depending on the shape, and then send Quick Stop if repeat is set to NO. If repeat is set to YES,
|
|
1011
|
+
* then the signal generator will run indefinitely and users must stop it.
|
|
1012
|
+
*
|
|
1013
|
+
* Before running profiles Motion Master will check if device supports the profile modes by looking at 0x6502 Supported drives modes.
|
|
1014
|
+
* If profile modes are not supported then the profiles will be generated on Motion Master. This means the targets will be computed up-front.
|
|
1015
|
+
* If profiles are supported then ramp, trapezoidal, and bidirectional signal generators are run in profile mode of operation.
|
|
1016
|
+
* Motion Master will set the following parameters:
|
|
1017
|
+
* - 0x6081:00 Profile velocity (only for position controller)
|
|
1018
|
+
* - 0x6083:00 Profile acceleration
|
|
1019
|
+
* - 0x6084:00 Profile deceleration
|
|
1020
|
+
* Motion Master knows when the profile has completed by comparing the demand with the actual value, taking into account the
|
|
1021
|
+
* holding duration and the shape of profile. Once the profile is considered complete Motion Master will send Quick Stop, but
|
|
1022
|
+
* only if repeat is set to NO.
|
|
1023
|
+
*
|
|
1024
|
+
* Sine wave profile is generated up-front on Motion Master. Targets are computed for each master cycle (millisecond).
|
|
1025
|
+
* Once the last computed target has been set, Motion Master will send Quick Stop if repeat is set to NO.
|
|
1026
|
+
*
|
|
1027
|
+
* For all signal generators Motion Master will modify the requested target based on
|
|
1028
|
+
* the software position limits and it will return warning.
|
|
1029
|
+
*/
|
|
768
1030
|
startSignalGenerator(props: MotionMasterMessage.Request.IStartSignalGenerator & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
769
1031
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
770
1032
|
mergeMap((deviceAddress) => {
|
|
@@ -777,6 +1039,9 @@ export class MotionMasterReqResClient {
|
|
|
777
1039
|
);
|
|
778
1040
|
}
|
|
779
1041
|
|
|
1042
|
+
/**
|
|
1043
|
+
* {@inheritDoc startSignalGenerator}
|
|
1044
|
+
*/
|
|
780
1045
|
async startSignalGeneratorAsync(props: MotionMasterMessage.Request.IStartSignalGenerator & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<void> {
|
|
781
1046
|
const status = await lastValueFrom(this.startSignalGenerator(props, requestTimeout, messageId));
|
|
782
1047
|
|
|
@@ -787,6 +1052,11 @@ export class MotionMasterReqResClient {
|
|
|
787
1052
|
throw new Error(`Failed to start signal generator. ${status.error?.code}: ${status.error?.message} ${JSON.stringify(props)}`);
|
|
788
1053
|
}
|
|
789
1054
|
|
|
1055
|
+
/**
|
|
1056
|
+
* Stop signal generator.
|
|
1057
|
+
*
|
|
1058
|
+
* This request will send Quick Stop to a device.
|
|
1059
|
+
*/
|
|
790
1060
|
stopSignalGenerator(props: MotionMasterMessage.Request.IStopSignalGenerator & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
791
1061
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
792
1062
|
mergeMap((deviceAddress) => {
|
|
@@ -799,6 +1069,9 @@ export class MotionMasterReqResClient {
|
|
|
799
1069
|
);
|
|
800
1070
|
}
|
|
801
1071
|
|
|
1072
|
+
/**
|
|
1073
|
+
* {@inheritDoc stopSignalGenerator}
|
|
1074
|
+
*/
|
|
802
1075
|
async stopSignalGeneratorAsync(props: MotionMasterMessage.Request.IStopSignalGenerator & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<void> {
|
|
803
1076
|
const status = await lastValueFrom(this.stopSignalGenerator(props, requestTimeout, messageId));
|
|
804
1077
|
|
|
@@ -861,6 +1134,13 @@ export class MotionMasterReqResClient {
|
|
|
861
1134
|
throw new Error(`Failed get ethercat network state. ${status.error?.code}: ${status.error?.message} ${JSON.stringify(props)}`);
|
|
862
1135
|
}
|
|
863
1136
|
|
|
1137
|
+
/**
|
|
1138
|
+
* Set EtherCAT network state.
|
|
1139
|
+
*
|
|
1140
|
+
* Set EtherCAT network state to one of: BOOT, INIT, PRE-OP, SAFE-OP, OP.
|
|
1141
|
+
*
|
|
1142
|
+
* From PRE-OP to OP MM will reinitialize slaves in order to get new PDO mapping.
|
|
1143
|
+
*/
|
|
864
1144
|
setEthercatNetworkState(props: MotionMasterMessage.Request.ISetEthercatNetworkState & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
865
1145
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
866
1146
|
mergeMap((deviceAddress) => {
|
|
@@ -873,6 +1153,9 @@ export class MotionMasterReqResClient {
|
|
|
873
1153
|
);
|
|
874
1154
|
}
|
|
875
1155
|
|
|
1156
|
+
/**
|
|
1157
|
+
* {@inheritDoc setEthercatNetworkState}
|
|
1158
|
+
*/
|
|
876
1159
|
async setEthercatNetworkStateAsync(props: MotionMasterMessage.Request.ISetEthercatNetworkState & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<void> {
|
|
877
1160
|
const status = await lastValueFrom(this.setEthercatNetworkState(props, requestTimeout, messageId));
|
|
878
1161
|
|
|
@@ -911,16 +1194,47 @@ export class MotionMasterReqResClient {
|
|
|
911
1194
|
throw new Error(`Failed start narrow angle calibration. ${status.error?.code}: ${status.error?.message} ${JSON.stringify(props)}`);
|
|
912
1195
|
}
|
|
913
1196
|
|
|
1197
|
+
/**
|
|
1198
|
+
* Set system client timeout.
|
|
1199
|
+
*
|
|
1200
|
+
* This request will update the client timeout.
|
|
1201
|
+
*
|
|
1202
|
+
* Client timeout specifies how long will Motion Master wait for the client to send ping or any other message before
|
|
1203
|
+
* considering it gone and clearing the resources (stopping procedures and monitorings) related to that client.
|
|
1204
|
+
*
|
|
1205
|
+
* Default client timeout is 1000ms.
|
|
1206
|
+
*
|
|
1207
|
+
* Client will typically change this once the connection is established.
|
|
1208
|
+
*/
|
|
914
1209
|
setSystemClientTimeout(props: MotionMasterMessage.Request.ISetSystemClientTimeout, messageId?: string) {
|
|
915
1210
|
const setSystemClientTimeout = MotionMasterMessage.Request.SetSystemClientTimeout.create(props);
|
|
916
1211
|
this.sendRequest({ setSystemClientTimeout }, messageId);
|
|
917
1212
|
return EMPTY;
|
|
918
1213
|
}
|
|
919
1214
|
|
|
1215
|
+
/**
|
|
1216
|
+
* {@inheritDoc setSystemClientTimeout}
|
|
1217
|
+
*/
|
|
920
1218
|
async setSystemClientTimeoutAsync(props: MotionMasterMessage.Request.ISetSystemClientTimeout, messageId?: string) {
|
|
921
1219
|
return await lastValueFrom(this.setSystemClientTimeout(props, messageId), { defaultValue: undefined });
|
|
922
1220
|
}
|
|
923
1221
|
|
|
1222
|
+
/**
|
|
1223
|
+
* Start system identification.
|
|
1224
|
+
*
|
|
1225
|
+
* pre-condition motor and encoder configured (setup wizard), without position and velocity tuning
|
|
1226
|
+
* torque only, used for computing the PID values during the auto tuning and full auto tuning and ctc which uses auto-tuning
|
|
1227
|
+
* error when, fault state, cannot set op mode, state, system failed, chirp profile is generate on master, each point in a cycle (millisecond)
|
|
1228
|
+
* CST sets targets, after the last target value MM sends Quick Stop, failed if fault, everything happens on master, but idea to run chirp on slave
|
|
1229
|
+
* and record data on slave, so that communication doesn't impact the result, MM records velocity and torque and computes, compute how many data is missing warning
|
|
1230
|
+
* error if there are not enough data, missing more than 80% of data points, if between 5%-80% warning, <5% ok, linear interpolation of missing data points
|
|
1231
|
+
* conversion every all velocity to SI, check amplitude of signal no torque, no velocity, or small amplitudes warning, errors 0 amplitudes
|
|
1232
|
+
* identification plant model, check stability of computed model (math only) can result in error, compute and write to plant_model.csv
|
|
1233
|
+
* set parameters integral limits 0x2012:4 0x2012:8, 0x2011:4 Position|Velocity loop integral limit
|
|
1234
|
+
* result plant_model.csv - check what values are and in what unit
|
|
1235
|
+
*
|
|
1236
|
+
* This request will turn motor
|
|
1237
|
+
*/
|
|
924
1238
|
startSystemIdentification(props: MotionMasterMessage.Request.IStartSystemIdentification & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
925
1239
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
926
1240
|
mergeMap((deviceAddress) => {
|
|
@@ -933,6 +1247,9 @@ export class MotionMasterReqResClient {
|
|
|
933
1247
|
);
|
|
934
1248
|
}
|
|
935
1249
|
|
|
1250
|
+
/**
|
|
1251
|
+
* {@inheritDoc startSystemIdentification}
|
|
1252
|
+
*/
|
|
936
1253
|
async startSystemIdentificationAsync(props: MotionMasterMessage.Request.IStartSystemIdentification & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<void> {
|
|
937
1254
|
const status = await lastValueFrom(this.startSystemIdentification(props, requestTimeout, messageId));
|
|
938
1255
|
|
|
@@ -943,6 +1260,15 @@ export class MotionMasterReqResClient {
|
|
|
943
1260
|
throw new Error(`Failed start system identification. ${status.error?.code}: ${status.error?.message} ${JSON.stringify(props)}`);
|
|
944
1261
|
}
|
|
945
1262
|
|
|
1263
|
+
/**
|
|
1264
|
+
* Get circulo encoder magnet distance.
|
|
1265
|
+
*
|
|
1266
|
+
* check encoder ordinal (1 or 2)
|
|
1267
|
+
* ring revision
|
|
1268
|
+
* is it based on fw 5 in fw <5 this doesn't exist error in that case
|
|
1269
|
+
* read encoder registers with OS command, registers read 2B and 2F, some values go through math depending on the version of Circulo, port, distance value is computed
|
|
1270
|
+
* @todo check what OS command
|
|
1271
|
+
*/
|
|
946
1272
|
getCirculoEncoderMagnetDistance(props: MotionMasterMessage.Request.IGetCirculoEncoderMagnetDistance & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
947
1273
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
948
1274
|
mergeMap((deviceAddress) => {
|
|
@@ -955,6 +1281,9 @@ export class MotionMasterReqResClient {
|
|
|
955
1281
|
);
|
|
956
1282
|
}
|
|
957
1283
|
|
|
1284
|
+
/**
|
|
1285
|
+
* {@inheritDoc getCirculoEncoderMagnetDistance}
|
|
1286
|
+
*/
|
|
958
1287
|
async getCirculoEncoderMagnetDistanceAsync(props: MotionMasterMessage.Request.IGetCirculoEncoderMagnetDistance & DeviceRefObj, requestTimeout: number, messageId?: string): Promise<{ distance: number | null | undefined, encoderOrdinal: number | null | undefined, position: number | null | undefined }> {
|
|
959
1288
|
const status = await lastValueFrom(this.getCirculoEncoderMagnetDistance(props, requestTimeout, messageId));
|
|
960
1289
|
|
|
@@ -965,6 +1294,39 @@ export class MotionMasterReqResClient {
|
|
|
965
1294
|
throw new Error(`Failed to get circulo encoder magnet distance. ${JSON.stringify(props)}`);
|
|
966
1295
|
}
|
|
967
1296
|
|
|
1297
|
+
/**
|
|
1298
|
+
* Start circulo encoder narrow angle calibration procedure.
|
|
1299
|
+
*
|
|
1300
|
+
* check encoder ordinal
|
|
1301
|
+
* check fw version 5
|
|
1302
|
+
* check if SMM, has to be disable safety encoder source type
|
|
1303
|
+
* ignore biss status bit, OS command for encoder to ignore BiSS status bits
|
|
1304
|
+
* initialize velocity profile PV
|
|
1305
|
+
* check software position limits
|
|
1306
|
+
* initialize intern values, feed constant, single turn resolution, si unit, get parameter values, gear ratio, what encoder, port, if gear ratio etc etc
|
|
1307
|
+
* if gear box and si unit velocity not mRPM, and position only encoder, and si unit * feed constant is <10% of gear ratio, error not enough velocity resolution
|
|
1308
|
+
* hardware description file, different values for RPM for different version of Circulo, inner|outer encoder ring, multiturn, not, change profile acc|dec max motor speed etc.
|
|
1309
|
+
* after everything rollback
|
|
1310
|
+
* check if enough turns is possible, if not enough space, error
|
|
1311
|
+
* set default calibration register values
|
|
1312
|
+
* set biss to raw mode, no longer position - raw position
|
|
1313
|
+
* ic house lib is initialized
|
|
1314
|
+
* remove previous files for high resolution data 4kHz, for each iteration, hight res data contains raw data from encoder
|
|
1315
|
+
* OS command configure HRD streaming, automatically sets data from encoder, can only configure how long to record
|
|
1316
|
+
* slave saves data to HRD files
|
|
1317
|
+
* after each iteration which lasts 6 seconds, every iteration is one direction, MM takes data recorded in HRD files and puts that passes that to
|
|
1318
|
+
* master/noniuns track data it takes 32-bit values are both splitted into 2 parts (master nonius), two arrays one master one nonious
|
|
1319
|
+
* that data are passed to iChouse library which give depending on encoder type track master nonius, return some sine offset, cos offset, gain, etc.
|
|
1320
|
+
* that procuderu can have errors: data out of range, motor to slow, bad data, internal error - if error in any iteration the procedure stops
|
|
1321
|
+
* if no error then check if calibration succeeded depending on the values (iterativelly improve values by writing them back to some registers), if not run another iteration
|
|
1322
|
+
* max iteration to run is 13 (up to 2 mins)
|
|
1323
|
+
* treshold is determined by Petr
|
|
1324
|
+
* if iteration is successfull, HRD files are moved after deinitializing (succesfful run),
|
|
1325
|
+
* the result of calibration is setting multiple register values
|
|
1326
|
+
* all parameters are reverted back, motor is rotated back to the starging position, commutation offset measurement (just one OS command) is run again
|
|
1327
|
+
* how many iterations are run are based on results
|
|
1328
|
+
* final itertion is for outputting does nothhing just measures the values
|
|
1329
|
+
*/
|
|
968
1330
|
startCirculoEncoderNarrowAngleCalibrationProcedure(props: MotionMasterMessage.Request.IStartCirculoEncoderNarrowAngleCalibrationProcedure & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
969
1331
|
return from(this.resolveDeviceAddress(props)).pipe(
|
|
970
1332
|
mergeMap((deviceAddress) => {
|
|
@@ -977,6 +1339,9 @@ export class MotionMasterReqResClient {
|
|
|
977
1339
|
);
|
|
978
1340
|
}
|
|
979
1341
|
|
|
1342
|
+
/**
|
|
1343
|
+
* {@inheritDoc startCirculoEncoderNarrowAngleCalibrationProcedure}
|
|
1344
|
+
*/
|
|
980
1345
|
async startCirculoEncoderNarrowAngleCalibrationProcedureAsync(props: MotionMasterMessage.Request.IStartCirculoEncoderNarrowAngleCalibrationProcedure & DeviceRefObj, requestTimeout: number, messageId?: string) {
|
|
981
1346
|
const status = await lastValueFrom(this.startCirculoEncoderNarrowAngleCalibrationProcedure(props, requestTimeout, messageId));
|
|
982
1347
|
|