【发布时间】:2020-07-30 00:18:24
【问题描述】:
我一直在尝试在没有任何 CAN 硬件的情况下在我的笔记本电脑 (Ubuntu 20 Virtualbox) 和 Raspberry Pi (Ubuntu 20) 之间建立 CAN 通信,因为在模拟环境中不会收到 CAN 消息。我想通过 wifi 或 USB 将 CAN 数据作为有效负载发送。然后我的python模拟环境应该能够将这些解释为CAN消息并适当地转发。
我从socketcan 尝试过vcan,但它只能在同一Linux 机器的2 个终端之间工作。有人建议我查看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()
【问题讨论】:
-
不确定你想做什么。为什么不简单地在两台机器之间打开一个 TCP 套接字并发送日期呢? TCP 协议不关心负载是 CAN 消息还是其他。
-
好的。我正在为 Pi 代表汽车 ECU 的特定汽车用例构建一个虚拟平台。这就是我必须使用 CAN 的原因,因为 ECU 之间通过 CAN 进行交互。
-
仍然没有得到它。是的,ECU 交换数据;是的,他们可能在车上使用 CAN。你想模拟什么?交换的数据?时机? CAN 协议使用定义明确的物理层,如果没有适当的硬件,您将无法对其进行仿真。那么你将模拟什么?
-
我将模拟防抱死制动系统用例。 1 RPI 应通过 CAN 将车速值发送到笔记本电脑。
-
但为什么一定要“通过 CAN”。如果要模拟制动系统,为什么发送速度值还不够?
标签: python linux usb wifi can-bus