moteus 0.3.58__py3-none-any.whl → 0.3.59__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/fdcanusb.py CHANGED
@@ -173,8 +173,11 @@ class Fdcanusb:
173
173
  bus_id = (command.destination |
174
174
  (0x8000 if command.reply_required else 0) |
175
175
  (command.can_prefix << 16))
176
+ hexdata = _hexify(command.data)
177
+ on_wire_size = self._round_up_dlc(len(command.data))
178
+ hexdata += '50' * (on_wire_size - len(command.data))
176
179
  cmd = "can send {:04x} {}{}\n".format(
177
- bus_id, _hexify(command.data), self._send_flags).encode('latin1')
180
+ bus_id, hexdata, self._send_flags).encode('latin1')
178
181
  self._serial.write(cmd)
179
182
  if self._debug_log:
180
183
  self._debug_log.write(f'{time.time()} > '.encode('latin1') +
@@ -197,3 +200,22 @@ class Fdcanusb:
197
200
  message.data = _dehexify(fields[2])
198
201
  message.arbitration_id = int(fields[1], 16)
199
202
  return message
203
+
204
+ def _round_up_dlc(self, size):
205
+ if size <= 8:
206
+ return size
207
+ if size <= 12:
208
+ return 12
209
+ if size <= 16:
210
+ return 16
211
+ if size <= 20:
212
+ return 20
213
+ if size <= 24:
214
+ return 24
215
+ if size <= 32:
216
+ return 32
217
+ if size <= 48:
218
+ return 48
219
+ if size <= 64:
220
+ return 64
221
+ return size
moteus/moteus.py CHANGED
@@ -14,6 +14,7 @@
14
14
 
15
15
  import asyncio
16
16
  import argparse
17
+ import copy
17
18
  import enum
18
19
  import importlib_metadata
19
20
  import io
@@ -617,12 +618,15 @@ class Controller:
617
618
  self.transport = get_singleton_transport()
618
619
  return self.transport
619
620
 
620
- def _make_query_data(self):
621
+ def _make_query_data(self, query_resolution=None):
622
+ if query_resolution is None:
623
+ query_resolution = self.query_resolution
624
+
621
625
  expected_reply_size = 0
622
626
 
623
627
  buf = io.BytesIO()
624
628
  writer = Writer(buf)
625
- qr = self.query_resolution
629
+ qr = query_resolution
626
630
  c1 = mp.WriteCombiner(writer, 0x10, int(Register.MODE), [
627
631
  qr.mode,
628
632
  qr.position,
@@ -672,21 +676,37 @@ class Controller:
672
676
 
673
677
  return buf.getvalue(), expected_reply_size
674
678
 
675
- def _make_command(self, *, query, source=0):
679
+ def _format_query(self, query, query_override, data_buf, result):
680
+ if query_override is not None:
681
+ query_data, expected_reply_size = \
682
+ self._make_query_data(query_override)
683
+ data_buf.write(query_data)
684
+ result.expected_reply_size = expected_reply_size
685
+ elif query:
686
+ data_buf.write(self._query_data)
687
+ result.expected_reply_size = self._default_query_reply_size
688
+
689
+ def _make_command(self, *, query, query_override=None, source=0):
676
690
  result = cmd.Command()
677
691
 
678
692
  result.destination = self.id
679
693
  result.source = source
680
- result.reply_required = query
694
+ result.reply_required = query or (query_override is not None)
681
695
  result.parse = self._parser
682
696
  result.can_prefix = self._can_prefix
683
697
  result.expected_reply_size = self._default_query_reply_size if query else 0
684
698
 
685
699
  return result
686
700
 
687
- def make_query(self):
688
- result = self._make_command(query=True)
689
- result.data = self._query_data
701
+ def make_query(self, query_override=None):
702
+ result = self._make_command(
703
+ query=True, query_override=query_override)
704
+ if query_override:
705
+ result.data, result.expected_reply_size = \
706
+ self._make_query_data(query_override)
707
+ else:
708
+ result.data = self._query_data
709
+ result.expected_reply_size = self._default_query_reply_size
690
710
  return result;
691
711
 
692
712
  async def query(self, **kwargs):
@@ -718,11 +738,12 @@ class Controller:
718
738
  async def custom_query(self, *args, **kwargs):
719
739
  return await self.execute(self.make_custom_query(*args, **kwargs))
720
740
 
721
- def make_stop(self, *, query=False):
741
+ def make_stop(self, *, query=False, query_override=None):
722
742
  """Return a moteus.Command structure with data necessary to send a
723
743
  stop mode command."""
724
744
 
725
- result = self._make_command(query=query)
745
+ result = self._make_command(
746
+ query=query, query_override=query_override)
726
747
 
727
748
  data_buf = io.BytesIO()
728
749
  writer = Writer(data_buf)
@@ -730,8 +751,7 @@ class Controller:
730
751
  writer.write_int8(int(Register.MODE))
731
752
  writer.write_int8(int(Mode.STOPPED))
732
753
 
733
- if query:
734
- data_buf.write(self._query_data)
754
+ self._format_query(query, query_override, data_buf, result)
735
755
 
736
756
  result.data = data_buf.getvalue()
737
757
 
@@ -743,12 +763,14 @@ class Controller:
743
763
  def make_set_output(self, *,
744
764
  position=0.0,
745
765
  query=False,
766
+ query_override=None,
746
767
  cmd=None
747
768
  ):
748
769
  """Return a moteus.Command structure with data necessary to send a
749
770
  set output nearest command."""
750
771
 
751
- result = self._make_command(query=query)
772
+ result = self._make_command(
773
+ query=query, query_override=query_override)
752
774
 
753
775
  data_buf = io.BytesIO()
754
776
  writer = Writer(data_buf)
@@ -756,23 +778,26 @@ class Controller:
756
778
  writer.write_varuint(cmd)
757
779
  writer.write_f32(position)
758
780
 
759
- if query:
760
- data_buf.write(self._query_data)
781
+ self._format_query(query, query_override, data_buf, result)
761
782
 
762
783
  result.data = data_buf.getvalue()
763
784
  return result
764
785
 
765
786
  def make_set_output_nearest(self, *,
766
787
  position=0.0,
767
- query=False):
788
+ query=False,
789
+ query_override=None):
768
790
  return self.make_set_output(
769
- position=position, query=query, cmd=Register.SET_OUTPUT_NEAREST)
791
+ position=position, query=query, query_override=query_override,
792
+ cmd=Register.SET_OUTPUT_NEAREST)
770
793
 
771
794
  def make_set_output_exact(self, *,
772
795
  position=0.0,
773
- query=False):
796
+ query=False,
797
+ query_override=None):
774
798
  return self.make_set_output(
775
- position=position, query=query, cmd=Register.SET_OUTPUT_EXACT)
799
+ position=position, query=query, query_override=query_override,
800
+ cmd=Register.SET_OUTPUT_EXACT)
776
801
 
777
802
  async def set_output(self, *args, cmd=None, **kwargs):
778
803
  return await self.execute(self.make_set_output(**kwargs, cmd=cmd))
@@ -788,15 +813,20 @@ class Controller:
788
813
  # "make/set_rezero".
789
814
  def make_rezero(self, *,
790
815
  rezero=0.0,
791
- query=False):
816
+ query=False,
817
+ query_override=None):
792
818
  return self.make_set_output(
793
- position=rezero, query=query, cmd=Register.SET_OUTPUT_NEAREST)
819
+ position=rezero, query=query, query_override=query_override,
820
+ cmd=Register.SET_OUTPUT_NEAREST)
794
821
 
795
822
  async def set_rezero(self, *args, **kwargs):
796
823
  return await self.execute(self.make_rezero(**kwargs))
797
824
 
798
- def make_require_reindex(self):
799
- result = self._make_command(query=False)
825
+ def make_require_reindex(self,
826
+ query=False,
827
+ query_override=None):
828
+ result = self._make_command(
829
+ query=query, query_override=query_override)
800
830
 
801
831
  data_buf = io.BytesIO()
802
832
  writer = Writer(data_buf)
@@ -807,8 +837,9 @@ class Controller:
807
837
  result.data = data_buf.getvalue()
808
838
  return result
809
839
 
810
- async def set_require_reindex(self):
811
- return await self.execute(self.make_require_reindex())
840
+ async def set_require_reindex(self, query=False, query_override=None):
841
+ return await self.execute(self.make_require_reindex(
842
+ query=query, query_override=query_override))
812
843
 
813
844
  def make_position(self,
814
845
  *,
@@ -823,11 +854,13 @@ class Controller:
823
854
  velocity_limit=None,
824
855
  accel_limit=None,
825
856
  fixed_voltage_override=None,
826
- query=False):
857
+ query=False,
858
+ query_override=None):
827
859
  """Return a moteus.Command structure with data necessary to send a
828
860
  position mode command with the given values."""
829
861
 
830
- result = self._make_command(query=query)
862
+ result = self._make_command(
863
+ query=query, query_override=query_override)
831
864
 
832
865
  pr = self.position_resolution
833
866
  resolutions = [
@@ -877,8 +910,7 @@ class Controller:
877
910
  if combiner.maybe_write():
878
911
  writer.write_voltage(fixed_voltage_override, pr.fixed_voltage_override)
879
912
 
880
- if query:
881
- data_buf.write(self._query_data)
913
+ self._format_query(query, query_override, data_buf, result)
882
914
 
883
915
  result.data = data_buf.getvalue()
884
916
 
@@ -887,16 +919,51 @@ class Controller:
887
919
  async def set_position(self, *args, **kwargs):
888
920
  return await self.execute(self.make_position(**kwargs))
889
921
 
922
+ async def set_position_wait_complete(
923
+ self,
924
+ period_s=0.025,
925
+ query_override=None,
926
+ *args, **kwargs):
927
+ """Repeatedly send a position mode command to a device until it
928
+ reports that the trajectory has been completed.
929
+
930
+ If the controller is unresponsive, this method will never return.
931
+ """
932
+
933
+ if query_override is None:
934
+ query_override = copy.deepcopy(self.query_resolution)
935
+ else:
936
+ query_override = copy.deepcopy(query_override)
937
+
938
+ query_override.trajectory_complete = mp.INT8
939
+
940
+ count = 2
941
+ while True:
942
+ result = await self.set_position(
943
+ query_override=query_override, *args, **kwargs)
944
+
945
+ if result is not None:
946
+ count = max(count - 1, 0)
947
+
948
+ if (count == 0 and
949
+ result is not None and
950
+ result.values[Register.TRAJECTORY_COMPLETE]):
951
+ return result
952
+
953
+ await asyncio.sleep(period_s)
954
+
890
955
  def make_vfoc(self,
891
956
  *,
892
957
  theta,
893
958
  voltage,
894
959
  theta_rate=0.0,
895
- query=False):
960
+ query=False,
961
+ query_override=None):
896
962
  """Return a moteus.Command structure with data necessary to send a
897
963
  voltage mode FOC command."""
898
964
 
899
- result = self._make_command(query=query)
965
+ result = self._make_command(
966
+ query=query, query_override=query_override)
900
967
  cr = self.vfoc_resolution
901
968
  resolutions = [
902
969
  cr.theta if theta is not None else mp.IGNORE,
@@ -932,8 +999,7 @@ class Controller:
932
999
  if combiner.maybe_write():
933
1000
  writer.write_velocity(theta_rate / math.pi, cr.theta_rate)
934
1001
 
935
- if query:
936
- data_buf.write(self._query_data)
1002
+ self._format_query(query, query_override, data_buf, result)
937
1003
 
938
1004
  result.data = data_buf.getvalue()
939
1005
 
@@ -946,12 +1012,14 @@ class Controller:
946
1012
  *,
947
1013
  d_A,
948
1014
  q_A,
949
- query=False):
1015
+ query=False,
1016
+ query_override=None):
950
1017
  """Return a moteus.Command structure with data necessary to send a
951
1018
  current mode command.
952
1019
  """
953
1020
 
954
- result = self._make_command(query=query)
1021
+ result = self._make_command(
1022
+ query=query, query_override=query_override)
955
1023
  cr = self.current_resolution
956
1024
  resolutions = [
957
1025
  cr.d_A if d_A is not None else mp.IGNORE,
@@ -976,8 +1044,7 @@ class Controller:
976
1044
  if combiner.maybe_write():
977
1045
  writer.write_current(d_A, cr.d_A)
978
1046
 
979
- if query:
980
- data_buf.write(self._query_data)
1047
+ self._format_query(query, query_override, data_buf, result)
981
1048
 
982
1049
  result.data = data_buf.getvalue()
983
1050
 
@@ -997,11 +1064,13 @@ class Controller:
997
1064
  maximum_torque=None,
998
1065
  stop_position=None,
999
1066
  watchdog_timeout=None,
1000
- query=False):
1067
+ query=False,
1068
+ query_override=None):
1001
1069
  """Return a moteus.Command structure with data necessary to send a
1002
1070
  within mode command with the given values."""
1003
1071
 
1004
- result = self._make_command(query=query)
1072
+ result = self._make_command(
1073
+ query=query, query_override=query_override)
1005
1074
 
1006
1075
  pr = self.position_resolution
1007
1076
  resolutions = [
@@ -1040,8 +1109,7 @@ class Controller:
1040
1109
  if combiner.maybe_write():
1041
1110
  writer.write_time(watchdog_timeout, pr.watchdog_timeout)
1042
1111
 
1043
- if query:
1044
- data_buf.write(self._query_data)
1112
+ self._format_query(query, query_override, data_buf, result)
1045
1113
 
1046
1114
  result.data = data_buf.getvalue()
1047
1115
 
@@ -1050,8 +1118,9 @@ class Controller:
1050
1118
  async def set_stay_within(self, *args, **kwargs):
1051
1119
  return await self.execute(self.make_stay_within(**kwargs))
1052
1120
 
1053
- def make_brake(self, *, query=False):
1054
- result = self._make_command(query=query)
1121
+ def make_brake(self, *, query=False, query_override=None):
1122
+ result = self._make_command(
1123
+ query=query, query_override=query_override)
1055
1124
 
1056
1125
  data_buf = io.BytesIO()
1057
1126
  writer = Writer(data_buf)
@@ -1059,8 +1128,7 @@ class Controller:
1059
1128
  writer.write_int8(int(Register.MODE))
1060
1129
  writer.write_int8(int(Mode.BRAKE))
1061
1130
 
1062
- if query:
1063
- data_buf.write(self._query_data)
1131
+ self._format_query(query, query_override, data_buf, result)
1064
1132
 
1065
1133
  result.data = data_buf.getvalue()
1066
1134
 
@@ -1069,7 +1137,8 @@ class Controller:
1069
1137
  async def set_brake(self, *args, **kwargs):
1070
1138
  return await self.execute(self.make_brake(**kwargs))
1071
1139
 
1072
- def make_write_gpio(self, aux1=None, aux2=None, query=False):
1140
+ def make_write_gpio(self, aux1=None, aux2=None,
1141
+ query=False, query_override=None):
1073
1142
  """Return a moteus.Command structure with data necessary to set one or
1074
1143
  more GPIO registers.
1075
1144
 
@@ -1077,7 +1146,8 @@ class Controller:
1077
1146
  significant bit is pin 0 on the respective port.
1078
1147
  """
1079
1148
 
1080
- result = self._make_command(query=query)
1149
+ result = self._make_command(
1150
+ query=query, query_override=query_override)
1081
1151
 
1082
1152
  data_buf = io.BytesIO()
1083
1153
  writer = Writer(data_buf)
@@ -1093,8 +1163,7 @@ class Controller:
1093
1163
  if combiner.maybe_write():
1094
1164
  writer.write_int8(aux2)
1095
1165
 
1096
- if query:
1097
- data_buf.write(self._query_data)
1166
+ self._format_query(query, query_override, data_buf, result)
1098
1167
 
1099
1168
  result.data = data_buf.getvalue()
1100
1169
  return result
moteus/pythoncan.py CHANGED
@@ -87,10 +87,13 @@ class PythonCan:
87
87
  arbitration_id = (command.destination |
88
88
  (0x8000 if reply_required else 0) |
89
89
  (command.can_prefix << 16))
90
+ on_wire_size = self._round_up_dlc(len(command.data))
91
+ full_message = (command.data +
92
+ bytes([0x50]) * (on_wire_size - len(command.data)))
90
93
  message = can.Message(arbitration_id=arbitration_id,
91
94
  is_extended_id=(arbitration_id >= 0x7ff),
92
- dlc=len(command.data),
93
- data=bytearray(command.data),
95
+ dlc=on_wire_size,
96
+ data=full_message,
94
97
  is_fd=True,
95
98
  bitrate_switch=not self._disable_brs)
96
99
 
@@ -99,3 +102,22 @@ class PythonCan:
99
102
  async def read(self):
100
103
  self._maybe_setup()
101
104
  return await self._reader.get_message()
105
+
106
+ def _round_up_dlc(self, size):
107
+ if size <= 8:
108
+ return size
109
+ if size <= 12:
110
+ return 12
111
+ if size <= 16:
112
+ return 16
113
+ if size <= 20:
114
+ return 20
115
+ if size <= 24:
116
+ return 24
117
+ if size <= 32:
118
+ return 32
119
+ if size <= 48:
120
+ return 48
121
+ if size <= 64:
122
+ return 64
123
+ return size
moteus/version.py CHANGED
@@ -12,4 +12,4 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- VERSION="0.3.58"
15
+ VERSION="0.3.59"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: moteus
3
- Version: 0.3.58
3
+ Version: 0.3.59
4
4
  Summary: moteus brushless controller library and tools
5
5
  Home-page: https://github.com/mjbots/moteus
6
6
  Author: mjbots Robotic Systems
@@ -4,20 +4,20 @@ moteus/aiostream.py,sha256=SLDXwdBMHIWVTAmeUGG6ke7sntfNVxd9CqapzfniJOo,3678
4
4
  moteus/calibrate_encoder.py,sha256=kY6mV1WkgCrD9z2YpRoqTTK_BUrRfop4_YJym9AQI-I,12403
5
5
  moteus/command.py,sha256=IXb0ToAg74fm8FYKPiOdjlzxosqdafLhqADffCvw5OY,1156
6
6
  moteus/export.py,sha256=dI8QjdqrcI3pi5fKfP25PwLvsIlVJ695x0ta0PVMKx8,1628
7
- moteus/fdcanusb.py,sha256=AMwqdvIRz4X9yA4qz8REuyFBfs3OcLcVqbGX28sEx4s,6729
8
- moteus/moteus.py,sha256=J7nzalhDTUvJq3h1FNjFnYLkrSVnL_IGDU1sw2PNsmU,43869
7
+ moteus/fdcanusb.py,sha256=6nfnqxwJqyqX0MOn7pj3-kqWq-Vzwx5M8I0wUux3RnA,7294
8
+ moteus/moteus.py,sha256=7lObHdVYCELclm6JMg-QygbAmRgNyQrS0BxkOjERJlo,46993
9
9
  moteus/moteus_tool.py,sha256=L-7IBs9YHcbd2nc8SPwCEinHvzp09iVb_JeQCUtNM2U,66800
10
10
  moteus/multiplex.py,sha256=EBOhAE-DHkS_AXtqUl2YEs745evvLMPIMeXQSYxF8zk,10102
11
11
  moteus/posix_aioserial.py,sha256=3JFiY5p4dtC2ztg6N5SOffnNk9lNcjie02yjD3UlJWo,2971
12
- moteus/pythoncan.py,sha256=lawewmkd9zQuE-Z1LurmpFD2iSWATei65SZb42um_Vg,3309
12
+ moteus/pythoncan.py,sha256=629d_DUfunyXpMZcaA6ICuvgodes-KH7OVDC7smco7s,3886
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=zpTmrEA7ncnYPk73r5YQJOdYXTB_LBw60As5aQhXRA0,609
17
+ moteus/version.py,sha256=lYdyuBwllEdH5WL5gQPVzkIpGpTIZtY-1x9F1WUWUa8,609
18
18
  moteus/win32_aioserial.py,sha256=SZsnoBWE0Uwo4ZZF8ALB1WNPRY9NiaCOBz6VfvVcnxA,1841
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,,
19
+ moteus-0.3.59.dist-info/METADATA,sha256=Wye8gTlX1__CYw-VJcnfC7w7ynANVPsjOkcGNtxGgOU,3417
20
+ moteus-0.3.59.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
21
+ moteus-0.3.59.dist-info/entry_points.txt,sha256=indCsEML1fmtWJU1WiV-d7UmmTaAMhyBLEc1iiKnexQ,57
22
+ moteus-0.3.59.dist-info/top_level.txt,sha256=aZzmI_yecTaDrdSp29pTJuowaSQ9dlIZheQpshGg4YQ,7
23
+ moteus-0.3.59.dist-info/RECORD,,