moteus 0.3.68__tar.gz → 0.3.70__tar.gz
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.
- {moteus-0.3.68 → moteus-0.3.70}/PKG-INFO +5 -5
- {moteus-0.3.68 → moteus-0.3.70}/README.md +4 -4
- {moteus-0.3.68 → moteus-0.3.70}/moteus/moteus.py +22 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/moteus_tool.py +60 -18
- {moteus-0.3.68 → moteus-0.3.70}/moteus/version.py +1 -1
- {moteus-0.3.68 → moteus-0.3.70}/moteus.egg-info/PKG-INFO +5 -5
- {moteus-0.3.68 → moteus-0.3.70}/setup.py +1 -1
- {moteus-0.3.68 → moteus-0.3.70}/moteus/__init__.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/aioserial.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/aiostream.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/calibrate_encoder.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/command.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/export.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/fdcanusb.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/multiplex.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/posix_aioserial.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/pythoncan.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/reader.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/regression.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/router.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/transport.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus/win32_aioserial.py +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus.egg-info/SOURCES.txt +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus.egg-info/dependency_links.txt +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus.egg-info/entry_points.txt +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus.egg-info/requires.txt +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/moteus.egg-info/top_level.txt +0 -0
- {moteus-0.3.68 → moteus-0.3.70}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: moteus
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.70
|
4
4
|
Summary: moteus brushless controller library and tools
|
5
5
|
Home-page: https://github.com/mjbots/moteus
|
6
6
|
Author: mjbots Robotic Systems
|
@@ -110,10 +110,10 @@ pr.kp_scale = moteus.F32
|
|
110
110
|
pr.kd_scale = moteus.F32
|
111
111
|
|
112
112
|
qr = moteus.QueryResolution()
|
113
|
-
qr.mode =
|
114
|
-
qr.position =
|
115
|
-
qr.velocity =
|
116
|
-
qr.torque =
|
113
|
+
qr.mode = moteus.INT8
|
114
|
+
qr.position = moteus.F32
|
115
|
+
qr.velocity = moteus.F32
|
116
|
+
qr.torque = moteus.F32
|
117
117
|
|
118
118
|
c = moteus.Controller(position_resolution=pr, query_resolution=qr)
|
119
119
|
```
|
@@ -90,10 +90,10 @@ pr.kp_scale = moteus.F32
|
|
90
90
|
pr.kd_scale = moteus.F32
|
91
91
|
|
92
92
|
qr = moteus.QueryResolution()
|
93
|
-
qr.mode =
|
94
|
-
qr.position =
|
95
|
-
qr.velocity =
|
96
|
-
qr.torque =
|
93
|
+
qr.mode = moteus.INT8
|
94
|
+
qr.position = moteus.F32
|
95
|
+
qr.velocity = moteus.F32
|
96
|
+
qr.torque = moteus.F32
|
97
97
|
|
98
98
|
c = moteus.Controller(position_resolution=pr, query_resolution=qr)
|
99
99
|
```
|
@@ -162,6 +162,7 @@ class Register(enum.IntEnum):
|
|
162
162
|
Q_CURRENT = 0x004
|
163
163
|
D_CURRENT = 0x005
|
164
164
|
ABS_POSITION = 0x006
|
165
|
+
POWER = 0x007
|
165
166
|
MOTOR_TEMPERATURE = 0x00a
|
166
167
|
TRAJECTORY_COMPLETE = 0x00b
|
167
168
|
REZERO_STATE = 0x00c
|
@@ -199,6 +200,7 @@ class Register(enum.IntEnum):
|
|
199
200
|
COMMAND_VELOCITY_LIMIT = 0x028
|
200
201
|
COMMAND_ACCEL_LIMIT = 0x029
|
201
202
|
COMMAND_FIXED_VOLTAGE_OVERRIDE = 0x02a
|
203
|
+
COMMAND_ILIMIT_SCALE = 0x02b
|
202
204
|
|
203
205
|
POSITION_KP = 0x030
|
204
206
|
POSITION_KI = 0x031
|
@@ -220,6 +222,7 @@ class Register(enum.IntEnum):
|
|
220
222
|
COMMAND_WITHIN_KD_SCALE = 0x044
|
221
223
|
COMMAND_WITHIN_MAX_TORQUE = 0x045
|
222
224
|
COMMAND_WITHIN_TIMEOUT = 0x046
|
225
|
+
COMMAND_WITHIN_ILIMIT_SCALE = 0x047
|
223
226
|
|
224
227
|
ENCODER_0_POSITION = 0x050
|
225
228
|
ENCODER_0_VELOCITY = 0x051
|
@@ -299,6 +302,7 @@ class QueryResolution:
|
|
299
302
|
q_current = mp.IGNORE
|
300
303
|
d_current = mp.IGNORE
|
301
304
|
abs_position = mp.IGNORE
|
305
|
+
power = mp.IGNORE
|
302
306
|
motor_temperature = mp.IGNORE
|
303
307
|
trajectory_complete = mp.IGNORE
|
304
308
|
rezero_state = mp.IGNORE
|
@@ -329,6 +333,7 @@ class PositionResolution:
|
|
329
333
|
velocity_limit = mp.F32
|
330
334
|
accel_limit = mp.F32
|
331
335
|
fixed_voltage_override = mp.F32
|
336
|
+
ilimit_scale = mp.F32
|
332
337
|
|
333
338
|
|
334
339
|
class VFOCResolution:
|
@@ -371,6 +376,9 @@ class Parser(mp.RegisterParser):
|
|
371
376
|
def read_current(self, resolution):
|
372
377
|
return self.read_mapped(resolution, 1.0, 0.1, 0.001)
|
373
378
|
|
379
|
+
def read_power(self, resolution):
|
380
|
+
return self.read_mapped(resolution, 10.0, 0.05, 0.0001)
|
381
|
+
|
374
382
|
def ignore(self, resolution):
|
375
383
|
self._offset += mp.resolution_size(resolution)
|
376
384
|
|
@@ -407,6 +415,9 @@ class Writer(mp.WriteFrame):
|
|
407
415
|
def write_current(self, value, resolution):
|
408
416
|
self.write_mapped(value, 1.0, 0.1, 0.001, resolution)
|
409
417
|
|
418
|
+
def write_power(self, value, resolution):
|
419
|
+
self.write_mapped(value, 10.0, 0.05, 0.0001, resolution)
|
420
|
+
|
410
421
|
|
411
422
|
def parse_register(parser, register, resolution):
|
412
423
|
if register == Register.MODE:
|
@@ -423,6 +434,8 @@ def parse_register(parser, register, resolution):
|
|
423
434
|
return parser.read_current(resolution)
|
424
435
|
elif register == Register.ABS_POSITION:
|
425
436
|
return parser.read_position(resolution)
|
437
|
+
elif register == Register.POWER:
|
438
|
+
return parser.read_power(resolution)
|
426
439
|
elif register == Register.TRAJECTORY_COMPLETE:
|
427
440
|
return parser.read_int(resolution)
|
428
441
|
elif register == Register.HOME_STATE or register == Register.REZERO_STATE:
|
@@ -642,6 +655,7 @@ class Controller:
|
|
642
655
|
qr.q_current,
|
643
656
|
qr.d_current,
|
644
657
|
qr.abs_position,
|
658
|
+
qr.power,
|
645
659
|
])
|
646
660
|
for i in range(c1.size()):
|
647
661
|
c1.maybe_write()
|
@@ -888,6 +902,7 @@ class Controller:
|
|
888
902
|
velocity_limit=None,
|
889
903
|
accel_limit=None,
|
890
904
|
fixed_voltage_override=None,
|
905
|
+
ilimit_scale=None,
|
891
906
|
query=False,
|
892
907
|
query_override=None):
|
893
908
|
"""Return a moteus.Command structure with data necessary to send a
|
@@ -909,6 +924,7 @@ class Controller:
|
|
909
924
|
pr.velocity_limit if velocity_limit is not None else mp.IGNORE,
|
910
925
|
pr.accel_limit if accel_limit is not None else mp.IGNORE,
|
911
926
|
pr.fixed_voltage_override if fixed_voltage_override is not None else mp.IGNORE,
|
927
|
+
pr.ilimit_scale if ilimit_scale is not None else mp.IGNORE
|
912
928
|
]
|
913
929
|
|
914
930
|
data_buf = io.BytesIO()
|
@@ -943,6 +959,8 @@ class Controller:
|
|
943
959
|
writer.write_accel(accel_limit, pr.accel_limit)
|
944
960
|
if combiner.maybe_write():
|
945
961
|
writer.write_voltage(fixed_voltage_override, pr.fixed_voltage_override)
|
962
|
+
if combiner.maybe_write():
|
963
|
+
writer.write_voltage(ilimit_scale, pr.ilimit_scale)
|
946
964
|
|
947
965
|
self._format_query(query, query_override, data_buf, result)
|
948
966
|
|
@@ -1098,6 +1116,7 @@ class Controller:
|
|
1098
1116
|
maximum_torque=None,
|
1099
1117
|
stop_position=None,
|
1100
1118
|
watchdog_timeout=None,
|
1119
|
+
ilimit_scale=None,
|
1101
1120
|
query=False,
|
1102
1121
|
query_override=None):
|
1103
1122
|
"""Return a moteus.Command structure with data necessary to send a
|
@@ -1115,6 +1134,7 @@ class Controller:
|
|
1115
1134
|
pr.kd_scale if kd_scale is not None else mp.IGNORE,
|
1116
1135
|
pr.maximum_torque if maximum_torque is not None else mp.IGNORE,
|
1117
1136
|
pr.watchdog_timeout if watchdog_timeout is not None else mp.IGNORE,
|
1137
|
+
pr.ilimit_scale if ilimit_scale is not None else mp.IGNORE,
|
1118
1138
|
]
|
1119
1139
|
|
1120
1140
|
data_buf = io.BytesIO()
|
@@ -1142,6 +1162,8 @@ class Controller:
|
|
1142
1162
|
writer.write_torque(maximum_torque, pr.maximum_torque)
|
1143
1163
|
if combiner.maybe_write():
|
1144
1164
|
writer.write_time(watchdog_timeout, pr.watchdog_timeout)
|
1165
|
+
if combiner.maybe_write():
|
1166
|
+
writer.write_pwm(ilimit_scale, pr.ilimit_scale)
|
1145
1167
|
|
1146
1168
|
self._format_query(query, query_override, data_buf, result)
|
1147
1169
|
|
@@ -54,7 +54,7 @@ class FirmwareUpgrade:
|
|
54
54
|
self.old = old
|
55
55
|
self.new = new
|
56
56
|
|
57
|
-
SUPPORTED_ABI_VERSION =
|
57
|
+
SUPPORTED_ABI_VERSION = 0x0107
|
58
58
|
|
59
59
|
if new > SUPPORTED_ABI_VERSION:
|
60
60
|
raise RuntimeError(f"\nmoteus_tool needs to be upgraded to support this firmware\n\n (likely 'python -m pip install --upgrade moteus')\n\nThe provided firmare is ABI version 0x{new:04x} but this moteus_tool only supports up to 0x{SUPPORTED_ABI_VERSION:04x}")
|
@@ -63,6 +63,13 @@ class FirmwareUpgrade:
|
|
63
63
|
lines = old_config.split(b'\n')
|
64
64
|
items = dict([line.split(b' ') for line in lines if b' ' in line])
|
65
65
|
|
66
|
+
if self.new <= 0x0106 and self.old >= 0x0107:
|
67
|
+
# motor_position.output.sign was broken in older versions.
|
68
|
+
if int(items[b'motor_position.output.sign']) != 1:
|
69
|
+
print("WARNING: motor_position.output.sign==-1 is broken in order versions, disabling")
|
70
|
+
items[b'motor_position.output.sign'] = '1'
|
71
|
+
pass
|
72
|
+
|
66
73
|
if self.new <= 0x0105 and self.old >= 0x0106:
|
67
74
|
# Downgrade the I2C polling rate.
|
68
75
|
for aux in [1, 2]:
|
@@ -279,6 +286,13 @@ class FirmwareUpgrade:
|
|
279
286
|
items[poll_rate_us_key] = str(int(poll_ms) * 1000).encode('utf8')
|
280
287
|
print("Upgrading I2C rates for version 0x0106")
|
281
288
|
|
289
|
+
if self.new >= 0x0107 and self.old <= 0x0106:
|
290
|
+
if int(items.get(b'motor_position.output.sign', 1)) == -1:
|
291
|
+
print("Upgrading from motor_position.output.sign == -1, " +
|
292
|
+
"this was broken before, behavior will change")
|
293
|
+
|
294
|
+
# No actual configuration updating is required here.
|
295
|
+
pass
|
282
296
|
|
283
297
|
lines = [key + b' ' + value for key, value in items.items()]
|
284
298
|
return b'\n'.join(lines)
|
@@ -305,6 +319,10 @@ def _round_nearest_4v(input_V):
|
|
305
319
|
return round(input_V / 4) * 4
|
306
320
|
|
307
321
|
|
322
|
+
def _average(x):
|
323
|
+
return sum(x) / len(x)
|
324
|
+
|
325
|
+
|
308
326
|
def expand_targets(targets):
|
309
327
|
result = set()
|
310
328
|
|
@@ -794,6 +812,8 @@ class Stream:
|
|
794
812
|
return cal_voltage
|
795
813
|
|
796
814
|
async def do_calibrate(self):
|
815
|
+
self.firmware = await self.read_data("firmware")
|
816
|
+
|
797
817
|
# Determine what our calibration parameters are.
|
798
818
|
self.calculate_calibration_parameters()
|
799
819
|
|
@@ -1239,6 +1259,16 @@ class Stream:
|
|
1239
1259
|
desired_encoder_bw_hz = min(
|
1240
1260
|
desired_encoder_bw_hz, 2e-2 / inductance)
|
1241
1261
|
|
1262
|
+
# Also, limit the bandwidth for halls based on the number
|
1263
|
+
# of poles and the estimated calibration speed.
|
1264
|
+
if hall_output:
|
1265
|
+
max_pole_bandwidth_hz = (
|
1266
|
+
0.5 * self.args.cal_motor_poles *
|
1267
|
+
self.args.cal_motor_speed)
|
1268
|
+
desired_encoder_bw_hz = min(
|
1269
|
+
desired_encoder_bw_hz, max_pole_bandwidth_hz)
|
1270
|
+
|
1271
|
+
|
1242
1272
|
# And our bandwidth with the filter can be no larger than
|
1243
1273
|
# 1/30th the control rate.
|
1244
1274
|
encoder_bw_hz = min(control_rate_hz / 30, desired_encoder_bw_hz)
|
@@ -1308,32 +1338,42 @@ class Stream:
|
|
1308
1338
|
|
1309
1339
|
start_time = time.time()
|
1310
1340
|
|
1341
|
+
SAMPLE_PERIOD_S = 0.02
|
1342
|
+
AVERAGE_PERIOD_S = 0.10
|
1343
|
+
|
1344
|
+
AVERAGE_COUNT = int(AVERAGE_PERIOD_S / SAMPLE_PERIOD_S)
|
1345
|
+
|
1311
1346
|
def sign(x):
|
1312
1347
|
return 1 if x >= 0 else -1
|
1313
1348
|
|
1314
|
-
|
1315
|
-
|
1349
|
+
velocity_samples = []
|
1350
|
+
|
1316
1351
|
while True:
|
1317
1352
|
data = await self.read_servo_stats()
|
1318
|
-
|
1353
|
+
velocity_samples.append(data.velocity)
|
1354
|
+
|
1355
|
+
if len(velocity_samples) > (3 * AVERAGE_COUNT):
|
1356
|
+
del velocity_samples[0]
|
1319
1357
|
|
1320
|
-
|
1358
|
+
recent_average = _average(velocity_samples[-AVERAGE_COUNT:])
|
1359
|
+
|
1360
|
+
# As a fallback, timeout after a fixed amount of waiting.
|
1321
1361
|
if (time.time() - start_time) > 2.0:
|
1322
|
-
return
|
1362
|
+
return recent_average
|
1323
1363
|
|
1324
|
-
if
|
1325
|
-
|
1364
|
+
if (len(velocity_samples) >= AVERAGE_COUNT and
|
1365
|
+
abs(recent_average) < 0.2):
|
1366
|
+
return recent_average
|
1326
1367
|
|
1327
|
-
if
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
return velocity
|
1332
|
-
old_change = change
|
1368
|
+
if len(velocity_samples) == 3 * AVERAGE_COUNT:
|
1369
|
+
average_1 = _average(velocity_samples[:AVERAGE_COUNT])
|
1370
|
+
average_2 = _average(velocity_samples[AVERAGE_COUNT:2*AVERAGE_COUNT])
|
1371
|
+
average_3 = recent_average
|
1333
1372
|
|
1334
|
-
|
1373
|
+
if sign(average_3 - average_2) != sign(average_2 - average_1):
|
1374
|
+
return recent_average
|
1335
1375
|
|
1336
|
-
await asyncio.sleep(
|
1376
|
+
await asyncio.sleep(SAMPLE_PERIOD_S)
|
1337
1377
|
|
1338
1378
|
return velocity
|
1339
1379
|
|
@@ -1393,8 +1433,10 @@ class Stream:
|
|
1393
1433
|
geared_v_per_hz = 1.0 / _calculate_slope(voltages, speed_hzs)
|
1394
1434
|
|
1395
1435
|
v_per_hz = (geared_v_per_hz *
|
1396
|
-
unwrapped_position_scale
|
1397
|
-
|
1436
|
+
unwrapped_position_scale)
|
1437
|
+
if self.firmware.version <= 0x0106:
|
1438
|
+
v_per_hz *= motor_output_sign
|
1439
|
+
|
1398
1440
|
print(f"v_per_hz (pre-gearbox)={v_per_hz}")
|
1399
1441
|
|
1400
1442
|
await self.command(f"conf set servopos.position_min {original_position_min}")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: moteus
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.70
|
4
4
|
Summary: moteus brushless controller library and tools
|
5
5
|
Home-page: https://github.com/mjbots/moteus
|
6
6
|
Author: mjbots Robotic Systems
|
@@ -110,10 +110,10 @@ pr.kp_scale = moteus.F32
|
|
110
110
|
pr.kd_scale = moteus.F32
|
111
111
|
|
112
112
|
qr = moteus.QueryResolution()
|
113
|
-
qr.mode =
|
114
|
-
qr.position =
|
115
|
-
qr.velocity =
|
116
|
-
qr.torque =
|
113
|
+
qr.mode = moteus.INT8
|
114
|
+
qr.position = moteus.F32
|
115
|
+
qr.velocity = moteus.F32
|
116
|
+
qr.torque = moteus.F32
|
117
117
|
|
118
118
|
c = moteus.Controller(position_resolution=pr, query_resolution=qr)
|
119
119
|
```
|
@@ -25,7 +25,7 @@ long_description = (here / 'README.md').read_text(encoding='utf-8')
|
|
25
25
|
|
26
26
|
setuptools.setup(
|
27
27
|
name = 'moteus',
|
28
|
-
version = "0.3.
|
28
|
+
version = "0.3.70",
|
29
29
|
description = 'moteus brushless controller library and tools',
|
30
30
|
long_description = long_description,
|
31
31
|
long_description_content_type = 'text/markdown',
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|