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.

image

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



image

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.

Written on October 1, 2024