moteus 0.3.56__py3-none-any.whl → 0.3.58__py3-none-any.whl
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/command.py +1 -0
- moteus/moteus.py +14 -2
- moteus/moteus_tool.py +34 -22
- moteus/multiplex.py +19 -0
- moteus/version.py +1 -1
- {moteus-0.3.56.dist-info → moteus-0.3.58.dist-info}/METADATA +1 -1
- {moteus-0.3.56.dist-info → moteus-0.3.58.dist-info}/RECORD +10 -10
- {moteus-0.3.56.dist-info → moteus-0.3.58.dist-info}/WHEEL +0 -0
- {moteus-0.3.56.dist-info → moteus-0.3.58.dist-info}/entry_points.txt +0 -0
- {moteus-0.3.56.dist-info → moteus-0.3.58.dist-info}/top_level.txt +0 -0
moteus/command.py
CHANGED
@@ -19,6 +19,7 @@ class Command():
|
|
19
19
|
reply_required = False
|
20
20
|
data = b''
|
21
21
|
can_prefix = 0x0000 # a 13 bit CAN prefix
|
22
|
+
expected_reply_size = 0
|
22
23
|
|
23
24
|
# If True, then the following parameters are used directly instead
|
24
25
|
# of being calculated from destination and source (i.e. for
|
moteus/moteus.py
CHANGED
@@ -606,7 +606,7 @@ class Controller:
|
|
606
606
|
self._can_prefix = can_prefix
|
607
607
|
|
608
608
|
# Pre-compute our query string.
|
609
|
-
self._query_data = self._make_query_data()
|
609
|
+
self._query_data, self._default_query_reply_size = self._make_query_data()
|
610
610
|
|
611
611
|
def _get_transport(self):
|
612
612
|
if self.transport:
|
@@ -618,6 +618,8 @@ class Controller:
|
|
618
618
|
return self.transport
|
619
619
|
|
620
620
|
def _make_query_data(self):
|
621
|
+
expected_reply_size = 0
|
622
|
+
|
621
623
|
buf = io.BytesIO()
|
622
624
|
writer = Writer(buf)
|
623
625
|
qr = self.query_resolution
|
@@ -633,6 +635,8 @@ class Controller:
|
|
633
635
|
for i in range(c1.size()):
|
634
636
|
c1.maybe_write()
|
635
637
|
|
638
|
+
expected_reply_size += c1.reply_size
|
639
|
+
|
636
640
|
c2 = mp.WriteCombiner(writer, 0x10, int(Register.MOTOR_TEMPERATURE), [
|
637
641
|
qr.motor_temperature,
|
638
642
|
qr.trajectory_complete,
|
@@ -644,6 +648,8 @@ class Controller:
|
|
644
648
|
for i in range(c2.size()):
|
645
649
|
c2.maybe_write()
|
646
650
|
|
651
|
+
expected_reply_size += c2.reply_size
|
652
|
+
|
647
653
|
c3 = mp.WriteCombiner(writer, 0x10, int(Register.AUX1_GPIO_STATUS), [
|
648
654
|
qr.aux1_gpio,
|
649
655
|
qr.aux2_gpio,
|
@@ -651,6 +657,8 @@ class Controller:
|
|
651
657
|
for i in range(c3.size()):
|
652
658
|
c3.maybe_write()
|
653
659
|
|
660
|
+
expected_reply_size += c3.reply_size
|
661
|
+
|
654
662
|
if len(qr._extra):
|
655
663
|
min_val = int(min(qr._extra.keys()))
|
656
664
|
max_val = int(max(qr._extra.keys()))
|
@@ -660,8 +668,9 @@ class Controller:
|
|
660
668
|
for i in range(min_val, max_val +1)])
|
661
669
|
for _ in range(c4.size()):
|
662
670
|
c4.maybe_write()
|
671
|
+
expected_reply_size += c4.reply_size
|
663
672
|
|
664
|
-
return buf.getvalue()
|
673
|
+
return buf.getvalue(), expected_reply_size
|
665
674
|
|
666
675
|
def _make_command(self, *, query, source=0):
|
667
676
|
result = cmd.Command()
|
@@ -671,6 +680,7 @@ class Controller:
|
|
671
680
|
result.reply_required = query
|
672
681
|
result.parse = self._parser
|
673
682
|
result.can_prefix = self._can_prefix
|
683
|
+
result.expected_reply_size = self._default_query_reply_size if query else 0
|
674
684
|
|
675
685
|
return result
|
676
686
|
|
@@ -702,6 +712,7 @@ class Controller:
|
|
702
712
|
c.maybe_write()
|
703
713
|
|
704
714
|
result.data = buf.getvalue()
|
715
|
+
result.expected_reply_size = c.reply_size
|
705
716
|
return result
|
706
717
|
|
707
718
|
async def custom_query(self, *args, **kwargs):
|
@@ -1157,6 +1168,7 @@ class Controller:
|
|
1157
1168
|
result.parse = make_diagnostic_parser(self.id, channel)
|
1158
1169
|
|
1159
1170
|
result.data = data_buf.getvalue()
|
1171
|
+
result.expected_reply_size = 3 + max_length
|
1160
1172
|
return result
|
1161
1173
|
|
1162
1174
|
async def diagnostic_read(self, *args, **kwargs):
|
moteus/moteus_tool.py
CHANGED
@@ -801,11 +801,9 @@ class Stream:
|
|
801
801
|
input_V, winding_resistance)
|
802
802
|
await self.check_for_fault()
|
803
803
|
|
804
|
-
#
|
805
|
-
|
806
|
-
|
807
|
-
# matter what we choose.
|
808
|
-
inductance = await self.calibrate_inductance(2.0 * resistance_cal_voltage)
|
804
|
+
# Determine our inductance.
|
805
|
+
inductance = await self.calibrate_inductance(
|
806
|
+
resistance_cal_voltage, winding_resistance)
|
809
807
|
await self.check_for_fault()
|
810
808
|
|
811
809
|
kp, ki, torque_bw_hz = None, None, None
|
@@ -820,7 +818,8 @@ class Stream:
|
|
820
818
|
await self.check_for_fault()
|
821
819
|
|
822
820
|
enc_kp, enc_ki, enc_bw_hz = await self.set_encoder_filter(
|
823
|
-
torque_bw_hz,
|
821
|
+
torque_bw_hz, inductance,
|
822
|
+
control_rate_hz=control_rate_hz)
|
824
823
|
await self.check_for_fault()
|
825
824
|
|
826
825
|
v_per_hz = await self.calibrate_kv_rating(
|
@@ -1119,12 +1118,25 @@ class Stream:
|
|
1119
1118
|
|
1120
1119
|
return winding_resistance
|
1121
1120
|
|
1122
|
-
async def calibrate_inductance(self, cal_voltage):
|
1121
|
+
async def calibrate_inductance(self, cal_voltage, winding_resistance):
|
1123
1122
|
print("Calculating motor inductance")
|
1124
1123
|
|
1125
1124
|
try:
|
1125
|
+
# High winding resistance motors typically have a much
|
1126
|
+
# larger inductance, and therefore need a longer
|
1127
|
+
# inductance period. We still need to keep this low for
|
1128
|
+
# low resistance/inductance motors, otherwise we can have
|
1129
|
+
# excessive peak currents during the measurement process.
|
1130
|
+
|
1131
|
+
# For phase resistances of 0.2 ohm or less, stick with 8
|
1132
|
+
# cycles, which for a 15kHz pwm rate would equal ~0.6ms of
|
1133
|
+
# on time. Increase that as phase resistance increases,
|
1134
|
+
# until it maxes at 32/2ms around 0.8 ohms of phase
|
1135
|
+
# resistance.
|
1136
|
+
ind_period = max(8, min(32, int(winding_resistance / 0.2)))
|
1137
|
+
|
1126
1138
|
await asyncio.wait_for(
|
1127
|
-
self.command(f"d ind {cal_voltage}
|
1139
|
+
self.command(f"d ind {cal_voltage} {ind_period}"), 0.25)
|
1128
1140
|
except moteus.CommandError as e:
|
1129
1141
|
# It is possible this is an old firmware that does not
|
1130
1142
|
# support inductance measurement.
|
@@ -1152,7 +1164,7 @@ class Stream:
|
|
1152
1164
|
print(f"Calculated inductance: {inductance}H")
|
1153
1165
|
return inductance
|
1154
1166
|
|
1155
|
-
async def set_encoder_filter(self, torque_bw_hz, control_rate_hz = None):
|
1167
|
+
async def set_encoder_filter(self, torque_bw_hz, inductance, control_rate_hz = None):
|
1156
1168
|
# Check to see if our firmware supports encoder filtering.
|
1157
1169
|
motor_position_style = await self.is_config_supported("motor_position.sources.0.pll_filter_hz")
|
1158
1170
|
servo_style = await self.is_config_supported("servo.encoder_filter.enabled")
|
@@ -1162,18 +1174,17 @@ class Stream:
|
|
1162
1174
|
if self.args.encoder_bw_hz:
|
1163
1175
|
desired_encoder_bw_hz = self.args.encoder_bw_hz
|
1164
1176
|
else:
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
desired_encoder_bw_hz = max(50, 2 * torque_bw_hz)
|
1177
|
+
# Don't let the encoder bandwidth be less than 10Hz by default.
|
1178
|
+
desired_encoder_bw_hz = max(10, 2 * torque_bw_hz)
|
1179
|
+
|
1180
|
+
# However, we limit the maximum encoder bandwidth for high
|
1181
|
+
# inductance motors, because they shouldn't be able to
|
1182
|
+
# accelerate that fast anyways.
|
1183
|
+
if inductance:
|
1184
|
+
# This is just a random constant that seems to work
|
1185
|
+
# well in practice.
|
1186
|
+
desired_encoder_bw_hz = min(
|
1187
|
+
desired_encoder_bw_hz, 2e-2 / inductance)
|
1177
1188
|
|
1178
1189
|
# And our bandwidth with the filter can be no larger than
|
1179
1190
|
# 1/10th the control rate.
|
@@ -1192,7 +1203,8 @@ class Stream:
|
|
1192
1203
|
await self.command(f"conf set servo.encoder_filter.kp {kp}")
|
1193
1204
|
await self.command(f"conf set servo.encoder_filter.ki {ki}")
|
1194
1205
|
elif motor_position_style:
|
1195
|
-
await self.
|
1206
|
+
commutation_source = await self.read_config_int("motor_position.commutation_source")
|
1207
|
+
await self.command(f"conf set motor_position.sources.{commutation_source}.pll_filter_hz {encoder_bw_hz}")
|
1196
1208
|
else:
|
1197
1209
|
assert False
|
1198
1210
|
return kp, ki, encoder_bw_hz
|
moteus/multiplex.py
CHANGED
@@ -244,21 +244,30 @@ class WriteFrame:
|
|
244
244
|
|
245
245
|
def __init__(self, buf):
|
246
246
|
self._buf = buf
|
247
|
+
self._size = 0
|
248
|
+
|
249
|
+
def size(self):
|
250
|
+
return self._size
|
247
251
|
|
248
252
|
def write(self, value, resolution):
|
249
253
|
self._buf.write(TYPES[resolution].pack(value))
|
254
|
+
self._size += TYPES[resolution].size
|
250
255
|
|
251
256
|
def write_int8(self, value):
|
252
257
|
self._buf.write(TYPES[INT8].pack(value))
|
258
|
+
self._size += 1
|
253
259
|
|
254
260
|
def write_int16(self, value):
|
255
261
|
self._buf.write(TYPES[INT16].pack(value))
|
262
|
+
self._size += 2
|
256
263
|
|
257
264
|
def write_int32(self, value):
|
258
265
|
self._buf.write(TYPES[INT32].pack(value))
|
266
|
+
self._size += 4
|
259
267
|
|
260
268
|
def write_f32(self, value):
|
261
269
|
self._buf.write(TYPES[F32].pack(value))
|
270
|
+
self._size += 4
|
262
271
|
|
263
272
|
def write_varuint(self, value):
|
264
273
|
while True:
|
@@ -266,6 +275,7 @@ class WriteFrame:
|
|
266
275
|
value >>= 7
|
267
276
|
this_byte |= 0x80 if value else 0x00
|
268
277
|
self._buf.write(bytes([this_byte]))
|
278
|
+
self._size += 1
|
269
279
|
|
270
280
|
if value == 0:
|
271
281
|
break
|
@@ -286,6 +296,7 @@ class WriteCombiner:
|
|
286
296
|
self.base_command = base_command
|
287
297
|
self.start_register = start_register
|
288
298
|
self.resolutions = resolutions
|
299
|
+
self.reply_size = 0
|
289
300
|
self._offset = 0
|
290
301
|
self._current_resolution = -1
|
291
302
|
|
@@ -320,6 +331,8 @@ class WriteCombiner:
|
|
320
331
|
|
321
332
|
write_command = [0x00, 0x04, 0x08, 0x0c][new_resolution] | self.base_command
|
322
333
|
|
334
|
+
start_size = self.writer.size()
|
335
|
+
|
323
336
|
if count <= 3:
|
324
337
|
# Use the shorthand formulation.
|
325
338
|
self.writer.write_int8(write_command + count)
|
@@ -329,4 +342,10 @@ class WriteCombiner:
|
|
329
342
|
self.writer.write_int8(count)
|
330
343
|
|
331
344
|
self.writer.write_varuint(self.start_register + this_offset)
|
345
|
+
|
346
|
+
end_size = self.writer.size()
|
347
|
+
|
348
|
+
self.reply_size += end_size - start_size
|
349
|
+
self.reply_size += count * resolution_size(new_resolution)
|
350
|
+
|
332
351
|
return True
|
moteus/version.py
CHANGED
@@ -2,22 +2,22 @@ moteus/__init__.py,sha256=1Prmih65X7Qz7WY8AUiSwUWXz3Dev8ggQS9xohL75M0,721
|
|
2
2
|
moteus/aioserial.py,sha256=lOBFPXManRBMsjMc1zuyw-NRt6CNVMvnj_mQqIZLpyI,1061
|
3
3
|
moteus/aiostream.py,sha256=SLDXwdBMHIWVTAmeUGG6ke7sntfNVxd9CqapzfniJOo,3678
|
4
4
|
moteus/calibrate_encoder.py,sha256=kY6mV1WkgCrD9z2YpRoqTTK_BUrRfop4_YJym9AQI-I,12403
|
5
|
-
moteus/command.py,sha256=
|
5
|
+
moteus/command.py,sha256=IXb0ToAg74fm8FYKPiOdjlzxosqdafLhqADffCvw5OY,1156
|
6
6
|
moteus/export.py,sha256=dI8QjdqrcI3pi5fKfP25PwLvsIlVJ695x0ta0PVMKx8,1628
|
7
7
|
moteus/fdcanusb.py,sha256=AMwqdvIRz4X9yA4qz8REuyFBfs3OcLcVqbGX28sEx4s,6729
|
8
|
-
moteus/moteus.py,sha256=
|
9
|
-
moteus/moteus_tool.py,sha256=
|
10
|
-
moteus/multiplex.py,sha256=
|
8
|
+
moteus/moteus.py,sha256=J7nzalhDTUvJq3h1FNjFnYLkrSVnL_IGDU1sw2PNsmU,43869
|
9
|
+
moteus/moteus_tool.py,sha256=L-7IBs9YHcbd2nc8SPwCEinHvzp09iVb_JeQCUtNM2U,66800
|
10
|
+
moteus/multiplex.py,sha256=EBOhAE-DHkS_AXtqUl2YEs745evvLMPIMeXQSYxF8zk,10102
|
11
11
|
moteus/posix_aioserial.py,sha256=3JFiY5p4dtC2ztg6N5SOffnNk9lNcjie02yjD3UlJWo,2971
|
12
12
|
moteus/pythoncan.py,sha256=lawewmkd9zQuE-Z1LurmpFD2iSWATei65SZb42um_Vg,3309
|
13
13
|
moteus/reader.py,sha256=jGADQTmONSBMQ25I5AqXELLqil2TEha1KjraPdOsf78,11932
|
14
14
|
moteus/regression.py,sha256=wpPlxAZ9nC9kfv0oX1K9W2AZNnBLbY8htAJz60SxIb8,1183
|
15
15
|
moteus/router.py,sha256=k4Tf6hWtHSgzznmdnj4NySe84-y9feYRxGz0yTrJtoc,2043
|
16
16
|
moteus/transport.py,sha256=3asI2A87eQDImLP74LNLtETaShQRiD9RuCjlxNY6AlE,1003
|
17
|
-
moteus/version.py,sha256=
|
17
|
+
moteus/version.py,sha256=zpTmrEA7ncnYPk73r5YQJOdYXTB_LBw60As5aQhXRA0,609
|
18
18
|
moteus/win32_aioserial.py,sha256=SZsnoBWE0Uwo4ZZF8ALB1WNPRY9NiaCOBz6VfvVcnxA,1841
|
19
|
-
moteus-0.3.
|
20
|
-
moteus-0.3.
|
21
|
-
moteus-0.3.
|
22
|
-
moteus-0.3.
|
23
|
-
moteus-0.3.
|
19
|
+
moteus-0.3.58.dist-info/METADATA,sha256=WCPxHMe0doKijEQK9-XAaN5FjXUxTLVdsFn1lRvP4wE,3417
|
20
|
+
moteus-0.3.58.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
21
|
+
moteus-0.3.58.dist-info/entry_points.txt,sha256=indCsEML1fmtWJU1WiV-d7UmmTaAMhyBLEc1iiKnexQ,57
|
22
|
+
moteus-0.3.58.dist-info/top_level.txt,sha256=aZzmI_yecTaDrdSp29pTJuowaSQ9dlIZheQpshGg4YQ,7
|
23
|
+
moteus-0.3.58.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|