Problem using cyclic Message

Issue #60 resolved
frriZ leet created an issue

Hello everyone, i'm using a Raspberry Pi for my Can application. I installed hardbyte python as follow the instructions.

So far, i'm able to execute the send_one.py program stored in the examples folder. I tried using socketcan_ctypes and socketcan_native when i execute the send_one. The message is received correctly by my other machine.

However, i can't execute the cyclic.py program, it gives me all sort of errors which I personnally ignore how to resolve it :( I use python 3.4

Here is the console output when i execute with socketcan_native config:

pi@raspberrypi:~/python-can/examples $ python3 cyclic.py
Carrying out cyclic tests with socketcan_ctypes interface
 Trying to send a message... {'channel': 'can0', 'interface': 'socketcan_ctypes'} INFO:can.socketcan.ctypes:Loading socketcan ctypes backend INFO:can.socketcan.ctypes:ifr.ifr_ifindex: 4 
INFO:can.socketcan.ctypes:Sending BCM TX_SETUP command Trying to change data INFO:can.socketcan.ctypes:Sending BCM TX_SETUP command stopped cyclic send INFO:can.socketcan.ctypes:Sending BCM TX_SETUP command starting again done Carrying out cyclic tests with socketcan_native interface
 Trying to send a message... {'channel': 'can0', 'interface': 'socketcan_native'} INFO:can.socketcan.native:Sending BCM command 
Traceback (most recent call last):   
File "cyclic.py", line 71, in <module>    
 test_simple_periodic_send()   
File "cyclic.py", line 25, in test_simple_periodic_send
task = can.send_periodic('can0', msg, 0.020)
 File "/usr/local/lib/python3.4/dist-packages/python_can-1.4.3-py3.4.egg/can/broadcastmanager.py", line 75, in send_periodic     return can.interface.CyclicSendTask(channel, message, period)   
File "/usr/local/lib/python3.4/dist-packages/python_can-1.4.3-py3.4.egg/can/interfaces/interface.py", line 88, in __new__     
return cls(channel, *args, **kwargs)
File "/usr/local/lib/python3.4/dist-packages/python_can-1.4.3-py3.4.egg/can/interfaces/socketcan_native.py", line 135, in __init__     self._tx_setup(message)   
File "/usr/local/lib/python3.4/dist-packages/python_can-1.4.3-py3.4.egg/can/interfaces/socketcan_native.py", line 143, in _tx_setup     self.bcm_socket.send(header + frame) 
OSError: [Errno 22] Invalid argument 

Before executing cyclic.py, i edited it, and remplaced every 'vcan0' with 'can0' because i'm using a real hardware on can0 interface.

Thanks in advance for your attention. Can anyone tell me how to resolve this issue ?

Comments (12)

  1. Brian Thorne repo owner

    What operating system do you have installed on the Raspberry Pi? What kernel is running (uname -a)?

    Also out of interest - what CAN hardware?

  2. frriZ leet reporter

    I've installed the latest rasbian jessie os i found on the raspberry site. I also did the updates/upgrades It's a Linux raspberrypi 4.1.19-v7+

    The can module is a Pican2 board I bought on skpang.co.uk I can install can-utils by

    sudo apt-get can-utils install
    

    All the commands like cansend, candump, work perfectly

    However, in my internship application, i would need a cyclic sending program. I'm not so good at programming so I have very little ideas on how to implant cycles with precise timestamp in .C programs (For example, i want to send a CAN frame with a period of 500ms) I tried using shell scripts, and executing them in the background in bashrc. For instance, the script would look something like

    #!/bin/bash
    while : 
    do
    cansend 400#1000000000
    sleep 0.5
    done
    

    I found your python-can libraries very very interesting in using in my project. I would like to to use them as well, but for some reason i ignore, it is not working :'( What would you recommend me

  3. Travis Travelstead

    I would say if you are very new to programming and what you are working on is not extremely time critical (most CAN is not especially at a 500ms delay) I would just keep it simple and write a basic loop. I also have not used the cyclic message capability, so I might not be a big help there.

    You can use the "time" library and some basic delay thresholds to make a fairly accurate loop that is simple to make and modify.

    import time
    import can
    
    DELAY_PERIOD = 0.5 #the delay period between sending
    timeLastSend = time.time()
    isRunning = True
    
    while(isRunning):
    
        if(time.time() - timeLastSend >= DELAY_PERIOD):
            #Do whatever
            #Send message
            #Something can be triggered to cause isRunning to be False and end the program
            timeLastSend = time.time()
    
        time.sleep(0.02) #You can change delay to balance accuracy and CPU usage.
    

    I just quickly wrote this in my reply and have not tested it. But the concept should be easy to see and copy.

    One other thing to make sure is that all the drivers are active. Below is a function I call in my program that call command line commands to setup CAN in the OS.

        def _hardwareConfig(self, channel):
            '''
            Pass channel string (example 'can0') to configure OS level drivers and interface.
            '''
    
            self.log.info('CAN hardware OS drivers and config for CAN0')
    
            #General CAN bus setup on the linux kernel
            subprocess.call(['modprobe', 'can']) #
            subprocess.call(['modprobe', 'can-dev']) #
            subprocess.call(['modprobe', 'can-raw']) #basic raw CAN packets
            subprocess.call(['modprobe', 'can-bcm']) #Broadcast manager
    
            subprocess.call(['ip', 'link', 'set', channel, 'type', 'can', 'bitrate', '500000' , 'restart-ms' , '5000'])
            subprocess.call(['ip', 'link', 'set', 'up', channel])
    
  4. frriZ leet reporter

    Thank you for your response Travis. I've implemented your code to the send_one.py example program, and i was able to do this: this script sends ID 400 data 10000000 every 250ms. I've tested it, and it works. (there was an indented block and syntax error in your code but i've fixed it). Here is the code:

    from __future__ import print_function
    
    import can
    import time
    
    def send_400():
        bus = can.interface.Bus()
        msg = can.Message(arbitration_id=0x400,
                          data=[2, 0, 0, 0, 0, 0, 0, 0],
                          extended_id=False)
    
        DELAY_PERIOD = 0.25 #the delay period btw sending
        timeLastSend = time.time()
        isRunning = True
    
        try:
            while(isRunning):   
                if(time.time() - timeLastSend >= DELAY_PERIOD):
                    bus.send(msg)
                    timeLastSend = time.time()
                    #time.sleep(0.02) #Change Delay to balance accuracy/CPU usage
    
            print("Message sent on {}".format(bus.channel_info))
        except can.CanError:
            print("Message NOT sent")
    
    if __name__ == "__main__":
        send_400()
    

    Now, I would like to put it in application with my project: i'm Trying to communicate with this CAN protocol with a device. Bassically, by sending the 400 frame every 250ms, i would get some response frames with ID from 401 to 406 containing all sort of information I need about the device.

    I looked up for the can_logger.py program located in the /home/pi/python-can/build/scripts-3.4 directory.

    Now, do you know how can I do something like: If canID 401 or 402 or 403 or 404 or 405 or 406 is received, i call out the can_logger [-f LOG_FILE] fonction, and store these frames in a .log file for offline analysis afterwards. What do you recommend me using afterwards to exploit that file: for instance, what do I need to look for, in order to create a script which opens the .log file, and do some decoding of the frames?

    Thanks in advance for taking the time in responding me. Sincerely

  5. Travis Travelstead

    I am glad it was helpful. Keep in mind I said I typed that code directly in the response and it was not tested at all.

    The nice things about sockets is they are buffered at the OS level so checking for messages are easy. Again to keep it simple I will share one approach. This is not perfect and is only intended to help you get started. The resources you need to put this together are provided by Brian and the community he has built around the library in its documentation.

    This is not a full program and you will need to put the concepts together.

    def getMessageList():
        #message list to store incoming bus messages
        messageList = []
    
        #Check if bus has message and store it
        fromBus = bus.recv()
    
        #If bus has a message go into loop to collect all available messages into a list
        while(fromBus is not None):
            #Add message to list
            messageList.append(fromBus)
            #Check for another message
            fromBus = bus.recv()
    
        return messageLIst
    

    After you have the list of messages you can iterate through them and deal with them as needed. If you are not sure google "python for loop lists" which should give you information.

    If you are not familiar on how to deal with the message look into the documentation here https://python-can.readthedocs.io/en/latest/message.html

    I do not want to get too much more into detail here as we are already outside of the scope of the issue report. I just want to help get your system running. Once the system is running and known to work it is easier to test the cyclic messages. I would suggest to try to use the cyclic message function after you get more comfortable. This is the most efficient way for many applications and it also helps get feedback to Brian to support the library.

  6. Andy Tran

    It seems like the Cyclic functions do not work well with Raspberry Pi. I am able to send single messages with the virtual can channel (vcan); however, I get issues trying the run the cyclic functions. I get the exact same problems mentioned by the OP as well as this post: https://bitbucket.org/hardbyte/python-can/issues/58/sending-periodically-doesnt-work-even (I am running the standard Rasbian jessie OS with Kernel version 4.4.38-v7+)

    *Note: I tried sending periodic messages with vcan on my VM running Ubuntu and it worked.

  7. Andy Tran

    Update:

    I did some debugging (i looked at the header format used by can4python) and found that it works on RaspberryPi when I use @# 3I4l2I0q for the bcm header format as opposed to @IIIlllII (in socket_native.py)

    Update: On the Raspberry pi, running 32bit OS, i did a calcsize('L') and got 4, and on an intel machine running 64-bit OS I got an 8. The limitation is on the 32-bit OS.

  8. Brian Thorne repo owner

    Andy do you want to report back if using = instead of @ fixes the issue? According to the struct docs it should use standard sizes instead of native.

  9. Brian Thorne repo owner
    • changed status to resolved
    • edited description

    Update - I replicated your findings. Have committed your suggested bcm frame format over on github. Will be fixed in the next version!

  10. Brian Buckett

    Hello, we're using a BeagleBone running the standard Jessie OS for our CAN application. We're having issues (likely 32bit related) with the periodic messages and BCM socket. We've pulled down the development branch which includes the the changes referenced here, but we're still seeing issues with both socketcan_native and socketcan_ctypes. For our application the native implementation is preferred, but output from both is below for reference.

    native output:

    DEBUG:can.socketcan.native:Sending BCM command
    Traceback (most recent call last):
      File "/home/dev/CAN/python-can/can/interfaces/socketcan/socketcan_native.py", line 147, in send_bcm
        return socket.send(data)
    OSError: [Errno 22] Invalid argument
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/opt/pycharm-2017.1.4/helpers/pydev/pydevd.py", line 1591, in <module>
        globals = debugger.run(setup['file'], None, None, is_module)
      File "/opt/pycharm-2017.1.4/helpers/pydev/pydevd.py", line 1018, in run
        pydev_imports.execfile(file, globals, locals)  # execute the script
      File "/opt/pycharm-2017.1.4/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
        exec(compile(contents+"\n", file, 'exec'), glob, loc)
      File "/home/dev/SoftwareProjects/builds/lanscan_mgmtcontroller/hardware_controller.py", line 106, in <module>
        controller.run()
      File "/home/dev/SoftwareProjects/builds/lanscan_mgmtcontroller/hardware_controller.py", line 49, in run
        self.CAN_sender.send_periodic_message(CANMessages.get_control_module_message(48, 50, 0, 0),  0.100)
      File "/home/dev/SoftwareProjects/builds/lanscan_mgmtcontroller/communications/CAN/CAN_sender.py", line 46, in send_periodic_message
        task = self._bus.send_periodic(message, period_in_seconds)
      File "/home/dev/CAN/python-can/can/interfaces/socketcan/socketcan_native.py", line 456, in send_periodic
        task = CyclicSendTask(self.channel, msg, period)
      File "/home/dev/CAN/python-can/can/interfaces/socketcan/socketcan_native.py", line 204, in __init__
        self._tx_setup(message)
      File "/home/dev/CAN/python-can/can/interfaces/socketcan/socketcan_native.py", line 213, in _tx_setup
        send_bcm(self.bcm_socket, header + frame)
      File "/home/dev/CAN/python-can/can/interfaces/socketcan/socketcan_native.py", line 153, in send_bcm
        base + "You are probably referring to a non-existing frame.")
    can.CanError: Couldn't send CAN BCM frame. OS Error 22: Invalid argument
    You are probably referring to a non-existing frame.
    

    ctypes output:

    DEBUG:can.socketcan.ctypes:Creating bcm socket on channel 'can0'
    DEBUG:can.socketcan.ctypes:Created bcm socket (un-connected fd=9)
    DEBUG:can.socketcan.ctypes:Connecting socket with id 9 to channel can0
    DEBUG:can.socketcan.ctypes:calling ioctl SIOCGIFINDEX
    INFO:can.socketcan.ctypes:ifr.ifr_ifindex: 3
    DEBUG:can.socketcan.ctypes:connect returned: 0
    DEBUG:can.socketcan.ctypes:Connected bcm socket
    DEBUG:can.socketcan.ctypes:Packing a can frame
    DEBUG:can.socketcan.ctypes:Data: bytearray(b'\x80\xbb\x00\x00P\xc3\x00')
    DEBUG:can.socketcan.ctypes:Type: <class 'bytearray'>
    DEBUG:can.socketcan.ctypes:sizeof frame: 16
    INFO:can.socketcan.ctypes:Sending BCM TX_SETUP command
    DEBUG:root:Error sending frame :-/
    

    *Note: Sending single messages works without issue. Also, we've confirmed the BCM header is being formatted using the @3I4l2I0q format string mentioned above.

    Any feedback would be appreciated!

  11. Log in to comment