项目原因需要使用python进行can的收发,将操作进行记录
之前在stm32和k60上用C收发过can,本来以为会很顺利,然而还是踩了很多坑
测试设备:
天准xavier Ubuntu18.04 python3.6
先给一个比较官方的链接(python_can)
SocketCAN — python-can 4.0.0 documentation
天准官方也给出了比较详细的命令行测试命令
sudo ip -details link show can0 可以查看can的详细信息
python_can数据发送代码
import can
import time
def msg_send(bus,msg,state_byte,speed,speed_brush,speed_wind,life_count):
speed_byte = speed.to_bytes(2,'big')
# print(state_byte+speed_byte)
speed_byte3 = speed_brush + 16*speed_wind
byte3 = speed_byte3.to_bytes(1,'big')
byte4 = (0).to_bytes(1,'big')
byte5 = (0).to_bytes(1,'big')
byte6 = (0).to_bytes(1,'big')
byte7 = life_count.to_bytes(1,'big')
msg.data = state_byte + speed_byte + byte3 + byte4 + byte5 + byte6 + byte7
print(msg)
bus.send(msg)
python 接收数据代码
import can
def msg_recive(bus):
msg = bus.recv()
print(msg)
# msg = can.Message(arbitration_id=0x1808DA28, data=[1, 5, 6, 53, 4, 51, 6, 6], extended_id=False)
# if(msg.arbitration_id == 0x1808DA28):
if(msg.arbitration_id == 0x180828DA):
data = msg.data
print(msg.data)
for i in range(8):
print(data[i])
can_bus = can.interface.Bus(channel = 'can0', bustyp = 'socketcan_ctypes')
while(True):
msg_recive(can_bus)
1. 采坑1 :循环发送的话会导致buffer问题
Traceback (most recent call last):
File "/home/nvidia/.local/lib/python3.6/site-packages/can/interfaces/socketcan/socketcan.py", line 679, in _send_once
sent = self.socket.send(data)
OSError: [Errno 105] No buffer space available
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/nvidia/can_test/socket_can.py", line 40, in
producer(10)
File "/home/nvidia/can_test/socket_can.py", line 29, in producer
bus.send(msg)
File "/home/nvidia/.local/lib/python3.6/site-packages/can/interfaces/socketcan/socketcan.py", line 658, in send
sent = self._send_once(data, msg.channel)
File "/home/nvidia/.local/lib/python3.6/site-packages/can/interfaces/socketcan/socketcan.py", line 681, in _send_once
raise can.CanError("Failed to transmit: %s" % exc)
can.CanError: Failed to transmit: [Errno 105] No buffer space available
改大buffer可以作为解决问题的一种暂时方案,但主要问题在于数据传输有问题,才会造成buffer阻塞。
(要注意在每次发送前,清空一次can buffer)
可以先尝试改大缓存,如果仍然报错,需要查找根本原因。
进入 root账户,在路径 /sys/class/net/can0下执行 echo 4096 > tx_queue_len
使用如下py脚本进行测试
每次重启后,再发都会稳定死在 第11次发送
使用win10PC,pcan软件连接can卡分析can数据,发现接收端没有收到数据,换了个can卡之后问题解决。(排查硬件故障也是软件的一部分工作啦)
采坑2 :用python应该多探索库函数,而不是和C一样啥都想自己写
比如我最初写的这个很蠢的代码 (os.system是最初测试用的,小问题)
def byte2hex(byte):
if(byte < 16):
ret = '0' + hex(byte)[2:]
else:
ret = hex(byte)[2:]
return ret
def send_can(distance,move_dis,life_count):
time1 = time.time()
byte1 = abs(int(distance) % 256)
byte2 = int(abs(int(distance) / 256))
if distance < 0:
byte2 = int(byte2 + 128) #处理负数
byte3 = abs(int(move_dis) % 256)
byte4 = int(abs(int(move_dis) / 256))
if move_dis < 0:
byte4 = int(byte4 + 128)
# byte5 =
# byte6 =
# byte7 =
can_id = '180828DA#'
str0 = '0A' #根据手册的状态分情况转一下十六进制
# str1 = hex(byte1)[2:]
# str2 = hex(byte2)[2:]
# str3 = hex(byte3)[2:]
# str4 = hex(byte4)[2:]
str1 = byte2hex(byte1)
str2 = byte2hex(byte2)
str3 = byte2hex(byte3)
str4 = byte2hex(byte4)
str5 = '00'
str6 = '00'
str7 = hex(life_count)[2:]
str_all = str7 + str6 + str5 + str4 + str3 +str2 + str1 +str0
send_cmd = 'cansend can0 '+ can_id + str_all
# os.system(send_cmd)
#time1 = time.time()
subprocess.call(send_cmd, shell=True)
time2 = time.time()
print("use subproces : ",time2 - time1)
time1 = time.time()
os.system(send_cmd)
time2 = time.time()
print("use system : ",time2 - time1)
while True:
send_can(distance111,move_dis111,life_count111)