RoboMed
Doktorun bilgisayardan yazdığı reçeteyi, hastaya fiziksel olarak teslim eden dört katmanlı bir sistem. A four-layer system that takes a prescription typed on a doctor's computer and puts the actual medication in the patient's hand.
Tek bakıştaAt a glance
Doktor reçeteyi bilgisayardan yazıyor. Hasta telefonuna gelen kodu bir makineye giriyor. Makine ilacı veriyor. Arada eczane yok. The doctor writes the prescription on a computer. The patient types a code from their phone into a machine. The machine hands over the medicine. No pharmacy in between.
RoboMed bunu yapan bir sistem. Yazılımını da makinesini de biz yaptık — iki kişi, beş ayda. Gövdeyi marangozhanede ham MDF'den kestirdik, elektroniğini kurduk, hastane yazılımını yazdık ve hepsini birbirine bağladık. RoboMed is the system that does that. We built both the software and the machine — two people, five months. We had the cabinet cut from raw MDF at a joinery, wired the electronics, wrote the hospital software, and connected it all together.
Reçete yazılırThe prescription is written
Doktor masaüstü uygulamadan ilaçları seçer. Reçeteye benzersiz bir kod verilir. The doctor picks the drugs in a desktop app. The prescription gets a unique code.
Hastaya haber giderThe patient is notified
Reçete kodu ve teslim talimatı e-posta ve SMS ile hastaya ulaşır. The code and collection instructions reach the patient by email and SMS.
İlaç teslim edilirThe medicine is dispensed
Hasta kimliğini ve kodunu girer; doğrulama geçince ilgili gözün motoru döner, kutu düşer. The patient enters their ID and code; once verified, the right slot's motor turns and the box drops.
Reçete dijital, ilaç değilThe prescription is digital, the medicine isn't
Bir yerde yazılım bitiyor ve insanın yürümesi gereken bir mesafe başlıyor. Projeyi o mesafeyi kapatmak için yaptık. At some point the software ends and a distance you have to walk yourself begins. We built this to close that distance.
Yazılım bitiyor, iş bitmiyorThe software finishes, the errand doesn't
Reçete artık bilgisayardan yazılıyor ve anında sisteme düşüyor. Ama ilacı almak için hâlâ eczaneye gidip sıra beklemek gerekiyor. Mesai bitince o seçenek de kapanıyor; geriye nöbetçi eczaneyi bulmak kalıyor. Prescriptions are typed into a computer and land in the system instantly. Getting the medicine, though, still means going to a pharmacy and standing in line — and once the working day ends, that option closes too. What's left is hunting down the one that's open at night.
Yazılımı bir makineye bağladıkWe wired the software to a machine
Üç rollü bir masaüstü uygulama — hasta, doktor, yönetici —, bir REST API, ortak bir SQL Server veritabanı ve fiziksel bir otomat. Otomat 16 gözlü; her göz kendi motoruyla, röle üzerinden çalışıyor. A desktop application with three roles — patient, doctor, administrator — a REST API, one shared SQL Server database, and a physical dispenser. The machine has 16 compartments, each driven by its own motor through a relay.
Dört parça, tek doğruFour pieces, one source of truth
Masaüstü uygulama ve sunucu aynı veritabanını paylaşıyor. Otomat ne bilmesi gerekiyorsa sunucudan istiyor. The desktop app and the server share one database. Whatever the machine needs to know, it asks the server for.
Bu ayrımı baştan yapmamız işimize yaradı: otomatın bildiği tek adres sunucuydu. Veritabanı şeması değiştiğinde makine tarafında hiçbir şeye dokunmadık. Drawing that line early paid off: the only address the machine knew was the server. When the database schema changed, we didn't have to touch the hardware side at all.
Makinenin içinde ne varWhat's inside the machine
Hazır bir otomat kartı ya da sürücü modülü kullanmadık. Her parça ayrı seçildi, 34 dijital pin elle dağıtıldı ve hepsi tek bir Arduino Mega üzerinde toplandı. We didn't use an off-the-shelf vending controller or driver module. Every part was picked separately, 34 digital pins were assigned by hand, and it all came together on a single Arduino Mega.
Arduino Mega 2560Arduino Mega 2560479 satırlines
ATmega2560 · 34 dijital pin kullanıldıdigital pins used
Sistemin beyni. Tuş takımı, ekran, röleler ve ses modülü doğrudan buna bağlı. Üzerinde 12 durumlu bir durum makinesi çalışıyor — her adımın kendi zaman aşımı ve kendi çıkış yolu var. The brain. Keypad, display, relays and the audio module all hang off it. It runs a 12-state machine where every step has its own timeout and its own way out.
ESP WiFi modülüESP WiFi module
UART 9600 baud · HTTP
Mega'nın internete açılan kapısı. Sunucuya HTTP isteğini bu atıyor, cevabı seri hat üzerinden Mega'ya satır satır aktarıyor. Projenin en çok uğraştıran parçası da tam olarak bu hat oldu. The Mega's door to the internet. It makes the HTTP request and passes the answer back over the serial line, line by line. This link is exactly what gave us the most trouble.
Röle kartıRelay board16 kanalch
aktif-düşük · pin 22–37active-low · pins 22–37
Her hazne kendi rölesine bağlı. Aktif-düşük çalıştığı için açılışta pinler boşta kalırsa röleler kendiliğinden çekebiliyor — bunu sonradan öğrendik. Every slot has its own relay. Because they're active-low, a floating pin at boot can pull them in on its own — something we learned the hard way.
Redüktörlü DC motorGeared DC motors16
helezon yay · 1500 ms çalışmacoil spring · 1500 ms run
Her motor bir helezon yayı çeviriyor, yay dönünce kutu öne itiliyor ve düşüyor. Sensör yok; süre sabit. Kutunun düştüğünü sistem görmüyor, sadece motoru belirli süre çalıştırıyor. Each motor turns a coil spring; as it turns, the box is pushed forward and drops. There's no sensor — the run time is fixed. The system never sees the box fall, it just runs the motor for a set duration.
Karakter ekranCharacter display20×4
4-bit paralel · pin 2–7 · I2C değil4-bit parallel · pins 2–7 · not I2C
Tüm arayüz bu dört satıra sığıyor: kimlik girişi, doğrulama, reçete listesi, ilaç adları ve teslim mesajı. Kısıt tasarımı da belirledi — her ekran en fazla 20 karakter. The entire interface fits in these four lines: ID entry, verification, prescription list, drug names and the handover message. The constraint shaped the design — 20 characters per line, no more.
Matris tuş takımıMatrix keypad4×4
satır 43–46 · sütun 47–50rows 43–46 · cols 47–50
Makinenin tek giriş aygıtı. Rakamlar veri, * silme, # onay. Dokunmatik ekran yok — bilerek: mekanik tuş hem daha ucuz hem eldivenle çalışıyor.
The machine's only input device. Digits for data, * to clear, # to confirm. No touchscreen — deliberately: mechanical keys are cheaper and work with gloves on.
Ses modülüAudio module10 kayıtclips
DFPlayer Mini + SD · ses 28/30volume 28/30
Her adımda sesli yönlendirme veriyor. Ekranı okuyamayan biri için önemliydi. Bu modülün seri hattı, ilerideki veri kaybı probleminin sebeplerinden biri olacaktı. It speaks a prompt at every step — important for anyone who can't read the screen. This module's serial line would later turn out to be one cause of the data-loss problem.
Güç kaynağı ve gövdePower supply and cabinet
ham MDF · 4 sıra bölmeraw MDF · 4 rows of bays
Motorlar, röleler ve kartlar aynı kaynaktan besleniyor. Ortak toprak hattını ve toplam akımı doğru hesaplamadığımız için birkaç kart yaktık — projenin en pahalı dersi buydu. Motors, relays and boards all share one supply. We didn't work out the common ground and the total current properly, and burned a few boards for it — the most expensive lesson of the project.
Zaman aşımı katmanları. Bir otomat kilitlenirse ilacı içeride kalır. Bu yüzden üç ayrı süre sayacı kurduk: sunucudan cevap için 15 saniye (liste çekerken 30), tuş takımında hareketsizlik için 45 saniye, tüm oturum için 90 saniye. Hangisi dolarsa dolsun sonuç aynı: bütün röleler kapanır, ekran başa döner. Layered timeouts. If a vending machine locks up, the medication stays inside. So we ran three separate timers: 15 seconds for a server reply (30 while fetching a list), 45 seconds of keypad inactivity, and 90 seconds for the whole session. Whichever expires, the outcome is the same — every relay opens and the screen returns to the start.
Reçeteden ilaca giden yolThe road from prescription to pill
Doktorun kaydı bitirdiği andan, kutunun hastanın eline düştüğü ana kadar altı adım. Six steps, from the moment the doctor hits save to the moment the box drops into the patient's hand.
Doktor reçeteyi yazarThe doctor writes the prescription
İlaç listesi, hastanın geldiği polikliniğe göre filtrelenmiş olarak açılıyor. Doktor dozu ve kullanım süresini giriyor; kayıt tamamlandığında reçeteye benzersiz bir kod veriliyor. The drug list opens already filtered by the clinic the patient came to. The doctor sets the dose and how long it runs, and once it's saved the prescription gets its own unique code.
Hasta bilgilendirilirThe patient is notified
Reçete oluşur oluşmaz hastaya hem e-posta hem SMS gidiyor. Reçete 30 gün geçerli; hasta bu süre içinde istediği zaman gelebiliyor. The moment it's created, an email and an SMS go out. The prescription stays valid for 30 days, so the patient can come whenever it suits them.
Otomatta kimlik doğrulamaIdentity check at the machine
Hasta tuş takımından kimliğini giriyor, telefonuna tek kullanımlık bir kod geliyor. Kod doğrulanmadan ekranda hiçbir reçete bilgisi görünmüyor. The patient enters their ID on the keypad and a one-time code arrives on their phone. Until that code checks out, nothing about the prescription shows up on screen.
Reçete seçimiPicking a prescription
Hastanın aktif reçeteleri karakter ekranda sırayla listeleniyor; hangisini alacağını tuş takımından seçiyor. Whatever prescriptions are still active get listed one by one on the character display, and the patient chooses from the keypad.
Makine ilacı düşürürThe machine dispenses
Sunucu seçilen reçetenin ilaç listesini gönderiyor, her ilaç kendi röle kanalına eşleniyor. İlgili gözün tekerleği dönüyor ve kutu aşağı düşüyor. The server sends back the drug list for that prescription, and each drug maps to its own relay channel. The wheel in that compartment turns and the box drops.
Reçete arşivlenirThe prescription is archived
Teslim kaydı bir veritabanı işlemi içinde yazılıyor. İşlem yarım kalırsa hiçbir şey değişmiyor — reçete aktif kalıyor, hasta tekrar deneyebiliyor. The hand-over is written inside a database transaction. If it stops halfway, nothing changes at all — the prescription stays active and the patient can try again.
Otomata giden reçete burada yazılıyorThe prescription the machine reads is written here
Masaüstü uygulama üç rol taşıyor: hasta, doktor ve yönetici. Arayüzün tamamı C# WinForms ile yazıldı; hazır bir tema kullanılmadı. The desktop app carries three roles: patient, doctor and admin. The whole interface was written in C# WinForms, with no off-the-shelf theme.
Ekran görüntülerindeki hasta ve doktor kayıtları test verisidir. Gerçek kişisel veri içeren ekranlar bu galeriye alınmadı. The patient and doctor records in these screenshots are test data. Screens containing real personal data were kept out of this gallery.
Hasta bunu nereden biliyor?How does the patient even know?
Sistemin en kolay atlanan parçası bu. Doktor reçeteyi yazdığı anda hastanın haberi olmalı — yoksa otomatın önüne kimse gelmez. İki kanal kurduk: e-posta ve SMS. Aynı bilgi, iki yoldan. This is the part that's easiest to forget. The moment the doctor writes a prescription, the patient has to know — otherwise nobody ever walks up to the machine. We built two channels: email and SMS. Same information, two routes.
Buradaki yazım hataları gerçek. Mesaj metninde “Otamatik”, “otamatına” ve “iilaçlarınızı” yazıyor. Metni koda gömdüğümüz ve tek bir yerden okumadığımız için kimse fark etmedi. Bugün olsa şablonları koddan çıkarır, ayrı bir dosyada tutardım — hem düzeltmesi kolay olurdu hem de iki kanalda aynı metni tekrar yazmam gerekmezdi. Those typos are real. The message text says “Otamatik”, “otamatına” and “iilaçlarınızı”. Because the copy was baked into the code and never read from one place, nobody caught it. Today I'd pull the templates out into their own file — easier to fix, and I wouldn't have to write the same text twice for two channels.
Arduino ile sunucuyu konuşturmakGetting the Arduino and the server to talk
Sistem çoğu zaman çalışıyordu. Ama arada bir, otomat sunucudan gelen reçete listesini eksik alıyordu — bazen tek bir ilaç geliyordu, bazen hiçbiri. O dönem sebebini uzun süre bulamadık; tekrar denediğimizde genelde düzeldiği için üstünü örtmüş olduk.
Most of the time it worked. Every so often, though, the machine received only part of the prescription list — sometimes a single drug, sometimes none at all. We couldn't work out why for a long time, and since retrying usually fixed it, we let it slide.
Aylar sonra koda geri dönüp okuyunca üç ayrı sebebin aynı anda çalıştığını gördüm:
Months later I went back and actually read the code, and saw three separate causes firing at once:
(1) Ses modülü için kullandığımız yazılımsal seri port, gönderdiği her bayt boyunca kesmeleri kapatıyordu — ve tam da veri akarken çalıyordu. The software serial port driving the sound module disabled interrupts for the length of every byte it sent — and it happened to play right while data was streaming in.
(2) Ekranda mesaj gösterirken beklettiğimiz süre boyunca gelen veriler 64 baytlık tampona sığmıyordu. Fazlası sessizce kayboluyordu. While we paused to show a message on the display, everything still arriving had to fit into a 64-byte buffer. Whatever didn't fit was dropped without a word.
(3) Sunucudaki okuma isteği aynı zamanda kaydı siliyordu. Yani veri bir kez eksik geldiğinde tekrar denemek işe yaramıyordu; geri kalanı artık hiçbir yerde yoktu. The read request on the server also deleted the record. So once a batch came in short, retrying was pointless — the rest of it no longer existed anywhere.
Bugün olsa ne yapardımWhat I'd do today
Ses modülünü kartın gerçek donanım portuna alırdım; yazılımsal seri portun kesmeleri kapatma alışkanlığından tamamen kurtulurdum. I'd move the sound module onto one of the board's real hardware ports and be rid of a software port that shuts off interrupts whenever it likes.
Veri akarken ekranda hiçbir bekleme yapmazdım. Gösterilecek bir mesaj varsa aktarım bittikten sonra gösterilir. I wouldn't hold the screen for anything while data is coming in. If there's a message to show, it can wait until the transfer is over.
Sunucu tarafında okuma ile silmeyi ayırırdım: önce rezerve et, ilaç fiziksel olarak düştükten sonra onayla. And on the server I'd separate reading from deleting: reserve first, confirm only once the medication has physically dropped.
Bu hatayı bulmak, bana projeyi yapmaktan daha çok şey öğretti. Çalışan bir sistemin neden çalıştığını bilmiyorsan, o sistem aslında çalışmıyordur — sadece henüz bozulmamıştır. Tracking that bug down taught me more than building the thing did. If you can't say why a working system works, it isn't working — it just hasn't broken yet.
Bugün farklı yapacaklarımWhat I'd change today
Proje teslim edildi ve çalıştı. Yine de baştan başlasam bu üç kararı ilk günden farklı verirdim. The project shipped and it worked. Even so, if I started over, these are three calls I'd make differently from day one.
Kimlik numarası ilk faktör olmamalıAn ID number shouldn't be the first factor
Kimlik numarası gizli bir bilgi değil. Halka açık bir ekranın önünde tuş takımına girilmesi başlı başına risk. Kart ya da QR tabanlı bir kimlik doğrulaması daha doğru olurdu. An ID number isn't a secret. Typing one into a keypad in front of a public screen is a risk in its own right; a card- or QR-based identity step would have been the sounder choice.
Şifreler saklanmamalı, özetlenmeliPasswords should be hashed, not stored
Şifreler veritabanında düz metin olarak duruyordu. Şemaya bir özet alanı bile eklemişiz ama hiç kullanmamışız — aklımıza gelmiş, sırası gelmemiş. Passwords sat in the database as plain text. We had even added a hash column to the schema and then never used it — the thought was there, the follow-through wasn't.
Önce hesap, sonra lehimDo the math before the soldering
Güç tüketimini ve ortak toprak hattını yeterince hesaplamadık, birkaç kart yaktık. Artık kâğıt kalemle akım hesabı yapmadan hiçbir şeye enerji vermiyorum. We never worked out the power draw and the common ground carefully enough, and burned a few boards for it. Nothing gets powered up now before I've done the current math on paper.
Gövde marangozhanede çıktıThe cabinet came out of a joinery
Otomat hazır alınmadı. Ham MDF'den kesildi, dört sıra hâlinde otuz iki bölmeye ayrıldı, sonra boyandı. Bu bölmelerin on altısına motor ve helezon yay takıldı; ilaç veren gözler bunlar. Elektronik de aynı gövdenin içine yerleşti. The machine wasn't bought off the shelf. It was cut from raw MDF, divided into thirty-two bays across four rows, then painted. Sixteen of those bays got a motor and a coil spring — those are the ones that dispense. The electronics went inside the same cabinet.
Üç haftada breadboard'dan makineyeFrom breadboard to machine in three weeks
Mayıs ayının tamamı montaj ve testle geçti. All of May went on assembly and testing.
Sistem önce masa üstünde kuruldu. Arduino, röle, tuş takımı ve ekran ilk kez birlikte çalıştı. The system went up on a desk first — Arduino, relays, keypad and display working together for the first time.
Yazılım devreye girdi. Ekran artık reçete akışını yönetiyor ve tuş takımından onay istiyor. The software came online. The screen now drove the prescription flow and asked for confirmation on the keypad.
Elektronik çalışırken marangozhanede gövde çıktı: ham MDF, dört sıra bölme, ön panelde ekran yuvası. With the electronics running, the cabinet came out of the workshop: raw MDF, four rows of bays, a cut-out for the screen.
Bitmiş otomat akışı uçtan uca tamamladı: kod doğrulandı, reçete çekildi, ilaç düştü. The finished machine completed the flow end to end: code verified, prescription fetched, item dispensed.
Makinenin kendisiThe machine itself
Görseller projenin kendi arşivinden. Ekran görüntülerinde kişisel veri bulunmuyor. The images come from the project's own archive. No personal data appears in the screenshots.
Detayını merak ettiniz mi?Curious about the details?
Hangi kararı neden verdiğimizi anlatabilirim. I can walk you through why we decided what we decided.
hello@omerfarukbagci.com