Linux Termios ile Arduino İletişim
Arduino ile haberleşmenin en basit ve kullanışlı yolu seri haberleşmedir. Bu haberleşme üzerinden belirli protokoller kullanılarak Arduino yönetilebilir. Ayrıca Linux/Unix tabanlı sistemlerde çalışan kod herhangi bir Linux dağıtımı kurulmuş Raspberry PI üzerinde de derlenip çalıştırılabilir. Böylelikle Raspberry internete bağlandığında uzaktan Arduino kartı kolaylıkla kontrol edilir.
Termios
Termios POSIX yapısı ile tty(TeleTYpewriter) giriş çıkışı sağlayan genel bir Linux kütüphanesidir. Termios sayesinde herhangi bir terminal (bunlara USB portları da dahil) senkron veya asenkron kontrol edilebilir. Termios yapısında gerekli olması gereken bazı özellikler aşağıda gösterilmektedir.
Çalışma Yapısı
Arduino ile seri haberleşme yapan programımız Linux üzerinde açılışta bir PIPE/FIFO dosyası oluşturuyor. Bu dosya üzerinden aldığı komutları termios kütüphanesi yardımıyla seri haberleşme kullanarak (USB) Arduino kartına iletiyor. Program başlatma parametresi olarak Arduino’nun bağlandığı USB portunu alıyor. (Örn. /dev/ttyUSB0) Eğer PIPE dosyasından “close” komutu gelirse kendini kapatıyor. Ayrıca program Arduino’dan gelen mesajları konsola yazdırıyor.
Arduino Tarafının Hazırlanması
Eğer Arduino kartınızda seri haberleşmeyi kullanan hazır bir program varsa bu kısmı atlayabilirsiniz. Arduino üzerinden bilgisayar ile seri haberleşmek için Arduino tarafından seri haberleşmenin açılması gerekir. Ayrıca dikkat edilmesi gereken önemli bir konu seri haberleşmenin istenildiği gibi gerçekleşebilmesi için iki tarafında aynı protokolü ve aynı hızı (baud rate) kullanmasıdır. Arduino tarafının setup ve loop fonksiyonları ile açıklamaları aşağıda gösterildiği gibidir.
Arduino üzerindeki program 8. ve 9. pinleri çıkış olarak ayarlar. Herhangi bir komut geldiğinde 9.pine çıkış verir. Arduino ile kurulan devrede 9.çıkışa bir led bağlanırsa komut geldiğinde bu led yanma ve sönme işlemi yaparak komutu aldığını bildirir. process_command ile Arduino aldığı komutu işler ve clear_buffer ile komutun kaydedildiği değişkeni temizler. Bu fonksiyonların ve global değişkenlerin tanımlamaları ise aşağıdaki gibidir.
process_command fonksiyonu incelendiğinde Arduino kartına ledon komutu geldiğinde led yakılma işlemi ve ledoff komutu geldiğinde led söndürme işlemi yapıldığı görülmektedir.
ArduinoSerialControl’un Kodlanması
Arduino ile seri haberleşme yapan ArduinoSerialControl programı modern C++ özelliklerini(C++17) ve multithreading yapısını kullanmaktadır. ArduinoSerialControl programında AscSerial ve AscPipe olmak üzere iki fonksiyon bulunmaktadır. AscSerial sınıfı Termios yapısını oluşturur, Arduino ile seri haberleşmeyi başlatır ve yürütür. AscPipe ise PIPE dosyasından gelen komutları AscSerial sınıfına iletir. Ana fonksiyonda ise program iç parçaçıklarını (thread) oluşturur ve kapanmak için “close” komutunu bekler.
AscSerial Sınıfının Kodlanması
AscSerial sınıfının header dosyası ve açıklaması aşağıdaki gibi olmalıdır.
Seri haberleşmeyi sağlayan AscSerial sınıfının fonksiyonları ise aşağıdaki gibidir.
initialize_communication fonksiyonun dikkat edilmesi gereken noktalarından ilki termios yapısının sıfırlanması ve ayarlarının yapıldığı kısımdır. Burada giriş ve çıkış protokolü sıfırlanır ancak kontrol bayraklarına birkaç protokol eklenmiştir. Bu bayraklardan CS8 bir karakterin 8 bit uzunluğunda olduğunu belirtir. CREAD ise alıcıyı(RX) aktif etmektedir böylelikle seri porttan okuma yapabiliriz. Son olan CLOCAL ise seri portun herhangi bir modem olmadığını belirtir ve modem kontrol bağlantılarını dikkate almaz.
initialize_communication fonksiyonunda dikkat edilmesi gereken ikinci nokta ise cfsetospeed ve cfsetispeed fonksiyonlarıdır. Bu fonksiyonlar ile seri haberleşmenin hız değeri yani baud rate belirlenmektedir. Baud rate tam olarak olmamakla birlikte saniyede aktarılan bit sayısını belirtmektedir. Örneğin seri haberleşmenin 115200 baud rate olması saniyede maksimum 115200 bit yani 14400 karakter aktarabildiği anlamına gelir.
51. satırda ise tcsetattr fonksiyonuyla seri cihazın haberleşme özelliklerini oluşturduğumuz termios yapısı ile değiştiriyoruz.
AscSerialIO sınıfının sürekli olarak seri terminalden(Arduino’dan) veri okuyan iş parçacığı start_serial_reading ve Arduino kartına komut gönderen send_to_serial fonksiyonu aşağıdaki gibidir.
AscPipeIO Sınıfının Kodlanması
AscPipeIO sınıfı PIPE dosyasında okunan komutları AscSerialIO sınıfına göndermektedir. PIPE dosyasından komut geldiğinde AscSerialIO->send_to_serial fonksiyonu çağrılmaktadır. Sınıfın header dosyası aşağıdaki gibidir.
initialize_pipe fonksiyonu ile PIPE dosyası oluşturulmaktadır. Eğer bu dosya, dosya sisteminde var ise silinip tekrardan oluşturulur. start_pipe_reading fonksiyonu ise sürekli olarak PIPE dosyasından veri alıp bunları AscSerialIO sınıfına göndermektedir. Bu fonksiyonlar ise aşağıdaki gibi tanımlanmaktadır.
initialize_pipe fonksiyonunda Pipe dosyası mkfifo Linux komutu ile oluşturulmaktadır. Bu fonksiyon ilk argüman olarak Pipe dosyasının ismini ikinci argüman olarak ise izin değerini almaktadır. start_pipe_reading fonksiyonunda ise Pipe dosyası open fonksiyonu ile açılır ve sürekli olarak read fonksiyonu ile bu dosyadan okuma işlemi yapılır. Eğer gelen veri kapatma komutu değil ise send_to_serial fonksiyonu ile Arduino kartına gönderilir.
ArduinoSerialControl programının ise başlangıç noktası ve bütün threadlerin oluşturulduğu main fonksiyonu aşağıdaki gibi olmaktadır.
main fonksiyonunda AscSerialIO ve AscPipeIO sınıfları oluşturulur. Programın 39. ve 40. satırlarında gerekli olan iş parçacıkları başlatılır. Böylelikle program Arduino’dan gelen mesajları yazdırabilir ve Pipe dosyası üzerinden Arduino kartına komut gönderebilir.
ArduinoSerialControl’un Derlenmesi ve CMakeLists
ArduinoSerialControl’un Linux üzerinde derlenmesi için threading kullanımdan dolayı pthread kütüphanesinin bağlayıcıya bildirilmesi gerekir. Örneğin:
g++ -o main main.cc -lpthread
CMake derleme sistemi ile programın derlenmesi için CMakeLists.txt dosyası aşağıdaki gibidir.
Programın derleme işlemi için build adında yeni bir klasör açılır. Bu klasör içinde cmake çalıştırılır ve ardından make ile build edilir:
mkdir -p build && cd build && cmake ../ && make
ArduinoSerialControl’un çalıştırılması
./ArduinoSerialControl <port>
Bu kısımda port yazan yere Arduino’nun bağlı olduğu tty ismi gelmelidir. Örneğin (/dev/ttyUSB0)
PIPE dosyası üzerinden komut verme
ArduinoSerialControl açıkken PIPE dosyasından komut vermek için oluşturduğu pipe dosyasına(değiştirmediyseniz /tmp/arduinocommand) yazma işlemi yapılması gerekir. Linux üzerindeki echo komutu ile bu kolaylıkla yapılabilir. Ancak dikkat edilmesi gereken önemli bir nokta vardır echo komutu otomatik olarak yazının sonuna newline(\n) karakterini eklemektedir. Bunun olmaması için echo komutunu -n parametresi ile çalıştırmamız gerekir. (Aksi halde “close” komutu çalışmaz.)
echo -n “Hello World” > /tmp/arduinocommand
Kapatmak için ise
echo -n “close” > /tmp/arduinocommand
ArduinoSerialControl Kaynak Kodları
Yazıda bahsedilen sistemin hazır haline GIT üzerinden erişmek için buraya tıklayabilir veya projeyi klonlayabilirsiniz.
git clone https://github.com/Spelchure/ArduinoSerialControl.git