moteus 0.3.72__py3-none-any.whl → 0.3.73__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/calibrate_encoder.py +1 -0
- moteus/moteus.py +103 -0
- moteus/moteus_tool.py +109 -3
- moteus/version.py +1 -1
- {moteus-0.3.72.dist-info → moteus-0.3.73.dist-info}/METADATA +11 -7
- {moteus-0.3.72.dist-info → moteus-0.3.73.dist-info}/RECORD +9 -9
- {moteus-0.3.72.dist-info → moteus-0.3.73.dist-info}/WHEEL +1 -1
- {moteus-0.3.72.dist-info → moteus-0.3.73.dist-info}/entry_points.txt +1 -0
- {moteus-0.3.72.dist-info → moteus-0.3.73.dist-info}/top_level.txt +0 -0
moteus/calibrate_encoder.py
CHANGED
moteus/moteus.py
CHANGED
@@ -252,6 +252,17 @@ class Register(enum.IntEnum):
|
|
252
252
|
MILLISECOND_COUNTER = 0x070
|
253
253
|
CLOCK_TRIM = 0x071
|
254
254
|
|
255
|
+
AUX1_PWM1 = 0x076,
|
256
|
+
AUX1_PWM2 = 0x077,
|
257
|
+
AUX1_PWM3 = 0x078,
|
258
|
+
AUX1_PWM4 = 0x079,
|
259
|
+
AUX1_PWM5 = 0x07a,
|
260
|
+
AUX2_PWM1 = 0x07b,
|
261
|
+
AUX2_PWM2 = 0x07c,
|
262
|
+
AUX2_PWM3 = 0x07d,
|
263
|
+
AUX2_PWM4 = 0x07e,
|
264
|
+
AUX2_PWM5 = 0x07f,
|
265
|
+
|
255
266
|
REGISTER_MAP_VERSION = 0x102
|
256
267
|
SERIAL_NUMBER = 0x120
|
257
268
|
SERIAL_NUMBER1 = 0x120
|
@@ -267,6 +278,16 @@ class Register(enum.IntEnum):
|
|
267
278
|
DRIVER_FAULT1 = 0x140
|
268
279
|
DRIVER_FAULT2 = 0x141
|
269
280
|
|
281
|
+
UUID1 = 0x150
|
282
|
+
UUID2 = 0x151
|
283
|
+
UUID3 = 0x152
|
284
|
+
UUID4 = 0x153
|
285
|
+
|
286
|
+
UUID_MASK1 = 0x0154
|
287
|
+
UUID_MASK2 = 0x0155
|
288
|
+
UUID_MASK3 = 0x0156
|
289
|
+
UUID_MASK4 = 0x0157
|
290
|
+
|
270
291
|
|
271
292
|
class Mode(enum.IntEnum):
|
272
293
|
"""Valid values for the Register.MODE register"""
|
@@ -347,6 +368,19 @@ class CurrentResolution:
|
|
347
368
|
q_A = mp.F32
|
348
369
|
|
349
370
|
|
371
|
+
class PwmResolution:
|
372
|
+
aux1_pwm1 = mp.INT16
|
373
|
+
aux1_pwm2 = mp.INT16
|
374
|
+
aux1_pwm3 = mp.INT16
|
375
|
+
aux1_pwm4 = mp.INT16
|
376
|
+
aux1_pwm5 = mp.INT16
|
377
|
+
aux2_pwm1 = mp.INT16
|
378
|
+
aux2_pwm2 = mp.INT16
|
379
|
+
aux2_pwm3 = mp.INT16
|
380
|
+
aux2_pwm4 = mp.INT16
|
381
|
+
aux2_pwm5 = mp.INT16
|
382
|
+
|
383
|
+
|
350
384
|
class Parser(mp.RegisterParser):
|
351
385
|
def read_position(self, resolution):
|
352
386
|
return self.read_mapped(resolution, 0.01, 0.0001, 0.00001)
|
@@ -507,6 +541,9 @@ def parse_register(parser, register, resolution):
|
|
507
541
|
return parser.read_int(resolution)
|
508
542
|
elif register == Register.CLOCK_TRIM:
|
509
543
|
return parser.read_int(resolution)
|
544
|
+
elif (register >= Register.AUX1_PWM1 and
|
545
|
+
register <= Register.AUX2_PWM5):
|
546
|
+
return parser.read_pwm(resolution)
|
510
547
|
else:
|
511
548
|
# We don't know what kind of value this is, so we don't know
|
512
549
|
# the units.
|
@@ -609,6 +646,7 @@ class Controller:
|
|
609
646
|
position_resolution=PositionResolution(),
|
610
647
|
vfoc_resolution=VFOCResolution(),
|
611
648
|
current_resolution=CurrentResolution(),
|
649
|
+
pwm_resolution=PwmResolution(),
|
612
650
|
transport=None,
|
613
651
|
can_prefix=0x0000):
|
614
652
|
self.id = id
|
@@ -616,6 +654,7 @@ class Controller:
|
|
616
654
|
self.position_resolution = position_resolution
|
617
655
|
self.vfoc_resolution = vfoc_resolution
|
618
656
|
self.current_resolution = current_resolution
|
657
|
+
self.pwm_resolution = pwm_resolution
|
619
658
|
self.transport = transport
|
620
659
|
self._parser = make_parser(id)
|
621
660
|
self._can_prefix = can_prefix
|
@@ -1315,6 +1354,70 @@ class Controller:
|
|
1315
1354
|
async def set_trim(self, *args, **kwargs):
|
1316
1355
|
return await self.execute(self.make_set_trim(*args, **kwargs))
|
1317
1356
|
|
1357
|
+
def make_aux_pwm(self, *,
|
1358
|
+
aux1_pwm1=None,
|
1359
|
+
aux1_pwm2=None,
|
1360
|
+
aux1_pwm3=None,
|
1361
|
+
aux1_pwm4=None,
|
1362
|
+
aux1_pwm5=None,
|
1363
|
+
aux2_pwm1=None,
|
1364
|
+
aux2_pwm2=None,
|
1365
|
+
aux2_pwm3=None,
|
1366
|
+
aux2_pwm4=None,
|
1367
|
+
aux2_pwm5=None,
|
1368
|
+
query=False,
|
1369
|
+
query_override=None):
|
1370
|
+
result = self._make_command(query=query, query_override=query_override)
|
1371
|
+
|
1372
|
+
pr = self.pwm_resolution
|
1373
|
+
resolutions = [
|
1374
|
+
pr.aux1_pwm1 if aux1_pwm1 is not None else mp.IGNORE,
|
1375
|
+
pr.aux1_pwm2 if aux1_pwm2 is not None else mp.IGNORE,
|
1376
|
+
pr.aux1_pwm3 if aux1_pwm3 is not None else mp.IGNORE,
|
1377
|
+
pr.aux1_pwm4 if aux1_pwm4 is not None else mp.IGNORE,
|
1378
|
+
pr.aux1_pwm5 if aux1_pwm5 is not None else mp.IGNORE,
|
1379
|
+
pr.aux2_pwm1 if aux2_pwm1 is not None else mp.IGNORE,
|
1380
|
+
pr.aux2_pwm2 if aux2_pwm2 is not None else mp.IGNORE,
|
1381
|
+
pr.aux2_pwm3 if aux2_pwm3 is not None else mp.IGNORE,
|
1382
|
+
pr.aux2_pwm4 if aux2_pwm4 is not None else mp.IGNORE,
|
1383
|
+
pr.aux2_pwm5 if aux2_pwm5 is not None else mp.IGNORE,
|
1384
|
+
]
|
1385
|
+
|
1386
|
+
data_buf = io.BytesIO()
|
1387
|
+
writer = Writer(data_buf)
|
1388
|
+
combiner = mp.WriteCombiner(
|
1389
|
+
writer, 0x00, int(Register.AUX1_PWM1), resolutions)
|
1390
|
+
|
1391
|
+
if combiner.maybe_write():
|
1392
|
+
writer.write_pwm(aux1_pwm1, pr.aux1_pwm1)
|
1393
|
+
if combiner.maybe_write():
|
1394
|
+
writer.write_pwm(aux1_pwm2, pr.aux1_pwm2)
|
1395
|
+
if combiner.maybe_write():
|
1396
|
+
writer.write_pwm(aux1_pwm3, pr.aux1_pwm3)
|
1397
|
+
if combiner.maybe_write():
|
1398
|
+
writer.write_pwm(aux1_pwm4, pr.aux1_pwm4)
|
1399
|
+
if combiner.maybe_write():
|
1400
|
+
writer.write_pwm(aux1_pwm5, pr.aux1_pwm5)
|
1401
|
+
if combiner.maybe_write():
|
1402
|
+
writer.write_pwm(aux2_pwm1, pr.aux2_pwm1)
|
1403
|
+
if combiner.maybe_write():
|
1404
|
+
writer.write_pwm(aux2_pwm2, pr.aux2_pwm2)
|
1405
|
+
if combiner.maybe_write():
|
1406
|
+
writer.write_pwm(aux2_pwm3, pr.aux2_pwm3)
|
1407
|
+
if combiner.maybe_write():
|
1408
|
+
writer.write_pwm(aux2_pwm4, pr.aux2_pwm4)
|
1409
|
+
if combiner.maybe_write():
|
1410
|
+
writer.write_pwm(aux2_pwm5, pr.aux2_pwm5)
|
1411
|
+
|
1412
|
+
self._format_query(query, query_override, data_buf, result)
|
1413
|
+
|
1414
|
+
result.data = data_buf.getvalue()
|
1415
|
+
|
1416
|
+
return result
|
1417
|
+
|
1418
|
+
async def set_aux_pwm(self, *args, **kwargs):
|
1419
|
+
return await self.execute(self.make_aux_pwm(*args, **kwargs))
|
1420
|
+
|
1318
1421
|
def _extract(self, value):
|
1319
1422
|
if len(value):
|
1320
1423
|
return value[0]
|
moteus/moteus_tool.py
CHANGED
@@ -52,6 +52,18 @@ def _wrap_neg_pi_to_pi(value):
|
|
52
52
|
return value
|
53
53
|
|
54
54
|
|
55
|
+
def lerp(array, ratio):
|
56
|
+
array_size = len(array)
|
57
|
+
|
58
|
+
left_index = int(math.floor(ratio * array_size))
|
59
|
+
right_index = (left_index + 1) % array_size
|
60
|
+
fraction = (ratio - left_index / array_size) * array_size
|
61
|
+
left_comp = array[left_index]
|
62
|
+
right_comp = array[right_index]
|
63
|
+
|
64
|
+
return (left_comp * (1.0 - fraction)) + (right_comp * fraction)
|
65
|
+
|
66
|
+
|
55
67
|
class FirmwareUpgrade:
|
56
68
|
'''This encodes "magic" rules about upgrading firmware, largely about
|
57
69
|
how to munge configuration options so as to not cause behavior
|
@@ -74,6 +86,42 @@ class FirmwareUpgrade:
|
|
74
86
|
lines = old_config.split(b'\n')
|
75
87
|
items = dict([line.split(b' ') for line in lines if b' ' in line])
|
76
88
|
|
89
|
+
if self.new <= 0x0108 and self.old >= 0x0109:
|
90
|
+
# When downgrading, we should warn if a motor thermistor
|
91
|
+
# value other than 47k is configured and enabled.
|
92
|
+
if (int(items.get(b'servo.enable_motor_temperature', '0')) != 0 and
|
93
|
+
int(float(items.get(b'servo.motor_thermistor_ohm', b'0.0'))) != 47000):
|
94
|
+
print("Motor thermistor values other than 47000 ohm not supported in firmware <= 0x0108, disabling")
|
95
|
+
items[b'servo.enable_motor_temperature'] = b'0'
|
96
|
+
|
97
|
+
items.pop(b'servo.motor_thermistor_ohm')
|
98
|
+
|
99
|
+
# Aux PWM out is not supported on <= 0x0108.
|
100
|
+
items.pop(b'aux1.pwm_period_us')
|
101
|
+
items.pop(b'aux2.pwm_period_us')
|
102
|
+
|
103
|
+
def make_key(mpsource, index):
|
104
|
+
return f'motor_position.sources.{mpsource}.compensation_table.{index}'.encode('utf8')
|
105
|
+
|
106
|
+
if make_key(0, 0) in items:
|
107
|
+
# Downsample encoder compensation bins.
|
108
|
+
print("Downsampling encoder compensation tables from version >= 0x0109")
|
109
|
+
for mpsource in range(0, 3):
|
110
|
+
bins = []
|
111
|
+
|
112
|
+
scale = float(items.pop(f'motor_position.sources.{mpsource}.compensation_scale'.encode('utf8'), 0.0)) / 127.0
|
113
|
+
new_size = 256
|
114
|
+
old_size = 32
|
115
|
+
ratio = new_size // old_size
|
116
|
+
|
117
|
+
for i in range(0, new_size):
|
118
|
+
key = make_key(mpsource, i)
|
119
|
+
bins.append(float(items.get(key)) * scale)
|
120
|
+
del items[key]
|
121
|
+
|
122
|
+
for i in range(0, old_size):
|
123
|
+
items[make_key(mpsource, i)] = str(bins[i*ratio]).encode('utf8')
|
124
|
+
|
77
125
|
if self.new <= 0x0107 and self.old >= 0x0108:
|
78
126
|
if float(items.get(b'servo.bemf_feedforward', '0')) == 0.0:
|
79
127
|
print("Reverting servo.bemf_feedforward to 1.0")
|
@@ -83,7 +131,7 @@ class FirmwareUpgrade:
|
|
83
131
|
# motor_position.output.sign was broken in older versions.
|
84
132
|
if int(items[b'motor_position.output.sign']) != 1:
|
85
133
|
print("WARNING: motor_position.output.sign==-1 is broken in order versions, disabling")
|
86
|
-
items[b'motor_position.output.sign'] = '1'
|
134
|
+
items[b'motor_position.output.sign'] = b'1'
|
87
135
|
pass
|
88
136
|
|
89
137
|
if self.new <= 0x0105 and self.old >= 0x0106:
|
@@ -344,6 +392,38 @@ class FirmwareUpgrade:
|
|
344
392
|
key = f'motor.offset.{i}'.encode('utf8')
|
345
393
|
items[key] = f'{offsets[i]}'.encode('utf8')
|
346
394
|
|
395
|
+
if self.new >= 0x0109 and self.old <= 0x0108:
|
396
|
+
# If we had a motor thermistor enabled in previous
|
397
|
+
# versions, it was with a value of 47000.
|
398
|
+
if int(items.get(b'servo.enable_motor_temperature', b'0')) != 0:
|
399
|
+
print("Thermistor from <= 0x0109 assumed to be 47000")
|
400
|
+
items[b'servo.motor_thermistor_ohm'] = b'47000'
|
401
|
+
|
402
|
+
def make_key(mpsource, index):
|
403
|
+
return f'motor_position.sources.{mpsource}.compensation_table.{index}'.encode('utf8')
|
404
|
+
|
405
|
+
new_size = 256
|
406
|
+
old_size = 32
|
407
|
+
ratio = new_size // old_size
|
408
|
+
|
409
|
+
if make_key(0, 0) in items:
|
410
|
+
print("Upsampling encoder compensation tables for version >= 0x0109")
|
411
|
+
for mpsource in range(0, 3):
|
412
|
+
old_bins = [float(items.get(make_key(mpsource, i)).decode('latin1')) for i in range(0, 32)]
|
413
|
+
scale = max([abs(x) for x in old_bins])
|
414
|
+
bins = []
|
415
|
+
for i in range(new_size):
|
416
|
+
if scale != 0.0:
|
417
|
+
old_i = i // ratio
|
418
|
+
value = lerp(old_bins, i / new_size)
|
419
|
+
int_value = int(127 * value / scale)
|
420
|
+
else:
|
421
|
+
int_value = 0
|
422
|
+
items[make_key(mpsource, i)] = str(int_value).encode('utf8')
|
423
|
+
|
424
|
+
items[f'motor_position.sources.{mpsource}.compensation_scale'.encode('utf8')] = str(scale).encode('utf8')
|
425
|
+
|
426
|
+
|
347
427
|
lines = [key + b' ' + value for key, value in items.items()]
|
348
428
|
return b'\n'.join(lines)
|
349
429
|
|
@@ -688,7 +768,13 @@ class Stream:
|
|
688
768
|
async def write_config_stream(self, fp):
|
689
769
|
errors = []
|
690
770
|
|
691
|
-
|
771
|
+
config_lines = fp.readlines()
|
772
|
+
|
773
|
+
for i, line in enumerate(config_lines):
|
774
|
+
if i % 20 == 0:
|
775
|
+
print(f"Writing config {100*i/len(config_lines):.0f}% ",
|
776
|
+
end='\r', flush=True)
|
777
|
+
|
692
778
|
line = line.rstrip()
|
693
779
|
if len(line) == 0:
|
694
780
|
continue
|
@@ -698,6 +784,8 @@ class Stream:
|
|
698
784
|
except moteus.CommandError as ce:
|
699
785
|
errors.append(line.decode('latin1'))
|
700
786
|
|
787
|
+
print()
|
788
|
+
|
701
789
|
if len(errors):
|
702
790
|
print("\nSome config could not be set:")
|
703
791
|
for line in errors:
|
@@ -861,6 +949,19 @@ class Stream:
|
|
861
949
|
|
862
950
|
return cal_voltage
|
863
951
|
|
952
|
+
async def clear_motor_offsets(self):
|
953
|
+
i = 0
|
954
|
+
while True:
|
955
|
+
try:
|
956
|
+
await self.command(f"conf set motor.offset.{i} 0")
|
957
|
+
except moteus.CommandError as ce:
|
958
|
+
if 'error setting' in ce.message:
|
959
|
+
# This means we hit the end of the offsets.
|
960
|
+
break
|
961
|
+
else:
|
962
|
+
raise
|
963
|
+
i += 1
|
964
|
+
|
864
965
|
async def do_calibrate(self):
|
865
966
|
self.firmware = await self.read_data("firmware")
|
866
967
|
|
@@ -870,6 +971,11 @@ class Stream:
|
|
870
971
|
print("This will move the motor, ensure it can spin freely!")
|
871
972
|
await asyncio.sleep(2.0)
|
872
973
|
|
974
|
+
# Force all existing offsets to 0, that way if we had a
|
975
|
+
# discontinuous offset error, sending the stop will be able to
|
976
|
+
# clear it (and we are about to overwrite them anyway).
|
977
|
+
await self.clear_motor_offsets()
|
978
|
+
|
873
979
|
# Clear any faults that may be there.
|
874
980
|
await self.command("d stop")
|
875
981
|
|
@@ -1852,7 +1958,7 @@ async def async_main():
|
|
1852
1958
|
type=float, default=0.1,
|
1853
1959
|
help='maximum allowed error in calibration')
|
1854
1960
|
parser.add_argument('--cal-max-kv-power-factor', type=float,
|
1855
|
-
default=1.
|
1961
|
+
default=1.25)
|
1856
1962
|
parser.add_argument('--cal-raw', metavar='FILE', type=str,
|
1857
1963
|
help='write raw calibration data')
|
1858
1964
|
|
moteus/version.py
CHANGED
@@ -1,23 +1,25 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: moteus
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.73
|
4
4
|
Summary: moteus brushless controller library and tools
|
5
5
|
Home-page: https://github.com/mjbots/moteus
|
6
6
|
Author: mjbots Robotic Systems
|
7
7
|
Author-email: info@mjbots.com
|
8
|
+
License: UNKNOWN
|
8
9
|
Keywords: moteus
|
10
|
+
Platform: UNKNOWN
|
9
11
|
Classifier: Development Status :: 3 - Alpha
|
10
12
|
Classifier: Intended Audience :: Developers
|
11
13
|
Classifier: License :: OSI Approved :: Apache Software License
|
12
14
|
Classifier: Programming Language :: Python :: 3
|
13
15
|
Requires-Python: >=3.7, <4
|
14
16
|
Description-Content-Type: text/markdown
|
15
|
-
Requires-Dist:
|
16
|
-
Requires-Dist:
|
17
|
-
Requires-Dist: pyelftools >=0.26
|
18
|
-
Requires-Dist:
|
19
|
-
Requires-Dist:
|
20
|
-
Requires-Dist:
|
17
|
+
Requires-Dist: importlib-metadata (>=3.6)
|
18
|
+
Requires-Dist: numpy (<2)
|
19
|
+
Requires-Dist: pyelftools (>=0.26)
|
20
|
+
Requires-Dist: pyserial (>=3.5)
|
21
|
+
Requires-Dist: python-can (>=3.3)
|
22
|
+
Requires-Dist: scipy (>=1.8.0)
|
21
23
|
Requires-Dist: pywin32 ; platform_system == "Windows"
|
22
24
|
|
23
25
|
# Python bindings for moteus brushless controller #
|
@@ -119,3 +121,5 @@ qr.torque = moteus.F32
|
|
119
121
|
|
120
122
|
c = moteus.Controller(position_resolution=pr, query_resolution=qr)
|
121
123
|
```
|
124
|
+
|
125
|
+
|
@@ -1,12 +1,12 @@
|
|
1
1
|
moteus/__init__.py,sha256=DxasQre5HmK3BS3I35K8GEUvFZF3_OE_hjVzQy-seIE,739
|
2
2
|
moteus/aioserial.py,sha256=GeWuvsZKCRrfBN33JZFjtBXPr-0sKpQv9shRn2ulcDA,1079
|
3
3
|
moteus/aiostream.py,sha256=YAkVF6QWsA49vqO-GgXEohDghqm_-nnajJzhO_Q9qNQ,3696
|
4
|
-
moteus/calibrate_encoder.py,sha256=
|
4
|
+
moteus/calibrate_encoder.py,sha256=R3gWoKY-ikYlXViiCrhX_0BH7Ahx3T7zvDjX47go-Wc,15167
|
5
5
|
moteus/command.py,sha256=UkOsbtkso6Oyex8CfbpAKpBNriik519ymxL86EZGkRs,1169
|
6
6
|
moteus/export.py,sha256=vRIfldaqz1eHtWo3993SvatATtu73TZbejL0hzQe8YE,1646
|
7
7
|
moteus/fdcanusb.py,sha256=7PrQiCTROY96gdT2zSZYU1bOCriw-I7H6NspaZpiEx4,7431
|
8
|
-
moteus/moteus.py,sha256=
|
9
|
-
moteus/moteus_tool.py,sha256=
|
8
|
+
moteus/moteus.py,sha256=vImSRBn6VEmoijD6hvrSRVxuv1_xVaEJU3F_3Wi6GiE,52498
|
9
|
+
moteus/moteus_tool.py,sha256=ALwXiDWVwiAx9yJu0o-2eKd47wyKH5mRPq264mZrn5E,79662
|
10
10
|
moteus/multiplex.py,sha256=LF6MuelzYHqqsCJuCB9YeEyUA03eBaTYRwAVotX3qm8,10120
|
11
11
|
moteus/posix_aioserial.py,sha256=2oDrw8TBEwuEQjY41g9rHeuFeffcPHqMwNS3nf5NVq8,3137
|
12
12
|
moteus/pythoncan.py,sha256=ofotOrDuaFhTLvaokaO3EJK6quVc75Bq-ue70lDMtXI,4071
|
@@ -14,10 +14,10 @@ moteus/reader.py,sha256=9i1-h4aGd4syfqtWJcpg70Bl-bmunkGU4FmXmOLyRt8,12121
|
|
14
14
|
moteus/regression.py,sha256=M5gjDBYJQ64iBXIrvBhMkD8TYhtlnQ85x8U4py0niGA,1196
|
15
15
|
moteus/router.py,sha256=501W5GZ12rFoc1lmcH3S7IYsoc-Q_-FJ4B3i37RzE3Q,2061
|
16
16
|
moteus/transport.py,sha256=WhkW2G9i25lkOlO55eI5_oXmU0PhDmxTeJ75Sg_7nTI,1021
|
17
|
-
moteus/version.py,sha256=
|
17
|
+
moteus/version.py,sha256=5_fWVR7dSRZGbeKSGDI9a1MBAxaHKTOCWtgVlCY30BE,627
|
18
18
|
moteus/win32_aioserial.py,sha256=culdl-vYxBKD5n2s5LkIMGyUaHyCcEc8BL5-DWEaxX8,2025
|
19
|
-
moteus-0.3.
|
20
|
-
moteus-0.3.
|
21
|
-
moteus-0.3.
|
22
|
-
moteus-0.3.
|
23
|
-
moteus-0.3.
|
19
|
+
moteus-0.3.73.dist-info/METADATA,sha256=HIVrIqvoZY517yT3s_Euh10uzoZjYn4KmSHj2r_7K04,3490
|
20
|
+
moteus-0.3.73.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
21
|
+
moteus-0.3.73.dist-info/entry_points.txt,sha256=indCsEML1fmtWJU1WiV-d7UmmTaAMhyBLEc1iiKnexQ,57
|
22
|
+
moteus-0.3.73.dist-info/top_level.txt,sha256=aZzmI_yecTaDrdSp29pTJuowaSQ9dlIZheQpshGg4YQ,7
|
23
|
+
moteus-0.3.73.dist-info/RECORD,,
|
File without changes
|