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