โปรเจกต์ การพัฒนา IR Remote และ Software Controller
ในบทความนี้เราพัฒนา IR Remote ทดแทนสำหรับ Speakers และ Projectors ซึ่งตัว IR Remote ถูกควบคุมโดย .NET application
ในบทความนี้เราพัฒนา IR Remote ทดแทนสำหรับ Speakers และ Projectors ซึ่งตัว IR Remote ถูกควบคุมโดย .NET application
มันเป็นสิ่งที่เราพยายามหาวิธีแก้ไขมาสักพักแล้ว เรามีชุดลำโพงและเครื่องโปรเจคเตอร์ซึ่งผู้ใช้มักจะทำรีโมทหาย วางผิดที่ หรือถูกขโมยไป โดยปกติแล้วเรื่องนี้ไม่น่าจะเป็นปัญหา เพราะเราแค่ติดต่อซัพพลายเออร์หรือผู้ผลิตเพื่อสั่งของใหม่มาทดแทน แต่ตอนนี้เราทำแบบนั้นไม่ได้อีกแล้ว
เรามีชุดลำโพง Vision AV-1000 ซึ่งเป็นลำโพง active แบบติดตั้งบนผนัง เชื่อมต่อกับโปรเจคเตอร์ EPSON รีโมทของโปรเจคเตอร์นั้นหาได้ง่าย แต่รีโมทของ AV-1000 เลิกผลิตไปแล้ว ตัวลำโพงเองก็ไม่มีปุ่มควบคุมแบบ manual สำหรับเลือก input หรือปรับเสียง bass/treble ฯลฯ มีเพียงปุ่มปรับระดับเสียงที่ด้านหลังเท่านั้น
เราตัดสินใจที่จะสร้างรีโมทลำโพงขึ้นมาเอง โดยให้มีราคาถูกที่สุดเท่าที่จะเป็นไปได้
แนวคิดนั้นง่ายมาก คือเราจะดักจับสัญญาณ IR จากรีโมทลำโพงที่ยังเหลืออยู่ แล้วบันทึกคำสั่งที่ถูกส่งออกมา
เราทำสิ่งนี้โดยการเชื่อมต่อ IR Receiver เข้ากับ Arduino ตัว Receiver มี 3 Pins เรียงจากซ้ายไปขวาคือ GND, +5V, SIGNAL และใช้งาน Arduino IRRemote library
รันตัวอย่าง Examples > IRRemote > IRrecvDumpv2 (ดูรูปด้านล่างที่เชื่อมต่อ IR Receiver เข้ากับ Arduino Uno สำหรับการทำต้นแบบ คุณสามารถใช้ Arduino nano ได้ แต่ต้อง upload/reset sketches เวลาทดสอบ)
หากรันได้อย่างถูกต้อง ให้เล็งรีโมทลำโพงไปที่ Receiver แล้วกดปุ่ม – เมื่อ IRReceiver ได้รับข้อมูล ไฟ LED สีแดงบน Board จะกะพริบ ทำให้คุณรู้ว่ามันกำลังทำงาน
เปิด Arduino serial monitor และคุณควรจะเห็นข้อมูลที่ได้รับแสดงออกมา (ดูรูปด้านล่าง)
โชคดีสำหรับเราที่โปรโตคอลที่รีโมทลำโพงใช้ถูกระบุว่าเป็น NEC protocol ขนาด 32 bits ซึ่ง IRRemote library มีฟังก์ชันในตัวสำหรับส่งข้อมูลนี้ซ้ำได้อยู่แล้ว ตอนนี้สิ่งที่เราต้องทำคือไล่กดรีโมทลำโพงทีละปุ่มเพื่อบันทึกรหัสของแต่ละปุ่มไว้ (ข้อมูลด้านล่าง)
RESET: 827D58A7
MUTE: 827DD827
INPUT 1: 827D708F
INPUT 2: 827D48B7
TREBLE UP: 827DF20D
TREBLE DOWN: 827DCA35
BASS UP: 827DF00F
BASS DOWN: 827DC837
VOLUME DOWN: 827D40BF
VOLUME UP: 827DC03F
ตอนนี้เรามีข้อมูลที่จำเป็นในการเลียนแบบสัญญาณ IR ของรีโมทแล้ว นั่นคือทั้งหมดที่เราต้องใช้ IR Receiver ดังนั้นจากนี้ไปเราจะถอดมันออกและดำเนินการส่วนที่เหลือของโปรเจกต์ต่อ
เพื่อให้เราสามารถสื่อสารกับมันได้ เราตัดสินใจว่าการมีซอฟต์แวร์บน PC เป็นวิธีที่ดีที่สุด เราอาจจะสร้างรีโมทขึ้นมาอีกอันก็ได้ แต่สุดท้ายมันก็อาจจะหายหรือวางผิดที่อีกอยู่ดี
ขั้นตอนต่อไปคือการเชื่อมต่อ IR LED และ Resistor เข้ากับ Arduino Board โดย IRRemote library จะส่งสัญญาณผ่าน Pin 3 ซึ่งเป็นวงจรที่พื้นฐานมากในการเชื่อมต่อ ในการใช้ Arduino nano ผมได้บัดกรี Resistor เข้ากับขาข้างหนึ่งของ IR LED และอีกด้านต่อเข้ากับ Pin บน Board โดยตรง ซึ่งมันทำงานได้สมบูรณ์แบบ เพราะคุณสามารถดันตัว LED ลงบน Board ให้แนบสนิทได้พอดี
เราจะใช้โปรแกรม VB.NET ง่ายๆ ในการสื่อสารกับ Arduino โดยมันจะเขียนข้อมูลไปยัง serial port และส่ง byte ออกไป – ใน Arduino sketch เราจะเฝ้าดู serial port เพื่อหา byte ที่เข้ามาและจับคู่พวกมันกับรหัสที่จะถูกส่งออกไปทาง IR ง่ายมาก!
/*
* IRremote: AV_Controller
* An IR LED must be connected to Arduino PWM pin 3.
* Version 0.1 01/04/16
*/
#include
IRsend irsend;
byte byteRead;
void(* resetFunc) (void) = 0; //declare reset function @ address 0
void setup() {
Serial.begin(9600);
Serial.println("***********************");
Serial.println("** AV-CONTROLLER **");
Serial.println("***********************");
Serial.println("Waiting for commands...");
}
void loop() {
if (Serial.available()) {
byteRead = Serial.read();
processResponse(byteRead);
}
}
void processResponse(byte byteInput) {
switch (byteInput) {
case '4':
Serial.println("Sending Command: TEST 4");
// irsend.sendNEC(0x827DD827, 32);
delay(40);
return;
break;
case 'a':
Serial.println("Sending Command: RESET");
irsend.sendNEC(0x827D58A7, 32);
delay(40);
Serial.println("Command Sent.");
return;
break;
case 'b':
Serial.println("Sending Command: MUTE");
irsend.sendNEC(0x827DD827, 32);
delay(40);
Serial.println("Command Sent.");
return;
break;
case 'c':
Serial.println("Sending Command: INPUT1");
irsend.sendNEC(0x827D708F, 32);
delay(40);
Serial.println("Command Sent.");
return;
break;
case 'd':
Serial.println("Sending Command: INPUT2");
irsend.sendNEC(0x827D48B7, 32);
delay(40);
Serial.println("Command Sent.");
return;
break;
case 'e':
Serial.println("Sending Command: TREBLE UP");
irsend.sendNEC(0x827DF20D, 32);
delay(40);
Serial.println("Command Sent.");
return;
break;
case 'f':
Serial.println("Sending Command: TREBLE DOWN");
irsend.sendNEC(0x827DCA35, 32);
delay(40);
Serial.println("Command Sent.");
return;
break;
case 'g':
Serial.println("Sending Command: BASS UP");
irsend.sendNEC(0x827DF00F, 32);
delay(40);
Serial.println("Command Sent.");
return;
break;
case 'h':
Serial.println("Sending Command: BASS DOWN");
irsend.sendNEC(0x827DC837, 32);
delay(40);
Serial.println("Command Sent.");
return;
break;
case 'i':
Serial.println("Sending Command: VOLUME DOWN");
irsend.sendNEC(0x827D40BF, 32);
delay(40);
Serial.println("Command Sent.");
return;
break;
case 'j':
Serial.println("Sending Command: VOLUME UP");
irsend.sendNEC(0x827DC03F, 32);
delay(40);
Serial.println("Command Sent.");
return;
break;
case 'x':
Serial.println("Resetting System...");
resetFunc();
return;
break;
break;
case 't':
Serial.println("OK");
return;
break;
break;
default:
break;
}
Serial.println("Unknown command.");
}
หลักการพื้นฐานของ sketch คือ เราจะตรวจจับข้อมูลที่เข้ามาทาง serial port หาก byte นั้นตรงกับตัวเลือกใน switch case ของเรา เราจะส่งคำสั่ง IR ที่เกี่ยวข้องออกไป หากไม่ตรง เราจะแสดงข้อความว่าเป็นคำสั่งที่ไม่รู้จัก
เราสามารถทดสอบโค้ดด้านบนได้โดยการเชื่อมต่อกับ COM port ของเราโดยใช้ PuTTy ให้เปิด PuTTy ขึ้นมาแล้วระบุ COM port ที่ Arduino เชื่อมต่ออยู่ เมื่อเชื่อมต่อแล้ว คุณควรจะเห็นผลลัพธ์จาก Serial println ในฟังก์ชัน setup()
ลองพิมพ์ตัวอักษร 'a' เพื่อส่งคำสั่ง RESET แล้วคุณควรจะเห็นผลลัพธ์ที่ตอบกลับมา คุณสามารถทดสอบกับชุดลำโพงได้เลย มันควรจะทำการ RESET ระดับเสียง/bass/treble ฯลฯ คุณสามารถดูผลลัพธ์ที่คาดหวังได้จาก screenshot ด้านล่าง
ตอนนี้เรามีแอปพลิเคชันที่ใช้งานได้แล้ว เราต้องทำให้มันดูสวยงามขึ้น เราคงไม่คาดหวังให้ผู้ใช้ทั่วไปมาเปิด PuTTy เข้า Serial port เพื่อส่งคำสั่งหรอกใช่ไหม? เราจะมาเริ่มออกแบบ Desktop application กัน
สิ่งแรกที่ต้องทำคือการสื่อสารกับ serial port จริงๆ แล้วเราเพิ่งเขียนบทความเกี่ยวกับเรื่องนี้ไปเมื่อเร็วๆ นี้ ลิงก์อยู่ที่นี่ คุณจะเห็นว่าเราตรวจหาโดยอัตโนมัติว่าควรใช้ COM port ไหนโดยการส่งสตริงตรวจสอบ แอปพลิเคชันจะวนลูปผ่าน COM ports ที่มีอยู่และส่งสตริง 't' ออกไป หาก COM port ใดตอบกลับมาว่า 'OK' แสดงว่าเราเจอพอร์ตที่ถูกต้องแล้ว วิธีนี้ช่วยให้ผู้ใช้ไม่ต้องมาคอยเลือกพอร์ตเอง
การส่งคำสั่งจะถูกรวมไว้ในฟังก์ชันเล็กๆ ที่ชื่อว่า sendCommand โค้ด .NET อยู่ด้านล่าง (มันยังทำหน้าที่สลับสีของ Picturebox เพื่อเลียนแบบการกะพริบของไฟ LED บนรีโมทด้วย)
Sub sendCommand(data As String)
PictureBox2.BackColor = Color.Green
If connected = True Then
If data <> "" Then
Try
Using com As IO.Ports.SerialPort =
My.Computer.Ports.OpenSerialPort(comPort)
com.WriteLine(data)
com.Close()
End Using
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End If
End If
PictureBox2.BackColor = Color.White
End Sub
โค้ดส่วนที่เหลือคุณสามารถดูได้ที่ด้านล่าง มันเป็นเพียงแค่การใช้ sendCommand('a') หรือสตริงอื่นๆ ที่คุณต้องการส่งไปยัง COM port ส่วนที่เหลือของแอปพลิเคชันเป็นเพียง GUI สวยๆ โค้ดและ screenshot ของแอปพลิเคชันขณะทำงานอยู่ด้านล่าง
คุณสามารถดูโค้ดแอปพลิเคชัน .NET ฉบับเต็มได้ที่ด้านล่าง พัฒนาโดยใช้ VS 2015 Community
Imports System.Threading
Public Class Form1
Dim connected As Boolean
Dim comPort As String
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
portConfig()
End Sub
Sub portConfig()
For Each p As String In My.Computer.Ports.SerialPortNames
Try
Using com As IO.Ports.SerialPort =
My.Computer.Ports.OpenSerialPort(p)
com.ReadTimeout = 1000
com.WriteLine("t")
Dim data As String = com.ReadLine()
If InStr(data, "OK") Then
lblConnection.Text = "Connected to " & p
comPort = p
connected = True
End If
com.Close()
End Using
Catch ex As Exception
End Try
Next
End Sub
Sub sendCommand(data As String)
PictureBox2.BackColor = Color.Green
If connected = True Then
If data <> "" Then
Try
Using com As IO.Ports.SerialPort =
My.Computer.Ports.OpenSerialPort(comPort)
com.WriteLine(data)
com.Close()
End Using
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End If
End If
PictureBox2.BackColor = Color.White
End Sub
Private Sub ConnectToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ConnectToolStripMenuItem.Click
portConfig()
End Sub
Private Sub ResetDeviceToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ResetDeviceToolStripMenuItem.Click
sendCommand("x")
End Sub
Private Sub ExitToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ExitToolStripMenuItem.Click
Application.Exit()
End
End Sub
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
Label1.Parent = PictureBox1
Label1.BackColor = Color.Transparent
Label2.Parent = PictureBox1
Label2.BackColor = Color.Transparent
Label3.Parent = PictureBox1
Label3.BackColor = Color.Transparent
Label4.Parent = PictureBox1
Label4.BackColor = Color.Transparent
Label5.Parent = PictureBox1
Label5.BackColor = Color.Transparent
Label6.Parent = PictureBox1
Label6.BackColor = Color.Transparent
Label7.Parent = PictureBox1
Label7.BackColor = Color.Transparent
Label8.Parent = PictureBox1
Label8.BackColor = Color.Transparent
Label9.Parent = PictureBox1
Label9.BackColor = Color.Transparent
Label10.Parent = PictureBox1
Label10.BackColor = Color.Transparent
End Sub
Private Sub Label1_Click(sender As Object, e As EventArgs) Handles Label1.Click
sendCommand("a")
End Sub
Private Sub Label2_Click(sender As Object, e As EventArgs) Handles Label2.Click
sendCommand("b")
End Sub
Private Sub Label3_Click(sender As Object, e As EventArgs) Handles Label3.Click
sendCommand("c")
End Sub
Private Sub Label4_Click(sender As Object, e As EventArgs) Handles Label4.Click
sendCommand("d")
End Sub
Private Sub Label5_Click(sender As Object, e As EventArgs) Handles Label5.Click
sendCommand("e")
End Sub
Private Sub Label6_Click(sender As Object, e As EventArgs) Handles Label6.Click
sendCommand("f")
End Sub
Private Sub Label7_Click(sender As Object, e As EventArgs) Handles Label7.Click
sendCommand("g")
End Sub
Private Sub Label8_Click(sender As Object, e As EventArgs) Handles Label8.Click
sendCommand("h")
End Sub
Private Sub Label9_Click(sender As Object, e As EventArgs) Handles Label9.Click
sendCommand("j")
End Sub
Private Sub Label10_Click(sender As Object, e As EventArgs) Handles Label10.Click
sendCommand("i")
End Sub
Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles Me.Resize
If Me.WindowState = FormWindowState.Minimized Then
NotifyIcon1.Visible = True
NotifyIcon1.Icon = SystemIcons.Application
NotifyIcon1.BalloonTipIcon = ToolTipIcon.Info
NotifyIcon1.BalloonTipTitle = "AV Controller"
NotifyIcon1.BalloonTipText = "Controller is minimized. Click the icon in the tray to open."
NotifyIcon1.ShowBalloonTip(50000)
ShowInTaskbar = False
End If
End Sub
Private Sub NotifyIcon1_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles NotifyIcon1.MouseDoubleClick
ShowInTaskbar = True
Me.WindowState = FormWindowState.Normal
NotifyIcon1.Visible = False
End Sub
End Class
ตอนนี้อุปกรณ์ทำงานได้แล้วและซอฟต์แวร์ควบคุมก็พร้อมใช้งาน ถึงเวลาคิดเรื่องการบรรจุหีบห่อ หากเราปล่อยวงจรไว้แบบเปลือยๆ คงไม่นานนักที่จะมีอะไรหกใส่มัน
เราใช้โปรแกรม 2D Design เพื่อออกแบบกล่องใส่ที่เรียบง่ายมาก
อย่างที่คุณเห็นจาก screenshot ของ 2D Design ทางด้านซ้าย มันเป็นการออกแบบที่พื้นฐานมาก เชื่อมต่อเข้าด้วยกันด้วยพลาสติกแบบมีเกลียว (สอดผ่านรู) ผลงานที่ผ่านการตัดด้วยเลเซอร์อยู่ด้านล่าง:
เราทำสิ่งต่างๆ ต่อไปนี้สำเร็จสำหรับโปรเจกต์นี้:
นี่เป็นโปรเจกต์ที่สนุกมากและมันจะตอบโจทย์การใช้งานได้เป็นอย่างดี สิ่งที่เราต้องทำก็แค่เสียบอุปกรณ์เข้ากับ PC และเปิดแอปพลิเคชัน .NET เพื่อควบคุมลำโพงในห้อง สิ่งต่อไปที่จะเพิ่มเข้าไปคือการควบคุมโปรเจกต์เตอร์และเครื่องปรับอากาศ
ต้นทุนรวมของโปรเจกต์นี้อยู่ที่ประมาณ 4 ปอนด์ โดยส่วนประกอบส่วนใหญ่หามาจาก eBay
สนับสนุนเพื่อรับ Source Code หรือแอปพลิเคชันสำหรับโปรเจกต์นี้
ประเมิน Project
เอาฟอร์มยาวออกจากท้ายหน้า Project แล้ว เหลือเป็นปุ่มให้กดไปกรอกหน้าเดียว ตัวใหญ่ เว้นบรรทัดเยอะ อ่านง่ายกว่า
รีวิวจากคนใช้งานจริง
ถ้าเคยสั่งงาน เคยอ่านหน้านี้แล้วได้ประโยชน์ หรือมีข้อเสนอแนะ ฝากรีวิวไว้ได้เลย
ยังไม่มีรีวิวบนหน้านี้ ถ้าเคยใช้งานหรือมีข้อเสนอแนะ เขียนเป็นคนแรกได้เลย