機(jī)械鐘琴設(shè)計(jì)——使用兩個(gè)伺服控制的木槌在鐘琴上演奏旋律
這是我的一個(gè)老項(xiàng)目,我從來(lái)沒(méi)有完成過(guò)。廢品抽屜競(jìng)賽是一個(gè)很好的機(jī)會(huì),最終把項(xiàng)目帶回家。這個(gè)故事中的很多文字都是6年前的,但我已經(jīng)編輯了很多。
簡(jiǎn)而言之就是鐘琴
鐘琴,一種帶有教堂大鐘的鐘琴,通常包括自動(dòng)化裝置。Netduino,這個(gè)項(xiàng)目的原始μC板。慈善機(jī)構(gòu)。從這些話中,我想出了charillino這個(gè)名字。我還是會(huì)以某種方式加入慈善。最終的微控制器板(μC)將具有物聯(lián)網(wǎng)功能,人們將能夠從網(wǎng)站上選擇歌曲,同時(shí)該項(xiàng)目為慈善機(jī)構(gòu)籌集資金。
這個(gè)樂(lè)器由25個(gè)鋁制琴鍵組成,或者說(shuō)是鋁制琴條,都是從我扔掉的鐘琴上取下來(lái)的。我是一名音樂(lè)老師,我有太多這樣的想法了。25根木條以半圓形放置在一塊400 * 800毫米的木板上,這是一塊來(lái)自Lundia書架的書寫架。兩個(gè)木槌敲打著欄桿。一個(gè)木槌連接在一個(gè)微伺服器上,執(zhí)行垂直打擊。微伺服連接到一個(gè)更大的伺服,使其水平轉(zhuǎn)動(dòng),允許木槌在任何酒吧打擊。木棒實(shí)際上是沿著兩個(gè)相互重疊的半圓放置的,優(yōu)化了每個(gè)木槌的擊球點(diǎn)。從G5開始,一個(gè)木槌主要敲擊小節(jié)的下端。另一個(gè)木槌敲到了G7的高端。
在每根棒子下面的木板上有一個(gè)洞,木板下面伸出一根鋁管。電子管作為聲音的共振器,放大聲音。
一個(gè)μC板控制伺服器,使它們播放旋律。
使項(xiàng)目自動(dòng)化
這是最大的變化,當(dāng)項(xiàng)目適應(yīng)垃圾抽屜比賽。我的一個(gè)學(xué)生送了我一個(gè)可愛(ài)的圣誕小精靈。我用粗鐵線給小精靈做了一個(gè)座位。他的腿很長(zhǎng)很邋遢,我把腳綁在木槌上,希望它們能抑制巨大的震動(dòng),這是我一直無(wú)法擺脫的。它幾乎起作用了。
音樂(lè)的數(shù)據(jù)結(jié)構(gòu)
我可以選擇midi,但是midi解析器太復(fù)雜了,通常需要在第一個(gè)音符發(fā)出之前將整個(gè)文件讀取到RAM中。相反,我采用了這樣的結(jié)構(gòu):
第一個(gè)數(shù)字是音調(diào)的中音數(shù)字。第二個(gè)數(shù)字是以毫秒為單位的時(shí)間戳,第三個(gè)數(shù)字是哪個(gè)木槌在敲擊,1代表低音,0代表距離。數(shù)據(jù)結(jié)構(gòu)將來(lái)可能會(huì)改變,如果我想把速度作為一個(gè)參數(shù),來(lái)改變音樂(lè)的動(dòng)態(tài)。沒(méi)有音符事件,因?yàn)椴槔锢Z只是敲擊小節(jié),而不會(huì)在之后減弱它們。
在其最簡(jiǎn)單的形式中,程序讀取一行,等待機(jī)器時(shí)鐘傳遞時(shí)間戳,然后右木槌轉(zhuǎn)向右鐘琴條并敲擊它。
但還有更多的原因。如果右邊的棒子離之前的打擊很遠(yuǎn),移動(dòng)到那里需要時(shí)間,所以如果木槌提前移動(dòng)到那里會(huì)更好。然而,拙劣的安排可能會(huì)導(dǎo)致兩個(gè)木槌碰撞,如果一個(gè)過(guò)早地移動(dòng)到下一個(gè)小節(jié)。寫得不好的安排可能會(huì)引起各種問(wèn)題。
我決定依靠書面安排。如果可能的話,我會(huì)提前把木槌搬到下一個(gè)酒吧。
在Musescore中編寫音樂(lè)
Musescore也許是最流行的免費(fèi)樂(lè)譜編輯器。
簡(jiǎn)單的兩五線譜就可以了:
在這個(gè)例子中,使用了Charillino的全系列。最高的是G7,最低的是G5。
這些注釋將被轉(zhuǎn)移到前面清單中所示的數(shù)據(jù)結(jié)構(gòu)中。這里我們可以使用Musescore的插件系統(tǒng)。有一個(gè)插件可以根據(jù)特定的配色方案給筆記上色。我使用了這個(gè)腳本,跳過(guò)了上色,而是讓腳本為每個(gè)音符寫midi數(shù)字和事件的時(shí)間。幸運(yùn)的是,有一個(gè)函數(shù)以毫秒為單位返回時(shí)間,并帶有無(wú)數(shù)小數(shù)。插件中的關(guān)鍵行是這樣的:
Cur是一個(gè)游標(biāo)對(duì)象,它指向樂(lè)譜中的一個(gè)元素。它可以是休止符,和弦或者別的什么。我從游標(biāo)對(duì)象讀取時(shí)間,并將其舍入到毫秒(沒(méi)有人會(huì)注意到亞毫秒級(jí)的錯(cuò)誤)。和弦由一個(gè)或幾個(gè)音符組成。插件遍歷嵌套循環(huán),最外面的遍歷所有五線譜,下一個(gè)遍歷一個(gè)五線譜中的所有和弦,最里面的遍歷一個(gè)和弦中的所有音符。因此,音調(diào)的音高或中音數(shù)可以從音符對(duì)象中讀取,而時(shí)間則從光標(biāo)對(duì)象中讀取。在我的代碼中,五線譜數(shù)(它轉(zhuǎn)移到木槌數(shù))保存在五線譜變量中。運(yùn)行此插件將在插件工具的控制臺(tái)窗口中顯示一個(gè)列表(必須在Musescore中打開)。清單看起來(lái)是這樣的:
注意,在輪到下一個(gè)五線譜之前,一個(gè)五線譜的所有音符都先出現(xiàn)。從這里,我復(fù)制文本并將其粘貼到Libreoffice的電子表格中,在那里我根據(jù)時(shí)間戳對(duì)它們進(jìn)行排序。我還添加了花括號(hào),以適應(yīng)C程序中的結(jié)構(gòu)數(shù)組。然后我將其從Libreoffice復(fù)制粘貼到Arduino IDE,到char伊利諾_tunes.h選項(xiàng)卡。
在Libreoffice中的表單:
當(dāng)我從Musescore中的控制臺(tái)復(fù)制數(shù)據(jù)時(shí),我將其粘貼到單元格A7中。重要的數(shù)據(jù)放在B、C和D列。在根據(jù)C列(時(shí)間戳)對(duì)所有內(nèi)容進(jìn)行排序之后,我在E列中創(chuàng)建代碼,并將其直接復(fù)制到Arduino IDE項(xiàng)目中的char伊利諾_tune .h文件中。對(duì)于新曲調(diào),我刪除a列中的內(nèi)容,將新數(shù)據(jù)粘貼到A7中并再次排序(a列現(xiàn)在顯示新列表的長(zhǎng)度)。E列很好地更新了自己,如果新的曲調(diào)比以前的更長(zhǎng),我只需要擴(kuò)展它。
我真的應(yīng)該學(xué)習(xí)Javascript并在Musescore插件中進(jìn)行排序。
程序流程
在其最簡(jiǎn)單的形式中,程序?qū)⑦\(yùn)行如下:
在char伊利諾_tunes.h文件中以結(jié)構(gòu)形式存儲(chǔ)大約10首曲調(diào)。一個(gè)只有10個(gè)音符的曲調(diào)可能是這樣的:
首先,我們?yōu)橐粋€(gè)音符事件定義Tunes結(jié)構(gòu)。然后我們將一個(gè)曲調(diào)定義為音符事件的數(shù)組。最后一個(gè)元素的時(shí)間戳為9999999,作為曲子結(jié)束的標(biāo)志(鍵和五線譜編號(hào)無(wú)關(guān))。我可以隨意命名一個(gè)曲調(diào)數(shù)組。在主程序中,我有一個(gè)指向這些曲調(diào)的指針數(shù)組:
當(dāng)程序啟動(dòng)時(shí),一切都設(shè)置好了,指針指向這個(gè)調(diào)音列表中的第一個(gè)元素。曲子奏起了。5秒的延遲,下一曲開始。當(dāng)?shù)竭_(dá)NULL元素時(shí),指針?lè)祷氐降谝粋€(gè)元素。
當(dāng)一個(gè)曲調(diào)演奏時(shí),一個(gè)木槌等待下一個(gè)樂(lè)章的發(fā)生。首先,木槌水平移動(dòng)到右邊的酒吧。然后,200毫秒后,它擊中了鍵。播放一個(gè)曲調(diào)的程序流程是這樣的:
?讀取每個(gè)木槌的第一個(gè)音符事件,并為之前200毫秒的水平移動(dòng)創(chuàng)建時(shí)間戳。
?記錄曲子的開始時(shí)間。注意,音符擊打的第一個(gè)時(shí)間戳可能是0,所以第一個(gè)水平移動(dòng)的時(shí)間戳可能是-200毫秒,但這不會(huì)導(dǎo)致問(wèn)題,因?yàn)橹鲿r(shí)鐘是millis(),總是大于1000的值。
?等待下一個(gè)時(shí)間戳。如果它是一個(gè)水平運(yùn)動(dòng),做這個(gè)運(yùn)動(dòng),然后再等待一次。如果是為了打擊,執(zhí)行打擊,搜索下一個(gè)事件,為水平移動(dòng)創(chuàng)建時(shí)間戳。這個(gè)步驟循環(huán),直到曲子播放完畢。所以下一個(gè)時(shí)間戳可以是木槌,可以是水平運(yùn)動(dòng)的時(shí)間戳,也可以是擊打的時(shí)間戳。
?當(dāng)一個(gè)曲調(diào)結(jié)束時(shí),等待5秒并選擇下一個(gè)曲調(diào),最終循環(huán)回到列表中的第一個(gè)曲調(diào)。
木槌如何移動(dòng)
水平運(yùn)動(dòng)將木槌置于桿上方約30毫米的位置。擊打使木槌迅速移動(dòng)到棒子上方約5毫米處。如果一切都校準(zhǔn)完美,木槌的靈活桿使木槌擊中酒吧一次。木槌保持在這個(gè)位置,直到下一個(gè)水平運(yùn)動(dòng)發(fā)生,同時(shí)將木槌從5毫米提高到30毫米。
電路圖
這個(gè)示意圖展示了我在2021年是如何設(shè)計(jì)它的。原理圖中顯示的Arduino Leonardo恰好具有與Netduino相同的外形因素,該項(xiàng)目中的原始μC板。我烤了一個(gè)Netduino。我還喝了一杯,但厭倦了。. NET東西-錯(cuò)誤的編程語(yǔ)言,一個(gè)乳齒象IDE。所以我現(xiàn)在切換到Seeeduino XIAO,稍后切換到一些ESP32板,如果我去物聯(lián)網(wǎng)。我最初選擇了一個(gè)12 V的電源和一個(gè)LM2596來(lái)把功率降低到5V。那時(shí)候我經(jīng)常在大多數(shù)項(xiàng)目中使用12V的鉛電池。
這是一個(gè)簡(jiǎn)單的設(shè)置,可以通過(guò)開關(guān)和電位器進(jìn)行改進(jìn),也許還可以使用顯示器。我不會(huì)在這個(gè)項(xiàng)目中深入討論。
在這個(gè)項(xiàng)目中使用的垃圾
倫迪亞書架。我閣樓上還有很多倫迪亞的零件。對(duì)于每一個(gè)新項(xiàng)目,我都檢查一下那里有什么。
為了這個(gè)項(xiàng)目,我把鐘琴扔了。它實(shí)際上并不是垃圾,但有15個(gè)鐘樓,一個(gè)鐘樓或多或少是垃圾。
精靈。這是我的一個(gè)學(xué)生送給我的圣誕禮物。它本身不是垃圾,但我找不到任何用途,它不適合我的家庭裝飾。反正我妻子也討厭它。
給小精靈的電線。我自己也有一些粗鋁線,放在我的一個(gè)雜物抽屜里,但它承受不了那么大的重量。所以我用了一些學(xué)校的生銹的4毫米鐵絲,從一個(gè)堆滿金屬碎片的垃圾角落里拿來(lái)做學(xué)校項(xiàng)目。這是一種交易,因?yàn)槲抑鞍盐业呐f鐵旗桿捐給了我們學(xué)校。
μC板,PCA9685,臨時(shí)原型板,都是從我的一個(gè)垃圾抽屜里找到的東西。再說(shuō)一次,不是垃圾本身,而是垃圾中的寶石。我們都知道自己的抽屜里裝滿了寶石,不是嗎?
實(shí)際上伺服器已經(jīng)變成垃圾了。由于早期的測(cè)試用了太重的木槌,垂直伺服器上的一些齒已經(jīng)磨損了,我不得不打開它們,把齒輪轉(zhuǎn)到新的位置,以避免磨損的齒。下次發(fā)生這種情況時(shí),我得把伺服器換掉??上Ы饘冽X輪對(duì)儀器來(lái)說(shuō)太吵了。
校準(zhǔn)charillino
一個(gè)打擊包括移動(dòng)垂直伺服從一個(gè)較高的位置到較低的位置。根據(jù)使用的伺服系統(tǒng)以及錘頭的扭矩和慣性扭矩有多大,這些角度值不可能在沒(méi)有測(cè)試的情況下提前設(shè)定。如果木槌打得太用力,就會(huì)粘在棒子上,發(fā)出難看的短金屬聲,或者木槌打了兩次才落在5mm的高度。如果它打得太輕,甚至不會(huì)每次都被擊中。我們想要一個(gè)清晰的單擊,讓振動(dòng)棒發(fā)出持續(xù)的聲音。
需要專門的校準(zhǔn)程序。結(jié)果將是一個(gè)查找表,其中包含每個(gè)鍵和每個(gè)槌的上、下位置的最佳角度。為了讓它更上一層樓,我們可以嘗試通過(guò)改變上部位置來(lái)加入強(qiáng)音和弱音。
我的校準(zhǔn)程序
校準(zhǔn)程序通過(guò)在計(jì)算機(jī)上輸入字母來(lái)工作。μC通過(guò)串行USB接收字母命令并發(fā)回角度值列表。下面是命令列表:
‘a(chǎn)’:移動(dòng)到上一個(gè)鍵。
“f”:移動(dòng)到下一個(gè)鍵。
‘1’:按當(dāng)前參數(shù)的鍵。
“3”:播放三個(gè)連續(xù)的鍵,直到當(dāng)前鍵來(lái)比較它們。
‘s’:將木槌的水平角度降低一個(gè)單位。
‘d’:將木槌的水平角度提高一個(gè)單位。
“w”:將擊槌的上位角度降低一個(gè)單位。
“e”:將擊打槌的上端角度提高一個(gè)單位。
“x”:將擊槌的下位角度降低一個(gè)單位。
“c”:將擊打槌的下位角度提高一個(gè)單位。
輸入兩個(gè)字母的角度將改變10個(gè)單位的角度。角度的數(shù)值不是以度為單位,而是在100到400的范圍內(nèi)。這都是關(guān)于伺服電機(jī)所需的特殊類型的PWM。我猜控制伺服電機(jī)的常規(guī)方法是servo.write(a);其中a是角度,在0到180的范圍內(nèi)。在這里,我使用數(shù)字來(lái)告訴脈沖在50hz或20ms周期中總共有多少個(gè)部分。
每次輸入后,所有27個(gè)音調(diào)的兩個(gè)陣列都被打印在串行上。如果μ C掛起,這種情況時(shí)有發(fā)生,我的電腦屏幕上總是有最新的更改。從那里,我可以將數(shù)組復(fù)制粘貼到Arduino IDE中的草圖中并重新編譯。校準(zhǔn)好后,我將相同的數(shù)組復(fù)制粘貼到實(shí)際的音樂(lè)播放程序中。
好吧,本來(lái)可以更好的。但這是個(gè)管用的查利諾琴。它播放播放列表中的所有17首曲子,然后重新開始。但無(wú)法產(chǎn)生可識(shí)別的曲調(diào)。木槌失去了精度。那么,我會(huì)毀掉整個(gè)項(xiàng)目嗎?不!我只需要改進(jìn)一下伺服器和木槌的動(dòng)力。伺服器可能需要更高的電壓,或更多的安培來(lái)獲得精度,必須檢查。伺服系統(tǒng)可能需要減速,就像你在3D打印機(jī)上看到的步進(jìn)電機(jī)那樣。也許可以調(diào)整伺服器的工作頻率,使之與擺動(dòng)木槌的頻率相適應(yīng)。每次罷工后,伺服器可能必須關(guān)閉一段時(shí)間,以避免持續(xù)的振蕩。木槌可能需要一個(gè)新的設(shè)計(jì),以減少振動(dòng)。小精靈可能需要更大的鞋子。
本文編譯自hackster.io