MỤC LỤC
Remote điều khiển PS2 Không Dây ( PS2 Robot Controller )



Remote điều khiển PS2 Không Dây ( PS2 Robot Controller ) là bộ Remote điều khiển robot, xe thông minh, điều khiển từ xa các thiết bị phong phú. Giao tiếp với vi điều khiển ngoại vi khác, dễ sử dụng.
Tay cầm điều khiển PS2 sử dụng điện áp 3.3VDC cho cấp nguồn và giao tiếp GPIO, nếu các bạn giao tiếp với các vi điều khiển 5VDC thì cần thêm một bộ chuyển đổi Logic để tránh trường hợp Receiver của tay bị cháy.
Đối với điều khiển robot, chỉ cần dùng các dây sau: Clock, Data, Command, VCC & GND, Attention. Clock, Data, Command, Attention nối với các chân I/O bất kỳ. Chân Data nên được kéo nguồn bằng điện trở từ 1k-10k. Clock: xung, đồng bộ hóa quá trình truyền dữ liệu. Data: dữ liệu từ gamepad về vi điều khiển; Command: dữ liệu từ vi điều khiển đến gamepad. Attention: Chip select VCC: 3-5V; GND:0V
- Điện áp bộ thu: 3.3VDC
- Tay cầm PS2, vật liệu ABS chất lượng cao.
- Công nghệ nhận không dây 2.4GHz, khoảng cách có thể lên đến 10m.
- Chế độ hoạt động kỹ thuật số / analog, có thể được chuyển bất cứ lúc nào, có đèn báo
- 4-trục 12-nút thiết kế để đáp ứng nhu cầu của các nút trò chơi (chế độ kỹ thuật số: 2-trục 10 nút; chế độ tương tự: 4-trục 12 nút).
- Nút có chức năng chụp liên tục và thao tác trò chơi thuận tiện hơn.
- Hai joystick analog có độ chính xác cao để điều khiển 360 độ
- Các phím trái và phải có mỗi động cơ rung tích hợp có thể thể hiện hiệu ứng rung động tinh tế.
- Kết nối nhanh, phản ứng nhanh, không chậm trễ.
- Hỗ trợ USB1.1 / 2.0 (yêu cầu bổ sung USB để PS2 chuyển đổi)
- Hỗ trợ WIN 98 / ME / 2000 / XP / Vista
- Nguồn: 2 pin AAA
Ví dụ của web https://www.hackster.io/
Phần cứng



Kết nối cho Arduino Uno:
- Digital pin 3 => H-Bridge ENA pin
- Digital pin 5 => H-Bridge IN1 pin
- Digital pin 4 => H-Bridge IN2 pin
- Digital pin 8 => H-Bridge IN3 pin
- Digital pin 7 => H-Bridge IN4 pin
- Digital pin 6 => H-Bridge ENB pin
- 5V pin => H-Bridge 5V pin
- Gnd pin => H-bridge Gnd pin
- Digital pin 10 => PS2 receiver pin 6
- Digital pin 11 => PS2 receiver pin 2
- Digital pin 12 => PS2 receiver pin 1
- Digital pin 13 => PS2 receiver pin 7
- 3.3V pin => PS2 receiver pin 5
- Gnd pin => PS2 receiver pin 4
Kết nối cho HBridge của L298:
- ENA pin => Arduino digital pin 3
- IN1 pin => Arduino digital pin 5
- IN2 pin => Arduino digital pin 4
- IN3 pin => Arduino digital pin 8
- IN4 pin => Arduino digital pin 7
- ENB pin => Arduino digital pin 6
- 5V pin => Arduino 5V pin
- Gnd pin => Arduino Gnd pin
- Gnd pin => Battery pack negative wire
- 12V pin => Battery pack positive wire
- OUT1 => Right motor negative wire
- OUT2 => Right motor positive wire
- OUT3 => Left motor positive wire
- OUT4 => Left motor negative wire
Kết nối bộ nhận của PS2:

- Pin 1 (data) => Arduino digital pin 12
- Pin 2 (command) => Arduino digital pin 11
- Pin 4 (ground) => Arduino Gnd pin
- Pin 5 (power) => Arduino 3.3V pin
- Pin 6 (attention) => Arduino digital pin 10
- Pin 7 (clock) => Arduino digital pin 13
Lập trình PS2
Thư viện PS2X cho Arduino, các bạn có thể tải xuống tại https://drive.google.com/file/d/1zcdgPpB5lUW3C6EyFFM6W_NZ7QldIUhO/view?usp=sharing hoặc https://github.com/madsci1016/Arduino-PS2X
Link tải Code cho bài viết: https://drive.google.com/drive/folders/1sTm1KzcUYrBsqHFnCw793Op5kVVPCjMy?usp=sharing
Quy ước nút nhấn trên tay PS2

Các nút chỉ hướng:
- PSB_PAD_UP = D-pad up button;
- PSB_PAD_DOWN = D-pad down button;
- PSB_PAD_LEFT = D-pad left button
- PSB_PAD_RIGHT = D-pad right button
Các nút hành động:
- PSB_GREEN or PSB_TRIANGLE = green triangle button
- PSB_RED or PSB_CIRCLE = red circle button
- PSB_BLUE or PSB_CROSS = blue x button
- PSB_PINK or PSB_SQUARE = pink square button
Các nút kích hoạt (triggers):
- PSB_L1 = left side trigger button 1
- PSB_R1 = right side trigger button 1
- PSB_L2 = left side trigger button 2
- PSB_R2 = right side trigger button 2
Sticks:
- PSB_L3 = left stick push button (yes, you can press the stick as a pussh button)
- PSB_R3 = right stick push button
Menu:
- PSB_SELECT = select button
- PSB_START = start button
Code nút điều khiển 4 hướng (code Sketch #1)
// PS2 Tank by Igor Fonseca @2019
// Controls a robotic tank using a PS2 joystick, using D-pad buttons
// based on an example using the PS2X library by Bill Porter 2011
// All text above must be included in any redistribution.
// include libraries
#include <PS2X_lib.h>
// These are used to set the direction of the bridge driver.
#define ENA 3 //ENA
#define MOTORA_1 4 //IN3
#define MOTORA_2 5 //IN4
#define MOTORB_1 8 //IN1
#define MOTORB_2 7 //IN2
#define ENB 6 //ENB
PS2X ps2x; // create PS2 Controller Class
//right now, the library does NOT support hot pluggable controllers, meaning
//you must always either restart your Arduino after you conect the controller,
//or call config_gamepad(pins) again after connecting the controller.
int error = 0;
byte type = 0;
byte vibrate = 0;
void setup(){
// Configure output pins
pinMode(ENA, OUTPUT);
pinMode(MOTORA_1, OUTPUT);
pinMode(MOTORA_2, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(MOTORB_1, OUTPUT);
pinMode(MOTORB_2, OUTPUT);
// Disable both motors
digitalWrite(ENA,0);
digitalWrite(ENB,0);
// Start serial communication
Serial.begin(57600);
error = ps2x.config_gamepad(13,11,10,12, true, true); //setup pins and settings: GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error
// Check for error
if(error == 0){
Serial.println("Found Controller, configured successful");
}
else if(error == 1)
Serial.println("No controller found, check wiring or reset the Arduino");
else if(error == 2)
Serial.println("Controller found but not accepting commands");
else if(error == 3)
Serial.println("Controller refusing to enter Pressures mode, may not support it.");
// Check for the type of controller
type = ps2x.readType();
switch(type) {
case 0:
Serial.println("Unknown Controller type");
break;
case 1:
Serial.println("DualShock Controller Found");
break;
case 2:
Serial.println("GuitarHero Controller Found");
break;
}
}
// Main loop
void loop(){
if(error == 1) //skip loop if no controller found
return;
else { //DualShock Controller
ps2x.read_gamepad(false, vibrate); // disable vibration of the controller
// Perform movements based on D-pad buttons
// MOVE FORWARD
if(ps2x.Button(PSB_PAD_UP)) {
digitalWrite(MOTORA_1,LOW);
digitalWrite(MOTORA_2,HIGH);
digitalWrite(MOTORB_1,HIGH);
digitalWrite(MOTORB_2,LOW);
analogWrite(ENB, 1023);
analogWrite(ENA, 1023);
Serial.println("Move forward");
}
// TURN RIGHT
if(ps2x.Button(PSB_PAD_RIGHT)){
digitalWrite(MOTORA_1,HIGH);
digitalWrite(MOTORA_2,LOW);
digitalWrite(MOTORB_1,HIGH);
digitalWrite(MOTORB_2,LOW);
analogWrite(ENB, 1023);
analogWrite(ENA, 1023);
Serial.println("Turn right");
}
// TURN LEFT
if(ps2x.Button(PSB_PAD_LEFT)){
digitalWrite(MOTORA_1,LOW);
digitalWrite(MOTORA_2,HIGH);
digitalWrite(MOTORB_1,LOW);
digitalWrite(MOTORB_2,HIGH);
analogWrite(ENB, 1023);
analogWrite(ENA, 1023);
Serial.println("Turn left");
}
// MOVE BACK
if(ps2x.Button(PSB_PAD_DOWN)){
digitalWrite(MOTORA_1,HIGH);
digitalWrite(MOTORA_2,LOW);
digitalWrite(MOTORB_1,LOW);
digitalWrite(MOTORB_2,HIGH);
analogWrite(ENB, 1023);
analogWrite(ENA, 1023);
Serial.println("Move back");
}
if (!ps2x.Button(PSB_PAD_DOWN) && !ps2x.Button(PSB_PAD_UP) && !ps2x.Button(PSB_PAD_RIGHT) && !ps2x.Button(PSB_PAD_LEFT)) {
analogWrite(ENB, 0);
analogWrite(ENA, 0);
}
delay(50);
}
}
Code Sketch #2 – Analog Stick and Digital Buttons (L2 and R2)

// PS2 Tank by Igor Fonseca @2019
// Controls a robotic tank using a PS2 joystick, using D-pad buttons
// based on an example using the PS2X library by Bill Porter 2011
// All text above must be included in any redistribution.
// include libraries
#include <PS2X_lib.h>
// These are used to set the direction of the bridge driver.
#define ENA 3 //ENA
#define MOTORA_1 4 //IN3
#define MOTORA_2 5 //IN4
#define MOTORB_1 8 //IN1
#define MOTORB_2 7 //IN2
#define ENB 6 //ENB
int motor_right_speed = 0;
int motor_left_speed = 0;
PS2X ps2x; // create PS2 Controller Class
//right now, the library does NOT support hot pluggable controllers, meaning
//you must always either restart your Arduino after you conect the controller,
//or call config_gamepad(pins) again after connecting the controller.
int error = 0;
byte type = 0;
byte vibrate = 0;
void setup(){
// Configure output pins
pinMode(ENA, OUTPUT);
pinMode(MOTORA_1, OUTPUT);
pinMode(MOTORA_2, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(MOTORB_1, OUTPUT);
pinMode(MOTORB_2, OUTPUT);
// Disable both motors
digitalWrite(ENA,0);
digitalWrite(ENB,0);
// Start serial communication
Serial.begin(57600);
error = ps2x.config_gamepad(13,11,10,12, true, true); //setup pins and settings: GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error
// Check for error
if(error == 0){
Serial.println("Found Controller, configured successful");
}
else if(error == 1)
Serial.println("No controller found, check wiring or reset the Arduino");
else if(error == 2)
Serial.println("Controller found but not accepting commands");
else if(error == 3)
Serial.println("Controller refusing to enter Pressures mode, may not support it.");
// Check for the type of controller
type = ps2x.readType();
switch(type) {
case 0:
Serial.println("Unknown Controller type");
break;
case 1:
Serial.println("DualShock Controller Found");
break;
case 2:
Serial.println("GuitarHero Controller Found");
break;
}
}
// Main loop
void loop(){
if(error == 1) //skip loop if no controller found
return;
else { //DualShock Controller
ps2x.read_gamepad(false, vibrate); // disable vibration of the controller
int nJoyL = ps2x.Analog(PSS_LX); // read left stick
nJoyL = map(nJoyL, 0, 255, 1023, -1023);
int motor_right_speed = 1023;
int motor_left_speed = 1023;
if (nJoyL < 0) {
motor_right_speed = motor_right_speed + nJoyL;
}
if (nJoyL > 0) {
motor_left_speed = motor_left_speed - nJoyL;
}
if(ps2x.Button(PSB_R2)) {
digitalWrite(MOTORA_1,LOW);
digitalWrite(MOTORA_2,HIGH);
digitalWrite(MOTORB_1,HIGH);
digitalWrite(MOTORB_2,LOW);
analogWrite(ENA, motor_right_speed);
analogWrite(ENB, motor_left_speed);
}
if(ps2x.Button(PSB_L2)) {
digitalWrite(MOTORA_1,HIGH);
digitalWrite(MOTORA_2,LOW);
digitalWrite(MOTORB_1,LOW);
digitalWrite(MOTORB_2,HIGH);
analogWrite(ENA, motor_right_speed);
analogWrite(ENB, motor_left_speed);
}
if(!ps2x.Button(PSB_L2) && !ps2x.Button(PSB_R2)) {
analogWrite(ENA, 0);
analogWrite(ENB, 0);
}
delay(50);
}
}
Code Sketch #3 – Left and Right Analog Sticks (Differential Drive)

// PS2 Tank by Igor Fonseca @2019
// Controls a robotic tank using a PS2 joystick, using D-pad buttons
// based on an example using the PS2X library by Bill Porter 2011
// All text above must be included in any redistribution.
// include libraries
#include <PS2X_lib.h>
// These are used to set the direction of the bridge driver.
#define ENA 3 //ENA
#define MOTORA_1 4 //IN3
#define MOTORA_2 5 //IN4
#define MOTORB_1 8 //IN1
#define MOTORB_2 7 //IN2
#define ENB 6 //ENB
PS2X ps2x; // create PS2 Controller Class
//right now, the library does NOT support hot pluggable controllers, meaning
//you must always either restart your Arduino after you conect the controller,
//or call config_gamepad(pins) again after connecting the controller.
int error = 0;
byte type = 0;
byte vibrate = 0;
void setup(){
// Configure output pins
pinMode(ENA, OUTPUT);
pinMode(MOTORA_1, OUTPUT);
pinMode(MOTORA_2, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(MOTORB_1, OUTPUT);
pinMode(MOTORB_2, OUTPUT);
// Disable both motors
digitalWrite(ENA,0);
digitalWrite(ENB,0);
// Start serial communication
Serial.begin(57600);
error = ps2x.config_gamepad(13,11,10,12, true, true); //setup pins and settings: GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error
// Check for error
if(error == 0){
Serial.println("Found Controller, configured successful");
}
else if(error == 1)
Serial.println("No controller found, check wiring or reset the Arduino");
else if(error == 2)
Serial.println("Controller found but not accepting commands");
else if(error == 3)
Serial.println("Controller refusing to enter Pressures mode, may not support it.");
// Check for the type of controller
type = ps2x.readType();
switch(type) {
case 0:
Serial.println("Unknown Controller type");
break;
case 1:
Serial.println("DualShock Controller Found");
break;
case 2:
Serial.println("GuitarHero Controller Found");
break;
}
}
// Main loop
void loop(){
if(error == 1) //skip loop if no controller found
return;
else { //DualShock Controller
ps2x.read_gamepad(false, vibrate); // disable vibration of the controller
int nJoyL = ps2x.Analog(PSS_LY); // read left stick
int nJoyR = ps2x.Analog(PSS_RY); // read right stick
nJoyL = map(nJoyL, 0, 255, 1023, -1023);
nJoyR = map(nJoyR, 0, 255, -1023, 1023);
// Perform movements based on both analog sticks
if(nJoyR>50) {
digitalWrite(MOTORA_1,HIGH);
digitalWrite(MOTORA_2,LOW);
analogWrite(ENA, 1023);
}
if(nJoyR<-50) {
digitalWrite(MOTORA_1,LOW);
digitalWrite(MOTORA_2,HIGH);
analogWrite(ENA, 1023);
}
if (abs(nJoyR)<50) {
analogWrite(ENA, 0);
}
if(nJoyL>50) {
digitalWrite(MOTORB_1,HIGH);
digitalWrite(MOTORB_2,LOW);
analogWrite(ENB, 1023);
}
if(nJoyL<-50) {
digitalWrite(MOTORB_1,LOW);
digitalWrite(MOTORB_2,HIGH);
analogWrite(ENB, 1023);
}
if (abs(nJoyL)<50) {
analogWrite(ENB, 0);
}
delay(50);
}
}
Code Sketch #4 – Left Analog Stick Only
// PS2 Tank by Igor Fonseca @2019
// Controls a robotic tank using a PS2 joystick, using left analog stick
// based on an example using the PS2X library by Bill Porter 2011
// All text above must be included in any redistribution.
// include libraries
#include <PS2X_lib.h> //for v1.6
// These are used to set the direction of the bridge driver.
#define ENA 3 //ENA
#define MOTORA_1 4 //IN3
#define MOTORA_2 5 //IN4
#define MOTORB_1 8 //IN1
#define MOTORB_2 7 //IN2
#define ENB 6 //ENB
int motor_right_speed = 0;
int motor_left_speed = 0;
PS2X ps2x; // create PS2 Controller Class
//right now, the library does NOT support hot pluggable controllers, meaning
//you must always either restart your Arduino after you conect the controller,
//or call config_gamepad(pins) again after connecting the controller.
int error = 0;
byte type = 0;
byte vibrate = 0;
void setup(){
// Configure output pins
pinMode(ENA, OUTPUT);
pinMode(MOTORA_1, OUTPUT);
pinMode(MOTORA_2, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(MOTORB_1, OUTPUT);
pinMode(MOTORB_2, OUTPUT);
// Disable both motors
digitalWrite(ENA,0);
digitalWrite(ENB,0);
// Start serial communication
Serial.begin(57600);
error = ps2x.config_gamepad(13,11,10,12, true, true); //setup pins and settings: GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error
// Check for error
if(error == 0){
Serial.println("Found Controller, configured successful");
}
else if(error == 1)
Serial.println("No controller found, check wiring or reset the Arduino");
else if(error == 2)
Serial.println("Controller found but not accepting commands");
else if(error == 3)
Serial.println("Controller refusing to enter Pressures mode, may not support it.");
// Check for the type of controller
type = ps2x.readType();
switch(type) {
case 0:
Serial.println("Unknown Controller type");
break;
case 1:
Serial.println("DualShock Controller Found");
break;
case 2:
Serial.println("GuitarHero Controller Found");
break;
}
}
// Main loop
void loop(){
if(error == 1) //skip loop if no controller found
return;
else { //DualShock Controller
ps2x.read_gamepad(false, vibrate); // disable vibration of the controller
int nJoyX = ps2x.Analog(PSS_LX); // read x-joystick
int nJoyY = ps2x.Analog(PSS_LY); // read y-joystick
nJoyX = map(nJoyX, 0, 255, -1023, 1023);
nJoyY = map(nJoyY, 0, 255, 1023, -1023);
// OUTPUTS
int nMotMixL; // Motor (left) mixed output
int nMotMixR; // Motor (right) mixed output
// CONFIG
// - fPivYLimt : The threshold at which the pivot action starts
// This threshold is measured in units on the Y-axis
// away from the X-axis (Y=0). A greater value will assign
// more of the joystick's range to pivot actions.
// Allowable range: (0..+127)
float fPivYLimit = 1023.0;
// TEMP VARIABLES
float nMotPremixL; // Motor (left) premixed output
float nMotPremixR; // Motor (right) premixed output
int nPivSpeed; // Pivot Speed
float fPivScale; // Balance scale between drive and pivot
// Calculate Drive Turn output due to Joystick X input
if (nJoyY >= 0) {
// Forward
nMotPremixL = (nJoyX>=0)? 1023.0 : (1023.0 + nJoyX);
nMotPremixR = (nJoyX>=0)? (1023.0 - nJoyX) : 1023.0;
} else {
// Reverse
nMotPremixL = (nJoyX>=0)? (1023.0 - nJoyX) : 1023.0;
nMotPremixR = (nJoyX>=0)? 1023.0 : (1023.0 + nJoyX);
}
// Scale Drive output due to Joystick Y input (throttle)
nMotPremixL = nMotPremixL * nJoyY/1023.0;
nMotPremixR = nMotPremixR * nJoyY/1023.0;
// Now calculate pivot amount
// - Strength of pivot (nPivSpeed) based on Joystick X input
// - Blending of pivot vs drive (fPivScale) based on Joystick Y input
nPivSpeed = nJoyX;
fPivScale = (abs(nJoyY)>fPivYLimit)? 0.0 : (1.0 - abs(nJoyY)/fPivYLimit);
// Calculate final mix of Drive and Pivot
nMotMixL = (1.0-fPivScale)*nMotPremixL + fPivScale*( nPivSpeed);
nMotMixR = (1.0-fPivScale)*nMotPremixR + fPivScale*(-nPivSpeed);
motor_left_speed = nMotMixL;
motor_right_speed = nMotMixR;
if (motor_right_speed > 50) {
digitalWrite(MOTORB_1,HIGH);
digitalWrite(MOTORB_2,LOW);
}
else if (motor_right_speed < -50) {
digitalWrite(MOTORB_1,LOW);
digitalWrite(MOTORB_2, HIGH);
}
else {
digitalWrite(MOTORB_1, LOW);
digitalWrite(MOTORB_2, LOW);
}
if (motor_left_speed > 50) {
digitalWrite(MOTORA_1, LOW);
digitalWrite(MOTORA_2, HIGH);
}
else if (motor_left_speed < -50) {
digitalWrite(MOTORA_1,HIGH);
digitalWrite(MOTORA_2,LOW);
}
else {
digitalWrite(MOTORA_1, LOW);
digitalWrite(MOTORA_2, LOW);
}
analogWrite(ENA, abs(motor_left_speed));
analogWrite(ENB, abs(motor_right_speed));
if (abs(motor_left_speed > 50) || abs(motor_left_speed > 50)) {
Serial.println("Moving!");
}
delay(50);
}
}