ทดลองใช้ Arduino Leonardo จำลองคีย์บอร์ดและเมาส์
บทความนี้จะทดสอบการใช้งานบอร์ด Arduino Leonardo โดยบอร์ด Leonardo เป็นบอร์ด Arduino แบบหนึ่งที่คล้ายกับ UNO มาก เรียกว่าถ้าดูเผินๆ นึกว่าเป็นบอร์ดเดียวกันเลยทีเดียว ไม่เชื่อก็ดูรูปได้ครับ
ความแตกต่างระหว่าง Arduino UNO และ Arduino Leonardo คือ UNO ใช้ MCU เป็น ATmega328 แต่ Leonardo ใช้ ATmega32u4 ซึ่ง ATmega32u4 จะมีความสามารถพิเศษ คือ สามารถทำหน้าที่เป็น USB to serial ได้ในตัวเอง ทำให้ไม่ต้องใช้ไอซีอีกตัวทำหน้าที่เป็น USB to Serial จะเห็นว่าบอร์ดจะว่างๆ มากกว่า UNO มาก
ข้อดีอีกอย่างของ Leonardo คือ จากการที่มันมีส่วนที่ติดต่อ USB ในตัว ทำให้มันสามารถจำลองตัวเองเป็นคีย์บอร์ดหรือเมาส์ได้ด้วย ในบทความนี้ จะมุ่งที่จุดนี้เป็นหลัก ดังนั้นความสามารถส่วนที่เหมือนกับ UNO ก็จะไม่พูดถึง
Keyboard Function
เรามาทดลองกับฟังก์ชัน Keyboard กันก่อน โดยมีฟังก์ชันดังนี้
- Keyboard.begin() เป็นคำสั่งให้เริ่มการจำลองบอร์ดเป็นคีย์บอร์ด
- Keyboard.end() เป็นคำสั่งให้สิ้นสุดการจำลองบอร์ดให้เป็นคีย์บอร์ด
- Keyboard.print() เป็นคำสั่งที่ส่งตัวอักษรหรือข้อความไปยังเครื่องคอมพิวเตอร์เสมือนกับมีการกดคีย์บอร์ด
- Keyboard.println() ทำงานเหมือนกับคำสั่ง Keyboard.print() แต่จะส่งการขึ้นบรรทัดใหม่ไปด้วย
ตัวอย่าง
#include <Keyboard.h>void setup() {
// make pin 2 an input and turn on the pullup resistor
// so it goes high unless connected to ground:
pinMode(2, INPUT_PULLUP);
Keyboard.begin();
}int count=0;void loop() {
//if the button is pressed
if (digitalRead(2) == LOW) {
//Send the message
Keyboard.print(“Hello!”);
delay(200);
count+=1;
if (count>5)
Keyboard.end();
}
}
เมื่อรันโปรแกรมนี้แล้วกดสวิตซ์ บนจอภาพไม่ว่าจะอยู่ในโปรแกรมอะไรก็ตาม จะแสดงข้อความ Hello! ออกมา จนครบ 5 ครั้งก็เลิกการจำลองเป็นคีย์บอร์ด แต่จากการทดลองพบว่าแม้จะครบ 5 ครั้งแล้ว ก็ยังทำงานเป็นคีย์บอร์ดอยู่ แต่จริงๆ แล้วฟังก์ชัน Keyboard.end(); ก็ไม่จำเป็นสักเท่าไร
สำหรับกลุ่มฟังก์ชันที่จะอธิบายต่อไปมีดังนี้
- Keyboard.press() เป็นคำสั่งสำหรับจำลองการกดปุ่มที่ไม่ใช่ปุ่มอักขระ เช่น ปุ่มพวก Ctrl, Alt หรือ Shift อะไรทำนองนี้ จำนวน 1 ปุ่ม
- Keyboard.release() เป็นคำสั่งสำหรับจำลองการปล่อยปุ่มที่ไม่ใช่ปุ่มอักขระ จำนวน 1 ปุ่ม
- Keyboard.releaseAll() เป็นคำสั่งสำหรับจำลองการปล่อยปุ่มที่ไม่ใช่ปุ่มอักขระทุกปุ่ม
ตัวอย่าง
#include <Keyboard.h>char ctrlKey = KEY_LEFT_CTRL;void setup() {
// make pin 2 an input and turn on the pullup resistor
// so it goes high unless connected to ground:
pinMode(2, INPUT_PULLUP);
// initialize control over the keyboard:
Keyboard.begin();
}void loop() {
while (digitalRead(2) == HIGH) {
// do nothing until pin 2 goes low
delay(500);
}
delay(1000); // new document:
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press(‘n’);
delay(100);
Keyboard.releaseAll();
// wait for new window to open:
delay(1000);
}
โปรแกรมในส่วน Setup กำหนดให้รับสวิตซ์ที่ขา 2 สำหรับในส่วน Loop จะอ่านขา 2 จนกว่าจะเป็น LOW (คือมีการกด) จากนั้น delay 500 ms ก่อนจะตรวจสอบการกดใหม่ เพื่อไม่ให้ตรวจสอบบ่อยมากเกินไป จากนั้น delay 1 วินาที เพื่อ debounce
จากนั้นจะมีการส่งการกดปุ่ม Ctrl ด้านซ้ายไป และส่งตัว n ตามไป ซึ่งรวมกันแล้วก็คือ Ctrl-N นั่นเอง ซึ่งผลจาก Ctrl-N จะทำให้ Arduino IDE ทำการ New Sketch โดยการเปิดหน้าต่างใหม่ขึ้นมา จากนั้น delay 100 ms และส่งข้อมูลปล่อยการกดปุ่มทั้งหมดไป
สรุปว่าโปรแกรมนี้เมื่อรันแล้ว ทุกครั้งที่กดสวิตซ์ จะเกิด Window ใหม่ขึ้นมา สำหรับปุ่มที่ไม่ใช้อักขระ ที่จะส่งไปได้ มีรายละเอียดดังรูป
คราวนี้ก็มาถึงฟังก์ชันสุดท้ายของ Keyboard
- Keyboard.write() ฟังก์ชันนี้จะจำลองการกดคีย์บอร์ด โดยส่งได้ครั้งละ 1 ตัวอักษรเท่านั้น แต่สามารถส่งได้หลายแบบ ตามตัวอย่าง
Keyboard.write(65); // sends ASCII value 65, or A
Keyboard.write('A'); // same thing as a quoted character
Keyboard.write(0x41); // same thing in hexadecimal
Keyboard.write(0b01000001); // same thing in binary
จะเห็นว่าส่งเป็นตัวเลข ตัวอักษร ฐานสิบหก ฐานสอง ได้หมด รวมถึงปุ่มที่เป็นไม่ใช่อักขระด้วย โดยใช้ค่าตามตารางข้างต้น
จากที่อธิบายมา คงจะเริ่มเห็นแล้วนะครับว่าจะเอาไปทำอะไรได้บ้าง เช่น
- อาจนำไปใช้จำลองเกมที่ใช้ปุ่มคีย์บอร์ด โดยทำเป็น Action ทำปุ่มใหญ่ๆ ให้ต่อย
- นำไปต่อกับจักรยาน เพื่อทำเกมปั่นจักรยาน
- ทำ Joy Stick ใช้เอง
- ทำ Numpad สำหรับคีย์บอร์ดที่ไม่มีแป้นพิมพ์
- ทำคีย์บอร์ดพิเศษสำหรับทำ Shortcut งานต่างๆ โดยเฉพาะ เช่น Cut, Copy, Paste
- ใช้ร่วมกับ Bluetooth ทำ Bluetooth Keyboard
- ทำปุ่มปุ่มใหญ่ๆ อยู่ข้างนอก เพื่อทำอะไรบางอย่าง เช่น Ctrl-Alt-Del
- เขียนโปรแกรมเพื่อทำงานซ้ำๆ เช่น ป้อนข้อมูลใน Excel หรือส่ง E-Mail
- อาจเอาไปเสียบเพื่อ Hack Password (ระวังคุกกันเองนะครับ)
เอาละครับสำหรับการใช้งานจำลองคีย์บอร์ดก็จบลงตรงนี้ จะเห็นได้ว่าเอาไปใช้อะไรได้เยอะเลย
Mouse Function
สำหรับ Mouse Function มีดังนี้
- Mouse.begin() เป็นคำสั่งให้เริ่มการจำลองบอร์ดเป็นเมาส์
- Mouse.end() เป็นคำสั่งสิ้นสุดการจำลองบอร์ดเป็นเมาส์
- Mouse.click() เป็นคำสั่งจำลองการคลิ๊กเมาส์
ตัวอย่าง
#include <Mouse.h>void setup() {
pinMode(2, INPUT_PULLUP);
//initiate the Mouse library
Mouse.begin();
}void loop() {
//if the button is pressed, send a left mouse click
if (digitalRead(2) == LOW) {
Mouse.click();
}
delay(1000);
}
โปรแกรมนี้จะจำลองบอร์ดเสมือนกับเมาส์ โดยเมื่อกดสวิตซ์ที่ต่อกับ Pin 2 จะเสมือนกับการกดเมาส์ วิธีการทดลอง คือ ให้เอา Cursor ของเมาส์ไปไว้ที่ปุ่ม แล้วกดปุ่ม ก็จะเห็นว่าเหมือนกับการกดปุ่มเมาส์เลยทีเดียว (หมายเหตุ ในการทดลองโปรแกรมให้ตรวจสอบให้ดีนะครับ เพราะเขียนผิด หรือต่อ Hardware ผิด จะเหมือนกับการกดปุ่มเมาส์ไปเรื่อยๆ ซึ่งจะยุ่งยากไม่น้อย เพราะเมื่อเสียบบอร์ดก็จะกดปุ่มไปเรื่อยๆ วิธีการที่ผมแก้ไขคือ ถอดบอร์ดแล้วกด Upload พอมันเริ่ม Upload ค่อยเสียบบอร์ด เนื่องจากพอร์ต USB จะทำหน้าที่ได้ครั้งละ 1 อย่าง พอเรา Upload มันจะทำหน้าที่เป็นเมาส์ไม่ได้อีก)
Mouse.move() ฟังก์ชันนี้จะจำลองการ move ของเมาส์ โดยมีพารามิเตอร์ จำนวน 3 ตัว ได้แก่ xVal, yVal และ wheel โดย xVal และ yVal จะเป็นการสั่งให้ move cursor ในแนว x และ y สำหรับ wheel จะเป็นจำนวนการ scroll ของล้อเมาส์ (ถ้ามี)
โปรแกรมต่อไปนี้จะจำลองการทำงานของ Mouse โดยผมใช้ Joystick Shield ในการเลื่อนเมาส์ โดยหน้าตาของ Joystick Shield มีตามรูป
โดยผมจะโยก Joystick เพื่อเลื่อน Cursor ของ Mouse โดยโปรแกรมมีดังนี้ (ถ้าไม่มี Joystick ก็สามารถใช้ตัวต้านทานปรับค่าได้ 2 ตัวแทนก็ได้)
#include <Mouse.h>int range = 12; // output range of X or Y movement
int responseDelay = 2; // response delay of the mouse, in ms
int threshold = range / 4; // resting threshold
int center = range / 2; // resting position value
int minima[] = {1023, 1023}; // actual analogRead minima for {x, y}
int maxima[] = {0, 0}; // actual analogRead maxima for {x, y}
int axis[] = {A0, A1}; // pin numbers for {x, y}void setup() {
Mouse.begin();
}void loop() {
// read and scale the two axes:
int xReading = readAxis(0);
int yReading = readAxis(1); // move the mouse:
Mouse.move(xReading, yReading, 0);
delay(responseDelay);
}/*
reads an axis (0 or 1 for x or y) and scales the
analog input range to a range from 0 to <range>
*/int readAxis(int axisNumber) {
int distance = 0; // distance from center of the output range int reading = analogRead(axis[axisNumber]); // if the current reading exceeds the max or min for this axis,
// reset the max or min:
if (reading < minima[axisNumber]) {
minima[axisNumber] = reading;
}
if (reading > maxima[axisNumber]) {
maxima[axisNumber] = reading;
} // map reading from the analog input range to the output range:
reading = map(reading, minima[axisNumber], maxima[axisNumber], 0, range); // if the output reading is outside from the rest position
// threshold, use it:
if (abs(reading — center) > threshold) {
distance = (reading — center);
} // the Y axis needs to be inverted in order to
// map the movemment correctly:
if (axisNumber == 1) {
distance = -distance;
} // return the distance for this axis:
return distance;
}
การทำงานโดยคร่าวๆ ของโปรแกรมข้างต้น คือ จะสร้างฟังก์ชัน readAxis ขึ้นมาเพื่อรับการเคลื่อนที่ของแต่ละแกน โดยในฟังก์ชัน จะอ่านค่า Analog ซึ่งก็คือตำแหน่งของ Joystick จากนั้นนำค่าไปเทียบกับ min, max ของแกน X และ Y หากมีค่าน้อยกว่า หรือมากกว่า ก็ให้เก็บค่าใหม่เป็น min, max
จากนั้นก็ตรวจสอบว่าค่าที่อ่านมากกว่า threshold คือ มีการขยับเยอะหน่อย (มีไว้เพื่อป้องกันการเปลี่ยนค่าเล็กน้อยของค่าที่อ่านได้) ก็ค่อยส่งค่าใหม่ไป ถ้าขยับน้อยก็ไม่เปลี่ยนค่า เพื่อให้เคอร์เซอร์เมาส์นิ่ง เวลาไม่ได้ทำอะไร
- Mouse.press() ฟังก์ชันนี้จะคล้ายกับฟังก์ชัน click() แต่จะเป็นการกดปุ่ม Mouse และจำลองการกดค้างเอาไว้ โดยสามารถเลือกปุ่มซ้ายหรือปุ่มขวา (หรือปุ่มกลาง) ได้ โดยการเรียกเป็น Mouse.press(MOUSE_LEFT), Mouse.press(MOUSE_RIGHT) หรือ Mouse.press(MOUSE_MIDDLE) โดยหากเรียกฟังก์ชันโดยไม่ส่งพารามิเตอร์ จะถือว่าเป็นการกดปุ่มซ้าย
- Mouse.release() ฟังก์ชันนี้จะตรงข้ามกับฟังก์ชัน press() คือเป็นการปล่อยปุ่มเมาส์ที่กำหนด
โปรแกรมข้างล่างนี้จะแสดงการคลิ๊กขวา โดยสวิตซ์ที่ขา 2 จะเป็นการกดคลิ๊กขวา และสวิตซ์ที่ขา 3 จะเป็นการปล่อยปุ่มคลิ๊กขวา วิธีทดสอบ คือ หลังจากที่โหลดโปรแกรมแล้ว ไปที่หน้าจอ Desktop จากนั้นกดสวิตซ์ 2 และกดสวิตซ์ 3 จะปรากฏเมนูเหมือนกับเรากดคลิ๊กขวา
#include <Mouse.h>void setup() {
//The switch that will initiate the Mouse press
//The switch that will terminate the Mouse press
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
//initiate the Mouse library
Mouse.begin();
}void loop() {
//if the switch attached to pin 2 is closed,
//press and hold the right mouse button
if (digitalRead(3) == LOW) {
Mouse.press(MOUSE_RIGHT);
}
if (digitalRead(4) == LOW) {
//if the switch attached to pin 3 is closed,
//release the right mouse button
Mouse.release(MOUSE_RIGHT);
}
}
หมายเหตุ เมื่อมีการเรียกใช้ฟังก์ชัน press() เมาส์จะไม่สามารถควบคุมผ่านเมาส์จริงๆ ได้
- Mouse.isPressed() ฟังก์ชันนี้ใช้ในการตรวจสอบสถานะของการกดปุ่มเมาส์แต่ละปุ่ม
ก็ครบทุกฟังก์ชันของเมาส์แล้วนะครับ ก็น่าจะเอาไปใช้ประโยชน์ได้ เช่น อาจใช้ร่วมกับเซ็นเซอร์ความเร่ง แล้วเขียนโปรแกรมสั่งการเมาส์ผ่านการเคลื่อนที่ของมือ หรืออื่นๆ
บอร์ดอื่นๆ
หากไม่มีบอร์ด Leonardo หรือคิดว่าบอร์ด Leonardo มีขนาดใหญ่เกินไป ยังมีบอร์ดอีกบอร์ดหนึ่งที่มีคุณสมบัติคล้ายกับ Leonardo แต่มีขนาดเล็กกว่า นั่นก็คือบอร์ด Arduino Micro โดยหน้าตาของแท้จะเป็นแบบนี้ ถ้าของเลียนแบบบอร์ดมักจะมีสีน้ำเงิน แต่หน้าตาเป็นแบบเดียวกัน ทั่วไปอาจจะไม่ค่อยคุ้นเคยมากนัก เพราะมักไม่ค่อยมีการนำมาใช้เท่าไร ส่วนใหญ่มักจะใช้ UNO กับ Nano กันมากกว่า (บอร์ด Arduino Pro Micro ก็ใช้งานได้เช่นกัน)
สามารถใช้งานได้เหมือนกัน (ทดสอบเรียบร้อยแล้ว)
อีกบอร์ดหนึ่งที่น่าสนใจเพราะมีขนาดเล็กลงไปอีก แต่ผมไม่มีเลยไม่ได้ทดสอบ แต่ก็น่าจะใช้ได้เหมือนกัน เพราะใช้ MCU เบอร์เดียวกัน บอร์ดนี้ชื่อ Beetle Board หน้าตาเป็นดังรูปนี่ครับ เล็กดีมากเลย แม้ I/O จะมีไม่มากก็ตาม
ก็เป็นอันว่าบทความนี้ก็จบลงแต่เพียงเท่านี้ น่าจะเป็นประโยชน์สำหรับผู้ที่จะนำ Arduino ไปควบคุม Mouse หรือ Keyboard กันตามสมควรนะครับ