add comments

This commit is contained in:
Oskar Weigl
2017-11-08 23:53:15 -08:00
parent 5dd1d01688
commit 49754af4cc
6 changed files with 57 additions and 16 deletions
+6 -3
View File
@@ -8,7 +8,10 @@ import time
import math
# Find a connected ODrive (this will block until you connect one)
my_drive = odrive.core.find_any(printer=print)
odrives = odrive.core.find_all(printer=print)
odrives = list(odrives) #force eval of generator to test finding functions
my_drive = odrives[0]
# my_drive = odrive.core.find_any(printer=print)
# The above call returns a python object with a dynamically generated type. The
# type hierarchy will correspond to the endpoint list in `MotorControl/protocol.cpp`.
@@ -29,7 +32,7 @@ my_drive.motor0.set_pos_setpoint(0.0, 0.0, 0.0)
# little sine wave to test
t0 = time.monotonic()
while True:
while False:
setpoint = 10000.0 * math.sin((time.monotonic() - t0)*2)
print("goto " + str(int(setpoint)))
my_drive.motor0.set_pos_setpoint(setpoint, 0.0, 0.0)
@@ -39,7 +42,7 @@ while True:
# Some more things you can try:
# Write to a read-only property:
# my_drive.vbus_voltage = 5 # fails with `AttributeError: can't set attribute`
my_drive.vbus_voltage = 11.0 # fails with `AttributeError: can't set attribute`
# Assign an incompatible value:
# my_drive.motor0.pos_setpoint = "I like trains" # fails with `TypeError: expected value of type float`
+19 -3
View File
@@ -68,12 +68,16 @@ def call_remote_function(channel, trigger_id, arg_properties, *args):
arg_properties[i].fset(None, args[i])
channel.remote_endpoint_operation(trigger_id, None, True, 0)
#Oskar: setattr_or_raise_if_undefined
def raise_if_undefined(self, name, value):
"""
If employed as an object's __setattr__ function, this function
makes sure that an assignment to an undefined attribute doesn't
create a new attribute but instead raises an exception
"""
#Oskar: hasattr internally calls fget to determine if the attribute exists,
# which unnessecarily creates bus traffic. We should try to solve this.
# Step-in on the hasattr line in the debugger to see this.
if hasattr(self, name):
object.__setattr__(self, name, value)
else:
@@ -124,6 +128,8 @@ def create_property(name, json_data, channel, printer):
printer("property {} has no specified ID".format(name))
return None
#Oskar: Bug: json_data calls this "access", but we look for "mode".
# The default should probably be "r" anyway, it's safer I'd say.
access_mode = json_data.get("mode", "rw")
return SimpleDeviceProperty(channel, id_str, property_type,
struct_format,
@@ -250,20 +256,30 @@ def find_usb_channels(vid_pid_pairs=odrive.util.USB_VID_PID_PAIRS, printer=nopri
continue
raise
def find_dev_serial_ports(search_regex):
try:
return ['/dev/' + x for x in filter(re.compile(search_regex).search, os.listdir('/dev'))]
except FileNotFoundError:
return []
def find_serial_channels(printer=noprint):
"""
Scans for serial ports.
Returns a generator of odrive.protocol.Channel objects.
Not every returned object necessarily represents a compatible device.
"""
#Oskar: Why not just use this tool to find the available ports?
# https://pyserial.readthedocs.io/en/latest/tools.html#module-serial.tools.list_ports
# Real serial ports or USB-Serial converters
linux_real_serial_ports = ['/dev/' + x for x in filter(re.compile(r'^ttyUSB').search, os.listdir('/dev'))]
linux_real_serial_ports = find_dev_serial_ports(r'^ttyUSB')
windows_real_serial_ports = [ "COM1", "COM2", "COM3", "COM4" ]
# Serial devices that are exposed by the platform
# for the device's USB connection
linux_usb_serial_ports = ['/dev/' + x for x in filter(re.compile(r'^ttyACM').search, os.listdir('/dev'))]
macos_usb_serial_ports = ['/dev/' + x for x in filter(re.compile(r'^tty\.usbmodem').search, os.listdir('/dev'))]
linux_usb_serial_ports = find_dev_serial_ports(r'^ttyACM')
macos_usb_serial_ports = find_dev_serial_ports(r'^tty\.usbmodem')
for port in linux_real_serial_ports + windows_real_serial_ports + linux_usb_serial_ports + macos_usb_serial_ports:
try:
+9 -4
View File
@@ -56,6 +56,10 @@ class ChannelBrokenException(Exception):
class DeviceInitException(Exception):
pass
#Oskar: I would just get rid of these "abstract classes",
# I think just looking and seeing that the classes have
# a process_packet or get_packet is enough.
class StreamSource(object):
pass
@@ -171,6 +175,7 @@ class Channel(PacketSink):
_expected_acks = {}
# Chose these parameters to be sensible for a specific transport layer
#Oskar: it's a timeout, not delay.
_resend_delay = 5.0 # [s]
_send_attempts = 5
@@ -203,11 +208,11 @@ class Channel(PacketSink):
crc16 = calc_crc16(CRC16_INIT, packet)
if (endpoint_id & 0x7fff == 0):
footer = PROTOCOL_VERSION
trailer = PROTOCOL_VERSION
else:
footer = self._interface_definition_crc
#print("append footer " + footer)
packet = packet + struct.pack('<H', footer)
trailer = self._interface_definition_crc
#print("append trailer " + trailer)
packet = packet + struct.pack('<H', trailer)
if (expect_ack):
self._expected_acks[seq_no] = None
+3
View File
@@ -55,6 +55,9 @@ def print_usage():
# that will leave that odrive variable in scope for the interactive session; just give the user some instructions
# that they can then do stuff like odrive.[tabcomplete]
# We can also make a function odrive.send_legacy_cmd(cmd_str), which is important for some features that
# we haven't ported yet.
def command_prompt_loop(device, history):
"""
Presents the command prompt indefinitely until something goes wrong