日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

魔方教学系统(基于QT)

發(fā)布時間:2023/12/8 windows 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 魔方教学系统(基于QT) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

之前沒能及時復(fù)盤寫下來 現(xiàn)在很多想不起來,慢慢回憶著寫吧

背景

之前指導(dǎo)本科生做的伺服電機(jī)的機(jī)械臂解魔方機(jī)器人,老師提出能不能低成本化,就嘗試了舵機(jī)和低價相機(jī),外邊做成黑色殼子阻絕光線的方法。最終把伺服電機(jī)機(jī)械臂替換成了兩個舵機(jī)和轉(zhuǎn)動平臺組成的執(zhí)行機(jī)構(gòu),四個相機(jī)減到一個相機(jī),實(shí)現(xiàn)的效果很成功。然后因?yàn)橛嬎銠C(jī)解魔方有個特點(diǎn),可以從一種狀態(tài)解算的任何另一種狀態(tài),所以又衍生出了用魔方機(jī)器人教學(xué)的想法。通過把打亂的魔方交給魔方機(jī)器人,造出指定的場景,從而達(dá)到反復(fù)訓(xùn)練的目的。

系統(tǒng)組成

下位機(jī)是一塊STM32的板卡,用來控制舵機(jī),操作相機(jī)抓圖,把魔方的角塊和顏色編碼后通過串口傳給上位機(jī)。上位機(jī)直接就是筆記本電腦,用QT寫的完整GUI界面,包括解魔方教學(xué)步驟的圖片和視頻,對應(yīng)的要機(jī)器人還原的指定狀態(tài)的選擇。確定后再傳回下位機(jī)控制舵機(jī)完成還原操作。
由于這套系統(tǒng)還在跟公司合作,以后可能會商業(yè)化,所以不能在這里放內(nèi)部結(jié)構(gòu)圖和完整代碼,有之前伺服電機(jī)解魔方機(jī)器人的圖,放一些示意一下。




學(xué)習(xí)到的技術(shù)

  • 顏色識別


顏色識別采用OpenCV實(shí)現(xiàn)。因?yàn)槟Х轿恢煤拖鄼C(jī)位置基本固定,先采用OpenCV的圖像標(biāo)定函數(shù),標(biāo)定出各個角塊的坐標(biāo)點(diǎn),然后采用HSV顏色模型來識別顏色。之所以不用RGB顏色模型也是考慮到外界環(huán)境可能出現(xiàn)的光照等原因?qū)︻伾R別造成的誤差。

在魔方拍攝與識別這一問題中只需要考慮其中的H 值與S 值即可,顯然明度的問題并不會影響到本文的顏色識別,而且它最大的優(yōu)點(diǎn)在于可以一定程度上削弱光照條件對識別結(jié)果的影響,這樣可以大大地提高本文的識別效果。當(dāng)然,忽略V 值的影響雖然不會在程序中影響到最終的識別情況,但是需要指出光照條件的變化H 值與S 值是會產(chǎn)生較大變化的,并不存在使用了HSV 模型就可以忽略光照條件的影響。

先把魔方還原,對每一個攝像頭進(jìn)行標(biāo)定。單獨(dú)啟動每一個攝像頭拍攝基準(zhǔn)照片,根據(jù)拍攝的照片在其上用鼠標(biāo)選擇取色基準(zhǔn)點(diǎn)。完成每一個攝像頭的標(biāo)定后開始編寫程序,將每一個攝像頭的每一個取色基準(zhǔn)點(diǎn)的橫縱坐標(biāo)值輸入,并同時取該點(diǎn)周圍的8個其他像素點(diǎn),讀入9個點(diǎn)的數(shù)據(jù)計算平均值,將得到的平均值作為最終的輸出結(jié)果。

因?yàn)楸疚牡哪Х接幸环N顏色是白色的,那本文大可以單獨(dú)考慮S 值來區(qū)分這一顏色。通過對白色的面進(jìn)行大量地拍攝和識別發(fā)現(xiàn),白色的小塊幾乎不會出現(xiàn)S 值超過70的情況,所以將S 上的閾值設(shè)置在70,只要是S 值低于70時,則將其認(rèn)為是白色。雖然看起來這樣的判定方法是有些單純的,但它的實(shí)際效果并不差,白色的識別準(zhǔn)確率在作者的實(shí)驗(yàn)中是最高的,在36次的實(shí)驗(yàn)中白色小塊沒有一次被識別錯誤的。

對于其他的五種顏色作者則都在H 值上進(jìn)行劃分。通過大量的拍攝圖像識別的情況來看,在白天的實(shí)驗(yàn)室內(nèi),保持一個相對恒定的光照條件時,以下的閾值設(shè)置效果較好,如果出現(xiàn)因?yàn)殚撝挡划?dāng)而導(dǎo)致的識別出錯問題則應(yīng)該根據(jù)實(shí)際情況對閾值進(jìn)行調(diào)整(實(shí)際情況來看這種操作也是比較有必要的,在上午、正午、傍晚時的閾值都需要進(jìn)行一定的微調(diào),尤其是紅色的上限值和橙色的下限值,在夜晚沒有外界自然光只有室內(nèi)日光燈和機(jī)器補(bǔ)光燈的條件下往往需要對閾值進(jìn)行較大的調(diào)整)。將紅色的閾值設(shè)置為H 值大于等于0且小于7,而橙色的閾值為大于等于7且小于33,將黃色的閾值設(shè)置為大于等于33且小于51,將綠色的閾值設(shè)置為大于等于51且小于80,將藍(lán)色的閾值設(shè)置為大于等于80且小于130,將大于等于130且小于180的部分判定為紅色(這種情況是極少出現(xiàn)的)。

  • 解法實(shí)現(xiàn)

人為地解魔方的方法有很多種,例如較為常見的有層先法和CFOP 法,這兩種方法具有一個極大的優(yōu)勢就是它們更容易形成讓人很快就能記住的解魔方的公式,即使是一個完全沒有接觸過三階魔方的普通人,也能很快地學(xué)會層先法解魔方的公式。

而計算機(jī)的解魔方算法就有很多種了,因?yàn)橛嬎銠C(jī)是不需要考慮公式和可記憶性問題的,也不需要考慮是否會花費(fèi)大量的時間去計算復(fù)雜的數(shù)學(xué)問題,只要算法在數(shù)學(xué)原理上沒有錯誤,編寫成對應(yīng)的程序就能完成解魔方的任務(wù)。目前已經(jīng)被開發(fā)的較為完善的有二階段算法、Thistlethwaite 算法、Jaap Scherphuis 算法等等。其中有的算法可能會檢索出最小還原路徑但犧牲的是求解的時間,有的可能求解極為迅速但可能其求解出的步驟會較多。單純?nèi)绻麨榇舜蔚闹悄軝C(jī)器人創(chuàng)意大賽中的解魔方項(xiàng)目取得好成績考慮的話,采用二階段算法或Thistlethwaite 算法是較為合適的,因?yàn)樗鼈兡芮蠼猥@得一個步驟不那么多的還原路徑,并且求解的速度相對較快,是兩種在速度和步驟數(shù)量上比較均衡的算法。

本文解魔方算法使用Thistlethwaite 算法。

魔方解算步驟的編碼

三階魔方具有6個顏色完全不同的面,每個面都有9個小色塊。本文將這9個色塊都按照第一行為1,2,3號,第二行為4,5,6號,第三行為7,8,9號進(jìn)行編號,在旋轉(zhuǎn)魔方時魔方本身的一個特點(diǎn)就是:每一個面最中間的那個5號色塊是并不會轉(zhuǎn)動的。因此只要保持魔方本身的姿態(tài)不變化,讓某一個顏色的色塊一直朝向某一個方向,就可以用一組字母來描述每個面。本文定義了U(up)、D(down)、L(left)、R(right)、F(front)、B(behind) 這幾個字母來描述6個面,同時本文規(guī)定,對于一個標(biāo)準(zhǔn)三階魔方其U 面為黃色,D 面為白色,L 面為橙色,R 面為紅色,F 面為藍(lán)色,B 面為綠色。至此,本文已經(jīng)完成了對魔方每個面的定義,每一個魔方只要通過這種擺放姿勢擺放,給出的一個還原路徑的執(zhí)行方式就唯一。
在規(guī)定了面的名稱后再對面的旋轉(zhuǎn)進(jìn)行規(guī)定。顯然每個面都只能順、逆時針旋轉(zhuǎn)90度和旋轉(zhuǎn)180度,本文將其定義為“1”,“3”,“2”三個數(shù)字。需要注意的是,這里的“順時針”和“逆時針”是指當(dāng)你面向這個面時的順時針和逆時針。舉個例子,將一個魔方的F 面朝向你的臉,此時的F 面順時針旋轉(zhuǎn)90度就是將1號色塊轉(zhuǎn)到3號色塊的位置這樣旋轉(zhuǎn),而此時的B 面順時針旋轉(zhuǎn)則需要你將魔方的B 面朝向你的臉,然后將1號色塊轉(zhuǎn)到3號色塊位置這樣旋轉(zhuǎn)。
通過對面的名稱和旋轉(zhuǎn)的規(guī)定,本文得到了U、D、L、R、F、B 六個字母和1、3、2這三個數(shù)字,將其組合就得到了F1、U2、D3等等這樣的組合,這種組合形成的一系列旋轉(zhuǎn)動作就是本文的還原路徑了。例如F1 U2 D3 R3 U2 L1 U1這個還原路徑,很顯然,如果你將F 面面朝自己,這個還原路徑將變成一個唯一的動作。

Thistlethwaite 算法是由Morwen B. Thistlethwaite 這位數(shù)學(xué)家設(shè)計并以他的名字進(jìn)行命名的一種計算機(jī)解魔方算法[11],整個解魔方的算法分為4個階段,每個階段完成一些工作來限制小塊的位置,當(dāng)魔方的每一個小塊都只剩下一個可能的位置時就完成了魔方的還原了[6]。
使用這種算法可以得到一種步驟極少的還原魔方的路徑,但是由于其四個還原步驟都相當(dāng)?shù)膹?fù)雜,并且需要大量的參考表(公式),作為一個普通的人類是完全無法使用這種方法來解魔方的,因?yàn)樗膮⒖急?#xff08;公式)多到根本無法記憶(僅僅第一個還原階段的位置數(shù)量就多達(dá)4.33*10 19種)。
對于這個算法的四個步驟做以下的簡單描述:
第一步,先進(jìn)行幾步旋轉(zhuǎn)來使得魔方的狀態(tài)變成不使用U1、U3、D1和D3這四種動作就可以完成復(fù)原的狀態(tài)。這個過程通常需要不超過十步來完成。
第二步,再將魔方的狀態(tài)調(diào)整到不需要F1、F3、B1和B3這四種動作就可以完成復(fù)原的狀態(tài)。這個過程的步驟數(shù)量或多或少,最多可能會出現(xiàn)十幾步。
第三步,將魔方調(diào)整到只需要F2、B2、L2、R2、U2和D2動作就能完成復(fù)原的狀態(tài)。這個過程所需要的步驟數(shù)量也是不確定的,要根據(jù)魔方的實(shí)際狀態(tài)來看。通常情況下也是需要十幾步的。
第四步,只使用F2、B2、L2、R2、U2和D2動作完成最后的調(diào)整,讓所有小塊可能出現(xiàn)的位置都變成唯一位置,完成魔方的復(fù)原。
整個過程看起來似乎并不是很難,簡單來說就是在逐次地限制小塊的位置可能性,讓小塊可能存在的位置數(shù)量越來越少,先限制U 面和D 面的小塊,再限制F 面和B 面的小塊,最后限制L 面和R 面的小塊,當(dāng)完成全部限制后,在U 面和D 面都只會存在有兩種顏色的小塊,F 面和B 面以及L 面和R 面也是如此,然后就可以通過F2、B2、L2、R2、U2 和D2 動作就能完成還原了。但是實(shí)際上執(zhí)行這四個步驟時所需要花費(fèi)的計算量是極為龐大的,下面的這張表格中顯示的就是執(zhí)行四個步驟時需要的一些數(shù)據(jù)量。

從數(shù)學(xué)的角度上來看,它實(shí)際上是一個嵌套組的序列,算法的每一個階段都是一張查找表,用來尋找到商陪集空間中每一個元素的解。而最后一列中顯示的就是這個陪集空間的順序,也就是每一個階段的查找表的大小。至于這個因子數(shù)量的計算公式,這和這種算法在限制不同面的小塊時是如何限制的有關(guān)。[6]具體的一些數(shù)學(xué)原理就非常深奧了,涉及到太多作者并沒有接觸過的更為高深和專業(yè)數(shù)學(xué)知識,在此就不多做分析和討論了。
在第一階段時,目標(biāo)是限制U 面與D 面都只能采用U2和D2的動作來進(jìn)行后續(xù)的調(diào)整,其實(shí)它所做的工作在魔方層面來看就是修正魔方的棱塊的方向,因?yàn)橐骍 面與D 面都只能轉(zhuǎn)半圈而不能轉(zhuǎn)四分之一圈,所以就決定了是不可能再調(diào)整四邊棱塊的了,通過這種限制就可以完成將四邊棱塊限制在一個完全正確的位置上。
在第二階段時,目標(biāo)是在第一階段的基礎(chǔ)上開始限制F 面與B 面的小塊。如果要求在F、B、U 和D 面都只能使用半圈的旋轉(zhuǎn)方式而不能使用四分之一圈的旋轉(zhuǎn)方式,那么這階段就可以完成對于八個角塊的位置確定,并對這八個角塊的方向進(jìn)行確定,讓角塊和第一階段確定的棱塊完成正確的拼接。在完成第二階段后,八個角塊和四個棱塊都會進(jìn)入位置確定,角塊方向不定的一種狀態(tài),但即使是方向不定但因?yàn)槟Х奖旧淼慕Y(jié)果和角塊的顏色,它們依然會受到移動限制。
在第三階段,開始限制剩下的L 面與R 面的小塊,目的是完成對所有面上小塊的限制,讓每一個面都只有“相對顏色”(例如F 面為藍(lán)色,B 面為綠色,則在完成第三階段后,F 面和B 面都只會存在藍(lán)色與綠色兩種顏色,絕不會出現(xiàn)其他的4種顏色在這兩個面中)。在此種狀態(tài)下,所有的角塊和棱塊都已經(jīng)進(jìn)入了正確的位置,只需要在進(jìn)行U2、D2、F2、B2、L2和R2這六種動作就能將魔方徹底地復(fù)原。
第四個階段就是只使用旋轉(zhuǎn)半圈的六種動作將魔方徹底地復(fù)原。
很顯然這個算法的搜索方法看起來很美好,但它使用的查找表實(shí)在是太大了,及時是計算機(jī)直接去運(yùn)行也會有不小的計算壓力,所以就需要想辦法來縮小這個檢查表。為了減小這個檢查表,Tistlethwaite 嘗試簡化了初始的這種搜索方法,這也是為什么有時他需要的實(shí)際還原步驟是比這個商空間的“直徑”(搜索出的最佳的還原路徑)要多一些的原因。在之后他的一些學(xué)生針對這個問題進(jìn)行了更深層次的研究,他們對這些嵌套組進(jìn)行了完整的分析,然后改進(jìn)了算法,讓搜索出的最佳還原路徑降低到五十步。再隨后,他們繼續(xù)研究了每一個階段的搜索算法,對每一個階段的搜索算法又進(jìn)行了全面而深入的分析,將最佳還原路徑降低到了45步。再之后又有一名叫做Hans Kloosterman 的人繼續(xù)改進(jìn)了第三階段和第四節(jié)段的算法,成功將最佳還原路徑的步驟降低到了42步,這個42步被實(shí)現(xiàn)的時間是在1991年[6]。再之后計算機(jī)的運(yùn)算能力開始大幅度提高,借助運(yùn)算性能更強(qiáng)的計算機(jī),數(shù)學(xué)家Mike Reid 通過更復(fù)雜的數(shù)學(xué)分析得出的結(jié)論是從第一階段到第二階段理論上需要12步即可完成,第三階段和第四階段理論上需要18步即可完成,將其組合起來后理論上30步之內(nèi)就可以完成用這種算法來求解任何一個打亂的三階魔方。

  • 全局變量的使用

當(dāng)時對面向?qū)ο罄斫獠簧羁?#xff0c;魔方的狀態(tài),因?yàn)樵谀Х浇馑憷镆灿玫?#xff0c;在串口通訊時也要用到,就定義成了全局變量。也順便記錄一下用全局變量的方法:

extern char color_sides[6][9];

在頭文件通過extern 聲明全局變量,其他地方需要使用時,只需include進(jìn)相應(yīng)的頭文件即可

但C++不提倡使用全局變量
因?yàn)槿肿兞縝ai容易導(dǎo)致代碼的可復(fù)用性下降,以及對象管理的困難。
試想,如果某個類使用了全局變量,則移植該類的時候,必須將全局變量也一起移植。更可怕的是,如果這個全局變量還是一個對象,并且初始化也在不同的類中實(shí)現(xiàn),那么所有這些代碼將被永久捆綁在一起,無法分離了。任何一個與此全局變量相關(guān)聯(lián)的代碼一旦有改動,即可對其他使用該變量的代碼產(chǎn)生不可預(yù)知的影響。

影響函數(shù)的封裝性能:我們肯定是希望我們寫的函數(shù)具有重入性,就如一個黑盒子一般,只 通過函數(shù)參數(shù)就能得到返回,內(nèi)部 實(shí)現(xiàn)要獨(dú)立,但是如果函數(shù)中使用了全局變量,這勢必就破壞了函數(shù)的封裝性,會造成對全局變量的依賴。

1 全局變量是很好。
2 但是有缺點(diǎn):容易被修改錯,尤其在工程很大的時候。
3 使用時一定要控制好全局變量的修改。
4 不過小工程小項(xiàng)目使用全局變量是很方便的!
1.全局變量在程序執(zhí)行過程中一直占用存儲單元,耗費(fèi)空間。
2.使函數(shù)的通用性、移植性降低了,耦合性變強(qiáng)了。
3.使程序的可讀性降低,難以判斷全局變量在一定時刻的具體值。

重新構(gòu)建你的數(shù)據(jù)結(jié)構(gòu),把公有數(shù)據(jù)成員抽離出來,單獨(dú)做成模塊,提供一個接口對其操作。
如果確實(shí)有大量數(shù)據(jù)需要共享的話,建議還是用單獨(dú)的類封裝一下。其實(shí)類的使用,個人認(rèn)為主要還是邏輯上清晰為第一原則

  • 播放器

因?yàn)橐菔窘饽Х浇虒W(xué)視頻,所以用QT寫了一個播放器。實(shí)現(xiàn)的功能主要有播放本地視頻,暫停,進(jìn)度條拖動。
用到的QT庫:
QMediaplayer:用于解析音頻文件和視頻文件。
使用QMediaplayer,除了需要添加必要的頭文件之外,還需要在.pro(Qt的工程配置文件)添加QT += multimedia。下面解析有關(guān)QMediaplayer的相關(guān)知識。
QMediaPlayer播放視頻要在界面上顯示出來,還需要其他類進(jìn)行輔助,比如QVideoWidget。

QVideoWidget:QVideoWidget繼承自QWidget,所有它可以作為一個普通窗口部件進(jìn)行顯示,也可以嵌入到其他窗口。將QVideoWidget指定為QMediaPlayer的視頻輸出窗口后,就可以顯示播放的視頻畫面。

如果播放無圖像,并報錯:

DirectShowPlayerService::doRender: Unresolved error code 80040266

原因:
Qt 中的多媒體播放,底層是使用DirectShowPlayerService,所以安裝一個DirectShow解碼器,例如LAV Filters,就可以解決運(yùn)行出錯問題

另外為了實(shí)現(xiàn)進(jìn)度條拖動跳轉(zhuǎn)功能,又用QSlider和事件過濾器單獨(dú)寫了個進(jìn)度條組件加到下面。通過信號槽與播放器連接,一旦拖動進(jìn)度條釋放鼠標(biāo)后就發(fā)出信號量,播放器里接收,通過player->setpostion設(shè)定進(jìn)度。

串口通訊
也用了QT庫。網(wǎng)上很多相關(guān)寫法,就不再贅述了。
#include
#include
記得配置文件.pro里要加QT += serialport

有個需要注意的地方,因?yàn)閭骰貋淼哪Х綌?shù)據(jù)較長,在觸發(fā)串口接收函數(shù)后,要先加上:

while (m_serialPort->waitForReadyRead(500));

延時等待一會兒,不然會出現(xiàn)數(shù)據(jù)不全的情況。

  • 線程

因?yàn)榻饽Х剿惴ㄐ枰欢〞r間,所以給它專門開個線程處理。
注意幾個點(diǎn):
線程處理函數(shù)里不能操作圖形界面,需要操作,要發(fā)信號量出來,在主線程里操作。
線程不能指定父對象,關(guān)窗口時記得delete

QT的線程真的很簡便:

t = new QThread(this); solve = new Solution; solve->moveToThread(t); t->start();

這就完成了,只要Solution類也繼承自QObject即可。
記得析構(gòu)的時候,把線程退出,并且delete掉。

  • 互斥鎖

因?yàn)橛袝r候識別有錯誤,會出現(xiàn)解不出來的情況,所以需要定時檢測算法有沒有結(jié)果。本來想直接寫個標(biāo)志位解決,但有個問題,可能查查看的時候,剛好那邊在寫,而且也分處兩個不同的線程,所以想到加個互斥鎖解決。

在Qt的多線程控制中,互斥量的訪問最簡單的控制是添加一個mutex鎖,對一個函數(shù)或者變量鎖定。

如果QMutex::lock()得不到這個鎖,那么它將會一直等直到得到該鎖為止,而另一個方法QMutex::tryLock()可以檢測當(dāng)前是否可以得到這個鎖,如果可以得到則返回1,否則返回0(不會一直等,但如果可以得到鎖,那就拿到鎖,不會光判斷而不獲取鎖),該函數(shù)只執(zhí)行一次,不會一直等到得到鎖為止。

最后就是設(shè)計模式的探討,不然情景選擇按鍵下全是switch,這個之后再補(bǔ)充。

相關(guān)代碼因?yàn)轫?xiàng)目還在進(jìn)行中,而且將來要商業(yè)化,所以不能放上來了。

總結(jié)

通過這次又對QT熟悉一點(diǎn),開發(fā)更加迅速,而且也算把師弟領(lǐng)進(jìn)門了。這個項(xiàng)目本身也很有趣,開發(fā)的過程中能夠樂在其中,并且也很有挑戰(zhàn)性,最后慢慢解出魔方,速度越來越快,真是感覺一切都值了。

參考文獻(xiàn):
http://bbs.mf8-china.com/forum.php?mod=viewthread&tid=38810
https://www.cnblogs.com/sixbeauty/p/3790693.html
https://www.cnblogs.com/dupengcheng/p/7205527.html
https://blog.csdn.net/qq_36969386/article/details/85072605

總結(jié)

以上是生活随笔為你收集整理的魔方教学系统(基于QT)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。