在Arduino项目中使用PS2游戏控制器

  • 内容
  • 评论
  • 相关

PS3手柄连接Arduino这篇文章中,我们了解到PS3手柄要实现与Arduino的连接,必须通过USB HOST shield扩展板,并且需要加载 USB Host Library 才能实现。今天来了解一下, 在Arduino项目中如何使用Playstation 2游戏控制器 。

PS2手柄

Playstation的游戏控制器从开发至今已经非常完美了,它设计精良且功能强大,非常适合作为Arduino项目的控制端使用,比如遥控车、机械臂和多足机器人。尽管Playstation 2游戏机已经过时了,但Playstation 2的游戏控制器却仍在大量生产,我们可以通过很低的价格购买到。

不仅如此,PS2游戏手柄可以很容易的连接到Arduino,它还包含了两个高品质的操纵杆,同时所有的按钮都是压敏的,这就为操控设备增加了更多的功能。

下面我们将演示了如何将Playstation 2游戏控制器连接到Arduino,以及如何使用PS2Xlib Arduino库轻松地控制各种设备。

将PS2游戏控制器连接到Arduino

要将PS2控制器连接到Arduino有两个选择。粗暴的方法是切断连接器的电缆,将电线直接焊接到排针上。下图中的电线颜色可以帮助我们识别电线的功能(比如白灰色的电线是震动电机7V-9V的供电线)。

PS2手柄接口定义
PS2手柄接口定义

另一种方法是保留手柄原有接口,购买接口电路板实现。 下图是Playstation 2手柄的接口定义。为了连接Arduino,我们只需要连接Data、Command、GND、3.3V、Attention、Clock即可。如果需要震动反馈功能,震动电机的针需要连接到7-9V的电源上。

 PS2手柄接口定义
PS2手柄接口定义

软件方面

说到软件,就一定要提到 Bill Porter,他编写了一个针对PS2手柄的库,这个库可以方便用户通过Arduino使用Playstation 2游戏控制器。这个库就是 PS2X library ,它的源代码我们可以从Github获得。下载后,将得到一个zip文件,这时可以通过Arduino IDE的导入ZIP库文件功能,直接导入 PS2X library 。

Arduino IDE的导入ZIP库文件
Arduino IDE的导入ZIP库文件

库中包含的示例文件可以很好地展示库的功能,和利用Playstation 2控制器的所有特性,它涵盖了使用Playstation 2控制器来驱动电机、舵机、伺服器和开关所需的基本内容。

要在Arduino中使用库,需要使用以下命令调用它:

#include <PS2X_lib.h> 
PS2X ps2x; 

在代码的 setup 部分,要让Arduino知道PS2控制器是如何连接到它的,命令如下:

 ps2x.config_gamepad(5,4,3,2, false, false); 

代码中的数字为Arduino的数字引脚,对应Playstation 2控制器引脚连接如下:

PS2手柄 :clock、 command、attention、 data、 压力灵敏度enabled、震动反馈 enabled。

如果想使用按钮的压力敏感功能,在上面的命令行中,你会把这个设置为“true”,如果想让震动提供反馈,也把对应值设置为“true”。要使用震动反馈特性,请详细查看PS2X library 附带的示例文件。

PS2控制器连接设置好后,Arduino就会不断地循环执行。每次循环完成后,Arduino均与PS2控制器完成通信并收集所有的输入数据。这个过程是通过以下命令完成的:

ps2x.read_gamepad(); 

PS2游戏手柄的按键功能

在PS2X库中使用的标签非常符合逻辑。下图显示了按钮和操作杆对应的名称。

PS2按钮和操作杆的标签
PS2按钮和操作杆的标签

上图中为彩色的按钮可以通过对应的名称来引用,如:

PSB_TRIANGLE, PSB_CIRCLE, PSB_CROSS, and PSB_SQUARE. 

在使用模拟的压感灵敏度功能时,前缀需要用“PSAB”代替“PSB”外,键名是相同的。比如,要允许绿色三角形按钮使用压力灵敏度时,名称应该是“PSAB_GREEN”或“PSAB_TRIANGLE”。

PS2按钮的操作有很多种,比如可以按下,按住保持,或不同的压力按下,所以也有许多 methods 可以应用于按钮和操纵杆。这些 methods 在PS2X库中包括 :
Button Pressed, Button, 和 Analog. 下面是一些如何使用这些方法的例子。

  1. ps2x.ButtonPressed(PSB_RED) 表示简单的按下红色圆圈按钮 。
  2. ps2x.Button(PSB_PAD_DOWN) 表示持续按住向下按钮。
  3. ps2x.Analog(PSAB_CROSS) 表示用于测量施加到“X”按钮上的压力(如果启用了压力灵敏度)。按钮前缀已经使用了“PSAB”的形式。
  4. ps2x.Analog(PSS_RY) 获取垂直方向上正确的模拟摇杆读数的命令。

PS2连接Arduino的实际运用

为了更深入说明PS2X库的使用,这里引入一个示例项目,它利用直流电机、电子速度控制器、一系列伺服电机和一个7-12V的LED阵列。如果将这些应用到实际项目中,它可能是一辆带有方向盘的汽车,包含两个额外的伺服电机来控制一个平移和倾斜支架,其他高电压和大电流的设备也可以由这样的系统触发。

下面是电路元件的示意图。ESC向伺服电机提供5.6V的电源。除此之外,连接Playstation 2游戏控制器和LED晶体管需要有三个1K的电阻,图中电容器不是必须的,因为电池供电已经能够提供一个相对平稳的电源。

PS2连接Arduino的实际运用

PS2连接Arduino的实际运用

接下来,定义我们想要使用的功能项,包括:一个用于开关LED的功能,两个模拟操纵杆来驱动伺服电机和ESC。对应PS2手柄,功能项对应按键如下图:

 PS2手柄功能区
PS2手柄功能区

控制代码

/*
以下代码演示了如何使用PS2游戏控制器来控制一系列伺服电机和电子速度控制器(ESC)和一个LED灯。
对应的接口连接如下:
1、Arduino 3.3V ——> PS2 3.3V
2、Arduino 5V ——> 两个1K上拉电阻的中点
3、Arduino D02 ——> PS2 data
4、Arduino D03 ——> PS2 attention
5、Arduino D04 ——> PS2 command
6、Arduino D05 ——> PS2 clock
7、Arduino D06 ——> ESC Signal 
8、Arduino D07 ——> 转向舵机 Signal
9、Arduino D08 ——> Servo 1 Signal
10、Arduino D09 ——> Servo 2 Signal
11、ArduinoPin D13 ——> LED 晶体管基极

该代码使用了Bill Porter开发的PS2X库。
控制关系为:
右侧摇杆:X-axis = Steering Servo left/right, 
         Y-axis = ESC forward/backward
左侧摇杆:X-axis = Servo 2 left/right, 
         Y-axis = Servo 1 left/right
三角形按钮(Triangle) = Toggle the LED
*/


#include <Servo.h>  //引入servo库
#include <PS2X_lib.h> // 引入PS2X库

PS2X ps2x;  //PS2控制器类
Servo SteeringServo;  //创建表示转向舵机的对象
Servo ServoN1;  //创建表示舵机1的对象
Servo ServoN2;  //创建表示舵机2的对象
Servo ESCcontrol;  //创建代表ESC的对象

const int LEDpin = 13;  //绿色LED在数字引脚13上

volatile boolean LEDHdlts; //LED开关

int PlyStnRStickUpDn = 0;  //读取PS2右侧摇杆向上/向下的值.
int PlyStnRStickLtRt = 0;  //读取PS2右侧摇杆向左/向右的值. 
int PlyStnLStickUpDn = 0; //读取PS2左侧摇杆向上/向下的值.
int PlyStnLStickLtRt = 0; //读取PS2左侧摇杆向左/向右的值.

int ESCSetting = 90; //设置ESC(角度).
int StrServoSetting = 90; //转向舵机的角度设置
int ServoN1Setting = 90; //舵机1的角度设置
int ServoN2Setting = 90; //舵机2的角度设置


void setup()
{
  ps2x.config_gamepad(5,4,3,2, false, false);
  //手柄的针设置:clock, command, attention, data, Pressures, Rumble
  //禁用了压力灵敏度和震动反馈.
  pinMode(LEDpin, OUTPUT);  //设置LED输出

  LEDHdlts = false;  //车头灯关闭
  SteeringServo.attach(7);// 将转向舵机连接到数字7脚
  ServoN1.attach(8);// 将舵机1连接到数字8脚
  ServoN2.attach(9);// 将舵机2连接到数字8脚
  ESCcontrol.attach(6,150,2250);// 将ESC连接到数字6脚
  //上面的ESC命令还包括信号设置,值为ESC的最大值和最小值.
  //不同的ESC这个值会不一样.

  //将ESC和舵机置中90度.
  ESCcontrol.write(90);
  SteeringServo.write(90);
  ServoN1.write(90);
  ServoN2.write(90);
  delay(5000); //延迟5秒,等待ESC和控制器完全初始化.

}

void loop()
{
  ps2x.read_gamepad(); //至少每秒调用一次,以便从控制器获取数据.

  if(ps2x.ButtonPressed(PSB_GREEN))  //三角按钮按下
  {
    LEDHdlts = !LEDHdlts; //切换LED灯标记
  }


//Analogue Stick readings
  PlyStnRStickUpDn = ps2x.Analog(PSS_RY); //右侧摇杆上/下
  PlyStnRStickLtRt = ps2x.Analog(PSS_RX); //右侧摇杆左/右
  PlyStnLStickUpDn = ps2x.Analog(PSS_LY); //左侧摇杆上/下
  PlyStnLStickLtRt = ps2x.Analog(PSS_LX); //左侧摇杆左/右

//PS2控制器的读数从0到255,中性点是128.对于x轴运动,0点在左边,对于y轴运动,0点在上面.

//变量,用于存储ESCs和Servos的值. 
//PS2摇杆的值将映射到0到180度.
  ESCSetting = map(PlyStnRStickUpDn,-256,256,0,179);
  StrServoSetting = map(PlyStnRStickLtRt,-256,256,0,179);
  ServoN1Setting = map(PlyStnLStickUpDn,-256,256,0,179);
  ServoN2Setting = map(PlyStnLStickLtRt,-256,256,0,179);

//将值写入到Servos或ESCs 
  ESCcontrol.write(ESCSetting);
  SteeringServo.write(StrServoSetting);
  ServoN1.write(ServoN1Setting);
  ServoN2.write(ServoN2Setting);

  digitalWrite(LEDpin,LEDHdlts); //根据LED灯的状态标志点亮LED
  delay(15);
}

当一切就绪后,连接电池后,就能够通过按下三角形按钮来点亮LED,移动操纵杆来控制舵机和运行电机了。