CoDrive
Simple Python API for Cosyne motor controllers over CAN FD.
The controller speaks CoLink, a simplified CiA 402 profile. codrive handles the bus,
the frame coding and the node addressing, so you work with drives instead of COB-IDs.
Install
pip install codrive
Connect to drive
from codrive import Link
# Auto-connect to the shipped USB adapter
link = Link()
link.connect()
# Add drive with ID 1
drive = link.add_drive(node_id=1)
# Print state name
print(drive.state.name)
# Disconnect from bus
link.disconnect()
connect() opens the shipped adapter and configures it automatically. add_drive waits
for the drive to answer, so an absent node raises TimeoutError.
In one scope, a with block connects and disconnects for you:
with Link() as link:
drive = link.add_drive(1)
Other CAN FD adapters
Pass any CAN FD capable python-can bus to Link(). Configure it for the controller's
bus yourself as SAE J2284-5: 500 kbit/s arbitration at an 80 % sample point, 5 Mbit/s
data at a 75 % sample point.
Using a PEAK PCAN-USB FD adapter:
import can
from codrive import Link
timing = can.BitTimingFd(
f_clock=80_000_000,
nom_brp=1, nom_tseg1=127, nom_tseg2=32, nom_sjw=32,
data_brp=1, data_tseg1=11, data_tseg2=4, data_sjw=4,
)
bus = can.Bus(interface="pcan", channel="PCAN_USBBUS1", timing=timing)
with Link(bus) as link:
drive = link.add_drive(node_id=1)
print(drive.state.name)
bus.shutdown()
A bus you open stays yours — the link leaves it open on disconnect, so close it yourself.
Move
Enable and set profile
Set the ramp limits once, enable, then command a mode. Each mode has its own call, so the units are visible at the call site:
drive.set_profile(velocity=800.0, acceleration=4000.0, torque_slope=5.0)
drive.enable()
enable() sets no mode, and disable(), quick_stop() and reset_fault() clear the
mode and setpoints. An enable therefore never starts motion by itself: after a stop or a
fault the drive comes back up idle. The set_profile() limits are kept, since a limit
cannot produce motion on its own.
Profile position mode
# Move to 1 rad using the velocity and acceleration from set_profile()
drive.move_to(1.0)
drive.wait_for_target()
# Move to 2 rad using the specified velocity and acceleration
drive.move_to(2.0, velocity=200.0, acceleration=1000.0)
drive.wait_for_target()
# Start position control without movement
current_position = drive.position
drive.move_to(current_position)
Profile velocity mode
# Run at 300 rad/s using the acceleration from set_profile()
drive.run_at(300.0)
drive.wait_for_target()
# Run at 50 rad/s using the specified acceleration
drive.run_at(50.0, acceleration=1000.0)
drive.wait_for_target()
Profile torque mode
# Set drive torque to 0.2 Nm using the torque slope from set_profile()
drive.apply_torque(0.2)
drive.wait_for_target()
# Set drive torque to 0.0 Nm using the specified torque slope
drive.apply_torque(0.0, slope=2.0)
drive.wait_for_target()
Stop and disable
# Standard method
drive.run_at(0.0)
drive.wait_for_target()
drive.disable()
# Also supported
drive.quick_stop()
drive.wait_for_target()
drive.disable()
wait_for_target() means the profile generator reached the commanded value, not that the
axis did — there is no following-error term, so it can return while the machine is still
turning. Add your own dwell before cutting torque.
Important: Do not call drive.disable() while the drive is spinning!
Record and plot
Once the drive has answered, its latest status is available as
print(drive.position) # rad
print(drive.velocity) # rad/s
print(drive.torque) # Nm
print(drive.state.name) # e.g. OPERATION_ENABLED
status = drive.status # for all status information
The received status can be recorded using
rec = link.record()
drive.move_to(1.0)
drive.wait_for_target()
rec.stop()
rec.plot()
Start and stop can sit in different cells or functions. Inside one scope, use a with
block:
with link.record() as rec:
drive.move_to(1.0)
drive.wait_for_target()
Read the columns yourself for anything beyond plot():
import matplotlib.pyplot as plt
samples = rec.samples()
plt.plot(samples.time, samples.position)
Faults
A fault ends the motion directly. reset_fault() only clears the fault if its cause is
gone; while it persists the drive stays in FAULT and the call raises TimeoutError.
from codrive import DriveState
if drive.state is DriveState.FAULT:
print(repr(drive.error)) # e.g. <ErrorCode.DC_LINK_UNDERVOLTAGE: 12832>
drive.reset_fault()
drive.error returns ErrorCode.NONE when there is no fault, and None for a code
codrive does not name — drive.status.error_code still holds the raw number. Both are
falsy, so compare against ErrorCode.NONE rather than testing for truth.
Multiple drives
All drives share one receive task, dispatched by node id:
with Link() as link:
axis1 = link.add_drive(1)
axis2 = link.add_drive(2)
for axis in (axis1, axis2):
axis.set_profile(velocity=800.0, acceleration=4000.0)
axis.enable()
with link.record() as rec:
axis1.move_to(1.57) # both axes move at once
axis2.move_to(-1.57)
axis1.wait_for_target()
axis2.wait_for_target()
axis1.disable()
axis2.disable()
rec.plot() # every node, one colour each
rec.plot(axis1) # one drive, by object or node id
Status
Early, and the API may still change.
License
Apache 2.0
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file codrive-0.2.1.tar.gz.
File metadata
- Download URL: codrive-0.2.1.tar.gz
- Upload date:
- Size: 15.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2591116420b79805f0506805595f841de5783a84e615030bba2cdcb1729890b7
|
|
| MD5 |
cab297d7f8ed8dcaaf4996dc349c159c
|
|
| BLAKE2b-256 |
2cdde1c01f4e414845af0be13892c677b2737b89955f31c1f988df05bdab3f18
|
File details
Details for the file codrive-0.2.1-py3-none-any.whl.
File metadata
- Download URL: codrive-0.2.1-py3-none-any.whl
- Upload date:
- Size: 17.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4cb2e8629819632aac148a0adc18c4294b9d79268b81fbfdcbf69530128f464e
|
|
| MD5 |
2c702d36fe3dc779f6f06bc532582263
|
|
| BLAKE2b-256 |
0ba6468b5db2c14634e669f3546f6e387f2b3be9a6151bb212d982b4e7be5c23
|