ICM20948 DMP代码详解(13)
接前一篇文章:ICM20948 DMP代码详解(12)
上一回完成了对inv_icm20948_set_chip_to_body_axis_quaternion函数第2步即inv_rotation_to_quaternion函数的解析。回到inv_icm20948_set_chip_to_body_axis_quaternion中来,继续往下进行解析。为了便于理解和回顾,再次贴出该函数源码:
void inv_icm20948_set_chip_to_body_axis_quaternion(struct inv_icm20948 *s, signed char *accel_gyro_matrix, float angle)
{int i;float rot[9];long qcb[4];long q_all[4];long q_adjust[4];for (i=0; i<9; i++)rot[i] = (float)accel_gyro_matrix[i];//convert Chip to Body transformation matrix to quaternion//inv_icm20948_convert_matrix_to_quat_fxp(rot, qcb);inv_rotation_to_quaternion(rot, qcb);//The quaterion generated is the inverse, take the inverse again.qcb[1] = -qcb[1];qcb[2] = -qcb[2];qcb[3] = -qcb[3];//now rotate by angle, negate angle to rotate other wayq_adjust[0] = (long)((1L<<30) * cosf(-angle*(float)M_PI/180.f/2.f));q_adjust[1] = 0;q_adjust[2] = (long)((1L<<30) * sinf(-angle*(float)M_PI/180.f/2.f));q_adjust[3] = 0;invn_convert_quat_mult_fxp(q_adjust, qcb, q_all);inv_icm20948_set_chip_to_body(s, q_all);
}
接下来是第3段代码:
//The quaterion generated is the inverse, take the inverse again.qcb[1] = -qcb[1];qcb[2] = -qcb[2];qcb[3] = -qcb[3];
在第2步中由旋转矩阵(数组rot[9])得到了四元数,在这里还需要进一步对于qcb[1]~qcb[3]做乘以-1操作。
接下来是第4段代码:
//now rotate by angle, negate angle to rotate other wayq_adjust[0] = (long)((1L<<30) * cosf(-angle*(float)M_PI/180.f/2.f));q_adjust[1] = 0;q_adjust[2] = (long)((1L<<30) * sinf(-angle*(float)M_PI/180.f/2.f));q_adjust[3] = 0;invn_convert_quat_mult_fxp(q_adjust, qcb, q_all);inv_icm20948_set_chip_to_body(s, q_all);
代码中的angle来自inv_icm20948_set_chip_to_body_axis_quaternion函数的第3个参数float angle,其对应的实参在inv_icm20948_init_matrix函数中传入,为0.0。

由于这里传入的值为0.0,因此以上代码片段
//now rotate by angle, negate angle to rotate other wayq_adjust[0] = (long)((1L<<30) * cosf(-angle*(float)M_PI/180.f/2.f));q_adjust[1] = 0;q_adjust[2] = (long)((1L<<30) * sinf(-angle*(float)M_PI/180.f/2.f));q_adjust[3] = 0;
实际上是:
//now rotate by angle, negate angle to rotate other wayq_adjust[0] = (long)((1L<<30);q_adjust[1] = 0;q_adjust[2] = 0;q_adjust[3] = 0;
接下来是invn_convert_quat_mult_fxp函数。
invn_convert_quat_mult_fxp(q_adjust, qcb, q_all);
其在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948DataConverter.c中,代码如下:
static void invn_convert_quat_mult_fxp(const long *quat1_q30, const long *quat2_q30, long *quatProd_q30)
{quatProd_q30[0] = inv_icm20948_convert_mult_q30_fxp(quat1_q30[0], quat2_q30[0]) - inv_icm20948_convert_mult_q30_fxp(quat1_q30[1], quat2_q30[1]) -inv_icm20948_convert_mult_q30_fxp(quat1_q30[2], quat2_q30[2]) - inv_icm20948_convert_mult_q30_fxp(quat1_q30[3], quat2_q30[3]);quatProd_q30[1] = inv_icm20948_convert_mult_q30_fxp(quat1_q30[0], quat2_q30[1]) + inv_icm20948_convert_mult_q30_fxp(quat1_q30[1], quat2_q30[0]) +inv_icm20948_convert_mult_q30_fxp(quat1_q30[2], quat2_q30[3]) - inv_icm20948_convert_mult_q30_fxp(quat1_q30[3], quat2_q30[2]);quatProd_q30[2] = inv_icm20948_convert_mult_q30_fxp(quat1_q30[0], quat2_q30[2]) - inv_icm20948_convert_mult_q30_fxp(quat1_q30[1], quat2_q30[3]) +inv_icm20948_convert_mult_q30_fxp(quat1_q30[2], quat2_q30[0]) + inv_icm20948_convert_mult_q30_fxp(quat1_q30[3], quat2_q30[1]);quatProd_q30[3] = inv_icm20948_convert_mult_q30_fxp(quat1_q30[0], quat2_q30[3]) + inv_icm20948_convert_mult_q30_fxp(quat1_q30[1], quat2_q30[2]) -inv_icm20948_convert_mult_q30_fxp(quat1_q30[2], quat2_q30[1]) + inv_icm20948_convert_mult_q30_fxp(quat1_q30[3], quat2_q30[0]);
}
这个函数中最主要就是调用了inv_icm20948_convert_mult_q30_fxp函数进行计算。inv_icm20948_convert_mult_q30_fxp函数在同文件中,代码如下:
long inv_icm20948_convert_mult_q30_fxp(long a_q30, long b_q30)
{long long temp;long result;temp = (long long)a_q30 * b_q30;result = (long)(temp >> 30);return result;
}
其实就是简单的乘法,之后再右移30位。
那么invn_convert_quat_mult_fxp函数的作用实际上就是计算两个四元数相乘的结果。
参考:四元数乘法计算-CSDN博客

回到inv_icm20948_set_chip_to_body_axis_quaternion函数中,接下来是inv_icm20948_set_chip_to_body函数。
invn_convert_quat_mult_fxp(q_adjust, qcb, q_all);inv_icm20948_set_chip_to_body(s, q_all);
其也在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948DataConverter.c中,代码如下:
/** Set the transformation used for chip to body frame
*/
void inv_icm20948_set_chip_to_body(struct inv_icm20948 * s, long *quat)
{memcpy(s->s_quat_chip_to_body, quat, sizeof(s->s_quat_chip_to_body));
}
这个函数很简单、也很好理解,就是把上一步计算好的q_all[4],赋给s->s_quat_chip_to_body。s_quat_chip_to_body是struct inv_icm20948的成员,相关定义如下:
typedef struct inv_icm20948 {struct inv_icm20948_serif serif;……/* data converter */long s_quat_chip_to_body[4];……
} inv_icm20948_t;
s->s_quat_chip_to_body在前文书解析inv_icm20948_init_matrix函数的时候讲到过,相关代码如下:

和上边的q_adjust数组类似。
//now rotate by angle, negate angle to rotate other wayq_adjust[0] = (long)((1L<<30);q_adjust[1] = 0;q_adjust[2] = 0;q_adjust[3] = 0;
至此,inv_icm20948_set_chip_to_body_axis_quaternion函数就解析完了。inv_icm20948_init_matrix函数也就解析完了。
回到icm20948_sensor_setup函数中,当前完成了第2段代码的解析,
/* Setup accel and gyro mounting matrix and associated angle for current board */inv_icm20948_init_matrix(&icm_device);
对于接下来步骤的解析请看下回。
相关文章:
ICM20948 DMP代码详解(13)
接前一篇文章:ICM20948 DMP代码详解(12) 上一回完成了对inv_icm20948_set_chip_to_body_axis_quaternion函数第2步即inv_rotation_to_quaternion函数的解析。回到inv_icm20948_set_chip_to_body_axis_quaternion中来,继续往下进行…...
【论软件需求获取方法及其应用】
摘要 2023 年 3 月,我所在的公司承接了某油企智慧加油站平台的建设工作。该项目旨在帮助加油站提升运营效率、降低运营成本和提高销售额。我在该项目中担任系统架构设计师,负责整个项目的架构设计工作。 本文以该项目为例,详细论述软件需求获…...
使用ESP8266和OLED屏幕实现一个小型电脑性能监控
前言 最近大扫除,发现自己还有几个ESP8266MCU和一个0.96寸的oled小屏幕。又想起最近一直想要买一个屏幕作为性能监控,随机开始自己diy。 硬件: ESP8266 MUColed小屏幕杜邦线可以传输数据的数据线 环境 Windows系统Qt6Arduino Arduino 库…...
Nexpose v6.6.266 for Linux Windows - 漏洞扫描
Nexpose v6.6.266 for Linux & Windows - 漏洞扫描 Rapid7 Vulnerability Management, release Aug 21, 2024 请访问原文链接:https://sysin.org/blog/nexpose-6/,查看最新版。原创作品,转载请保留出处。 作者主页:sysin.o…...
ess6新特性
1、let、const 块级作用域声明变量和常量 2、箭头函数 不能构建函数 不能new 没.prototype属性 没有this指向 this指向是根据上下文的 往上层查找 没有arguments(参数) 3、模板字符串 ${} 字符串中嵌入表达式 4、解构赋值 5、Promise 处理异步操作的标准机制 6、for of 遍历…...
C语言蓝桥杯:语言基础
竞赛常用库函数 最值查询 min_element和max_element在vector(迭代器的使用) nth_element函数的使用 例题lanqiao OJ 497成绩分析 第一种用min_element和max_element函数的写法 第二种用min和max的写法 二分查找 二分查找只能对数组操作 binary_search函数,用于查找…...
axure之变量
一、设置我们的第一个变量 1、点击axure上方设置一个全局变量a 3 2、加入按钮、文本框元件点击按钮文档框展示变量值。 交互选择【单击时】【设置文本】再点击函数。 点击插入变量和函数直接选择刚刚定义的全局变量,也可以直接手动写入函数(注意写入格式。) 这…...
vue缓存用法
Store 临时缓存 特点:需要定义,有初始值、响应式、全局使用、刷新重置 Pinia官方文档 https://pinia.vuejs.org 创建 store 缓存 示例代码 import {defineStore} from pinia import {store} from //storeexport const useMyStore defineStore({// 定义…...
栈入门,括号匹配问题
利用栈这道题应该很轻松可以解决,下面给出常用的代码: public static boolean isValid(String s) {// 创建一个栈来保存左括号Stack<Character> stack new Stack<>();// 遍历字符串中的每个字符for (char c : s.toCharArray()) {// 如果是…...
Vue入门学习笔记-表单
可以使用v-model 指令在表单控件元素上创建双向数据绑定。 引言: Vue采用了MVVM(Model-View-ViewModel)架构模式,通过指令可以快速实现数据和视图的双向绑定 修改视图层时,模型层也会改变;修改模型层&#…...
TCP通信三次握手、四次挥手
目录 前言 一、三次握手 TCP三次握手的详细过程 二、四次挥手 四次挥手的详细过程 前言 前面我说到了,UDP通信的实现,但我们经常说UDP通信不可靠,是因为他只会接收和发送,并不会去验证对方收到没有,那么我们说TCP通…...
【实施文档】软件项目实施方案(Doc原件2024实际项目)
软件实施方案 二、 项目介绍 三、 项目实施 四、 项目实施计划 五、 人员培训 六、 项目验收 七、 售后服务 八、 项目保障措施软件开发管理全套资料包清单: 工作安排任务书,可行性分析报告,立项申请审批表,产品需求规格说明书&am…...
BeanFactory vs. ApplicationContext
在Spring框架中,BeanFactory和ApplicationContext都是用于管理Spring容器中的bean的接口,但它们在功能和应用场景上有所不同。下面是它们的主要区别: 1. 基础功能 vs. 扩展功能 BeanFactory: 是Spring框架的最基础的IoC容器,提供…...
JDBC客户端连接Starrocks 2.5
<?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://ma…...
004——双向链表和循环链表
目录 双向链表 双向链表的初始化(与单链表类似) 增: Ⅰ)头插法 Ⅱ)尾插法 Ⅲ)中间插入 删 改 查 整体代码示例: 循环链表 循环单链表 编辑 循环双链表 双向链表 不同于单链表&…...
framebuffer帧缓存
framebuffer:帧缓冲,帧缓存 Linux内核为显示提供的一套应用程序接口。(驱动内核支持) framebuffer本质上是一块显示缓存,往显示缓存中写入特定格式的数据就意味着向屏幕输出内容。framebuffer驱动程序控制LCD显示设备࿰…...
24_竞赛中的高效并查集
菜鸟:老鸟,我最近在做一个与社交网络相关的项目,需要频繁地检查两个用户是否属于同一个群组。但我发现每次检查都很耗时,性能很差。你有什么建议吗? 老鸟:你可以试试使用并查集(Union-Find&…...
新手c语言讲解及题目分享(十七)--运算符与表达式专项练习
本文主要讲解c语言的基础部分,运算符与表达式的学习,在这一部分中,往往有许多细节的东西需要去记住。当各种运算符一起用时,就会存在优先级的关系,本文末尾有各种运算符的优先级顺序表。 参考书目和推荐学习书目&#…...
香帅的金融学讲义:深入剖析与解读
香帅的金融学讲义:深入剖析与解读 金融学,这个看似高深复杂的学科,实则与我们的生活息息相关。从个人理财到国家宏观经济政策,金融学无处不在。那么,如何更好地理解金融学呢?今天,我们就来借助…...
java基础-IO(6)转换流InputStreamReader、OutputStreamWriter
引入: 从第一节可知,流分为两类:字节流和字符流,转换流就是在两者之间进行转换。 字节流转换为字符流; 字符流转换为字节流。 字符集 字符集:定义了可用字符及其对应的数字编码的集合。常见的字符集有UT…...
Vulhub 中的 Cacti-CVE-2025-24367
0x00 前言先看结果吧,复现是成功了,但是没拿到shell,和我想的不一样。漏洞原理:Cacti是一款利用RRDTool数据存储和图形化功能的完整网络图形化解决方案。在Cacti 1.2.28及以前版本中存在一个命令注入漏洞,该漏洞允许已…...
PPTist:零基础打造专业级在线演示文稿的完整指南
PPTist:零基础打造专业级在线演示文稿的完整指南 【免费下载链接】PPTist PowerPoint-ist(/pauəpɔintist/), An online presentation application that replicates most of the commonly used features of MS PowerPoint, allowing for the…...
Steam创意工坊模组下载神器:跨平台游戏玩家的必备工具
Steam创意工坊模组下载神器:跨平台游戏玩家的必备工具 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你知道吗?作为一名游戏爱好者,你是否曾…...
收藏必备!小白程序员快速入门RAG,解锁大模型知识检索与增强(干货满满)
本文详细介绍了RAG(检索增强生成)的概念、流程及优化策略。RAG通过从数据库检索上下文文档,有效提升LLM答案的准确性与时效性,解决纯生成模型的局限性。文章覆盖了文档加载、切分、向量化存储,以及检索与生成两个核心阶…...
Perplexity习语查询响应延迟超800ms?3个冷启动配置错误正在 silently 毁掉你的语言生产力
更多请点击: https://kaifayun.com 第一章:Perplexity习语查询功能概览 Perplexity 的习语查询功能专为语言学习者与内容创作者设计,支持对英语中高频、多义、文化负载型习语进行上下文感知的精准解析。该功能不仅返回标准释义,还…...
Seraphine:如何通过智能战绩查询和BP辅助提升英雄联盟竞技体验
Seraphine:如何通过智能战绩查询和BP辅助提升英雄联盟竞技体验 【免费下载链接】Seraphine 英雄联盟战绩查询工具 项目地址: https://gitcode.com/gh_mirrors/se/Seraphine 想象一下这样的场景:你刚刚进入英雄联盟的排位赛BP阶段,屏幕…...
parse库错误处理与异常管理:构建可靠的字符串解析应用
parse库错误处理与异常管理:构建可靠的字符串解析应用 【免费下载链接】parse Parse strings using a specification based on the Python format() syntax. 项目地址: https://gitcode.com/gh_mirrors/pa/parse 在Python开发中,字符串解析是一项…...
革命性AI emojis:一键生成个性化Slack表情的完整指南
革命性AI emojis:一键生成个性化Slack表情的完整指南 【免费下载链接】emojis Turn your ideas into emojis in seconds. Generate your favorite Slack emojis with just one click. 项目地址: https://gitcode.com/gh_mirrors/em/emojis GitHub加速计划的e…...
3分钟掌握UnityPackage Extractor:无需Unity轻松提取资源包
3分钟掌握UnityPackage Extractor:无需Unity轻松提取资源包 【免费下载链接】unitypackage_extractor Extract a .unitypackage, with or without Python 项目地址: https://gitcode.com/gh_mirrors/un/unitypackage_extractor 你是否曾因需要查看Unity资源包…...
LangGraph 是什么?为什么它越来越像 AI Agent 时代的“操作系统”
文章目录一、为什么普通的“聊天式 AI”不够用了?1. 状态容易丢2. 流程难控制3. 执行失败后很难恢复4. 决策过程不透明二、LangGraph 到底是什么?1. 编排2. 运行时三、为什么很多人会说:LangGraph 像 Agent Server 的“操作系统”?…...
