PB -6- Arduino Bluetooth Servo kontrolü
Bilgisayarın bluetooth özelliğini kullanarak, Arduino’ya bağlı servo motoru döndürüyoruz. Arduino’ya program yükledikten sonra, kablonun diğer ucunu bilgisayardan çıkarıp, bir telefon şarj adaptörüne bağlayabilirsin.
Arduino’ya bilgi yollamak için HC-05 bluetooth modülünü kullanıyoruz. Önceki yazıda bu modülden biraz bahsetmiştim. Bilgisayar, HC-05 modülünü, seri port (COM port) olarak görüyor. Yani HC-05, bluetooth-seri port çevirici olarak çalışıyor.
Bu kez Arduino’nun RX’ini, HC-05 modülünün TX’ine bağlıyoruz. Bilgi akışı tek yönlü olacağından tek tel bağlamak yeterlidir. Bu projede HC-05 modülünün RX pini kullanılmadığından dirençlerle voltaj bölmeye gerek kalmadı. Burada yapacağımız iş için bilgisayar yerine cep telefonu veya Android tablet de kullanabilirsin. Google Play’den gerekli bluetooth programını indirmen yeterli olacaktır. Motorun istenen açıya dönmesi için bilgi akışı bu şekildedir :
PureBasic (Bilgisayar) ➡️ Bluetooth (Hava) ➡️ HC-05 ➡️ Kablo ➡️ Arduino ➡️ Servo motor
Aşağıdaki kodu Arduino’ya yüklüyoruz.. Öncesinde, RX’e takılı olan kabloyu çıkaralım.
#include <Servo.h>
Servo myservo;
int pos = 0; // servo position 0-180
void setup() {
myservo.attach(9);
Serial.begin(19200);
}
void loop() {
if(Serial.available()){
pos = Serial.parseInt();
myservo.write(pos);
}
delay(20);
}
Bu kodu Arduino’ya yükledikten sonra, HC-05 modülünden gelen kabloyu Arduino’da RX pinine takabiliriz. Yine PB-5 DHT11 yazısındaki comPort.pb kodunu boş bir dizine kopyalayalım. Aşağıdaki kodu da, servo.pb olarak aynı dizine kaydet.
XIncludeFile "comPort.pb"
Global ComData.udtComData
Enumeration EventCustomValue #PB_Event_FirstCustomValue
#My_Event_NewData
#My_Event_NewState
EndEnumeration
; ---------------------------------------------------------------------------
Procedure ReceiveCB(Text.s)
PostEvent(#My_Event_NewData, 0, 0, 0, AllocateString(Text))
EndProcedure
Procedure MyEventNewDataCB()
Protected Text.s
Text = FreeString(EventData())
AddGadgetItem(0, -1, Text)
SetGadgetState(0, CountGadgetItems(0) - 1)
SetGadgetState(0, -1)
EndProcedure
BindEvent(#My_Event_NewData, @MyEventNewDataCB())
; ---------------------------------------------------------------------------
Procedure StatusCB(Status, *ComData.udtComData)
PostEvent(#My_Event_NewState, 0, 0, Status, *ComData)
EndProcedure
Procedure MyEventNewStateCB()
Protected Text.s, Status, *ComData.udtComData
Status = EventType()
*ComData = EventData()
Select Status
Case #ComStatus_OpenPort
Text = "ComStatus: Open Port " + *ComData\Port
Case #ComStatus_ClosePort
Text = "ComStatus: Close Port " + *ComData\Port
Case #ComStatus_ErrorOpenPort
Text = "ComError: Open Port " + *ComData\Port
Case #ComStatus_ErrorSend
Text = "ComError Send: Port " + *ComData\Port + " - " + SerialPortErrorText(*ComData\SendError)
Case #ComStatus_ErrorReceive
Text = "ComError Receive: Port " + *ComData\Port + " - " + SerialPortErrorText(*ComData\ReceiveError)
Case #ComStatus_ErrorDataSize
Text = "ComError Send: Port " + *ComData\Port + " - Send data size to big."
EndSelect
If Bool(Text)
StatusBarText(0, 0, Text)
EndIf
EndProcedure
BindEvent(#My_Event_NewState, @MyEventNewStateCB())
; ---------------------------------------------------------------------------
Procedure InitComport()
With ComData
If \Status
ProcedureReturn 2 ; Always running
EndIf
\Port = "COM7"
\Baud = 115200
\Parity = #PB_SerialPort_NoParity
\DataBit = 8
\StopBit = 1
\Handshake = #PB_SerialPort_NoHandshake
\BufferSize = 2048
\EndOfText = ""
\StatusCB = @StatusCB()
\ReceiveCB = @ReceiveCB()
\ThreadID = CreateThread(@thComport(), ComData)
If Not \ThreadID
ProcedureReturn 0 ; Error create thread
Else
ProcedureReturn 1 ; ok
EndIf
EndWith
EndProcedure
Procedure SendToHC05(Angle)
If ComData\Status = #ComThread_Running And ComData\SendSignal = #False
ComData\SendText = Str(Angle)
ComData\SendSignal = #True
EndIf
EndProcedure
Define Event, Text.s, i
OpenWindow(0, #PB_Ignore, #PB_Ignore, 200, 200, "Servo test",
#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CreateStatusBar(0, WindowID(0))
AddStatusBarField(#PB_Ignore)
ButtonGadget(0, 55, 20, 90, 25, "0°")
ButtonGadget(1, 55, 50, 90, 25, "90°")
ButtonGadget(2, 55, 80, 90, 25, "180°")
ButtonGadget(3, 55, 130, 90, 25, "On/Off")
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_CloseWindow
If ComData\Status
MessageRequester("Info", "Comport Is Open!", #PB_MessageRequester_Warning)
Else
Break
EndIf
Case #PB_Event_Gadget
Select EventGadget()
Case 0
SendToHC05(0)
Case 1
SendToHC05(90)
Case 2
SendToHC05(180)
Case 3 ; on/off button
If ComData\Status
ComData\Exit = 1
Else
If Not InitComport()
StatusBarText(0, 0, "Comport " + ComData\Port + ": Error Create Thread")
EndIf
EndIf
EndSelect
EndSelect
ForEver
Program çalışınca farkettim ki motor istenen açıya gidiyor hemen ardından 0 dereceye geri dönüyor. Bu sorunun satır sonu karakterlerinden kaynaklandığını gördüm. InitComport() prosedüründe \EndOfText = “” değişkenini bu şekilde düzeltince sorun çözüldü. Motor döndüğü açıda kalıyor artık 🏍️ Bu arada HC-05 modülüne bluetooth (com port) üzerinden istenen baud ile bağlanılabiliyor. HC-05, baud’u otomatik olarak algılıyor. SG90 isminde bir servo aldım, ağırlığı 9 gr. fakat malesef 180 yerine 170 derece civarında dönüyor. Daha büyük servo alırsan, direk Arduino’dan beslemek sıkıntılı olabilir. Motoru, dışarıdan 5V telefon şarj adaptörü ile besleyebilirsin. Bu durumda motorun GND sinyalini Arduino ile birleştirmen gerekecektir.