Exadler / DMCC_Library

Code library for the beaglebone DMCC (Dual Motor Controller Cape)
4 stars 10 forks source link

Slow Python API calls, request for I2C protocol #3

Closed napratin closed 8 years ago

napratin commented 10 years ago

We ran some timing tests using the DMCC Python API, and the results show that each call is taking way too long for it to be usable (e.g., when setting 4 motors on one by one, we need that to happen pretty much instantaneously, but there's a clear delay per motor call). We understand that this is because the entire initialization routine occurs for each Python-to-C call.

Since we need an efficient Python interface to the DMCC capes, we tried to re-implement the library in native Python (see this fork). So far, we haven't been able to make much progress as the protocol between the Beaglebone and the cape is not easily discernible from the code.

@paulctan / @sarahttan: Could you please provide us with the I2C protocol that the cape uses to communicate (i.e. all the different commands along with parameters, byte order etc.)? Also, if there are any other necessary initialization steps, it would be great to know them as well. Needless to say, once we have a stable Python library we'll be glad to contribute it back. Thanks!

paulctan commented 10 years ago

Here is a link to a very ROUGH document on the I2C protocol between the BeagleBone and the DMCC. We really need to clean it up a bit before we release it, so we are putting it on a temporary google doc link: https://docs.google.com/document/d/1vNoH5H8ODUPpGeQgL33aTz3tzo64SsbbzK1ySuSa2As/edit?usp=sharing

Basically, the protocol goes like this: set parameters for Motor 1 or Motor 2 or both, then send the execute command (0xff ) to actually execute the parameters/commands that you set. That way, you can guarantee that Motor 1 and Motor 2 start at the same time.

Feel free to comment here with any further questions, and we look forward to helping you out with the code so that we can merge it back into the main DMCC library. Please keep us posted on any of your projects with the DMCC (we would love to see some pictures!!)

Also, if you could share with us some of your benchmarking data and test code, we'd like to try to see where the bottleneck is as well.

Thanks!

napratin commented 10 years ago

Thanks a lot, @paulctan! This should definitely help us get moving in the right direction. We'll post back here if we have any questions.

I'll also clean up our benchmarking code to remove unnecessary dependencies and share with you.

napratin commented 10 years ago

Here are a few things we are juggling with right now:

paulctan commented 10 years ago
jschornick commented 10 years ago

@paulctan -- Many thanks for the I2C protocol document! I've spent a bit of time hacking at the work @napratin and @dfarrell07 began with our fork (http://github.com/NCSUhardware/DMCC_Library) of your library. I think we're in a good place from a performance perspective, as indicated by one of the Python test programs I included in our reimplementation:

# dmcc_motor_test 
DMCC #1 @ 0x2d : Voltage = 8.302

DMCC #1 @ 0x2d:
  100 reads in...  0.239 seconds (2.39 ms each).
  100 sets in...  0.213 seconds (2.13 ms each).

So that's all good!

In the process of getting here, I converted (most of) the I2C protocol information you provided in the Google doc into a machine readable (YAML) description. This data file is processed by a generic I2C library (https://github.com/jschornick/i2c_device), allowing us to more easily poke at the various registers you expose. Most of the functional verification went as expected, but a few of the device registers don't behave as described.

Most importantly, reading the PowerMotor[12] values (0x02-0x05) in either PID mode always reports zero...

(from: https://github.com/NCSUhardware/DMCC_Library/blob/master/examples/dmcc_pid_test)

# dmcc_pid_test 
DMCC #1 @ 0x2d : Voltage = 8.275
PID constants (pos): (0, 0, 0)
Setting to:  (-5000, -200, -500)
PID constants (pos): (-5000, -200, -500)
Setting position target to 5000...
  S:0, Pos: +000000, Vel: +000, Err: 0, Pow: 000.0, Cur: 0 mA
  S:0, Pos: +000319, Vel: +143, Err: 0, Pow: 000.0, Cur: 182 mA
  S:0, Pos: +000963, Vel: +285, Err: 0, Pow: 000.0, Cur: 101 mA
  S:0, Pos: +001611, Vel: +289, Err: 0, Pow: 000.0, Cur: 95 mA
  S:0, Pos: +002280, Vel: +291, Err: 0, Pow: 000.0, Cur: 91 mA

You'll also note that the status bits and PID error are also consistently zero. In each case, I'm writing Refresh (0x00) to Execute (0xff) before reading, which has the desired result when querying the other registers (such as the QEI position/velocity).

Can you help clarify why the status, power, and error aren't reporting as expected? Do you have some sample code of these features working in any language?

paulctan commented 10 years ago

I don't think those bits/values were implemented in the released firmware. You should probably ignore them for now.

I'm glad you were able to get the performance numbers up. We'll spend sometime testing and re-integrating your code into the main branch when you guys are satisfied with it.

paulctan commented 8 years ago

Updated I2C communication document can be found here -

https://docs.google.com/document/d/1vNoH5H8ODUPpGeQgL33aTz3tzo64SsbbzK1ySuSa2As/edit?usp=sharing