Python 如何在没有任何CAN硬件的两台Linux机器之间发送和接收CAN消息?
我一直在尝试在我的笔记本电脑(Ubuntu20VirtualBox)和RaspberryPI(Ubuntu20)之间建立CAN通信,而不使用任何CAN硬件,因为这样在模拟环境中无法获得CAN消息。我想通过wifi或USB将CAN数据作为有效负载发送。然后,我的python模拟环境应该能够将这些消息解释为CAN消息并适当地转发 我曾尝试过Python 如何在没有任何CAN硬件的两台Linux机器之间发送和接收CAN消息?,python,linux,usb,wifi,can-bus,Python,Linux,Usb,Wifi,Can Bus,我一直在尝试在我的笔记本电脑(Ubuntu20VirtualBox)和RaspberryPI(Ubuntu20)之间建立CAN通信,而不使用任何CAN硬件,因为这样在模拟环境中无法获得CAN消息。我想通过wifi或USB将CAN数据作为有效负载发送。然后,我的python模拟环境应该能够将这些消息解释为CAN消息并适当地转发 我曾尝试过socketcan中的vcan,但它只能在同一台Linux机器的两个终端之间工作。有人建议我看一下slcan。除了使用实际的CAN硬件,似乎没有其他选择。我在任何
socketcan
中的vcan
,但它只能在同一台Linux机器的两个终端之间工作。有人建议我看一下slcan
。除了使用实际的CAN硬件,似乎没有其他选择。我在任何地方都找不到任何教程或其他帮助
如果有人能建议如何在没有任何can硬件的情况下通过wifi或USB在2台Linux机器之间发送和接收can消息,我将不胜感激
我尝试过的Python源代码:
import sys
import socket
import argparse
import struct
import errno
class CANSocket(object):
FORMAT = "<IB3x8s"
FD_FORMAT = "<IB3x64s"
CAN_RAW_FD_FRAMES = 5
def __init__(self, interface=None):
self.sock = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW)
if interface is not None:
self.bind(interface)
def bind(self, interface):
self.sock.bind((interface,))
self.sock.setsockopt(socket.SOL_CAN_RAW, self.CAN_RAW_FD_FRAMES, 1)
def send(self, cob_id, data, flags=0):
cob_id = cob_id | flags
can_pkt = struct.pack(self.FORMAT, cob_id, len(data), data)
self.sock.send(can_pkt)
def recv(self, flags=0):
can_pkt = self.sock.recv(72)
if len(can_pkt) == 16:
cob_id, length, data = struct.unpack(self.FORMAT, can_pkt)
else:
cob_id, length, data = struct.unpack(self.FD_FORMAT, can_pkt)
cob_id &= socket.CAN_EFF_MASK
return (cob_id, data[:length])
def format_data(data):
return ''.join([hex(byte)[2:] for byte in data])
def generate_bytes(hex_string):
if len(hex_string) % 2 != 0:
hex_string = "0" + hex_string
int_array = []
for i in range(0, len(hex_string), 2):
int_array.append(int(hex_string[i:i+2], 16))
return bytes(int_array)
def send_cmd(args):
try:
s = CANSocket(args.interface)
except OSError as e:
sys.stderr.write('Could not send on interface {0}\n'.format(args.interface))
sys.exit(e.errno)
try:
cob_id = int(args.cob_id, 16)
except ValueError:
sys.stderr.write('Invalid cob-id {0}\n'.format(args.cob_id))
sys.exit(errno.EINVAL)
s.send(cob_id, generate_bytes(args.body), socket.CAN_EFF_FLAG if args.extended_id else 0)
def listen_cmd(args):
try:
s = CANSocket(args.interface)
except OSError as e:
sys.stderr.write('Could not listen on interface {0}\n'.format(args.interface))
sys.exit(e.errno)
print('Listening on {0}'.format(args.interface))
while True:
cob_id, data = s.recv()
print('%s %03x#%s' % (args.interface, cob_id, format_data(data)))
def parse_args():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
send_parser = subparsers.add_parser('send', help='send a CAN packet')
send_parser.add_argument('interface', type=str, help='interface name (e.g. vcan0)')
send_parser.add_argument('cob_id', type=str, help='hexadecimal COB-ID (e.g. 10a)')
send_parser.add_argument('body', type=str, nargs='?', default='',
help='hexadecimal msg body up to 8 bytes long (e.g. 00af0142fe)')
send_parser.add_argument('-e', '--extended-id', action='store_true', default=False,
help='use extended (29 bit) COB-ID')
send_parser.set_defaults(func=send_cmd)
listen_parser = subparsers.add_parser('listen', help='listen for and print CAN packets')
listen_parser.add_argument('interface', type=str, help='interface name (e.g. vcan0)')
listen_parser.set_defaults(func=listen_cmd)
return parser.parse_args()
def main():
args = parse_args()
args.func(args)
if __name__ == '__main__':
main()
导入系统
导入套接字
导入argparse
导入结构
输入错误号
类CANSocket(对象):
FORMAT=“CAN是一种广播协议,而不是TCP之类的连接协议或UDP之类的数据报协议。但是,如果您想要抽象硬件,但仍然模拟CAN的高层行为,我建议最好的方法是使用UDP(但是,@M.Spiller建议的TCP也可以工作,只意味着处理UDP不需要麻烦的接受连接),并发送和接收与CAN帧相同字节结构的数据包。您还需要考虑过滤器和错误帧
如果要在linux上使用socketcan,您的UDP数据包应该如下所示:
struct {
uint16_t id; /* CAN ID of the frame */
uint8_t dlc; /* frame payload length in bytes */
uint8_t data[8]; /* CAN frame payload */
} simulated_udp_can_frame;
您应该阅读以了解更多详细信息。不确定您想做什么。为什么不简单地打开两台机器之间的TCP套接字并发送日期?TCP协议不关心有效负载是CAN消息还是其他内容。好的。我正在为Pi代表Automot的特定汽车用例构建一个虚拟平台ive ECU。这就是为什么我必须使用CAN,因为ECU通过CAN相互交互。仍然没有得到它。是的,ECU交换数据;是的,他们可能在车内使用CAN。你想模拟什么?交换的数据?计时?CAN协议使用定义良好的物理层,如果没有适当的硬件,就无法模拟e、 那么,您将模拟什么?我将模拟防抱死制动系统用例。1 RPI应通过CAN将车速值发送到笔记本电脑。但为什么必须是“通过CAN”"。如果您想模拟制动系统,为什么发送速度值还不够?因此,如果没有CAN硬件,您将错过许多需要做的事情,例如设置比特率等。但是您可以“假装”CAN硬件在那里,并且您正在从一端发送帧到另一端。但实际上,您将发送帧UDP。有关帧的重要内容是设置过滤器、消息ID和位顺序,因为这对于真正的CAN软件至关重要。您可以从socketCAN文档中了解这一点。您可以编写代码,使这些内容:过滤器、帧和ID与真正的硬件用途相同。是的。CAN套接字类似于:socket(PF_CAN、SOCK_RAW、CAN_RAW);UDP套接字是套接字(AF_INET、SOCK_DGRAM、IPPROTO_UDP);但它们都是套接字。使用CAN套接字可以读写;使用UDP可以发送和接收;但是数据的布局可以是相同的,如前所述。如果使用相同的wifi,则两台linux机器应该位于同一子网中,或者至少每台机器上的ip地址应该可以与另一台机器访问。如果没有CAN硬件,则不能进入g获取CAN套接字。该套接字由内核创建,需要一个驱动程序和一个ip接口,该接口将被称为can0或类似于eth0的类似接口。对于您所设计的环境,在没有CAN硬件的两台计算机之间;是的,完全正确。使用UDP和假装。如果您可以在一台计算机上演示,您可以d使用vcan。如果你在一台电脑上有一些插入式CAN硬件或CAN仿真器,那么你就可以使用CAN插座。但是两台电脑之间没有硬件?你必须假装UDP是最简单的方法。兄弟。我在这里猜,但我认为你是CAN的新手。从应用软件的角度来看(顺便说一句,我在汽车硬件/软件设计公司工作),关于CAN,你必须了解的是它有一个面向位的消息结构,即你必须以位而不是字节来考虑数据。从维基百科关于CAN的文章开始,特别是关于框架布局的部分。