blog:2024-04-18_share_深入淺出講解foc演算法與svpwm技術
2024-04-18 Share: 深入淺出講解FOC演算法與SVPWM技術
Local Backup
0.前言
最近想做一個機器人項目,設計需要用到高性能超小體積的伺服馬達。
馬達這一性能滿足專案需求的基本上只有無刷馬達可以選了–又要大功率、大扭矩,又要體積小,成本還最好不要太高,選擇低KV值的無刷馬達顯然是最合適的。我預計的方案中計畫把減速器也省略了,採用扭力無刷馬達直驅。那麼作為機器人硬體三大核心部件(馬達、減速器、驅動器)之一的驅動器,我感覺是有必要自己設計一下的,因此這裡把我學習FOC過程中看到的一些有關無刷馬達向量控制的資料和個人理解整理分享出來。
本人非自控/電控專業,如文章有疏漏歡迎指出~
0.1 什麼是FOC?
FOC(Field-Oriented Control),直譯是磁場定向控制,也稱為向量控制(VC,Vector Control),是目前無刷直流馬達(BLDC)和永磁同步馬達(PMSM)高效控制的最優方法之一。 FOC旨在透過精確地控制磁場大小與方向,使得馬達的運動轉矩平穩、雜訊小、效率高,並且具有高速的動態響應。
簡單來說就是,FOC是一種對無刷馬達的驅動控制方法,它可以讓我們對無刷馬達進行「像素級」控制,實現許多傳統馬達控制方法所無法達到的效果~
0.2 FOC驅動器和無刷電調的區別
FOC的優點:
1, 低轉速下控制
2, 馬達換向
3, 力矩控制
4, 噪音
電調的優勢:
1.從電機原理說起
1.1 一些基礎知識
左手定則
右手定則
右手螺旋定則(即安培定則)
PWM(脈衝寬度調變)
1.2 無刷馬達原理
檢視下圖情況中的直流馬達基本模型,根據磁極異性相吸同性相斥的原理,中間永磁體在兩側電磁鐵的作用下會被施加一個力矩並發生旋轉,這就是馬達驅動的基本原理:
-
對於簡化的無刷馬達來說,以三相二極內轉子馬達為例,定子的三相繞組有星形聯結方式和三角聯結方式,而三相星形聯結的二二導通方式最為常用,這裡就用該模型來做個簡單分析:
-
如上圖所示,無刷馬達三相的連接方式是每一相引出導線的一頭,而另一頭和其他相兩兩相連。這個情況下假如我們對A、B極分別施加正電壓和負電壓,那麼由右手螺旋定則可以判斷出線圈磁極的方向如下圖:
-
思考一下這時候中間的轉子處於什麼角度的時候收到的力矩最大呢?
沒錯就是和CO(O為中心點)連線平行的時候,磁鐵會受到A、B兩個磁極一推一拉的作用,直到旋轉到與AB連線平行的且磁鐵內部磁力線方向和AB間磁力線方向一致的時候,受合力矩為0且穩定,也就是上圖右邊的狀態。換句話說,AB相通電會讓轉子努力轉到上圖右邊的狀態。至於C這時暫時不起作用。
同理,我們下一階段換成AC相通電,這時候轉子會傾向於轉到下圖右邊水平的角度:
-
然後BC相通電:
-
…
以此類推,可以得到每個通電狀態下轉子的角度,就是下圖中的6個狀態,每個狀態相隔60度,6個過程即完成了完整的轉動,共進行了6次換相:
-
整個過程就好像騎在驢子上吊一根胡蘿蔔一樣,旋轉的磁場牽引著永久磁鐵不斷旋轉:
-
而這個換向的操作,就是需要驅動器去完成的。
這也是無刷馬達和有刷馬達最大的區別,即不像有刷馬達的機械換向,無刷馬達是透過電子換向來驅動轉子不斷地轉動,馬達的電壓和KV值決定了馬達轉速,而馬達的轉速就決定了換向的頻率。
至於什麼時候怎麼知道該換到哪個供電相?如何產生更平滑的換向電壓?如何提高電源的利用效率?這些都是FOC控制方法要探討和解決的問題。
1.3 關於BLDC和PMSM的差別
無刷馬達其實可以分為無刷直流馬達(BLDC,我們航模上都是用這種)和永磁同步馬達(PMSM),結構大同小異,主要區別在於製造方式(線圈繞組方式)不同導致的一些特性差異(例如反電動勢的波形)。
從上面分析的無刷馬達模型其實可以看到,由於轉子在磁場中只有6個穩定的狀態,因此旋轉過程其實是不平滑的,存在扭矩的抖動(沒有通電的時候可以用手轉一下無刷電機,會感受到這種「顆粒感」)。因此為了解決這個問題,從「硬體」和從「軟體」出發有兩個解決方案,這就衍生出了BLDC和PMSM的區別。
簡單來說,BLDC由於反電動勢接近梯形波,所以肯定是會有上面說的抖動問題的,但是轉一圈抖6下太明顯了,如果我增加電機槽、極對數(也就是磁鐵對數),那以前是360度裡面抖6下,現在變成120度裡面抖6下,甚至更小,這樣「顆粒感」不就變得更小了嘛?實際買到的BLDC馬達基本上都是多極對的(例如下圖),原理跟之前的分析是一樣的,出來的都是三相信號(圖中的三條線),可以自己進行類推。 BLDC也可以結合抗齒槽演算法的FOC進行力矩補償來實現平滑控制。
-
而另一方面,為什麼我們非得用方波這種不平滑的波來驅動馬達呢,用正弦波它不香嗎?是的,這就是PMSM解決問題的方式,由於PMSM的反電動勢被設計為正弦波的形狀,我們用軟體和演算法結合PWM技術將方波轉變成等效的SPWM正弦波或SVPWM馬鞍波,再來驅動電機,結果美滋滋,控制效果很理想。當然為了產生更好的波形、更好的旋轉磁場,驅動器、控制演算法就變得非常複雜,這也是FOC的實作原理,後面會詳細介紹。
1.3 驅動電路實現
無刷馬達的驅動電路主要使用三相逆變電路來實現,如下圖:
-
所謂逆變電路,即把直流電變換為交流電,或者簡單點說就是一個可以產生不同電流流向的電路,透過前面的馬達模型分析我們也可以看出,對於無刷馬達的驅動是需要在不同時刻施加不同方向的電壓(電流)的,因此需要逆變電路。
而逆變電路具體的實現則一般是採用半橋MOS電路來製作的。半橋電路的原型如下,其實很簡單,就是兩個MOS管組成的上橋臂和下軸臂,中間引出一條輸出線:
-
用3個半橋電路就可以組合成三相逆變電路,每個半橋引出的一條輸出線跟無刷馬達的一根相線相連,就完成了最基本的無刷驅動電路。
原理方面,MOS管可以看作電壓控制的高速電子開關,在MOS管的閘極(上圖中的High Drive和Low Drive)施加高電平或低電平,就可以控制MOS源極和汲極的導通或關閉。例如在下圖中,我們打開第一組半橋的上橋臂、第二組和第三組半橋的下橋臂(其餘的關閉),那麼就可以讓電流從電源正極流過馬達的a相,流經b、c相,然後回到電源負極:
三相逆變驅動電路
於是透過控制三個半橋的不同開關狀態,我們可以控制電流在馬達中的不同流向了。
注意,在這個電路中,每個狀態下馬達的三相線圈都會有電流;而在上一節的範例中我們同一時刻只會讓兩相線圈有電流,另一相不起作用。
那麼這麼修改的原因是啥呢?當然是:浪費可恥啊~
浪費一相不用那不就白白損失了一部分扭力嘛?透過上圖中的方式驅動原理也是和之前分析一致的,但是可以產生更大的扭矩,所以當然是更好的選擇啦。
接下來我們將半橋電路的狀態做一個編碼,先限定一個半橋只有兩種狀態:
或許有人會問,為什麼一個半橋只能上橋臂和下橋臂有導通?都關閉或都導通不行? ?
害,仔細想想就知道,上下都導通顯然是不可能的,因為這就等於把電源短路了啊…
那上下都斷開呢?也不需要,因為這樣就回到前面提到的,這時候馬達有一相不起作用,浪了個費。
實際上半橋驅動電路的實現會比上面的分析要複雜一些,例如需要考慮開關管的開關頻率、開啟和關斷時間不對稱、死區問題等等,我後面設計的FOC驅動使用的是專用的半橋MOS閘極驅動IC來實現的。
1.4 旋轉的三相馬達波形
按照前面的無刷電機基本模型,假設我們拿到這樣一個電機,手動勻速轉動它的轉子,然後用示波器觀察它的三相輸出電壓(也就是反電動勢產生的電壓),會看到什麼波形呢?
其實很自然可以想到,我們會得到3根正弦曲線,而且三根曲線兩兩相位差為120°:
-
實際上三相發電機的發電原理就是這樣的,輸出的就是三相振幅為220V的交流電(線電壓為380V,即
V)。
發電機反過來就是電動馬達啦,所以假如反過來我們在三相無刷馬達的三相線圈上輸入上述三相正弦電壓,那麼就可以驅動無刷馬達平穩高效地旋轉了。
而這也是FOC驅動無刷馬達的基本手段,即透過計算所需電壓向量,使用SVPWM技術產生調試訊號,驅動三相逆變電路,合成出等效的三相正弦電壓驅動馬達。
這個會在後面進行詳細介紹。
2.FOC控制原理
2.1 FOC演算法的Pipeline
2.2 Clark變換與Park變換
前面分析了,如果要平穩地驅動三相馬達轉動,我們就需要產生三個相位相差120度的正弦波,但是我們最終的控制對像是MOS管的開通和關斷,只有電壓最大值和0值兩個狀態啊,怎麼去產生連續變化的正弦波呢?
對了,用前面提到的PWM技術就可以做到,所謂SPWM就是這麼幹的,如下圖:
-
大家觀察一下上圖的波形,我們用上面座標系中的正弦波和三角波的交點投影到下面的座標軸,以此確定PWM的佔空比變化規律,這樣合成的PWM波,經過低通濾波器之後,其實就等效為了一個正弦波!所以SPWM就是在PWM的基礎上用正弦波來調變合成的具有正弦波規律變化的方波。
不過SPWM調試方式在FOC實作中並不常用,原因是SPWM要比後面要說的SVPWM的母線電壓利用率低15%。
另一方面,從控制的角度來看,我們甚至根本不想跟什麼三個正弦波打交道!
因為要對於非線性的訊號進行準確控制就要使用複雜的高階控制器,這對於建模成本、處理器算力、控制即時性等都是不利的。簡單來說就是,咱們控制器的回饋輸入變數不是三個電流取樣值嘛,你要我穩穩地追蹤三個正弦波太麻煩!能不能簡單點追蹤一條直線(常數)啊?
答案是可以的~只需應用一點數學小技巧
Clark變換
我們回到上面FOC控製過程9個步驟的第1步,也就是對馬達的三個相電流進行取樣,這一步驟會使用串聯的取樣電阻(Shunt)進行電流取樣。
由於馬達工作的電流一般很大,所以採樣電阻的阻值非常小,甚至和導線的電阻接近了,因而實際的採樣電路PCB設計的時候還有一些講究,比如使用開爾文接法(Kelvin connections)。
但是我們實際電路設計時可以不使用三個取樣器(實際上有單取樣電阻、雙取樣電阻和三取樣電阻接法),只需要兩個就夠了。因為由基爾霍夫電流定律(KCL),在任一時刻,流入節點的電流總和等於流出節點的電流總和,也就是說
只需要知道其中兩個就可以計算出第三個了。
這三個電流基本上就是三個相位相差120度的正弦波,在把這些訊號輸入控制器回授控制之前,我們先來做點數學遊戲:
我們知道三相座標系
如下:
問題:這明明是一個二維平面內的座標系,為啥要用3個座標軸來表示呢?
而且很明顯
這三個基向量是非正交的,學過線性代數的同學可能會想到,我們可以做一個很簡單的基變換將其正交化為一個直角坐標系,我們把新的直角座標系命名為
座標系,變換公式如下:
其實就是個很簡單的座標軸投影計算,寫成矩陣形式如下:
於是我們就回到直角座標系啦,是不是很開心,變換前後的波形如下:
可以看到變換後其實還是正弦波…只不過我們少了一個需要控制的變數了,現在只需要控制
這兩個變量,讓其滿足上圖的下面的波形變化規律就可以控制電機旋轉了,頻率還是不變的。
注意這裡的
是我們虛擬出來的變量,所以在計算出一組
後,我們透過上述公式的反向變換公式轉換回去再應用到馬達的三相上。
就這?
當然不是,如果只是為了減少一個控制變數那這個變換/反變換操作顯然有點多此一舉。
有趣的是我們還可以接著變換:雖然
座標系下少了一維變量,但是新的變數還是非線性的(正弦),有沒有辦法把它們線性化呢?有的,Park变换就是做這個工作的。
Park變換
這一步我們接著Clark变换將
座標系旋轉 θ 度,其中 θ 是轉子目前的角度,如下圖:
-
變換公式如下:
-
也很簡單,就是作用了一個旋轉矩陣,寫成矩陣形式:
-
也就是說,這個 d-q 座標係是始終跟著轉子旋轉的!
這個操作是可行的,因為我們會透過編碼器輸入轉子的即時旋轉角度,所以這個角度總是已知數。經過這一步的變換,我們會發現,一個勻速旋轉向量在這個座標系下變成了一個定值! (顯然的嘛,因為參考系相對於該向量靜止了),這個座標系下兩個控制變數都被線性化了!
Park變換前後的波形
接下來如果我們以
這兩個值作為反饋控制的對象,那麼顯然就可以使用一些線性控制器來進行控制了,例如PID(是的,儘管學術界有很多酷炫的高級控制方法, 但是工業界還是偏愛PID)。
至此我們已經理解完上面FOC控製過程9個步驟的前3步了。
2.3 PID控制
PID(比例、積分、微分)控制是啥這篇文章就不多講解了,基礎中的基礎,也有大把文章做介紹的,不熟悉的可以自行搜尋相關資料。
在FOC控制中主要用到三個PID環,從內環到外環依序為:電流環、速度環、位置環。
也就是說:我們透過電流回饋來控制馬達電流(扭力) → 然後透過控制扭力來控制馬達的轉速→ 再透過控制馬達的轉速控制馬達位置。
其中最內環的電流換控制框圖如下:
PID電流環
可以看出來,這也就是前面提到的FOC控制9個步驟所描述的過程。實際上只用到了PI控制,沒有引入微分,因為如果推導一下電壓和電流的傳遞函數會發現這其實就是一個一階慣性環節(而且實際上我們可以透過零極點對消來簡化掉PI參數,只需要控制一個參數即電流頻寬即可)。
上圖中的Speed & Position模組可以是編碼器,或是霍爾感測器等能感應轉子位置的感測器。
特別說明一下其中的
,前兩者大家都知道是透過Clark变换和Park变换得到的,而後兩者是我們預期希望前兩者達到的值,這個值具體代表了什麼物理量呢?參考一下下圖:
-
也就是說我們一通操作將轉子磁鏈進行了解耦,分解為了轉子旋轉的徑向和切向這兩個方向的變數:
其中
是我們需要的,代表了期望的力矩輸出
而
是我們不需要的,我們希望盡可能把它控制在0
FOC的控制目標
透過PID控制器使用上述輸入(電流取樣值、編碼器位置)和輸出(MOS管開關狀態)完成對馬達電流的閉迴路控制。
然後進入到下一層的速度環:
速度-電流雙環控制
在上圖中,
是速度設定值,ω 是馬達的轉速回饋,可以透過馬達編碼器或霍爾感測器等計算得到,依然是使用PI控制。
將計算得到的馬達速度 ω 與速度設定值
進行誤差值計算,代入速度PI環,計算的結果作為電流環的輸入,就實現了速度-電流的雙閉環控制。
最外一層是位置環,也就是可以控制馬達旋轉到某個精確的角度並保持,控制框圖如下:
位置-速度-電流三環控制
同理應該很簡單可以理解,上圖位置控制PID只用了P項(也可以使用PI)。
在實際使用中,由於編碼器無法直接返回馬達轉速 ω ,因此可以透過計算一定時間內的編碼值變化量來表示馬達的轉速(也即用平均速度代表瞬時速度)。當馬達轉速比較高的時候,這樣的方式是可以的;但是在位置控制模式的時候,馬達的轉速會很慢(因為是要求轉子固定在某個位置嘛),這時候用平均測速法會存在非常大的誤差(轉子不動或動地很慢,編碼器就沒有輸出或只輸出1、2個脈衝)。
所以為了避免速度環節帶來的誤差,在做位置控制的時候可以只使用位置與電流組成的雙環來控制,不過此時需要對位置環做一定的變化,控制框圖如下:
位置-電流雙閉環控制
由於去掉了速度環,這裡的位置環我們使用完整的PID控制,即把微分項加上(因為位置的微分就是速度,這樣可以減小位置控制的震盪加快收斂;積分項的作用是為了消除靜態誤差)。
好了,至此整個控制迴路基本上捋清楚了,但還有一些細節我們沒講到,就是上面框圖中的SVPWM模块。
細心的同學可會發現,在整個控制流程圖裡面有Park变换和對應的反Park变换 ,但是卻沒有Clark变换對應的反Clark变换,取而代之的是一個SVPWM模块。
以下會對SVPWM技術進行詳細介紹。
2.4 空間電壓向量
什麼是空間電壓向量?
空間電壓向量是我們在控制馬達過程中虛擬出來的向量,既然是向量,自然是有大小和方向的,那麼它的大小和方向是什麼呢?
還是以前面三相逆變驅動電路那幅圖中的狀態為例,輸入100的狀態:
-
此時等效電路如圖:
-
因此馬達中三個相電壓(相電壓是每相對於馬達中間連接點的電壓)可以表示為:
-
其實就是個最簡單的分壓電路,其中
是母線電壓,也就是電源電壓。
如果我們規定指向中心的方向為正,反之為負,那麼此時我們可以畫出下圖中的三個電壓向量
(左邊),以及它們的合成電壓向量
(右):
-
也就是說,這個狀態下我們可以認為馬達中存在一個向量
所表徵的電壓(電流);然後根據右手螺旋定則,可以判斷出磁場的磁力線方向,也是和向量
一致的。
再結合前面章節的分析,轉子永久磁鐵會努力旋轉到內部磁力線和外部磁場方向一致,所以這個向量其實可以表徵我們希望轉子旋轉到的方向,也即所需要產生的磁場方向了。而這個向量是會不斷在空間中旋轉的,它的振幅不變,為相電壓峰值
,且以角速度
勻速旋轉。
我們後面將會看到,SVPWM演算法的目的,就是使用三相橋的開關狀態把在空間中旋轉的向量表示出來,我們把這個向量稱為空間電壓向量。
用數學公式來表示的話就是:
-
為了研究各相上下橋臂不同開關組合時逆變器輸出的空間電壓向量,我們定義開關函數
為:
-
的全部可能組合共有8個,包括
6個非零向量 :
和
兩個零向量:
可以看出零向量狀態下馬達三相間電壓都為0不產生轉矩(不考慮反電動勢)。
以下以其中一種開關組合為例分析,假設
,也即這張圖的狀態:
-
如前文分析,此時的電壓向量為AO方向,大小為
,我們把這個向量畫在座標軸中如圖:
ABC座標系和αβ座標系下的向量表示
注意上圖的(100)向量方向和AO方向是相反的(變成OA方向),這跟正方向的定義有關,這樣的規定比較直觀一些。
同時可以注意到兩個零向量其實和原點重合了,因為這兩個狀態下馬達中產生力矩的磁場為0(不考慮旋轉過程中的反電動勢所產生的阻力力矩)。
同理,上圖還可以看出其餘5個空間電壓向量,它們的端點組成了一個正六邊形,同時把平面劃分成了六個扇區(也就是圖中的Ⅰ、Ⅱ、Ⅲ、Ⅳ 、Ⅴ、Ⅵ)。
那這裡問題就來了:由這6個空間電壓向量只能產生6個方向的力矩啊,我們要怎麼產生任意方向的力矩呢?
2.5 SVPWM技術
既然是“向量控制”,當然是有辦法的,答案就是:使用這6個空間電壓向量作為基底向量來合成任意向量。在每一個磁區,選擇相鄰兩個電壓向量以及零向量,依照伏秒平衡原則來合成每個磁區內的任意電壓向量,即:
-
離散化後等效為下式:
-
式子中的
是我們預期得到的電壓向量,T是一個PWM週期。
和
分別是用於合成
的兩個空間電壓向量,也就是上面說的6個基底向量中的兩個,至於是哪兩個?這跟
所在的磁區有關,例如
在Ⅰ扇區,那麼
和
就是
和
;
和
就是在一個週期T中
和
所佔的時間。
指的是兩個零向量,可以是
也可以是
,零向量的選擇比較靈活,透過合理地配置零向量可以讓空間電壓向量的切換更平順,後面會做說明。
所以上面公式的意義就是:我們可以週期性地在不同空間電壓向量之間切換,只要合理地配置不同基底向量在一個週期中的佔空比,就可以合成出等效的任意空間電壓向量了。
是不是跟PWM的想法完全一樣呢,這也是為什麼這個方法被成為SVPWM(空間電壓向量脈寬調變)。
下面舉一個例子,假設我們要合成圖中所示的
,在Ⅰ區:
-
顯然我們可以透過
和
來合成
,那麼如圖將
投影分解到
和
的方向,由正弦定理有:
-
-
-
其中m為SVPWM的調變係數(即調變比):
顯然在電流環控制過程中m設定得越大代表了期望力矩越大。
而零向量分配的時間為:
為什麼
?這是我們將PWM波形設定為中央對齊模式對稱配置零向量的結果,後面會提到。
現在一個週期內所有狀態的持續時間我們都得到了,還差一個順序,也就是各個狀態切換的順序。
問題:不是任意順序都可以嘛?反正是做積分,重要的是持續時間而不是順序,一個週期內怎麼切換都行啊。
是的,理論上任何切換順序都是ok的,但是實際上我們需要考慮更多限制,例如因為MOS管存在開關損耗,我們希望能盡量減少MOS管的開關次數,那麼以最大限度減少開關損耗為目的,我們就可以設計出下面的切換順序:
-
上圖可以看出來,在每個狀態切換的時候,都只有一個相發生了轉變:000 → 100 → 110 → 111 → 110 → 100 → 000,這也是所謂的七段式SVPWM調製法。
同時我們透過在合理的位置插入兩個零向量,並且對零向量在時間上進行了平均分配,以使產生的PWM對稱,從而有效地降低了PWM的諧波分量。
同理,我們也可以列出在其他磁區時的切換順序:
-
至此,SVPWM的工作完成了,我們得到了每一時刻所需的空間電壓向量以及它們持續的時間,在處理器中賦值給對應通道的捕獲比較寄存器產生相應的三個PWM波形,控制MOS管的開關,進而產生我們期望的電壓、電流、力矩。
總結
至此FOC的原理和整個控制連結都講完了,回想一下整個過程,再試著解答最開始提到的問題:為什麼在FOC控制中要做這麼多變換和反變換?
因為所謂的「向量控制」其實就是在做解耦,把互相耦合的三相磁鏈解耦成容易控制的交軸
和直軸
。整個過程就好比我們在做訊號處理的時候,透過FFT把訊號變換到頻域進行處理之後再IFFT反變換回時域是一個道理。
另外值得一提的是,本文介紹的是有感的FOC控制方法,其實FOC可以做到無感控制(也就是不需要編碼器等額外的感測器),當然控制演算法也會更複雜,需要引進前饋控制、觀測器等概念,無感的好處就是結構安裝更簡單,可以避免位置感測器失效的風險等等,當然這又是另一個話題了。
FOC是個強大的控制方法,透過對馬達的“像素級”控制,可以實現很多應用,因為可以做“力控”,FOC是許多機器人驅動單元的基礎部件,例如:
MIT Mini Cheetah四腳機器人
又例如,因為可以做到力矩的精確控制,我們可以用FOC驅動器配合無刷馬達來實現各種力回饋裝置,這就好像iPhone的Haptic Engine一樣,可以模擬出各種以假亂真的物理效果:
羅技的力回饋方向盤
最後順便提一下,我最近也在設計一個FOC向量驅動器,熟悉我的同學應該知道我做東西的風格就是–唯小不破,因此這次也是準備設計一個超迷你的高性能FOC驅動器。硬體已經基本完成了,電路設計如下圖,分為上下疊板設計,將邏輯單元和功率單元分開:
邏輯控制板
功率輸出板
最後組裝起來是這樣的:
同時我也為驅動器設計了一個外殼(畢竟顏值就是正義啊~):
參考
-
-
-
-
-
《現代馬達控制技術》-王成元
《小型交流伺服馬達控制電路設計》-石島勝
TMC4671-Datasheet
Permalink blog/2024-04-18_share_深入淺出講解foc演算法與svpwm技術.txt · Last modified: 2024/04/18 14:58 by
jethro