1

I'm currently using Popen to send instructions to a utility (canutils... the cansend function in particular) via the command line.

The entire function looks like this.

def _CANSend(self, register, value, readWrite = 'write'):
    """send a CAN frame"""
    queue=self.CANbus.queue
    cobID = hex(0x600 + self.nodeID)     #assign nodeID
    indexByteLow,indexByteHigh,indexByteHigher,indexByteHighest = _bytes(register['index'], register['objectDataType'])
    subIndex = hex(register['subindex'])
    valueByteLow,valueByteHigh,valueByteHigher,valueByteHighest = _bytes(value, register['objectDataType'])
    io = hex(COMMAND_SPECIFIER[readWrite])
    frame = ["cansend", self.formattedCANBus, "-i", cobID, io, indexByteLow, indexByteHigh, subIndex, valueByteLow, valueByteHigh, valueByteHigher, valueByteHighest, "0x00"]
    Popen(frame,stdout=PIPE)
    a=queue.get()
    queue.task_done()
    return a

I was running into some issues as I was trying to send frames (the Popen frame actually executes the command that sends the frame) in rapid succession, but found that the Popen line was taking somewhere on the order of 35 ms to execute... every other line was less than 2 us.

So... what might be a better way to invoke the cansend function (which, again, is part of the canutils utility..._CANSend is the python function above that calls ) more rapidly?

yegorich
  • 4,653
  • 3
  • 31
  • 37
Chris
  • 9,603
  • 15
  • 46
  • 67
  • 1
    have you tried [`python-can`](http://python-can.readthedocs.org/en/latest/) on Python versions before 3.3? – jfs Apr 05 '14 at 20:27

1 Answers1

4

I suspect that most of that time is due to the overhead of forking every time you run cansend. To get rid of it, you'll want an approach that doesn't have to create a new process for each send.

According to this blog post, SocketCAN is supported by python 3.3. It should let your program create and use CAN sockets directly. That's probably the direction you'll want to go.

ʇsәɹoɈ
  • 22,757
  • 7
  • 55
  • 61
  • hmmmm.... I actually have my _CANSend function set up inside a class. I suppose I could initialize the process upon instantiation of the class and then just send messages as needed. Does that seem like an appropriate approach (I've only just started to use subprocess) – Chris May 05 '13 at 02:37
  • Also, (and I should have mentioned this) I'm using a beaglebone which ships with python 2.7, so a solution that can be used in that case is preferable – Chris May 05 '13 at 02:38
  • If your code is calling Popen, then it is creating a new process to do its work. Moving it into a class will not change that. – ʇsәɹoɈ May 05 '13 at 02:41
  • 1
    Your options would seem to be: (a) Get a python 3.3 build for your beaglebone. (b) Write your program in C and access the CAN API directly. (c) Write a python 2.7 extension or make use of a dynamic library module to access the CAN API from python 2.7. (d) Write or find a program that can perform multiple CAN operations based on commands from another program, and command a single instance of it from python. – ʇsәɹoɈ May 05 '13 at 02:43
  • Option a) of those is probably the easiest. – marko May 05 '13 at 23:20
  • @ʇsәɹoɈ: (b+) use `ctypes` to access CAN API directly. (c+) use [existing module](http://python-can.readthedocs.org/en/latest/). – jfs Apr 05 '14 at 20:30
  • As J.F. Sebastian says [python-can](https://bitbucket.org/hardbyte/python-can/) supports python 2.7 via ctypes, and python 3.3+ via the native socket api. – Hardbyte May 30 '16 at 22:31