【问题标题】:Why is canlib behaving so slow?为什么 canlib 的行为如此缓慢?
【发布时间】:2021-03-06 05:41:10
【问题描述】:

这可能是在黑暗中拍摄,但这种行为让我很难过。

我正在为嵌入式电机控制器编写控制 gui,通过 CAN 与 PC 通信(使用 kvaser light leaf 2)。根据 Kvaser Can King 的说法,该总线为 1M bit/s,并且使用了大约 29% 的总线。问题是当我向嵌入式设备发送特定数据的请求时,在显示在我的 gui 上之前会有大约 10 到 15 秒的长时间延迟。延迟开始很小,如果我在启动时请求数据,它只有大约 1 秒。如果我让它静置几分钟

我写的第一个 gui 是在 python 中使用 tkinter。我发现性能是微不足道的:这意味着在我开始遇到延迟问题之前,我可以对 CAN 消息进行少量处理。我认为这是因为 python 是一种解释性语言,也许它跟不上速度太慢了。所以我用 C# 写了一个新的 gui,因为它是一种编译语言,应该运行得更快。但我遇到了同样的问题。用不同的主机、不同的嵌入式开发板和不同的 kvaser 尝试过,同样的问题。

有人知道会发生什么吗?

所以我的 python 线程方法如下所示:


def can_thread():  
    global finished  
    global can_log_name  
    global temp_log_name  
    global yoko_log_name  
    global time_last  
    global logging  
    global start_time  
    global TU1_active  
    global TU2_active  
    global TV1_active  
    global TV2_active  
    global TW1_active  
    global TW2_active  
    global Tcool_active  
    global state_dic  
    global printlog  
    global yoko_cmd  
    global can_timeout  
    global missed_messages  
    finished = None  
    start_time = time()  
    time_last_1Hz = time()  
    time_last_4Hz = time()  
    while not finished:  
        time_now = time()  
        elapsed_time_1Hz = time_now - time_last_1Hz  
        elapsed_time_4Hz = time_now - time_last_4Hz  
        finished = get_can_message()  
        if elapsed_time_1Hz > 1:  
            if logging == True:  
                if not temp_log_name == None:  
                    tempText = str(text_time)+ "," + \  
                               TU1_temp["text"] + "," + \  
                               TU2_temp["text"] + "," + \  
                               TV1_temp["text"] + "," + \  
                               TV2_temp["text"] + "," + \  
                               TW1_temp["text"] + "," + \  
                               TW2_temp["text"] + "," + \  
                               ULPF_current["text"] + "," + \  
                               VLPF_current["text"] + "," + \  
                               WLPF_current["text"] + "," + \  
                               Tcool_temp["text"]  
                    f = open(temp_log_name, "a")  
                    f.write(tempText + "\n")  
                    f.close  
                if not yoko_log_name == None:  
                    f = open(yoko_log_name, "a")  
                    f.write(str(text_time)+ "," + yoko_cmd)  
                    f.close  
            time_last_1Hz = time_now  
        if elapsed_time_4Hz > 0.25:  
            while incoming_message_queue.qsize() > 0:  
                frame = incoming_message_queue.get()  
                if frame.id == broadcast_frame_id + get_id():  
                    broadcast_frame(frame)  
                    None  
                elif frame.id == UTA2_frame_id + get_id():  
                    UTA2_frame(frame)  
                    None  
                elif frame.id == volt_cur_pow_frame_id + get_id():  
                    volt_curr_pwr_frame(frame)  
                    None  
                elif frame.id == state_faults_frame_id + get_id():  
                    state_faults_frame(frame)  
                    None  
                else:  
                    None  
            if missed_messages > 2:  
                can_inidicator_lbl["bg"] = "red"  
                can_inidicator_lbl["text"] = "CAN Timeout"  
            else:  
                can_inidicator_lbl["bg"] = "green"  
                can_inidicator_lbl["text"] = "CAN Traffic detected"  
            elapsed_time_4Hz = time_now  
        while outgoing_message_queue.qsize() > 0:  
            msg = outgoing_message_queue.get()  
            cn.ch.write(msg)  

我的 C# Thread 方法如下所示:

private void CanThread()
        {
            while(m_OkToRunThread)
            {
                try
                {
                    var result = m_CanMessage.ReadCanBusWithWait(m_canHandle, CAN_TIMEOUT);
                    if(result == Canlib.canStatus.canOK)
                    {
                        m_canTimeoutCount = 0;
                        m_canTimedOut = false;
                        CanMessageEventArgs e = new CanMessageEventArgs();
                        e.Message = m_CanMessage;
                        e.CanTimeOut = m_canTimedOut;
                        OnMessageReceived(e);
                    }
                    else if(result == Canlib.canStatus.canERR_NOMSG)
                    {
                        m_canTimeoutCount++;
                        if(m_canTimeoutCount > ALLOWED_TIMED_OUT_MESSAGES)
                        {
                            m_canTimedOut = true;
                            CanMessageEventArgs e = new CanMessageEventArgs();
                            e.Message = m_CanMessage;
                            e.CanTimeOut = m_canTimedOut;
                            OnMessageReceived(e);
                        }
                    }
                    else
                    {
                        m_OkToRunThread = false;
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                    //m_OkToRunThread = false;
                }
            }
        }

【问题讨论】:

  • 请创建一个 minimal 示例来演示问题!
  • 第一篇文章已编辑以显示线程方法
  • 您如何知道您的 CAN 总线设置为 1Mbps?你在上面放了一个范围吗?那将是相当有启发性的。您应该能够看到序列之间是否存在较长的延迟,或者是否真的是比特流变慢了。
  • 您是否遇到错误? CAN 本来就不是高性能的,但它可以在重试的低质量连接中存活下来。
  • 10-15 秒的延迟不太可能与 CAN 总线有关。我宁愿怀疑你的线程实现中存在死锁或饥饿。

标签: python c# can-bus


【解决方案1】:

就像在软件领域很多次一样,我找到了导致我的代码出现所有问题的人,他就是我。

为了通知用户嵌入式处理器仍在工作/未冻结,我每次进入 GUI 时都会在 GUI 上打印原始 CAN 消息。

我在 C# 中切换到“检测到 CAN/CAN 超时”指示,我所有的滞后问题都消失了。 CAN 消息的 ToString 方法并非微不足道,每次消息以 1Mb/s 总线的 29% 负载进入时调用该方法需要大量处理。它只是落后于公共汽车,延迟来自缓冲。

请注意,此解决方案在 python 中不起作用。 python 的解释特性跟不上这些速度。首先在 python 中尝试了解决方案但没有成功,这就是为什么我花了这么长时间才在 C# 中找到它的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 2016-03-27
    • 2013-10-19
    • 2011-05-03
    • 2017-09-01
    相关资源
    最近更新 更多