【毕业设计】基于STM32的解魔方机器人


4ff5afc23dd4dfd6fa5db49786bd54fb.jpeg

1、方案设计

1.采用舵机作为魔方机器人的驱动电机,从舵机的驱动原理可知:舵机运行的速度和控制器的主频没有关系,所以采用单片机和采用更高主频的嵌入式处理器相比在控制效果上没有什么差别。单片机编程过程简单,非常容易上手,而且不需要进行操作系统的移植,非常适合对魔方机器人的舵机进行控制。

2.复原时间是魔方机器人的一个非常重要,可以说是最为重要的一个参数,本文的软件设计中涉及到了大量的算法,如 Kocemba 复原算法和 KNN 分类算法等,而控制器主频对于算法运行时间的长短起着决定性的作用。

所以在本文的方案设计中,我们把核心算法全部交给 Allwinner A20 运行的 APP。


2、设计原理

1、Kociemba算法
Kociemba算法,又称为二阶段算法,是一个使用较短时间和较少次数还原魔方的算法。按照以前网上的说法,详细的原理可以在网页http://kociemba.org/cube上面找到。然而现在这一个网页也是已经不存在了,其他网站所介绍的也是非常的简略。幸好,在我的努力之下,还是找到一些零星的资料,主要是一些外文的论文和一些github项目。通过几天的加班阅读,我总算是理解了大部分的内容。我把自己所理解的只是写在这篇论文上面,希望能给和我一样的魔方爱好者一些启发,同时也算是一个抛砖引玉,希望能够获得读者们更好的建议。
2、从魔方的状态数说起

这篇文章讨论的对象是三阶魔方,原则上Kociemba算法可以变形为四阶魔方的,但是这并不是本文要讨论的内容。首先我们先对魔方的元素进行命名上面的约定,魔方由26个方块组成,每个方块由1到3个面是露在外面的,有1个面的我们称为中心方块,两个面为边,三个面的为角。通过旋转,每个角有8中位置、3个方向,每个边有12种位置、2个方向。我们假定魔方的中心方块是不会移动的,也就是说,只有非中间层的面可以旋转,以后也是不考虑中间面的旋转。所以会产生变化的只有边和角的位置和方向,不考虑组合的合法性,魔方的总组合为: 8!12!(38)*(212)种

但是魔方会包括非法的情况,这里要考虑到魔方的状态集的问题。我们约定魔方的所有边和角的位置和方向为魔方的一个状态。魔方从一个状态通过若干次的旋转后,魔方的新状态一定和原状态在一个状态集里面。可以证明,魔方的状态集分成12个,每一个的总数是一样的,所以,实际上魔方的状态数为: 8!12!(38)*(212)/12种

这个数大概是4.3万亿亿,具体大小不必细究,反正非常大。如果使用最暴力的算法,例如DFS、BFS等,绝对会耗尽计算机的资源,更高阶的魔方就不用说了。所以,我们要对这些状态进行裁剪,Kociemba使用的就是因式分解的算法。打个比方,如果m=a*b,且a、b>2,那么令n=a+b,必有n<m。同理,将上面的式子分解为:8!、12!、(38)、(212),至少可以将空间缩小为一亿分之一。当然,实际上算法对其做出了更多的工作。

同理,将上面的式子分解为:8!、12!、(38)、(212),至少可以将空间缩小为一亿分之一。当然,实际上算法对其做出了更多的工作。<> 最后,我们将将魔方的面分为6个:T(上)、D(下)、F(前)、B(后)、L(左)、R(右)。面向X面,顺时针旋转X面90度表示为X、旋转半周为X2、逆时针旋转90度为X’。

3、魔方的特殊性质

人们发现,魔方具有一些优良的性质,这些性质可以帮助将状态数分解:
1.指定角的方向后,对于所有的面,旋转两次并不会改变角的方向,会有相对的两个面(例如前和后),旋转一次不会改变角的方向。其他面旋转一次,会按照特定的规律变换方向,如果我们把方向编码为0、1、

2,假如某一个面的四个角原始方向按照顺时针是co0、co1、co2、co3,那么如果这个面的一次旋转会改变四个角的方向的话,对角的两个角会变成co0+1、co2+1另外两个对角会变成co1-1、co3-1。 2.指定边的方向后,只有两个相对的面的旋转会改变边的方向,其余面的旋转不会改变。

下面,我们假定一次旋转上下面不会改变魔方的角的方向,一次旋转左右面会改变魔方边的方向。至于具体如何编码,我会在下下面详细阐述。

通过这两种性质,我们将魔方的状态分成两个状态集G1、G2。其中G1状态为魔方的原始状态经过若干步规定以内的旋转所组成的状态集,这规定的旋转包括:T、T’、D、D’、T2、D2、F2、B2、L2、R2。根据上面的假定,这些旋转不会改变魔方8个角的方向,也不会改变12条边的方向,而且原始状态下中间的四条边,在这个集合里面依然在中间层内。根据这一个结论,我们可以将魔方的总数减少为: 4!*8!*8!/12

第一个4!表示中间四条边的位置排列,第二个8!表示上下四条边的位置排列,第三个8!表示8个角的位置排列。在使用因式分解,总数就变为:4!+8!+8!,这个数少于10万,并且在下面会看到,使用这一种裁剪方法会获得较高的精度。

G2表示以G1的所有状态为原始状态,经过若干次任意旋转后的状态集,在这个状态集里面内有什么优良的的性质可以利用,所以实际上使用了单纯的裁剪手段。也是分成三组,第一组为编号为0到3的所有边的方向和位置,第二组为编号为4到11的所有边位置上面边的方向,第三组为所有角的方向,所以总数为A(12,4)*(26)+28+3^8种。

4、搜索算法

Kociemba算法使用了搜索算法还原魔方。具体来说,就是先使用搜索算法转换为G1状态,在使用另一种搜索方式转换为原始状态。使用何种搜索算法对于还原魔方至关重要,搜索算法选得不好,例如使用BFS解决问题,会耗尽计算机的资源。经过前辈的不断探索,最终改良出IDA*。所谓IDA*,就是A*算法加上迭代加深的升级版。迭代加深就是可以保证搜索树上面的任一个节点都可以获得精确的启发函数值,要实现迭代加深就必须先对搜索树上的各个节点进行预先的计算,也就是初始化。

具体到这里,就是在A*的启发函数初始化的时候,制作一个映射表,然后通过魔方从原始状态为起点进行若干次操作,组成一个根节点为魔方的原始状态的、具有一定深度的操作树。遍历操作树上面的所有节点,也就是每一个状态,从表上可以映射为一个启发函数值,其值的的大小就为节点的深度。因为此时的魔方的状态就是魔方在原始状态通过等于其深度的次数的操作结果,经过相反的操作当然可以还原魔方。同时,可以知道,操作数上面必然会有状态相同的不同节点,因为启发函数的值应该为最小值才可以保证精度,因此,我们在遍历操作树的时候,使用广度优先搜索,保证浅层的节点先被记录,而深层的同状态节点因为映射已经存在就会被忽略。

有了映射表,在调用启发函数的时候,根据当前的魔方状态,经过查表可以获得启发函数的值,使用A*算法判断魔方的下一个判断即可,同时因为迭代加深的缘故,节点的判断函数都是准确的,不需要记录对未搜索的可达节点。

那么,问题推到了映射表上面,如何设计高效的映射表?

5、映射表的设计

映射表只是一个概念,它代表从魔方的特定状态向最小还原步数的映射。具体需要选择什么实现,还需要看实际情况。实际需求可以总结为一下几点:
1.映射表初始化后不会发生改动,也就是说不需要动态的改动映射的内容和规模。
2.映射需要一个比较高的效率。
3.映射的规模是已知的。
4.映射表应该覆盖所有的状态编码组合。

第2条决定了不应该使用像std::map之类的树型映射表,最佳方案应该是数组。因为数组查询速度快,规模是固定的。只要我们找到一个哈希函数,将当前魔方的状态转换为一个整数,就可以完成映射表了。

6、方块编码

我认为,这一部分是算法的核心之一,之前的各种设计各种规律都是建立在这种编码方案之上的。这说明一个好的建模方案可以大大地减少问题的难度。

首先,我要介绍角的编码,容易知道,魔方有八个角,分别编码为0至7,编码与位置的对应关系与问题的解决没有关系。同理,魔方的12条边编码为0值11。

真正的问题在于边和方块的方向问题。我们知道,边和角的方向没有固定的参照物,因此,我们在编码的时候,通过规定某一些方向的方法规定方块的方向。对于边的方向,这比较简单,只要是0或者1即可。

对于角,情况就有点复杂,我在这里举个例子,说明一下编码的过程:

我们将T、F、R面交界处的角方块,暂称为方块1,方块1的原始位置为位置1。我们要求在位置1上面的各种角方块面,都要按照T、F、R方向的顺序表示,如果1号方块在1号位置的顺序刚好就是T、F、R,那么我们认为此时1号方块的方向就是0,除此之外,还有的可能的顺序就是F、R、T和R、T、F,我们分别标号为1和2。

由于T和D旋转是不会改变方块的方向,所以我们可以来一个T’旋转,是的T、F、L面交界处的角方块,我们暂称为方块2,到达位置1。此时从T、F、R面上面读取方块2,可以读到T、L、F。也就是所,方块2在顺序为T、L、F的时候是0号方向,我们模仿1号方块,认为顺序L、F、T为1号方向,F、T、L为2号。同理可以知道T面的其他角。

由于F2旋转是不活改变角的方向,所以我们进行F2旋转,此时方块2旋转至F、D、R的交接面处,暂称为位置3。此时T、L、F面的方向为D、R、F,所以我们认为方块3的0号方向顺序为D、R、F。同理可以知道D面的其他角。


通过这种建模方式,可以模仿上面说道的魔方的这些优良性质,保证搜索算法和映射表的成立。

3、硬件设计框图


a332f01c740432110e8c3ff6df226e32.jpeg


4、软件设计框架


a2255795d2320ef154aa7646f00d5080.jpeg

5、原理图


e76dbd6039d563b269838e354ddd3064.jpeg

42924ccb1af937122432b11b4f66d01d.jpeg

6、工程设计图纸

42db926ec1df57b548481bd9387d1357.jpeg

7、 源代码
1bb15bb48d62248876fa93b95f17ea7e.jpeg

8、全部资料


7523d9708aa339be756429e2d0e8b707.jpeg

9、资料获取

关注我后,在后台回复关键字。

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

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

相关文章

orb-slam2学习总结

目录 视觉SLAM 1、地图初始化 2、ORB_SLAM地图初始化流程 3、ORB特征提取及匹配 1、对极几何 2、对极约束 &#xff08;epipolar constraint&#xff09; 3、基础矩阵F、本质矩阵E 5、单目尺度不确定性 6、单应矩阵&#xff08;Homography Matrix&#xff09; 6.1 什么是单应矩…

【Spark精讲】RDD特性之数据本地化

首选运行位置 上图红框为RDD的特性五&#xff1a;每个RDD的每个分区都有一组首选运行位置&#xff0c;用于标识RDD的这个分区数据最好能够在哪台主机上运行。通过RDD的首选运行位置可以让RDD的某个分区的计算任务直接在指定的主机上运行&#xff0c;从而实现了移动计算而不是移…

【matlab进阶学习-6】 读取log数据data.txt文件,并做处理,导出报告/表格/图表

原始文件 原始文件格式txt&#xff0c;每一行对应一个数据&#xff0c;数据之间由逗号分割开 对应意思 时刻&#xff0c;电压&#xff0c;电流&#xff0c;功率&#xff0c;容量&#xff0c;&#xff0c;电流&#xff0c;功率&#xff0c;&#xff0c;RTC时间&#xff0c;状态…

内网服务器部署maven私服简记

前言 很多企业希望创建自己的maven私服&#xff0c;但服务器无法和外网连通&#xff0c;所以这里介绍一套完整的内网部署nexus的解决方案。实现的方式也很简单&#xff0c;将下载好的nexus安装和项目所需的依赖仓库都上传到服务i去上去&#xff0c;通过脚本的方式实现批量导入…

CSS的三大特性(层叠性、继承性、优先级---------很重要)

CSS 有三个非常重要的三个特性&#xff1a;层叠性、继承性、优先级。 层叠性 场景&#xff1a;相同选择器给设置相同的样式&#xff0c;此时一个样式就会覆盖&#xff08;层叠&#xff09;另一个冲突的样式。层叠性主要解决样式冲突 的问题 原则&#xff1a;  样式冲突&am…

autojs-练手-视频号点赞(进阶版)

注释很详细&#xff0c;直接上代码 较初阶版新增内容 1. 简单但好用的ui界面 为方便大家参考&#xff0c;ui界面的模板单独拿出来了 ui界面模板 2. opencv图像识别 3. 需加载情况特殊处理&#xff08;防卡壳&#xff09; 4. 增加自动判断是否已点赞的情况 源码部分 // 启用…

HarmonyOS4.0从零开始的开发教程14Web组件的使用

HarmonyOS&#xff08;十二&#xff09;Web组件的使用 1 概述 相信大家都遇到过这样的场景&#xff0c;有时候我们点击应用的页面&#xff0c;会跳转到一个类似浏览器加载的页面&#xff0c;加载完成后&#xff0c;才显示这个页面的具体内容&#xff0c;这个加载和显示网页的…

智能优化算法应用:基于水循环算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于水循环算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于水循环算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.水循环算法4.实验参数设定5.算法结果6.参考文…

无需公网IP联机Minecraft,我的世界服务器本地搭建教程

目录 前言 1.Mcsmanager安装 2.创建Minecraft服务器 3.本地测试联机 4. 内网穿透 4.1 安装cpolar内网穿透 4.2 创建隧道映射内网端口 5.远程联机测试 6. 配置固定远程联机端口地址 6.1 保留一个固定TCP地址 6.2 配置固定TCP地址 7. 使用固定公网地址远程联机 8.总…

Vue 中 v-model 的修饰符

lazy 修饰符&#xff1a;将 v-model 改为失去焦点后更新数据。 number 修饰符&#xff1a;将 v-model 数据转为数字类型。 trim 修饰符&#xff1a;去除 v-model 数据中的首尾空格。 语法格式&#xff1a; // lazy 修饰符 <input v-model.lazy"数据"> // nu…

靠谱的车- 华为OD统一考试(C卷)

靠谱的车- 华为OD统一考试&#xff08;C卷&#xff09; OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 程序员小明打了一辆出租车去上班。出于职业敏感&#xff0c;他注意到这辆出租车的计费表有点问题&#xf…

【JNA与C++基本使用示例】

JNA中java与C使用注意事项和代码示例 JNA关系映射表使用案列注意代码示例C代码java代码 JNA关系映射表 使用案列 注意 JNA只支持C方式的dll使用C的char* 作为返回值时&#xff0c;需要返回的变量为malloc分配的地址C的strlen函数只获得除/0以外的字符串长度 代码示例 C代码…

基于PaddleNLP的深度学习对文本自动添加标点符号(一)

前言 目前以深度学习对文本自动添加标点符号研究很少&#xff0c;已知的开源项目并不多&#xff0c;详细的介绍就更少了&#xff0c;但对文本自动添加标点符号又在古文识别语音识别上有重大应用。 基于此&#xff0c;本文开始讲解基于PaddleNLP的深度学习对文本自动添加标点符号…

鸿蒙开发之状态管理@Prop和@Link

一、用法 在父子组件需要进行数据同步的时候&#xff0c;可以通过Prop和Link装饰器来做到。在父组件中用State装饰&#xff0c;在自组件中用Prop或Link装饰。 结论&#xff1a;Prop用于子组件只监听父组件的数据改变而改变&#xff0c;自己不对数据改变 Link用于子组件与父组…

Proxmox VE 安装 OpenWrt 配置旁路由教程

话不多说&#xff0c;本篇文章将记录如何在 Proxmox VE 环境通过虚拟机安装 OpenWrt 配置旁路由的过程&#xff0c;仅做参考。 PVE 创建虚拟机 名称随意&#xff0c;GuestOS 选择 Linux&#xff0c;不使用任何 iso 镜像。&#xff08;记住你的 VMID&#xff09; 清空将要创建…

机器学习---Adaboost算法

1. Adaboost算法介绍 Adaboost是一种迭代算法&#xff0c;其核心思想是针对同一个训练集训练不同的分类器&#xff08;弱分类器&#xff09;&#xff0c;然 后把这些弱分类器集合起来&#xff0c;构成一个更强的最终分类器&#xff08;强分类器&#xff09;。Adaboost算法本身…

Qt 线程

&#x1f4a1; 进度条显示拷贝进度&#xff08;verson 1&#xff09; 窗口上放置一个按钮和一个进度条部件&#xff0c;点击按钮&#xff0c;进行拷贝操作 —— 打开对话框选择源文件&#xff0c;然后再打开一个对话框 选择 目标文件存放位置和名称。拷贝过程中进度条显示当前…

十三、YARN资源分配调用

1、为什么要先学习YARN组件&#xff1f; 在Hadoop文件系统中&#xff0c;YARN作为Hadoop系统的第三大组件&#xff0c;其中&#xff0c;第二大组件MapReduce组件是基于YARN运行的&#xff0c;即没有YARN无法运行MapReduce程序&#xff0c;所以需要同时学习YARN。 2、YARN &…

Day58力扣打卡

打卡记录 下一个更大元素 IV&#xff08;单调栈 x2&#xff09; 链接 class Solution:def secondGreaterElement(self, nums: List[int]) -> List[int]:ans [-1] * len(nums)s []t []for i, x in enumerate(nums):while t and nums[t[-1]] < x:ans[t.pop()] x # t…

『npm』一条命令快速配置npm淘宝国内镜像

&#x1f4e3;读完这篇文章里你能收获到 一条命令快速切换至淘宝镜像恢复官方镜像 文章目录 一、设置淘宝镜像源二、恢复官方镜像源三、查看当前使用的镜像 一、设置淘宝镜像源 npm config set registry https://registry.npm.taobao.org服务器建议全局设置 sudo npm config…