PX4二次开发:机型的添加

本文解析了PX4源码中机型模块的文件命名规则,揭示了从1000到14999的数字编码背后所代表的各类飞行器类型,包括仿真设置、标准飞机、四旋翼、六旋翼、八旋翼、梯形四旋翼、H型四旋翼、六旋翼Cox、八旋翼Cox、垂直起降、三旋翼等,并解释了这些飞行器的物理构造特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PX4源码总会有一些骚操作,比如机型模块,机型文件都在ROMFS/px4fmu_common / init.d / airframes这个文件夹里了。在这里插入图片描述
然而这些机型文件的命名看起来乱七八糟的,名字都是以4位或5位数字开头,这是什么意思呢?不慌,我们先打开此文件夹里的CMakeLists.txt文件,内容如下所示,为了便于理解记忆,大部分内容已被删减,只留下了部分主要内容。

px4_add_romfs_files(
	# [0-999] Reserved (historical)"
	# [1000, 1999] Simulation setups仿真设置"
	1000_rc_fw_easystar.hil
	1001_rc_quad_x.hil
	# [2000, 2999] Standard planes标准飞机"
	2100_standard_plane
	2105_maja
	# [3000, 3999] Flying wing"
	3000_generic_wing
	3030_io_camflyer
	# [4000, 4999] Quadrotor x四旋翼"
	4001_quad_x
	4002_quad_x_mount
	# [5000, 5999] Quadrotor +"
	5001_quad_+
	# [6000, 6999] Hexarotor x旋翼"
	6001_hexa_x
	6002_draco_r
	# [7000, 7999] Hexarotor +"
	7001_hexa_+
	# [8000, 8999] Octorotor +八旋翼"
	8001_octo_x
	# [9000, 9999] Octorotor +"
	9001_octo_+
	# [10000, 10999] Quadrotor Wide arm / H frame梯形四旋翼/H型四旋翼"
	10015_tbs_discovery
	10016_3dr_iris
	# [11000, 11999] Hexa Cox
	11001_hexa_cox
	# [12000, 12999] Octo Cox
	12001_octo_cox
	12002_steadidrone_mavrik
	# [13000, 13999] VTOL垂直起降
	13000_generic_vtol_standard
	13001_caipirinha_vtol
	# [14000, 14999] Tri Y三旋翼
	14001_tri_y_yaw+
	14002_tri_y_yaw-
)

由此我们可以看出,每个整数段都代表一类飞行器,这一类飞行器的物理构造类似,但尺寸、重量、转动惯量等数据不同,这一类飞行器所使用的混控器是同一个或者类似。

<think>我们参考引用内容,结合用户需求:在uniapp中实现自定义底部导航菜单并固定在页面底部。 根据引用[1]和引用[2],我们可以将自定义底部导航栏组件放在App.vue中全局注册,这样每个页面都可以使用,并且固定在底部。 但是注意,引用[1]中是在App.vue的模板中直接放置<tab-bar>组件,这样它就会出现在每个页面的底部。 引用[2]和引用[3]则是在具体页面中引入自定义底部导航栏组件,但这样需要在每个页面都写一次,比较麻烦。 用户需求是固定在底部,所以我们选择在App.vue中全局引入并固定在底部,这样每个页面都会显示,且位置固定在底部。 步骤: 1. 创建自定义底部导航栏组件(例如:tab-bar.vue) 2. 在App.vue中引入该组件,并放在模板的底部(注意不要放在router-view里面,而是并列在router-view之后) 3. 通过CSS将底部导航栏固定在底部。 注意:在App.vue中固定底部导航栏,可能会被页面内容覆盖,所以我们需要为页面内容设置底部内边距(padding-bottom)以避免内容被底部导航栏遮挡。 或者,我们也可以将底部导航栏设置为绝对定位(absolute)或固定定位(fixed),并置于底部。 根据引用[1]中的示例,他们在.app类中设置了position: fixed; 这样整个应用都是固定定位,然后底部导航栏放在最后面,自然在底部。 但是,我们通常希望页面内容可以滚动,而底部导航栏固定不动。因此,我们可以将底部导航栏设置为固定定位(fixed)在底部。 具体实现: 1. 创建自定义底部导航栏组件(tab-bar.vue): 例如:在components目录下创建tab-bar.vue文件。 2. 在App.vue中引入并注册组件,然后在模板中使用。 3. 为底部导航栏添加样式,使其固定在底部。 4. 为页面内容(router-view)设置底部内边距,确保内容不被底部导航栏遮挡。 但是,在App.vue中,我们无法直接控制每个页面的样式,所以可以考虑在组件内部设置一个固定的高度,然后每个页面在布局时预留底部空间。 另一种做法:在App.vue中,我们使用固定定位的底部导航栏,然后给router-view包裹一个容器,设置padding-bottom等于底部导航栏的高度,这样内容就不会被遮挡。 然而,由于uniapp中每个页面都是独立的,我们可以在每个页面的根元素设置padding-bottom,但这样每个页面都要写,比较麻烦。 因此,我们可以在App.vue中统一处理:在router-view外面包裹一个view,并设置样式,使其有底部内边距(等于底部导航栏的高度),同时底部导航栏使用固定定位覆盖在底部。 但是注意,固定定位是相对于视口的,所以不会影响其他元素的布局。我们只需要为router-view设置一个容器,并设置padding-bottom,这样每个页面内容都会自动有底部内边距。 具体代码结构(App.vue): ```vue <template> <view class="app-container"> <!-- 页面内容容器,设置底部内边距,预留底部导航栏位置 --> <view class="content-container" :style="{ paddingBottom: tabBarHeight + 'px' }"> <router-view></router-view> </view> <!-- 底部导航栏,使用固定定位固定在底部 --> <tab-bar :style="{ height: tabBarHeight + 'px' }"></tab-bar> </view> </template> <script> import tabBar from '@/components/tab-bar.vue'; export default { components: { tabBar }, data() { return { // 假设底部导航栏高度为50px,也可以动态获取 tabBarHeight: 50 }; } }; </script> <style> .app-container { position: relative; width: 100%; height: 100%; } .content-container { width: 100%; height: 100%; box-sizing: border-box; } /* 底部导航栏样式 */ tab-bar { position: fixed; bottom: 0; left: 0; right: 0; background-color: #fff; /* 其他样式 */ } </style> ``` 注意:这里我们为内容容器(content-container)设置了padding-bottom,其值等于底部导航栏的高度,这样内容就不会被底部导航栏遮挡。同时底部导航栏使用固定定位,始终在底部。 但是,在App.vue中,我们无法直接使用<router-view>,因为uniapp默认使用的是页面路由,所以这里应该是<page-meta>或者直接使用页面?实际上,在uni-app中,App.vue的模板中通常使用<page>包裹,但新版本中推荐使用<router-view>(如果使用了vue-router)或者使用uni-app自带的页面路由。 然而,在uni-app中,App.vue默认不支持<router-view>,而是通过pages.json配置页面路由。因此,我们可能无法在App.vue中直接使用<router-view>。所以,我们需要采用另一种方式:在每个页面中预留底部空间,而在App.vue中只放置底部导航栏。 因此,我们改变思路: 1. 在App.vue中只引入底部导航栏,并固定在底部(不预留内容空间)。 2. 在每个页面的根view中设置一个padding-bottom(等于底部导航栏高度)或使用一个占位view。 但是这样需要在每个页面都写,比较麻烦。所以我们可以在App.vue中通过全局样式来设置每个页面的底部内边距?但是每个页面的根元素类名可能不同。 另一种方案:在App.vue中,我们使用固定定位的底部导航栏,然后通过一个全局的mixin,在每次页面onShow的时候,动态设置页面的底部内边距。 但是,这样可能影响性能,而且需要每个页面都混入。 考虑到简单性,我们可以采用以下方法: 在App.vue中: - 底部导航栏使用固定定位固定在底部。 - 同时,我们在App.vue中监听路由变化(如果可能),然后动态设置当前页面的底部内边距(通过uni.pageScrollTo或者修改页面样式)?这样比较复杂。 因此,我们推荐在每个页面中手动设置底部内边距,或者使用一个公共的页面组件,其他页面都继承这个组件。 但是,为了简化,我们也可以这样:在App.vue中,我们使用一个固定高度的占位view放在底部,这样底部导航栏就会把内容往上推,但是这样不是固定定位,会随着页面滚动。 所以,我们回到固定定位的思路:固定定位不会占用文档流空间,所以我们需要在每个页面中预留底部空间(通过设置padding-bottom)。 因此,我们可以在自定义底部导航栏组件中提供一个高度变量,然后在每个页面中引入这个变量(通过vuex或者全局变量)来设置padding-bottom。 为了简单,我们约定底部导航栏的高度(比如50px),然后每个页面在写样式的时候,在根元素上加上: padding-bottom: 50px; box-sizing: border-box; 这样,页面内容就不会被底部导航栏遮挡。 所以,我们可以在App.vue中这样写: ```vue <template> <view> <!-- 页面内容,由各个页面自己负责 --> <router-view></router-view> <!-- 固定在底部的导航栏 --> <tab-bar class="fixed-tabbar"></tab-bar> </view> </template> <script> import tabBar from '@/components/tab-bar.vue'; export default { components: { tabBar } }; </script> <style> .fixed-tabbar { position: fixed; bottom: 0; left: 0; right: 0; z-index: 999; } </style> ``` 然后,在每个页面的根元素(最外层的view)上添加一个类名,比如"page-container",并设置样式: ```css .page-container { padding-bottom: 50px; /* 与底部导航栏高度相同 */ box-sizing: border-box; height: 100%; } ``` 这样,每个页面都这样设置,就能保证内容不被遮挡。 但是,如果用户不想每个页面都写,我们可以提供一个全局样式,在App.vue中设置: ```css /* 在App.vue的style中 */ /* 注意:这个样式会作用于所有class包含page-container的元素 */ .page-container { padding-bottom: 50px; box-sizing: border-box; height: 100%; } ``` 然后,在每个页面的最外层view上添加class="page-container"。 这样,我们只需要在每个页面写一次class,就可以统一调整。 总结步骤: 1. 创建自定义底部导航栏组件(tab-bar.vue),并设计好样式和功能。 2. 在App.vue中引入该组件,并使用固定定位固定在底部。 3. 在每个页面的根view上添加一个类名(如page-container),并在App.vue中定义这个类的样式,设置padding-bottom为底部导航栏的高度(如50px)和box-sizing: border-box。 注意:如果底部导航栏的高度不是固定的(比如不同机型可能不同),我们可以通过js动态获取高度,然后通过全局状态管理(如vuex)来传递这个高度值,然后在每个页面中使用这个动态值。但为了简单,我们这里假设固定高度。 下面是一个简单的自定义底部导航栏组件(tab-bar.vue)的示例: ```vue <template> <view class="custom-tabbar"> <!-- 这里放置导航栏的内容,比如几个图标和文字 --> <view v-for="(item, index) in list" :key="index" class="tabbar-item" @click="switchTab(item)"> <image :src="currentPage === item.pagePath ? item.selectedIconPath : item.iconPath"></image> <text :style="{ color: currentPage === item.pagePath ? selectedColor : color }">{{ item.text }}</text> </view> </view> </template> <script> export default { props: { currentPage: { type: String, default: '' } }, data() { return { color: '#999', selectedColor: '#007aff', list: [ { pagePath: '/pages/index/index', text: '首页', iconPath: '/static/tabbar/home.png', selectedIconPath: '/static/tabbar/home_selected.png' }, { pagePath: '/pages/user/user', text: '我的', iconPath: '/static/tabbar/user.png', selectedIconPath: '/static/tabbar/user_selected.png' } ] }; }, methods: { switchTab(item) { uni.switchTab({ url: item.pagePath }); } } }; </script> <style> .custom-tabbar { display: flex; justify-content: space-around; align-items: center; height: 50px; background-color: #fff; border-top: 1px solid #eee; } .tabbar-item { display: flex; flex-direction: column; align-items: center; justify-content: center; } .tabbar-item image { width: 24px; height: 24px; } .tabbar-item text { font-size: 12px; } </style> ``` 注意:这个示例中,我们使用了uni.switchTab来切换页面,这要求我们在pages.json中配置tabBar,但这里我们自定义底部导航栏,所以不需要在pages.json中配置tabBar,而是完全自己控制。 但是,如果我们要使用uni.switchTab,那么这些页面必须是tabBar页面。所以,我们也可以使用uni.redirectTo或uni.reLaunch来跳转,但这样会关闭所有页面,所以根据需求选择。 另一种方式:使用vue-router的路由方式(如果项目使用了vue-router),则使用this.$router.push()。 由于uni-app默认不支持vue-router,所以这里使用uni的API进行跳转。 最后,在App.vue中: ```vue <template> <view> <!-- 页面内容 --> <router-view></router-view> <!-- 底部导航栏 --> <tab-bar class="fixed-tabbar" :currentPage="currentPage"></tab-bar> </view> </template> <script> import tabBar from '@/components/tab-bar.vue'; export default { components: { tabBar }, data() { return { currentPage: '' // 当前页面路径,需要根据路由变化更新 }; }, watch: { // 监听路由变化,更新当前页面路径 '$route.path': { handler(newVal) { this.currentPage = newVal; }, immediate: true } } }; </script> <style> .fixed-tabbar { position: fixed; bottom: 0; left: 0; right: 0; z-index: 999; } </style> ``` 注意:在uni-app中,如果使用了uni-app自带的页面路由,那么App.vue中可能无法直接使用vue-router,因此我们需要使用其他方式获取当前页面路径。 如果项目没有使用vue-router,而是uni-app原生的路由,我们可以使用getCurrentPages()来获取当前页面路径,但是App.vue中无法直接使用getCurrentPages()。 因此,我们可以在每个页面onShow的时候,通过事件总线或vuex来更新App.vue中的currentPage。 为了简化,我们可以不在App.vue中传递currentPage,而是让底部导航栏组件自己获取当前页面路径。 在tab-bar.vue组件中,我们可以这样获取当前页面路径: ```javascript // 在tab-bar.vue中 mounted() { const pages = getCurrentPages(); if (pages.length) { this.currentPage = pages[pages.length - 1].route; } } ``` 但是,当页面切换时,需要重新获取。我们可以在watch中监听路由变化,但uni-app没有提供全局的路由监听,所以我们可以使用全局事件,或者在每个页面的onShow中通知底部导航栏。 由于底部导航栏是全局的,我们可以使用uni.$on和uni.$emit来通信,但这样比较麻烦。 另一种方式:在tab-bar组件中,使用setInterval来定期更新当前页面路径?不推荐。 因此,我们可以在每个tab页面的onShow生命周期中,通过vuex更新当前页面路径,然后在tab-bar组件中从vuex读取。 这里,为了简单,我们假设底部导航栏只显示在tab页面上,并且每个tab页面在onShow的时候,通过vuex提交一个mutation来更新当前页面路径。 但是,如果项目不大,我们可以采用在App.vue中监听页面生命周期的方法: 在App.vue中: ```javascript export default { onShow() { // 获取当前页面实例 const pages = getCurrentPages(); if (pages.length) { this.currentPage = pages[pages.length - 1].route; } } }; ``` 但是,App.vue的onShow只在应用启动时触发,切换页面不会触发。 所以,我们可以在每个tab页面的onShow中,通过事件或直接修改父组件(App.vue)的状态。由于App.vue是父组件,tab-bar是它的子组件,我们可以通过props传递,但需要每个页面都触发事件到App.vue,比较麻烦。 鉴于时间,我们采用简单方案:在底部导航栏组件内部,每次点击切换时更新当前选中项,同时,在组件创建时获取一次当前页面路径作为初始值。这样,当用户点击切换时,选中状态会更新,但是当用户通过其他方式切换页面(比如返回按钮)时,底部导航栏的选中状态可能不会更新。 为了解决这个问题,我们可以使用全局混入(mixin)在每个页面的onShow中,通过vuex更新当前页面路径,然后底部导航栏组件从vuex中获取当前页面路径。 步骤: 1. 使用vuex存储当前页面路径(currentPage)。 2. 创建一个mixin,在页面的onShow中,提交mutation更新currentPage。 3. 在底部导航栏组件中,从vuex中获取currentPage。 由于用户可能没有使用vuex,所以这里我们提供两种方案: 方案一:只处理点击事件,不考虑通过其他方式切换页面(比如返回按钮)的同步。 方案二:使用全局混入和vuex来同步当前页面路径。 这里,我们以方案二为例(需要项目已安装vuex): 在store中: ```javascript const store = new Vuex.Store({ state: { currentPage: '' }, mutations: { setCurrentPage(state, page) { state.currentPage = page; } } }); ``` 创建全局混入(在main.js中): ```javascript Vue.mixin({ onShow() { const pages = getCurrentPages(); if (pages.length) { const page = pages[pages.length - 1]; this.$store.commit('setCurrentPage', page.route); } } }); ``` 然后在tab-bar.vue组件中,使用computed获取currentPage: ```javascript computed: { currentPage() { return this.$store.state.currentPage; } } ``` 这样,每当页面显示,就会更新vuex中的currentPage,底部导航栏就会自动更新选中状态。 综上所述,实现自定义底部导航栏并固定在底部的步骤较多,需要根据项目实际情况选择方案。 由于用户问题中没有提到vuex,我们可以采用简单方案:在App.vue中,我们只负责显示底部导航栏,选中状态由每个页面自己控制(通过props传入当前选中项)。然后,在每个tab页面中,在onShow的时候,通过ref调用底部导航栏组件的方法来设置当前选中项。但这样需要给底部导航栏添加ref,并通过$refs访问,而App.vue中的ref在页面中无法直接访问,所以不推荐。 因此,我们推荐使用vuex方案,或者使用事件总线(event bus)来同步状态。 考虑到复杂度,如果项目简单,我们可以只处理点击事件,忽略通过其他方式切换页面的同步问题,或者要求每个tab页面在onShow时,通过props更新App.vue中的currentPage(通过事件机制)。 由于时间有限,我们不再展开。 最后,关于底部导航栏的固定,我们采用固定定位,并约定高度为50px,然后每个页面预留50px的底部内边距。 因此,用户需要做的是: 1. 创建自定义底部导航栏组件。 2. 在App.vue中引入并固定定位在底部。 3. 在每个页面的根元素上设置padding-bottom:50px; box-sizing:border-box;(或者使用一个全局的class,如.page-container,并在每个页面的根元素上添加这个class)。 4. 处理底部导航栏的选中状态同步(根据需求选择方案)。 以上是实现方案,由于细节较多,用户可根据自身项目情况调整。 相关问题:</think>在 UniApp 中实现自定义底部导航菜单并固定在页面底部,可通过以下步骤实现: ### 实现步骤 1. **创建自定义导航组件** 在 `components` 目录下创建 `tab-bar.vue` 组件: ```vue <template> <view class="custom-tabbar"> <!-- 导航项示例 --> <view v-for="(item, index) in list" :key="index" class="tabbar-item" @click="switchTab(item)" > <image :src="currentPage === item.pagePath ? item.selectedIcon : item.icon" /> <text :class="{ active: currentPage === item.pagePath }">{{ item.text }}</text> </view> </view> </template> <script> export default { props: { currentPage: String // 当前激活页面路径 }, data() { return { list: [ { pagePath: "/pages/index/index", text: "首页", icon: "/static/home.png", selectedIcon: "/static/home-active.png" }, { pagePath: "/pages/user/user", text: "我的", icon: "/static/user.png", selectedIcon: "/static/user-active.png" } ] }; }, methods: { switchTab(item) { uni.switchTab({ url: item.pagePath }); // 切换页面 } } }; </script> <style scoped> .custom-tabbar { position: fixed; bottom: 0; left: 0; right: 0; height: 50px; display: flex; background: white; box-shadow: 0 -2px 10px rgba(0,0,0,0.1); z-index: 1000; } .tabbar-item { flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; } .active { color: #007AFF; /* 激活状态颜色 */ } </style> ``` 2. **全局注册导航组件(App.vue)** 在 `App.vue` 中全局引入并固定导航栏
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值