第3章--CANoe library开发 - 基础功能

>>>返回总目录<<<

本章目标

  1. 创建专栏的CANoe工程;
  2. 熟悉CANoe提供的常见接口;
  3. 开发CANoe library的基础功能。

前言

在介绍完behave之后,我们来讨论一下CANoe库的开发。

由于在实际测试中会涉及到大量CANoe的操作,因此,我们需要利用CANoe提供的COM接口来开发一个方便易用的库。

COM接口可以简单理解为CANoe提供的基础接口,其他程序可以通过这些接口控制CANoe。

CANoe准备

安装

那么在开始这项任务之前,首先需要做一些准备工作:完成CANoe的安装。如果你还没有安装CANoe,请参考以下链接进行安装:

https://blog.csdn.net/weixin_48143996/article/details/129486663

创建工程

以下是创建工程的详细步骤:

  1. 创建工程

首先,我们需要创建一个新的CANoe工程。在CANoe打开的主界面上,点击“File”按钮,并按照下图中所示的步骤进行设置。

![]](https://img-blog.csdnimg.cn/e484a4c23f3e488c92c31e5fc701f9b2.png)

  1. 保存工程

在创建工程后,需要将其保存到PyCharm工程目录下。在CANoe中,点击“Save”按钮并按照下图中所示的步骤进行设置。
在这里插入图片描述

  1. 添加通讯arxml

接下来,我们需要将PowerTrain.arxml文件放置在database文件夹中,如下图所示。
可以在安装的CANoe Sample configuration中找到PowerTrain.arxml,参考路径:C:\Users\Public\Documents\Vector\CANoe\Sample Configurations 16.4.4\CAN\CANSystemDemo_Autosar\Databases
在这里插入图片描述

然后,在CANoe工程中导入该arxml文件。
在这里插入图片描述
4. 配置CAN1,CAN2为CAN FD

由于现在普遍使用CAN FD,这里将CAN1和CAN2配置成CAN FD。在CANoe中,按照下图所示的步骤进行设置。
在这里插入图片描述

  1. 添加系统变量

需要添加两个系统变量:send_eng_msg和eng_speed。在CANoe中,按照下图所示的步骤创建这些变量。
在这里插入图片描述

  1. 添加节点

接下来,在CAN1上添加一个节点。请注意,这里是CAN1,而不是CAN2。在CANoe中,按照下图所示的步骤进行设置。
在这里插入图片描述

  1. 编写节点CAPL

CAPL是一种类C的编程语言,大家现在不用深究,看代码中的注释,明白大概是干什么就行。

最后,我们需要使用CAPL编写节点代码。在打开的CAPL browser(如果没有打开就再点击上图中第三步的按键)中,按照下图所示的步骤进行设置,并输入以下代码:
在这里插入图片描述

/*@!Encoding:936*/
includes
{
  
}

variables
{  
  msTimer timer500; // 声明的这个CAPL文件中的全局变量,msTimer类型(毫秒计时器)
}

on start
{

}

on timer timer500	// 事件触发,当timer500计时完成会被触发,timer500的设置在下面
{
  // 这里的内容,每次timer500被触发后都会执行一遍
  int spd;	// 声明局部变量spd,存放系统变量eng_speed的值
  pdu EngineData eng_pdu;	// 把arxml中的pdu“EngineData”声明为变量eng_pdu,便于后面设置信号,发送
  spd = sysGetVariableInt(sysvar::pyCANoe::eng_speed);	// 获取系统变量的值
  eng_pdu.EngSpeed = spd;	// 信号赋值
  triggerPDU(eng_pdu);	// 触发PDU发送,把PDU可以当作message
}

on sysvar pyCANoe::send_eng_msg	// 事件触发,当send_eng_msg的值“改变”时,会触发该部分程序
{
  int val;
  val = sysGetVariableInt(sysvar::pyCANoe::send_eng_msg);	// 获取系统变量的值
  if (val == 0) {	// 根据系统变量的值,确定是要开启timer,还是关闭timer
    write("stop sending engine message");
    cancelTimer(timer500);	// 关闭timer,也就是停止报文发送,因为报文是由这个timer触发的
  }
  else if (val == 1) {
    write("start sending engine message");
    setTimerCyclic(timer500, 500);	// 设置循环timer,timer会不断循环计时500ms,到了就触发。
  }
}

on sysvar pyCANoe::eng_speed	// 这部分只是用来输出系统变量的值的变化情况
{
  write("sysvar eng_speed set to %d", @pyCANoe::eng_speed);
}
仿真验证

在开发过程中,验证是一个至关重要的步骤,而仿真验证是其中一种非常有效的方法,它可以确保每个部件都能按照预期工作,并且在整个系统组装之前就进行了测试。

在进行仿真验证时,我们首先会验证每个部件的功能是否符合预期。例如这里我们我们先验证写好的CAPL能否通过直接改变系统变量来发送报文,如果验证成功,那么说明CAPL这部分的功能是按照我们的预期执行的。接下来,如果使用Python程序执行相同操作时出现了问题,那么大概率就是Python程序的问题。这样的方法使得我们可以快速排除问题,并且避免在后期的开发中浪费时间和资源。

具体来说,我们可以按照下图所示的顺序开启仿真,并更改eng_speed(改变信号的值)和send_eng_msg(控制报文是否发送)变量的值,观察Trace窗口是否有相关变化。
在这里插入图片描述

Python控制CANoe基础接口

运行CANoe软件

下面的代码会检查是否有CANoe在运行,如果没有,那么就会打开一个CANoe,如果已经CANoe运行,程序就会连接上已有的CANoe。代码执行成功之后,返回的是"Application"对象。

import time,os
from win32com.client import *
from win32api import Sleep
import types

app = DispatchEx("CANoe.Application")
打开configuration

根据传入的文件路径,打开相应的配置文件。

cfgPath = "D:\demo.cfg"
app.Open(cfgPath)
启动仿真

获取“Measurement”对象并启动仿真,为了等待仿真启动,加入了3秒的等待时间。

meas = app.Measurement
meas.Start()
time.sleep(3)
读写信号

获取"Bus"对象,注意这里的传入参数并不是网络名称,而是总线类型,即便有多个CAN网络,也是通过下面的方式获取,传入参数可以有其他值,例如:“LIN”,“FlexRay”,“Ethernet”。

can_bus = app.GetBus('CAN')

基于"Bus"对象,传入channel,报文名称以及信号名称可以获取相应的"Signal"对象,然后读取或者写入信号的值。

但有时当写入信号的值时,可能会看到CANoe软件报错,具体报错内容不记得了。这个问题通常是由于采用的IG模块或者自动从通讯数据库读取初始值后自动发送报文,且没有配置interaction layer所导致的。我没有深入研究这个问题,如果遇到这种情况,可以咨询Vector。

平时我习惯在CAPL中定义报文的发送,并通过系统变量来更改特定信号的值。然后外部程序改变系统变量的值就可以改变信号的值。

另外,设置信号值的时候,可能会遇到数据类型不匹配的情况,需要注意一下。

sig1 = can_bus.GetSignal(0,'EngineData','EngSpeed')
# 读信号的值,physical value
print("signal value:",sig1.Value)
# 读信号的值,raw value
print("signal raw value:",sig1.RawValue)

# 写信号的值
sig1.Value = 1000
读写系统变量

程序可以根据名称获取"namespace"对象,通过变量名称获取"Variable"对象,然后读、写系统变量的值,写变量的值的时候也需要注意数据类型,namespace和变量名称请查看下面的图。

ns_name = "can_py_inter"
var_name = "voltage_value"

ns_obj = app.System.Namespaces(ns_name)
sysvar_obj = sys_ns.Variables(var_name)

# 读系统变量的值
sys_value = sysvar_obj.Value

# 写系统变量的值
sysvar_obj.Value = 12

在这里插入图片描述

COM接口使用

在使用COM接口时,我们经常会面临一些困惑。例如,我们如何知道各个对象具有哪些成员和方法?如果你遇到这类问题,可以参考下面文章中的“vector help文档阅读部分”进行解决。

https://zhuanlan.zhihu.com/p/604627246

Library开发

库安装

首先需要安装pywin32库。具体操作请参见以下截图:
在这里插入图片描述

代码详解

完整的代码放在后面了,这部分仔细介绍各部分代码。

init方法

此外,在代码编写过程中,我们需要仔细理解每个部分的含义。其中,init方法是一个特殊函数,当您初始化一个类的对象时,该方法将被执行。在本例中,我们定义了一个名为CANoeInterface的类,当您执行以下代码时,init方法将被调用:

init方法(方法就是函数,只不过在面向对象的编程语言中,通常会把类中定义的函数称为这个类的方法,专栏中会混用这两个名词)是当你初始化一个类(类是class的翻译,就是类型的意思)的对象时会执行的内容,控制CANoe的类的名字是CANoeInterface,当执行下面这一句代码时就会调用init方法。

n_canoe = CANoeInterface(project_folder + config_name)

以下是完整的代码,并包含了对各个部分的详尽注释,请仔细查看。

class CANoeInterface:
    def __init__(self, a_config_name):
        self.config_name = a_config_name	# 把传入参数赋给类中的一个变量,这样类中的各个方法都可以使用
        self.app = DispatchEx("CANoe.Application")
        # 1. 这一步会建立python程序与CANoe软件之间的连接,如果CANoe没有打开,这一句代码会打开CANoe,
        # 如果已经打开了,则会直接连接这个已经打开了的CANoe;
        # 2. 如果你的电脑上安装了不同版本的CANoe,这里默认会打开最后安装的CANoe,因为最后安装的CANoe会更新
        # 注册表中的某个值,程序会根据注册表的这个值来确定要打开的CANoe;例如你电脑上先安装了CANoe 11,后面又
        # 安装了CANoe 16,此时运行程序会自动打开CANoe 16,如果你希望Python控制CANoe 11,有两个方法:1) 提前
        # 打开CANoe 11,参考1中的说明,因为提前打开了CANoe 11,所以程序会直接与CANoe 11建立连接,2) CANoe安装
        # 目录下有个程序可以更新注册表,具体的内容我不记得了,后面找到信息了补上。
        # 3. 还有一个方法是Dispatch(),也可以打开CANoe,好像就是不论有没有已经打开的CANoe,都会重新打开一个,我
        # 没有使用这个方法。
        self.ver = self.app.Version  # 获取CANoe的版本
        self.running = lambda: self.app.Measurement.Running
        # lambda是Python中的匿名函数(就是没有名字的函数,因为有时候程序员觉得给函数取名字也很费劲)
        # 这里self.running是一个函数,后面每一次使用self.running(),就相当于调用
        # return self.app.Measurement.Running,即CANoe仿真是否在运行。
        # 不能去掉lambda,直接使用self.running = self.app.Measurement.Running,因为这样只是
        # 获取现在的值,后面值就不会改变了。
        self.app.Configuration.Modified = False
        # 这一步是标记configuration没有做过修改,因为操作CANoe的时候(调整窗口,增加观测量等),经常会导致
        # CANoe configuration的变更,如下图所示,config名字右上角带星号说明有变更了,而程序在遇到变更过的
        # configuration时,直接打开别的config会报错(人在此时操作,打开别的config时,会收到提示是否要保存
        # 这个config)。很多时候这种变更是不需要保存的,所以程序这里直接标记为没有变更,后续的操作就能正常执行。
        self.stop_measurement()
        # 这一步操作的原因和上一步类似,因为有时候你操作的CANoe可能正处于运行中(例如上一次测试异常中断,但是
        # CANoe没有停),所以需要判断状态并停止运行。
        print(f"Open config: {self.config_name}")
        self.app.Open(self.config_name)  # 打开你需要的config

在这里插入图片描述

Measurement start/stop方法
    def start_measurement(self):
        # 开始仿真的函数
        if not self.running():
            # 和上面解释的一样,self.running是一个函数,这里调用函数来判断measurement是否在运行
            # 当measurement没有运行时,执行下面代码
            print("Starting measurement")
            self.app.Measurement.Start()  # 控制开始measurement
            sleep(2)  # 开始仿真需要一些时间,这里做一个延时,避免后续的操作在measurement还没有开始就执行

    def stop_measurement(self):
        # 同上,停止measurement的代码
        if self.running():
            print("Stopping measurement")
            self.app.Measurement.Stop()
            sleep(2)

    def close_canoe(self):
        # 关闭CANoe程序的代码;实际测试时通常不执行
        # 两个原因:
        # 1. CANoe打开比较费时,
        # 2. 测试完成之后CANoe中还保存了测试的trace,方便查看
        if self.app is not None:
            print("Close CANoe")
            self.app.Quit()
            self.app = None
get/set system variable
    def get_system_variable(self, sysvar_full_name):
        # sysvar_full_name: py_CANoe::eng_speed
        tokens = sysvar_full_name.split("::")
        namespace = self.app.System.Namespaces(tokens[0])
        # tokens[0]是py_CANoe,即namespace的名字
        var_value = namespace.Variables(tokens[1]).Value
        # tokens[1]是eng_speed,即系统变量的名字
        return var_value

    def set_system_variable(self, sysvar_full_name, value):
        # 和get_sys_var相同
        tokens = sysvar_full_name.split("::")
        namespace = self.app.System.Namespaces(tokens[0])
        sys_value = namespace.Variables(tokens[1])
        if isinstance(sys_value.Value, int):
            # 这里的判断是确定该系统变量的类型,并进行相应的转型,我一般是使用int,所以没有尝试别的数据类型
            # 如果类型不匹配会导致赋值失败,且Python不会报错。
            set_value = int(value)
        else:
            set_value = float(value)
        sys_value.Value = set_value
get/set signal

这里set_signal_value需要配置interaction layer,我一直没有弄,有些问题,后续补上。

    def get_signal_value(self, signal_full_name):
        # signal_full_name: CAN::EngineData::EngSpeed
        tokens = signal_full_name.split("::")
        signal = self.app.GetBus(tokens[0]).GetSignal(0, tokens[1], tokens[2])
        # tokens[0]: CAN(Bus类型), tokens[1]: EngineData(message或者pdu名称), tokens[2]: EngSpeed(信号名)
        return signal.Value

    def set_signal_value(self, signal_full_name, value):
        tokens = signal_full_name.split("::")
        signal = self.app.GetBus(tokens[0]).GetSignal(0, tokens[1], tokens[2])
        signal.Value = float(value)

功能测试

测试代码

在完成功能开发后,为了确保程序的正确性,需要进行功能测试。我们通过添加以下代码到py_canoe.py文件中来进行测试:

if __name__ == '__main__':
	# 这一句是判断是否执行的当前python文件,如果是在别的文件中执行,则不会运行以下代码。
    # 只有在直接运行py_canoe.py的时候会运行下面的代码,别的文件中import py_canoe时不会运行。
    project_folder = r"D:\11_projects\21_demo\09_auto_test"
    config_name = r"\canoe_project\auto_test.cfg"
    n_canoe = CANoeInterface(project_folder + config_name)
    n_canoe.start_measurement()
    send_msg_flag = "pyCANoe::send_eng_msg"
    sys_var_eng_spd = "pyCANoe::eng_speed"
    print("send_msg_flag value at start:", n_canoe.get_system_variable(send_msg_flag))
    print("eng_spd value at start:", n_canoe.get_system_variable(sys_var_eng_spd))
    n_canoe.set_system_variable(send_msg_flag, 1)
    sleep(1)
    n_canoe.set_system_variable(sys_var_eng_spd, 3000)
    sleep(2)
    print("send_msg_flag value after change:", n_canoe.get_system_variable(send_msg_flag))
    print("eng_spd value after change:", n_canoe.get_system_variable(sys_var_eng_spd))
	# set/get signal的部分后面再补
    n_canoe.stop_measurement()
Python输出

在执行了上述代码后,Python会输出以下信息:
在这里插入图片描述

CANoe trace

在CANoe的Trace窗口,我们可以看出信号的变化情况:
在这里插入图片描述

总结

本章我们完成了Python控制CANoe的基本功能开发,在后续,还将继续扩展该库,以提供更多的功能。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Canoe是一种常见的皮艇,在水上运动、娱乐和探险等方面都有广泛的应用。以下是Canoe常用操作: 1. 上下船:Canoe的进出非常重要,要注意不要让水进入船里。可以站在沙滩或浅水处,把Canoe推入水中,然后慢慢爬进去。下船时也是反着来,膝盖轻轻着陆,扶着边缘慢慢站起来。 2. 控制航向和速度:Canoe是一种需要配合双桨使用的船,双手各握一根桨。在左右桨配合的情况下,可以控制船体的航向和速度。如果希望向左转,可以在右边划水。如果希望加速,可以双桨反复划动。 3. 防止翻船:在划水时要保持平衡,避免船体左右晃动,导致翻船。如果船体有一边高出水面,可以调整重心,让低的一边压水,保持平衡。 4. 注意安全:Canoe是一种比较安全的皮艇,但也要注意安全。在划水之前,要检查桨和绳索是否有松动或损坏。在远离岸边和水深处划船时,要戴上救生衣,以便在意外情况下保护自己。 总之,使用Canoe需要一定的技巧和经验,需要慢慢积累,熟悉Canoe的操作才能更好地享受划船的乐趣。 ### 回答2: 使用船划的技巧和方法,主要取决于你要旅行的地点和条件。基本上,船划可以分为平稳水面和崎岖的水流。在平稳的水面,船划者可以使用一些基本的技巧和方法,在船头驱动船尾,控制船的方向。而在崎岖的水流中,船划者需要更加高超的船划技巧和方法,才能防止船失控,摔倒或者陷入危险之中。 在正常的船划中,要注意以下几点:首先,打个好底板,划一下慢一下快,适应水流。然后可以通过手法控制船的方向,同时划的力度也是需要注意的,如果船划的太累,会影响到后面的行程。另外,在船划过程中,要时刻留意周围环境,防止遇到危险的情况,比如不可预测的水流或者巨石。 此外,船划时还要注意一些细节问题,比如需要正确佩戴救生衣和带上头盔,以确保自身安全;在船划前需要仔细检查船只,确保其完好无损,并正确安装和使用相关设备,比如橡皮艇三角水果筐装置、红外线导轮、桨锁固定线等等。 在平静水面上常用的操作方法包括:划直线,划弯线,反向划行,停船泊岸,调整方向等。如想划直线,则需要将船头对准望远镜上的目标点,平直的划动桨;如想划弯线,则需要左桨在船头左侧舒展,右桨在后面划动;如想反向划行,则需要左右两桨同时顺时针或逆时针划动;如想停船泊岸,则需要将船头靠岸,左右两桨平直划动;如想调整方向,则需要将左右两桨的力度相等,轻松转向。这些技巧都需要船划者多多练习和把握。 总之,娴熟的船划技术和操作方法对于保证船和人的安全,顺利完成行程非常重要。因此,学习船划者可以多听别人的建议,多练习,逐渐提高水平,更好地控制自己和船只。 ### 回答3: Canoe是一种轻便的独木舟,广泛应用于白水漂流、野生动植物观察、钓鱼等活动中。使用Canoe前,需要熟悉其基本操作技巧,以下是Canoe的常用操作: 1. 坐稳 Canoe:在刚开始使用 Canoe 时,需要将身体往中间靠拢,保持重心稳定,膝盖放松微弯,双手握住 Canoe 的桨柄控制行进方向,以保证 Canoe 平稳前行。 2. 转向 Canoe:转向 Canoe 有两种方法,一种是使用 paddling 方式,通过划桨的正反向控制坐舱的转向,另外一种是空翻转向,采用身体向左或向右转动,然后 Canoe 就会自动向相反的方向旋转。 3. 调整 Canoe 的姿态:在划船过程中,Canoe 可能会向左或向右偏航,需要及时调整 Canoe 姿态。当 Canoe 向左偏航时,需要右边桨刮更深入水中或者左边桨控制桨头向左,使 Canoe 保持平衡状态。同理,当 Canoe 向右偏航时,则需要左边桨进行调整。 4. 刹车:当 Canoe 要进入弯道或者下降时需提前减速,可以倒退划桨或者采用抓水刹车方式使其缓慢前行,可控制 Canoe 前进速度。 5. 在 Canoe 中保持安全:在 Canoe 旅行过程中,一定要保持安全意识,避免突然站立行走、拍打 Canoe 或其他失去平衡的行为。 总而言之,Canoe 的使用需要一定的技巧和经验,掌握了基本的操作方法才能更好地享受旅行过程。在使用过程中需注意安全,遵守相关规定和建议,以免发生意外情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值