You are on page 1of 11

Raspberry Pi Color Tracking Using PID - OscarLiang.

net

http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/

Log in (http://blog.oscarliang.net/wp-login.php) Register (http://blog.oscarliang.net/wp-login.php?action=register)


Build A Quadcopter From Scratch Hardware Overview (http://blog.oscarliang.net/build-a-quadcopter-beginners-tutorial-1/) Fun Projects (http://blog.oscarliang.net/fun-projects-1/)

Raspberry Pi Color Tracking Using PID


Posted on June 30, 2013 (http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/) by Oscar (http://blog.oscarliang.net/author/oscar/)

Project Introduction
In this project I implemented OpenCV color recognition on the Raspberry Pi (http://blog.oscarliang.net/tag/raspberry-pi/) that uses PID to control the pan-tilt servo system. In this post, I will explain briefly how color tracking works, and how to use PID control algorithm to improve tracking performance. Like my previous face recognition tutorial (http://blog.oscarliang.net/raspberry-pi-face-recognition-opencv/), I will be using the Wall-E robot (http://blog.oscarliang.net/wall-e-robot-in-real-life/) in this Raspberry Pi Color Tracking project as an example.

1 of 11

1/23/2014 12:25 PM

Raspberry Pi Color Tracking Using PID - OscarLiang.net

http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/

The Raspberry Pi has relatively small computational capacity compared to a laptop or PC. Because of that you might notice the sluggish result in face recognition. But in color tracking, the result is quite smooth and satisfactory because the computational process is not as complex as face recognition. We can use Raspberry Pi to control the servos directly using interface like ServoBlaster (https://github.com/richardghirst/PiBits/tree/master/ServoBlaster). But instead, I use the Arduino (http://blog.oscarliang.net/tag/arduino/) as a servo controller. Not only its easier to manage, but also there is PID library (http://playground.arduino.cc/Code/PIDLibrary) already available as a library on Arduino (http://arduino.cc/en/). So this is how it works: the Raspberry Pi detects the color, work out the coordinates and send to the Arduino via I2C (http://blog.oscarliang.net/raspberry-pi-arduino-connectedi2c/). The Arduino will then feed the data to the PID controller to calculate how much and to which direction to turn the servos.

2 of 11

1/23/2014 12:25 PM

Raspberry Pi Color Tracking Using PID - OscarLiang.net

http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/

What is PID and How to Use It?


PID is a closed loop control system that is trying to minimize the error. In simple words, it takes the inputs from your sensor, and you tell it what your target set-point is, and it will come up with a output adjustment which aims to help your system to get closer to the set-point.

PID closed loop controller

3 of 11

1/23/2014 12:25 PM

Raspberry Pi Color Tracking Using PID - OscarLiang.net

http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/

To understand more about the PID control system, I found this basic PID tutorial (http://robot-kingdom.com/pid-controller-tutorial-for-robots/) very useful. The most important factor of a optimal PID controller is its three constant parameters. To achieve good performance, we need to play around with different values to see different results. I will also talk about some tuning practices that I found helpful.

How to Use Arduino PID Controller


Using PID on Arduino is very easy, simply follow the instructions on this page (https://github.com/br3ttb/Arduino-PID-Library/) to setup the library and we are good to go! Following the examples provided in the library, its not hard to see how to use it. Basically, we need to: include the library
#include <PID_v1.h&gt

define the necessary variables


double Setpoint, Input, Output;

Construct the PID controller and establish links with the variables, specify the tuning constants
PID myPID(&Input, &Output, &Setpoint, 0.4, 0.4, 0, DIRECT);

Measure input and feed into the PID controller, and retrieve output
Input = meansurement; myPID.Compute(); Adjustment = Output;

Tips on Tuning the PID constants


Depending on how you are using the output to adjust your system, the PID constants parameters will be different, so make sure have settled down on that before you start tuning. Sometimes not all three constants are needed (can be zero), its all down to your requirements and performance. If you dont think some of the constants are helping, then set it to zero. To start with, I usually set all PID constant parameters to 0, and then tune each constant in order, then randomly fine tune each one. P (proportional), the key here is to get a quick strong response without any shake or
4 of 11 1/23/2014 12:25 PM

Raspberry Pi Color Tracking Using PID - OscarLiang.net

http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/

vibration. From a small number and work your way up. The error rate at this point will be high and final accurate leveling will be slow. When this is set too high you will produce a high speed shake. I (integral). The Integral algorithm will add more and more to the corrective action. This can help to balance inherent inconsistencies to the system, smoothing out errors over time. When this is set too high it will produce a slow wobble or oscillation (overshoot?), when its set too low errors will occur (damping effect?). D (derivative). This parameter can have positive effect on overall stability of a mechanical system, i.e. it helps to overcome the inertia faster, etc.

Raspberry Pi Color Tracking and Source Code


Color Tracking using OpenCV is really simple, We basically need to go through this steps on the Raspberry Pi every time. Capture Image Throw away the pixels which are not falling in the range and high-light the pixel which are in the range, so you will see a black image with white dots and puddles. When the detected color has a large enough area, calculate the center position of that color using image moments. Send the position off to. In the source code, we can choose whatever color you want to track. Look for the InRangeS() (http://docs.opencv.org/modules/core/doc /operations_on_arrays.html#cv.InRangeS) function. It takes source, lower bound color, upper bound color and destination. Just replace the lower bound and upper bound colors with the HSV values. You can find this value of your favorite color using Gimp or MS Paint. Note that software like Gimp and MS paint use Hue value ranging from 0-360, Saturation and Value from 0-100%. But OpenCV uses 0-180 for Hue and 0-255 for Saturation and Value. So you need to do some conversion before plugging the values in.
1 2 3 4 5 6 7 8 9 10 # Raspbery Pi Color Tracking Project # Code written by Oscar Liang # 30 Jun 2013 import cv2.cv as cv import smbus bus = smbus.SMBus(1) address = 0x04

5 of 11

1/23/2014 12:25 PM

Raspberry Pi Color Tracking Using PID - OscarLiang.net http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/ 11 def sendData(value): 12 bus.write_byte(address, value) 13 # bus.write_byte_data(address, 0, value) 14 return -1 15 16 def readData(): 17 state = bus.read_byte(address) 18 # number = bus.read_byte_data(address, 1) 19 return state 20 21 def ColorProcess(img): 22 23 # returns thresholded image 24 imgHSV = cv.CreateImage(cv.GetSize(img), 8, 3) 25 # converts BGR image to HSV 26 27 cv.CvtColor(img, imgHSV, cv.CV_BGR2HSV) 28 imgProcessed = cv.CreateImage(cv.GetSize(img), 8, 1) 29 30 # converts the pixel values lying within the range to 255 and stores it in the destination 31 cv.InRangeS(imgHSV, (100, 94, 84), (109, 171, 143), imgProcessed) return imgProcessed 32 33 34 def main(): 35 36 # captured image size, change to whatever you want 37 width = 320 38 height = 240 39 40 capture = cv.CreateCameraCapture(0) 41 # Over-write default captured image size 42 43 cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_WIDTH,width) 44 cv.SetCaptureProperty(capture,cv.CV_CAP_PROP_FRAME_HEIGHT,height) 45 46 cv.NamedWindow( "output", 1 ) 47 cv.NamedWindow( "processed", 1 ) 48 49 while True: 50 51 frame = cv.QueryFrame(capture) 52 cv.Smooth(frame, frame, cv.CV_BLUR, 3) 53 54 imgColorProcessed = ColorProcess(frame) 55 mat = cv.GetMat(imgColorProcessed) 56 57 # Calculating the moments 58 moments = cv.Moments(mat, 0) 59 area = cv.GetCentralMoment(moments, 0, 0) 60 moment10 = cv.GetSpatialMoment(moments, 1, 0) 61 moment01 = cv.GetSpatialMoment(moments, 0,1) 62 63 # Finding a big enough blob 64 if(area > 60000): 65 66 # Calculating the center postition of the blob 67 posX = int(moment10 / area) 68 posY = int(moment01 / area) 69 70 # check slave status and send coordinates 71 state = readData() 72 if state == 1: 73 sendData(posX) 74 sendData(posY) 75 print 'x: ' + str(posX) + ' y: ' + str(posY) 76 77 # update video windows 78 cv.ShowImage("processed", imgColorProcessed) 79 cv.ShowImage("output", frame) 80 6 of 11 1/23/2014 12:25 PM

Raspberry Pi Color Tracking Using PID - OscarLiang.net 81 if cv.WaitKey(10) >= 0: 82 break 83 84 return; 85 86 if __name__ == "__main__": 87 main()

http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/

Sourcecode on The Arduino


The code on the Arduino is mainly about how the servos are controlled by PID and how to use PID. I think I have explained pretty much everything here in the How PID works in Arduino section. One thing I noticed about Arduino PID library is that you have to explicitly specify both negative and positive range of the output like this: myPIDX.SetOutputLimits(-255, 255); Otherwise if the output will only be positive, which means in our case, the servo will only be told to turn right and not the other way. Last note is on the variable called status. It will be set to 0 when we are receiving and executing the command from raspberry pi, tell the pi we are busy and not ready for the next command yet. This is because Color tracking is so fast and the commands are sent more frequent than the Arduino can handle, which the problem we didnt have in face recognition.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 // Raspbery Pi Color Tracking Project // Code written by Oscar Liang // 30 Jun 2013 #include <Wire.h> #include <Servo.h> #include <PID_v1.h> #define SLAVE_ADDRESS 0x04 #define NUM_DATA 2 byte data[NUM_DATA]; byte cur_data_index; byte state; Servo servoNeckX; Servo servoNeckY; const byte servoNeckX_pin = 3; const byte servoNeckY_pin = 4; // Servo Angle constrains (Good Practice! <img src="http://blog.oscarliang.net /wp-includes/images/smilies/icon_smile.gif (http://blog.oscarliang.net /wp-includes/images/smilies/icon_smile.gif)" alt=":)" class="wp-smiley"> const int lrServoMax = 2300; // looking right const int lrServoMin = 700; const int udServoMax = 2100; // looking down const int udServoMin = 750; // looking up // Init Servo Position int posX = 1500;

7 of 11

1/23/2014 12:25 PM

Raspberry Pi Color Tracking Using PID - OscarLiang.net http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/ 31 int posY = 1300; 32 33 // --- Init PID Controller --34 35 //Define Variables we'll be connecting to 36 double SetpointX, InputX, OutputX; 37 double SetpointY, InputY, OutputY; 38 39 //Specify the links and initial tuning parameters 40 // face tracking: 0.8, 0.6, 0 41 // color tracking: 0.4, 0.4, 0 42 PID myPIDX(&InputX, &OutputX, &SetpointX, 0.4, 0.4, 0, DIRECT); 43 PID myPIDY(&InputY, &OutputY, &SetpointY, 0.4, 0.4, 0, DIRECT); 44 45 void setup() { 46 47 // --- I2C Setup --48 49 // initialize i2c as slave 50 Wire.begin(SLAVE_ADDRESS); 51 52 // define callbacks for i2c communication 53 Wire.onReceive(receiveData); 54 Wire.onRequest(sendData); 55 56 // --- Setup PID --57 58 SetpointX = 100; 59 SetpointY = 70; 60 myPIDX.SetOutputLimits(-255, 255); 61 myPIDY.SetOutputLimits(-255, 255); 62 63 //turn PIDs on 64 myPIDX.SetMode(AUTOMATIC); 65 myPIDY.SetMode(AUTOMATIC); 66 // --- Setup Servos --67 68 69 servoNeckX.attach(servoNeckX_pin); 70 servoNeckX.writeMicroseconds(posX); 71 72 servoNeckY.attach(servoNeckY_pin); 73 servoNeckY.writeMicroseconds(posY); 74 75 state = 1; 76 cur_data_index = 0; 77 78 Serial.begin(9600); // start serial for output 79 Serial.println("Ready!"); 80 81 } 82 83 void loop() { 84 delay(20); 85 } 86 87 // callback for received data 88 void receiveData(int byteCount){ 89 90 // Update Slave Status - Occupied 91 state = 0; 92 93 while(Wire.available()) { 94 95 data[cur_data_index++] = Wire.read(); 96 97 // When we have received both X and Y coordinates 98 if(cur_data_index >= NUM_DATA){ 99 cur_data_index = 0; 100 101 // Calculate PID outputs with Inputs 8 of 11 1/23/2014 12:25 PM

Raspberry Pi Color Tracking Using PID - OscarLiang.net http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/ 102 InputX = data[0]; 103 InputY = data[1]; 104 myPIDX.Compute(); 105 myPIDY.Compute(); 106 107 // Update Servo Position 108 posX = constrain(posX + OutputX, lrServoMin, lrServoMax); 109 posY = constrain(posY - OutputY, udServoMin, udServoMax); 110 servoNeckX.writeMicroseconds(posX); 111 servoNeckY.writeMicroseconds(posY); 112 113 // Update Slave Status - Available 114 state = 1; 115 116 } 117 118 } 119 } 120 121 // callback for sending data 122 void sendData(){ 123 Wire.write(state); 124 }

Conclusion
Hope you enjoyed this post and found it helpful :-). Leave me a comment if you have any suggestion or question.

If you find this article useful. To help us maintain and improve this website.

Related Articles:

Raspberry Pi Face

Raspberry Pi and Arduino

Connect Raspberry Pi

Raspberry Pi and Arduino

(http://blog.oscarliang.net (http://blog.oscarliang.net (http://blog.oscarliang.net (http://blog.oscarliang.net


This entry was posted in Featured (http://blog.oscarliang.net/category/featured/), Raspberry Pi /raspberry/raspberry/connect/raspberry-pi-and(http://blog.oscarliang.net/category/raspberry-pi-2/), Robot (http://blog.oscarliang.net/category/robot/) and tagged pi-facepi-arduinoraspberry-pi-andarduinoarduino (http://blog.oscarliang.net/tag/arduino/), raspberry pi (http://blog.oscarliang.net/tag/raspberry-pi/). Bookmark the permalink (http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/).

recognitionopencv/)

connected-i2c/)

arduino-

connected-serialgpio/)

usb-cable/)

9 of 11

1/23/2014 12:25 PM

Raspberry Pi Color Tracking Using PID - OscarLiang.net


Build A Quadcopter From Scratch Hardware Overview (http://blog.oscarliang.net/build-a-quadcopter-beginners-tutorial-1/)

http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/
Fun Projects (http://blog.oscarliang.net/fun-projects-1/)

5 thoughts on Raspberry Pi Color Tracking Using PID


Raspberry Pi Face Recognition Using OpenCV - OscarLiang.net (http://blog.oscarliang.net /raspberry-pi-face-recognition-opencv/) says:
June 30, 2013 at 11:37 pm (http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/#comment-254)

[...] Here is the Arduino code. Note that this code uses a very dummy and basic open loop control method, I only use this because of its simplicity. For a more optimal control method, please see Color Tracking Using PID. [...]
Reply (/raspberry-pi-color-tracking-opencv-pid/?replytocom=254#respond)

Jason M says:
July 3, 2013 at 8:12 pm (http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/#comment-275)

Very Useful, thank!


Reply (/raspberry-pi-color-tracking-opencv-pid/?replytocom=275#respond)

Raspberry PI urmareste culoarea | Robofun Blog (http://robofun.ro/blog/raspberry-pi-urmaresteculoarea/) says:


August 12, 2013 at 8:02 am (http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/#comment-516)

[...] Detalii complete. [...]


Reply (/raspberry-pi-color-tracking-opencv-pid/?replytocom=516#respond)

nutt_Thailand says:
January 15, 2014 at 3:24 am (http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/#comment-1220)

Sorry, Im a rookie I want to know how to connect wire between raspi arduino servo . Thanks, for this : )
Reply (/raspberry-pi-color-tracking-opencv-pid/?replytocom=1220#respond)

10 of 11

1/23/2014 12:25 PM

Raspberry Pi Color Tracking Using PID - OscarLiang.net

http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/

Oscar (http://OscarLiang.net) says:


January 15, 2014 at 11:43 am (http://blog.oscarliang.net/raspberry-pi-color-tracking-opencv-pid/#comment-1226)

Servo is connected to the Arduino, like described here (http://blog.oscarliang.net/how-to-control-a-servo/) Arduino is connected to the RPi via I2C, just like described here (http://blog.oscarliang.net/raspberrypi-arduino-connected-i2c/).
Reply (/raspberry-pi-color-tracking-opencv-pid/?replytocom=1226#respond)

Leave a Reply

11 of 11

1/23/2014 12:25 PM

You might also like