Sunday, September 2, 2018

Raspberry Pi servo control using DS4 controller

Raspberry Pi servo control using DS4 controller

In the previous post here,  I successfully connected DS4 controller to Raspberry Pi.
It is time for me to control something using this framework.
The easiest way for me is to control the servo using DS4 input events as I have the servo controller board and tilt & pan servos from Adafruit.
My goal is to use joystick on the DS4 to control the pan & tilt of servo and see how it works.
I expect it would not be so great using joystick as it is a bit sensitive and may be difficult to control servo naturally or precisely. 
Well, let's see how it goes...


Setup
As always, I am using Raspberry Pi 3 Model B (not Plus) for this setup.
The setup looks like this in my environment.
Connecting DS4 to Raspberry Pi can be referred to my previous work here
Also, the using Adafruit servo controller shield board and pan & tilt servo kit can be referred to my previous work here as well.

Adafruit servo controller shield board requires the external power supply but you may be able to use Raspberry Pi 5V by connecting the power and ground pins to the shield board depending on the servo you use.


                          


My approach:
My approach here is to obtain the variation from the default (center) position of the joystick data and convert the number to the servo control signal with a simple scale factor.
Something like this.

    Servo value = (Joystick current value - Joystick center value) x scale factor

To do this, I need to understand the DS4 joystick operation and range of the return values.

There are so many descriptions if you google it but what I did was to add the following line in the python. 

    print (gamepad.capabilities(verbose=True))

This will give you the default value and maximum and minimum value of the each event of the input device.

From this message, left joystick returns 127 as the center value and maximum 255 and minimum 0. 

This means the maximum variation value that I get from joystick is 128 and minimum is -127.

    Maximum variation value = 255 - 127 = 128

    Miminum variation value = 0 - 127 = -127

I just want to move the servo around +/-90 degrees horizontally, and my servo range is as below.

    +90: 570
    0: 370    
    -90: 170

Based on the above, I decided the equation to be like this.

    Servo value = (Joystick current value - 127) x 1/10

One thing that I cannot forget is that I am using evdev and it only returns the input event when there is a change in the value.

This means if I move the joystick to the all the way left or right, the joystick value does not change from the point which results in no servo movement. 



Notes:
Before moving forward, I would recommend to double check the minimum and maximum rotations of your servo. 
Joystick is sensitive and servo might go crazy if the tuning is not done properly.
I would also recommend to place the servo securely with something.

In my case, I used cramp and place it on my desk tightly.


Python code for testing
Now the time to implement the code for both DS4 joystick and servo control.
As I mentioned above and same as my previous work, I used evdev and python for this quick example.
    *** Depending on the python version, you may get different result and my python version is 2.7.13.

If you need the input event numbers of your controller, you can use the following commands to idendify the numbers.


Check input events:
$ ls /dev/input

Install input-utils:
If you do not know which event is mouse or keyboard, follow this.

$ sudo apt-get install input-utils
$ lsinput    

Video:
Here is the video of the quick test.
 

Example:

This is the python example code.

#!/usr/bin/python

from Adafruit_PWM_Servo_Driver import PWM
import time

from evdev import InputDevice, categorize, ecodes, KeyEvent
gamepad = InputDevice('/dev/input/event7')
absMed = 128

pwm = PWM(0x40)

servo0Min = 60
servo0Mid = 360
servo0Max = 660

pwm.setPWMFreq(60)
pwm.setPWM(0, 0, servo0Mid)
time.sleep(1)

step0 = servo0Mid
step0Var = 0

for event in gamepad.read_loop():
    if event.type == ecodes.EV_ABS:
 if event.code == 0 and abs(event.value-absMed) > 20:
  step0Var = (event.value - absMed)/10
  print ('step0Var:' + str(step0Var))
  print ('step0   :' + str(step0))
      step0 += step0Var
  if step0 > servo0Max:
   step0 = servo0Max
  elif step0 < servo0Min:
   step0 = servo0Min
      pwm.setPWM(0, 0, step0)
  step0Var = 0

Crate a python script file as below and copy&paste the above code.
nano ds4-servo-test.py
Run the python script.
python ds4-servo-test.py
Press any buttons on the DS4 and you will see the outputs in the terminal.
Done!



No comments:

Post a Comment