moteus 0.3.87__py3-none-any.whl → 0.3.88__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
@@ -136,17 +136,34 @@ class Fdcanusb:
136
136
  # individually.
137
137
  return [await self._do_command(x) for x in commands]
138
138
 
139
+ def _parse_message(self, line):
140
+ fields = line.split(b" ")
141
+ message = CanMessage()
142
+ message.data = _dehexify(fields[2])
143
+ message.arbitration_id = int(fields[1], 16)
144
+
145
+ flags = fields[3] if len(fields) > 3 else ''
146
+ if b'E' in flags:
147
+ message.is_extended_id = True
148
+ if b'B' in flags:
149
+ message.bitrate_switch = True
150
+ if b'F' in flags:
151
+ message.is_fd = True
152
+
153
+ return message
154
+
139
155
  async def _do_command(self, command):
140
156
  await self.write(command)
141
157
  reply_required = command.reply_required
142
158
 
143
159
  # Get the OK response.
144
- ok_response = await self._readline(self._serial)
145
- if not ok_response.startswith(b"OK"):
146
- raise RuntimeError("fdcanusb lost synchronization, got: " +
147
- ok_response.decode('latin1'))
160
+ while True:
161
+ ok_response = await self._readline(self._serial)
162
+ if ok_response.startswith(b"OK"):
163
+ break
164
+ # Ignore spurious responses until we get an OK.
148
165
 
149
- if reply_required:
166
+ while reply_required:
150
167
  line = await self._readline(self._serial)
151
168
 
152
169
  if not line.startswith(b"rcv"):
@@ -157,16 +174,15 @@ class Fdcanusb:
157
174
  self._debug_log.write(f'{time.time()} < '.encode('latin1') +
158
175
  line.rstrip() + b'\n')
159
176
 
160
- fields = line.split(b" ")
161
- message = CanMessage()
162
- message.data = _dehexify(fields[2])
163
- message.arbitration_id = int(fields[1], 16)
177
+ message = self._parse_message(line)
178
+
179
+ moteus_id = (message.arbitration_id >> 8) & 0x7f
164
180
 
165
- # We are assuming that only one device is responding at a
166
- # time, thus we don't even need to look at the
167
- # source/destination or CAN prefix.
181
+ if command.raw or moteus_id == command.destination:
182
+ return command.parse(message)
168
183
 
169
- return command.parse(message)
184
+ # We are not raw and the message wasn't from the device we
185
+ # were writing to, so just loop and try some more.
170
186
 
171
187
  async def write(self, command):
172
188
  # This merely sends a command and doesn't even wait for an OK
@@ -201,10 +217,7 @@ class Fdcanusb:
201
217
  self._debug_log.write(f'{time.time()} < '.encode('latin1') +
202
218
  line.rstrip() + b'\n')
203
219
 
204
- fields = line.split(b" ")
205
- message = CanMessage()
206
- message.data = _dehexify(fields[2])
207
- message.arbitration_id = int(fields[1], 16)
220
+ message = self._parse_message(line)
208
221
  return message
209
222
 
210
223
  def _round_up_dlc(self, size):
moteus/moteus.py CHANGED
@@ -578,7 +578,7 @@ class Result:
578
578
  def make_parser(id):
579
579
  def parse(message):
580
580
  result = Result()
581
- result.id = id
581
+ result.id = (message.arbitration_id >> 8) & 0x7f
582
582
  result.values = parse_reply(message.data)
583
583
 
584
584
  # We store these things just for reference, so that our
@@ -630,6 +630,11 @@ def make_diagnostic_parser(id, channel):
630
630
  return parse
631
631
 
632
632
 
633
+ class FaultError(RuntimeError):
634
+ def __init__(self, mode, code):
635
+ super(FaultError, self).__init__(f"Fault mode={mode} code={code}")
636
+
637
+
633
638
  class Controller:
634
639
  """Operates a single moteus controller across some communication
635
640
  medium.
@@ -1019,6 +1024,9 @@ class Controller:
1019
1024
  reports that the trajectory has been completed.
1020
1025
 
1021
1026
  If the controller is unresponsive, this method will never return.
1027
+
1028
+ If the controller reports a fault or position mode timeout, a
1029
+ FaultError exception will be raised.
1022
1030
  """
1023
1031
 
1024
1032
  if query_override is None:
@@ -1026,6 +1034,10 @@ class Controller:
1026
1034
  else:
1027
1035
  query_override = copy.deepcopy(query_override)
1028
1036
 
1037
+ if query_override.mode == mp.IGNORE:
1038
+ query_override.mode = mp.INT8
1039
+ if query_override.fault == mp.IGNORE:
1040
+ query_override.fault = mp.INT8
1029
1041
  query_override.trajectory_complete = mp.INT8
1030
1042
 
1031
1043
  count = 2
@@ -1041,6 +1053,12 @@ class Controller:
1041
1053
  result.values[Register.TRAJECTORY_COMPLETE]):
1042
1054
  return result
1043
1055
 
1056
+ current_mode = result.values.get(Register.MODE, Mode.STOPPED)
1057
+ fault_code = result.values.get(Register.FAULT, 0)
1058
+
1059
+ if current_mode == Mode.FAULT or current_mode == Mode.TIMEOUT:
1060
+ raise FaultError(current_mode, fault_code)
1061
+
1044
1062
  await asyncio.sleep(period_s)
1045
1063
 
1046
1064
  def make_vfoc(self,
moteus/moteus_tool.py CHANGED
@@ -1618,13 +1618,15 @@ class Stream:
1618
1618
  # non-linear, corrupting the result.
1619
1619
 
1620
1620
  # What we'll do is take the very last result, and the last
1621
- # result that is less than 70% of the current of the last
1621
+ # result that is less than X% of the current of the last
1622
1622
  # result.
1623
1623
 
1624
1624
  last_result = results[-1]
1625
1625
 
1626
- less_than = [x for x in results if x[1] < 0.60 * last_result[1]][-1]
1627
-
1626
+ less_than_X = [x for x in results if x[1] < 0.60 * last_result[1]]
1627
+ if len(less_than_X) == 0:
1628
+ raise RuntimeError(f"Could not detect resistance, is motor connected? Peak current only {last_result[1]:.3f}A w/ {last_result[0]:.3f}V applied.")
1629
+ less_than = less_than_X[-1]
1628
1630
 
1629
1631
  resistance = ((last_result[0] - less_than[0]) /
1630
1632
  (last_result[1] - less_than[1]))
moteus/pythoncan.py CHANGED
@@ -95,16 +95,16 @@ class PythonCan:
95
95
  async def _do_command(self, command):
96
96
  await self.write(command)
97
97
 
98
- if not command.reply_required:
99
- return None
98
+ while command.reply_required:
99
+ reply = await self.read()
100
100
 
101
- reply = await self._reader.get_message()
101
+ moteus_id = (reply.arbitration_id >> 8) & 0x7f
102
102
 
103
- # We're assuming only one device will respond, so the source,
104
- # destination, and CAN prefix should all match without
105
- # checking.
103
+ if command.raw or command.destination == moteus_id:
104
+ return command.parse(reply)
106
105
 
107
- return command.parse(reply)
106
+ # We did not get a response from the device we were hoping
107
+ # for, so just keep waiting.
108
108
 
109
109
  async def write(self, command):
110
110
  reply_required = command.reply_required
@@ -125,7 +125,12 @@ class PythonCan:
125
125
 
126
126
  async def read(self):
127
127
  self._maybe_setup()
128
- return await self._reader.get_message()
128
+ while True:
129
+ frame = await self._reader.get_message()
130
+ if not frame.is_error_frame:
131
+ return frame
132
+ # Just ignore error frames entirely and keep reading until
133
+ # we get a good one.
129
134
 
130
135
  def _round_up_dlc(self, size):
131
136
  if size <= 8:
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.87"
15
+ VERSION="0.3.88"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: moteus
3
- Version: 0.3.87
3
+ Version: 0.3.88
4
4
  Summary: moteus brushless controller library and tools
5
5
  Home-page: https://github.com/mjbots/moteus
6
6
  Author: mjbots Robotic Systems
@@ -13,7 +13,6 @@ Classifier: Programming Language :: Python :: 3
13
13
  Requires-Python: >=3.7, <4
14
14
  Description-Content-Type: text/markdown
15
15
  Requires-Dist: importlib-metadata >=3.6
16
- Requires-Dist: numpy <2
17
16
  Requires-Dist: pyelftools >=0.26
18
17
  Requires-Dist: pyserial >=3.5
19
18
  Requires-Dist: python-can >=3.3
@@ -4,20 +4,20 @@ moteus/aiostream.py,sha256=YAkVF6QWsA49vqO-GgXEohDghqm_-nnajJzhO_Q9qNQ,3696
4
4
  moteus/calibrate_encoder.py,sha256=Ami5e-LFw4RLoLseKcZx9QfS1PjQZJUwygvNZfPqd04,15494
5
5
  moteus/command.py,sha256=UkOsbtkso6Oyex8CfbpAKpBNriik519ymxL86EZGkRs,1169
6
6
  moteus/export.py,sha256=XitBUuf4MDRIneXQSUptizIhZi2BdHyFO2Vo_2d2CFI,1742
7
- moteus/fdcanusb.py,sha256=7PrQiCTROY96gdT2zSZYU1bOCriw-I7H6NspaZpiEx4,7431
8
- moteus/moteus.py,sha256=vImSRBn6VEmoijD6hvrSRVxuv1_xVaEJU3F_3Wi6GiE,52498
9
- moteus/moteus_tool.py,sha256=i_XvLfALdd3UitmXdO63tj0iGwCCkaSsBZSyrkgYS9Y,97847
7
+ moteus/fdcanusb.py,sha256=SOAvUlleI6bKwQiApo7nYAaqBM4JoNPn4PHdPqsgsQQ,7707
8
+ moteus/moteus.py,sha256=QH1y5W-KQ0hKoGDPv7lLkWTIS7YBS5pNO3gbYKoF5vw,53241
9
+ moteus/moteus_tool.py,sha256=FmV-opl8PyhOHY9z_B86dyLuwbMwtkMRsH2CCNOf1Fo,98072
10
10
  moteus/multiplex.py,sha256=2tdNX5JSh21TOjN6N9LKribLQtVYyyYbXjzwXB64sfA,12119
11
11
  moteus/posix_aioserial.py,sha256=2oDrw8TBEwuEQjY41g9rHeuFeffcPHqMwNS3nf5NVq8,3137
12
- moteus/pythoncan.py,sha256=M5Qba3aCzO_GyXcIsLJxjw3NrPgUk4CUnHOQIhQeIb0,4786
12
+ moteus/pythoncan.py,sha256=j7Gv9tugQqTZbanm1lQGIoTvfmeS2kAxigB0n1a50lo,5039
13
13
  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=0H-9-BkLhMrpt7WebRlIy2uP-2RmS0Y-oPCO-T9QBJY,627
17
+ moteus/version.py,sha256=bYmrQeWLHbeSIrqSgHNqnNU3m7WMEJx3w6Szx9slMuo,627
18
18
  moteus/win32_aioserial.py,sha256=culdl-vYxBKD5n2s5LkIMGyUaHyCcEc8BL5-DWEaxX8,2025
19
- moteus-0.3.87.dist-info/METADATA,sha256=JIFUMH7iwTghDJf4fdupl4uwLj2vPCKCFHsp8yj3FSc,3441
20
- moteus-0.3.87.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
21
- moteus-0.3.87.dist-info/entry_points.txt,sha256=accRcwir_K8wCf7i3qHb5R6CPh5SiSgd5a1A92ibb9E,56
22
- moteus-0.3.87.dist-info/top_level.txt,sha256=aZzmI_yecTaDrdSp29pTJuowaSQ9dlIZheQpshGg4YQ,7
23
- moteus-0.3.87.dist-info/RECORD,,
19
+ moteus-0.3.88.dist-info/METADATA,sha256=9dBQGXpZ4BTL8pA26Cvh2aD5WlHdgRj-3klygfDOvMA,3417
20
+ moteus-0.3.88.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
21
+ moteus-0.3.88.dist-info/entry_points.txt,sha256=accRcwir_K8wCf7i3qHb5R6CPh5SiSgd5a1A92ibb9E,56
22
+ moteus-0.3.88.dist-info/top_level.txt,sha256=aZzmI_yecTaDrdSp29pTJuowaSQ9dlIZheQpshGg4YQ,7
23
+ moteus-0.3.88.dist-info/RECORD,,