CAA DMU模块仿真

news2024/11/27 22:45:22

背景

本人由于项目原因,需要基于CATIA格式文件研究CAM的一些操作,其中就包括仿真功能,而CATIA中适合实现仿真功能的模块就是 DMU (Digital Mock-Up) 模块,本人研究了很长时间,尝试了很多方案,特地记录下来方便后续查看。

CATIA提供的CAA可以为C++编程提供支持,但是CAA编程又与一般的C++编程有所不同,主要是CATIA是基于COM组件架构构建的,CATIA使用C++来实现它的COM架构,在CAA中除了少数的几个数学和几何类可以实例化,其它的类型都是接口。举个简单的例子,例如有一个特征对象,要获取这个特征对象的别名,

// 拿到特征对象
CATISpecObject* piSpecObj = GetSpecObj();
// 获取别名
CATIAlias* piAlias = NULL;
pSpecObj->QueryInterface(IID_CATIAlias, (void**)&piAlias);
if (NULL != piAlias)
	printf("特征名称 %s\n", piAlias->GetAlias().ConvertToChar());

并不是通过访问特征对象的属性实现的,而是通过,CATISpecObject 继承自父类 CATBaseUnknown 的 QueryInterface 方法来查询当前对象是否支持 CATIAlias 接口,从而判断是否能获取它的别名。有关COM架构的内容可以参考《COM技术内幕》这本书,这也是开始的时候最让我困惑的地方(居然几乎没有可以实例化的类型,好不容易拿到了对象我竟然不知道它的具体类型,只有一个模糊的CATISpecObject* 这样的基类指针,有时候甚至是 CATBaseUnknow* 指针,更不知道怎么访问)。

但这也同样是COM架构的优势,它不需要事先知道另一个组件的细节,因此可以置换另一个组件,只要实现相同的接口。
在这里插入图片描述
同时它还可以实现像OLE这种在我看来十分神奇的技术,它可以让你通过一段VBA或者Python脚本,拿到正在运行的CATIA应用程序对象,例如下面的VBA脚本

Set CATIA = GetObject(,"CATIA.application");

然后可以访问它的 Documents,Cameras,Windows 这些属性,可以实现类似CAA一样的脚本操作。
在这里插入图片描述

DMU模块基础概念

CAA 开发资料最主要是 CATIA 软件下载时自带的一个 百科全书 里面有各种模块的描述还有一些案例(在CATIA软件安装目录下的 CAAV5HomePage.htm 的HTML文件,可以使用浏览器打开)这是它的一个在线版本
还有就是根目录下 intel_a\code\bin 下有一些可执行程序,里面有一个 CNextHelpViewer.exe 是对 百科全书中接口对象的一个整理。
另外我所知道的就是 icax 和 COE 论坛的CAA板块,有时可以找到一些讨论。

在百科全书主页中,点击 site map, 搜索DMU关键字可以找到所有DMU部分的资料
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

其中ENOVIA模块中的资料是重复的
Kinematics Overview 中可以了解到 构建运动的基本概念(Product, 关节,命令,机制)
Product 是部件,关节是对Product之间运动约束的描述(构造运动副),命令可以为关节的运动约束指定参数,机制是Product和关节的集合,其中的一个Product附着在地面上,被定义为Fix。

Simulation Overview 中可以了解到 仿真操作的基本概念(动画对象,状态,采样,通道,重放)
大概就是,重放是一个场景,里面有很多的动画对象,每一个动画对象包含很多属性,这些属性会随着时间的推移发生变化,使用通道(Channel )刻画一个属性随着时间的变化,采样是每个时刻对应的属性值,状态是属性值。

DMU模块仿真

使用 DMU 仿真,首先需要定义运动学,之后计算仿真动画(重放)

定义运动学

定义运动学,可以在CATIA中手动操作,也可以使用CAA代码实现,我这演示手动操作的步骤,基本流程如下

  • 定义固定部件
  • 首先需要定义各个组件之间的运动学关系,定义不同类型的关节(运动副),关于关节的定义可以参考 DMU 运动机构仿真教程、DMU 运动机构分析
  • 定义驱动命令

定义完驱动命令,然后自由度降为0,设置好 fix 部件,提示可以仿真即可。

计算仿真动画

这个步骤是CAA仿真的难点,实现仿真功能其实并不是太难,只需要了解各个部件之间怎么运动,设置对应的层级关系和变换矩阵,使用例如OSG库是非常容易实现的,但是找到CAA中支持的接口来实现确实难上加难,我尝试过一些方案,但是每个方案的实现都遇到了问题,首先我尝试了使用装配树移动的功能,装配树(CATIProduct)有 CATIMovable 接口,可以查询子 CATIProduct 或 CATIPart 的位置,并且可以移动它们的位置,但是当我想计算变换矩阵的时候却遇到了很大的问题, 因为 CATIMovable 接口查询到的位置,并不是 CATIPart 的默认坐标系原点的位置(即Part三个平面的交点位置),而且在CATIPart 坐标系下也找不到 CATIMovable 接口查询到的位置,这让这个变换的链条断掉了,目前还没有找到解决方案,不过在COE论坛上似乎有VBA下的解决方案,但是我尝试后还是无法实现,貌似接口不一样。于是,我又尝试了新建线程 + CATIKinMechanism设置命令参数 的方案,但是找不到CATIA对多线程线程安全的支持,新线程中 CATIKinMechanism设置命令参数 会导致场景更新,如果场景更新没有结束立马有调用 设置命令参数的方法,程序就会崩溃,使用Sleep函数需要设置一个非常大的间隔才能保证安全,但是这已经无法满足连续仿真的要求了。在这之后我找到了教程 Creating a Product’s Motion in a Document 但是我开始的时候直接否定了这个方案,因为CATIReplayChannelProductMove添加Sample要求的参数是变换矩阵,而我知道CAA中计算一个准确的变化矩阵是不可行的。于是我开始尝试 CATIReplayChannelScalarObserver,但是构造的 Replay 无论如何都无法开始播放。

最后,当我遍历并打印 装配树重放结点 想看看程序构建的回放和CATIA DMU模块中操作创建出的回放有什么不同时,发现他是用正是CATIReplayChannelProductMove,再当我回头看 CATIKinMechanim 接口时找到了 GetProductMotion 方法,这才走通了DMU仿真的过程。
在这里插入图片描述
简单来说,DMU仿真的过程,假设你已经构造好了运动学,有一组命令了,可以通过 CATIKinMechanism 接口的 SetCmdValues 方法设置命令参数,之后通过 GetProductMotion 方法拿到这组命令参数对特定的Product产生的变换矩阵,下面是通过顶层Product获取CATIKinMechanism 的示例

CATDocument* pDoc = Utils::GetDocumentFromProduct(pTopProduct);

CATIKinMechanismFactory* piMechanismFactoryOnDocument = NULL;
HRESULT HR = pDoc->QueryInterface(IID_CATIKinMechanismFactory,(void**)&piMechanismFactoryOnDocument);
if (!SUCCEEDED(HR)) return;

CATLISTP(CATBaseUnknown) listOfMechanisms;
HR = piMechanismFactoryOnDocument->ListInstances (listOfMechanisms);
if (!SUCCEEDED(HR)) return;

if (listOfMechanisms.Size() < 1)
{
	Utils::DisplaySimpleWindowMsg("提示", "创建机制,没有可仿真的机制");
	return;
}

// 获取第一个机制
CATIKinMechanism* piMechanism = NULL;
listOfMechanisms[1]->QueryInterface(IID_CATIKinMechanism, (void**)&piMechanism);
CATIAlias_var mechanismAlias = piMechanism;
Utils::Log("use mechanism %s", mechanismAlias->GetAlias().ConvertToChar());

之后通过从相应Product对象中获取的 CATIReplayChannelProductMove接口的 AddSample 方法,将时间和 对应的变换矩阵填入即可,下面是一段示例代码。

// 获取 IReplayFactory
CATIReplayFactory* piReplayFactory = NULL;
HRESULT HR = pDoc->QueryInterface(IID_CATIReplayFactory,(void**)&piReplayFactory);
if (!SUCCEEDED(HR)) return;
// 创建一个新的 Replay
CATIReplay* piReplay = NULL;
HR = piReplayFactory->CreateInstance (&piReplay);
if (!SUCCEEDED(HR)) return;
// 获取 ReplayChannelProductMoveFactory
CATIReplayChannelProductMoveFactory* piReplayChannelProductMoveFactory = NULL;
HR = piReplay->QueryInterface(IID_CATIReplayChannelProductMoveFactory,(void**)&piReplayChannelProductMoveFactory);


CATIProduct* topProduct = Utils::GetTopProduct();
CATListValCATBaseUnknown_var* pProductList = topProduct->GetChildren("CATIProduct");
if (NULL == pProductList) 
{
	Utils::DisplaySimpleWindowMsg("提示", "没有找到仿真部件");
	return;
}

// 遍历相关的Product,将它们对应的 ReplayChannelProductMove 存入 channelProductMoves 中
int nProducts = pProductList->Size();
CATIProduct* targetProduct = Utils::GetTargetProduct();
std::vector<CATIProduct*> childProducts;
std::vector<CATIReplayChannelProductMove*> channelProductMoves;
for(int i=1; i <= nProducts; i++)
{
	CATIProduct* pProduct = NULL;
	(*pProductList)[i]->QueryInterface(IID_CATIProduct, (void**)&pProduct);
	if ( pProduct != targetProduct && pProduct)
	{
		childProducts.push_back(pProduct);

		CATIReplayChannelProductMove* pChannelProductMove = NULL;
		piReplayChannelProductMoveFactory->CreateInstance((CATBaseUnknown **)&pProduct, &pChannelProductMove);
		if (pChannelProductMove != NULL)
		{
			channelProductMoves.push_back(pChannelProductMove);
		}

	}
}

下面是我的AddReplayFrame 函数的定义,供大家参考


void SimulationCmd2::ApplyFrame(CATIKinMechanism* piMechanism, const Utils::Frame& frame)
{
	CATLISTP(CATBaseUnknown)* listOfCmds = NULL;
	piMechanism->GetCmdList(&listOfCmds);

	int size = listOfCmds->Size();
	double *cmdValues = new double[size];


	std::vector<std::pair<CATUnicodeString, double>> vec;
	vec.push_back(std::pair<CATUnicodeString, double>("X", frame.x));
	vec.push_back(std::pair<CATUnicodeString, double>("Y", frame.y));
	vec.push_back(std::pair<CATUnicodeString, double>("Z1", frame.z1));
	vec.push_back(std::pair<CATUnicodeString, double>("Z2", frame.z2));
	vec.push_back(std::pair<CATUnicodeString, double>("A", frame.a));
	vec.push_back(std::pair<CATUnicodeString, double>("B", frame.b));

	for(std::vector<std::pair<CATUnicodeString, double>>::iterator iterVec = vec.begin(); iterVec != vec.end();iterVec++)
	{
		std::map<CATUnicodeString,int>::iterator iter = m_commandFieldMap.find(iterVec->first);
		if (iter != m_commandFieldMap.end())
		{
			if (iter->second >= 0 && iter->second < size)
			{
				cmdValues[iter->second] = iterVec->second;
			}
		}
	}

	static int index = 0;
	Utils::Log("apply cmd values index %d", ++index);
	for(int i=0; i < size; i++)
		Utils::Log("index %d %f", i, cmdValues[i]);
	Utils::Log("end ");
	piMechanism->SetCmdValues(size, cmdValues);
	
	
	delete[] cmdValues;
}

void SimulationCmd2::AddReplayFrame(CATIKinMechanism* piMechanism, 
					const std::vector<CATIProduct*>& products, 
					const std::vector<CATIReplayChannelProductMove*>& channelProductMoves,
					const Utils::Frame& frame, double timeMillSec)
{
	ApplyFrame(piMechanism, frame);
	Utils::Log("ApplyFrame, x=%f,y=%f,z1=%f, z2=%f,a=%f,b=%f, time=%f", frame.x, frame.y, frame.z1, frame.z2, frame.a, frame.b, timeMillSec);

	int nProducts = products.size();
	assert(products.size() == channelProductMoves.size());

	for(int j=0; j < nProducts; j++)
	{
		CATIProduct* pProduct = products.at(j);
		double *motion = NULL;
		piMechanism->GetProductMotion(pProduct, &motion);

		channelProductMoves.at(j)->AddSample(timeMillSec, motion);

		delete motion;

	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1055857.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为云云耀云服务器L实例评测|Docker部署及应用

文章目录 前言&#x1f4e3; 1.前言概述&#x1f4e3; 2.服务器攻击✨ 2.1 问题描述✨ 2.2 处理方法 &#x1f4e3; 3.Docker简介&#x1f4e3; 4.安装Docker✨ 4.1 卸载旧版docker✨ 4.2 安装依赖包✨ 4.3 安装GPG证书✨ 4.4 配置仓库✨ 4.5 正式安装Docker✨ 4.6 配置用户组✨…

Spring Boot的魔法:构建高性能Java应用

文章目录 Spring Boot&#xff1a;简化Java开发Spring Boot的性能优势1. 内嵌服务器2. 自动配置3. 起步依赖4. 缓存和优化5. 异步处理 实际示例&#xff1a;构建高性能的RESTful API总结 &#x1f389;欢迎来到架构设计专栏~Spring Boot的魔法&#xff1a;构建高性能Java应用 ☆…

洛谷P1102 A-B 数对题解

目录 题目A-B 数对题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1提示传送门 代码解释亲测 题目 A-B 数对 题目背景 出题是一件痛苦的事情&#xff01; 相同的题目看多了也会有审美疲劳&#xff0c;于是我舍弃了大家所熟悉的 AB Problem&#xff0c;改用 …

Python与Scrapy:构建强大的网络爬虫

网络爬虫是一种用于自动化获取互联网信息的工具&#xff0c;在数据采集和处理方面具有重要的作用。Python语言和Scrapy框架是构建强大网络爬虫的理想选择。本文将分享使用Python和Scrapy构建强大的网络爬虫的方法和技巧&#xff0c;帮助您快速入门并实现实际操作价值。 一、Pyt…

“链圈”十年反思

2013 年 11 月&#xff0c;Vitalik Buterin 发表了以太坊白皮书的第一个版本。事后人们经常把这视为“区块链 2.0” 时代开启的标志&#xff0c;但在当时&#xff0c;其实是以太坊的出现才使得“区块链”作为一项单独的技术从“数字货币”当中分离出来。换句话说&#xff0c;比…

基于Java的大学生英语考试答题系统设计与实现(亮点:答题系统、报名系统、在线视频、在线聊天、附件下载)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

2023 年最佳多 GPU 深度学习系统指南

动动发财的小手&#xff0c;点个赞吧&#xff01; 本文[1]提供了有关如何构建用于深度学习的多 GPU 系统的指南&#xff0c;并希望为您节省一些研究时间和实验时间。 1. GPU 让我们从有趣&#xff08;且昂贵&#xff09;的部分开始&#xff01; 购买 GPU 时的主要考虑因素是&am…

flutter开发实战-webview插件flutter_inappwebview使用

flutter开发实战-webview插件flutter_inappwebview使用 在开发过程中&#xff0c;经常遇到需要使用WebView&#xff0c;Webview需要调用原生的插件来实现。常见的flutter的webview插件是webview_flutter&#xff0c;flutter_inappwebview。之前整理了一下webview_flutter&…

htb-cozyhosting

HTB-CozyHosting https://app.hackthebox.com/machines/CozyHosting ──(kwkl㉿kwkl)-[~] └─$ tail -l /etc/hosts …

凉鞋的 Unity 笔记 103. 检视器:GameObject 的微观编辑和查看

103. 检视器&#xff1a;GameObject 的微观编辑和查看 在上一篇&#xff0c;笔者简单介绍了场景层次 与 GameObject 的增删改查&#xff0c;如下所示&#xff1a; 在这一篇&#xff0c;我们接着往下学习。 我们知道在 场景层次 窗口&#xff0c;可以对 GameObject 进行增删改…

金融帝国实验室(CapLab)官方更新_V9.1.15版本(2023年第64次)

〖金融帝国实验室〗&#xff08;Capitalism Lab&#xff09;游戏更新记录&#xff08;2023年度&#xff09; ————————————— ◎游戏开发&#xff1a;Enlight Software Ltd.&#xff08;微启软件有限公司&#xff09; ◎官方网站&#xff1a;https://www.capitalis…

力扣-338.比特位计数

Idea 直接暴力做法&#xff1a;计算从0到n&#xff0c;每一位数的二进制中1的个数&#xff0c;遍历其二进制的每一位即可得到1的个数 AC Code class Solution { public:vector<int> countBits(int n) {vector<int> ans;ans.emplace_back(0);for(int i 1; i < …

洛谷P5732 【深基5.习7】杨辉三角题解

目录 题目【深基5.习7】杨辉三角题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1传送门 代码解释亲测 题目 【深基5.习7】杨辉三角 题目描述 给出 n ( n ≤ 20 ) n(n\le20) n(n≤20)&#xff0c;输出杨辉三角的前 n n n 行。 如果你不知道什么是杨辉三角&#xf…

基于SpringBoot的每日推购物推荐网站的设计与实现

目录 前言 一、技术栈 二、系统功能介绍 商品信息管理 销售排行统计 商品类型管理 个人信息 商品 我的订单管理 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息互联网购物的飞速发展&#xff0c;一般企业都去创建属于自己的电商平台以及购物管…

Emacs之default-tab-width与tab-width用法总结(一百二十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

IO流之File类

File类 File 对应的硬盘上的文件或者文件夹 位于java.io包下 File对文件/文件夹进行操作&#xff0c;但是无法对文件内容进行操作&#xff0c;读取/写入不可以操作&#xff0c;但是可以创文件夹/读取文件路径,IO流才可以进行操作 文件/文件夹的路径&#xff1a;linux使用/作为文…

【剑指Offer】8.二叉树的下一个结点

题目 给定一个二叉树其中的一个结点&#xff0c;请找出中序遍历顺序的下一个结点并且返回。注意&#xff0c;树中的结点不仅包含左右子结点&#xff0c;同时包含指向父结点的next指针。下图为一棵有9个节点的二叉树。树中从父节点指向子节点的指针用实线表示&#xff0c;从子节…

SSM 中的拦截器(Interceptor):作用与实现原理

SSM 中的拦截器&#xff08;Interceptor&#xff09;&#xff1a;作用与实现原理 拦截器&#xff08;Interceptor&#xff09;是 Spring 框架中的一个重要组件&#xff0c;也在 Spring Spring MVC MyBatis&#xff08;SSM&#xff09;等框架中起到了关键作用。本文将深入探讨…

阿里云关系型数据库RDS详细说明

阿里云RDS关系型数据库大全&#xff0c;关系型数据库包括MySQL版、PolarDB、PostgreSQL、SQL Server和MariaDB等&#xff0c;NoSQL数据库如Redis、Tair、Lindorm和MongoDB&#xff0c;阿里云百科分享阿里云RDS关系型数据库大全&#xff1a; 目录 阿里云RDS关系型数据库大全 …

基于Java的在线课程教程计划管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…