Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Building an Enhanced Security System with a Web Cam and a Servo : Page 2

Once you crack the surface of what's possible using .NET to control hardware devices you may find yourself quickly sucked in to this kind of programming. In this article, learn to control a Web cam mounted on a servo to create a sophisticated monitoring application.


advertisement
Programming the Servo
Now that you understand how servos work and how to make them turn, I'll show you how to put your new knowledge into action and write some PBASIC code. For this purpose, Parallax supplies the BASIC Stamp Editor, which can be downloaded from Parallax's Web site free of charge.

In the BASIC Stamp Editor, create a new BS2 program, and add the following directive at the top of the program to indicate that this is a Basic Stamp 2 program and that it uses PBASIC version 2.5:

' {$STAMP BS2} ' {$PBASIC 2.5}

I'll now define the required variables:


'---I/O pin that is connected to servo--- Servo_pin CON 15 '---minimum pulse duration for clockwise-most--- RIGHTMOST VAR Word '---minimum pulse duration for anti-clockwise-most--- LEFTMOST VAR Word '---center pulse duration--- CENTER VAR Word '---pause duration--- PAUSE_DURATION VAR Word ' the smaller the value, the smoother the turn '---scanning speed--- SCANNING_STEP VAR Word ' the bigger the value, the faster it scans '---used for loop variant--- i VAR Word '---keep track of current position--- CURRENT_POSITION VAR Word '---the step for the turning--- ROTATION_STEP VAR Word Once the variables are defined, I'll initialize them: '**********init the values********** RIGHTMOST = 190 LEFTMOST = 1180 CENTER = 685 PAUSE_DURATION = 40 ' the bigger the value, the slower it is CURRENT_POSITION = CENTER ' always turn to the center point ROTATION_STEP = 20 ' the bigger the value, the more it turns SCANNING_STEP = 1 ' the bigger the value, the faster it scans '***********************************

Scanning from Left to Right and Vice Versa
The first block of code that you will write is to make the servo turn from one direction to another and then vice versa. Essentially, this will later allow you to use the web cam to scan from left to right.

'**********Scanning Mode********** Scan: '---Anti-clockwise sweep--- FOR i = CURRENT_POSITION TO LEFTMOST STEP SCANNING_STEP PULSOUT Servo_pin, i CURRENT_POSITION = i PAUSE PAUSE_DURATION NEXT '---clockwise sweep--- FOR i = CURRENT_POSITION TO RIGHTMOST STEP SCANNING_STEP PULSOUT Servo_pin, i CURRENT_POSITION = i PAUSE PAUSE_DURATION NEXT GOTO Scan '*********************************

As you can see here, the servo first rotates anti-clockwise and then clockwise. It then repeats the whole process again in an infinite loop.

Centralizing the Servo
The next block of code to write is to position the servo at the center of its rotation.

'**********Center********** Centralize: FOR i = 1 TO 40 PULSOUT Servo_pin, CENTER PAUSE PAUSE_DURATION NEXT CURRENT_POSITION = CENTER GOTO Main '**************************

Here, I issued 40 pulses to ensure that there are enough pulses to send the servo to the center of the rotation.

Panning the Servo
You will also write two blocks of code to allow the servo to turn in small increments. This will allow you to tilt your web cam to the desired position:

'**********Turn anti-clockwise********** AntiClockwise: CURRENT_POSITION = CURRENT_POSITION + ROTATION_STEP IF (CURRENT_POSITION <= LEFTMOST) THEN FOR i = 1 TO 10 PULSOUT Servo_pin, CURRENT_POSITION PAUSE PAUSE_DURATION NEXT ELSE CURRENT_POSITION = LEFTMOST ENDIF GOTO Main '*************************************** '**********Turn clockwise********** Clockwise: CURRENT_POSITION = CURRENT_POSITION - ROTATION_STEP IF (CURRENT_POSITION >= RIGHTMOST) THEN FOR i = 1 TO 10 PULSOUT Servo_pin, CURRENT_POSITION PAUSE PAUSE_DURATION NEXT ELSE CURRENT_POSITION = RIGHTMOST ENDIF GOTO Main '***************************************

Testing the Program
To test the program, you can call the blocks of code you have just written (place them after the variable's initialization block), like this (in bold):

'**********init the values********** RIGHTMOST = 190 LEFTMOST = 1180 CENTER = 685 PAUSE_DURATION = 40 ' the bigger the value, the slower it is CURRENT_POSITION = CENTER ' always turn to the center point ROTATION_STEP = 20 ' the bigger the value, the more it turns SCANNING_STEP = 1 ' the bigger the value, the faster it scans '*********************************** Main: GOTO Scan ' or 'GOTO Centralize ' or 'GOTO Scan ' or 'GOTO AntiClockwise ' or 'GOTO Clockwise

Press Ctrl-R to compile the program and copy it into the BS2. (Tip: Change the values of the following variable to see how the servo reacts:)

PAUSE_DURATION = 40 ' the bigger the value, the slower it is CURRENT_POSITION = CENTER ' always turn to the center point ROTATION_STEP = 20 ' the bigger the value, the more it turns SCANNING_STEP = 1 ' the bigger the value, the faster it scans

Passing Data into the BS2
Now that we are able to control the servo by writing a PBASIC program, what about controlling the servo from within a .NET Windows application? But to do that you'd need to do more than connect your application to the BS2; you'd need to pass data into it.

To pass data into the BS2, you need to use the SERIN function in PBASIC. THE SERIN function receives asynchronous serial data through the I/O pins of the BS2. In addition, the BS2 has two dedicated serial input/output pins (Sout and Sin; see Figure 4).

Figure 4. The serial input/output pins of the BS2 are highlighted.
Now I'm going to modify my program so that it can receive incoming data from a Windows application. After the initialization of the variables, declare a byte variable to store the incoming data:

'**********init the values********** RIGHTMOST = 190 LEFTMOST = 1180 CENTER = 685 PAUSE_DURATION = 40 ' the bigger the value, the slower it is CURRENT_POSITION = CENTER ' always turn to the center point ROTATION_STEP = 20 ' the bigger the value, the more it turns SCANNING_STEP = 1 ' the bigger the value, the faster it scans '*********************************** command VAR Byte ' declare a byte variable

Next, modify the Main: label as follows:

Main: SERIN 16, 16468, [STR command\1] ' Get 1-byte string CheckCommand: IF command = "1" THEN GOTO Clockwise ENDIF IF command = "2" THEN GOTO AntiClockwise ENDIF IF command = "3" THEN GOTO Centralize ENDIF IF command = "4" THEN GOTO Scan ENDIF GOTO Main

The SERIN function takes in the following arguments:
  • 16—Specifies the dedicated serial input pin Sin.
  • 16468—the baudmode. This value can be obtained from the help documentation in the Basic Stamp Editor. This value specifies a baud rate of 9600bps, N81.
  • [STR command\1]—indicates that it is expecting a single byte string
Once the data is received, it is checked and the corresponding servo operation is performed by calling the appropriate blocks of code. Note that for simplicity, I am not controlling how fast the servo turns, etc., from my Windows application. For that, you need to modify the BS2 program directly.

Also, you need to modify the block of code for scanning. If you observe, the scanning process is in an infinite loop, and once it is started there is no way to stop it. Hence we need to insert the code (in bold) below so that after rotating one complete cycle, it waits for incoming data for one second before it continues with the scanning:

'**********Scanning Mode********** Scan: '---Anti-clockwise sweep--- FOR i = CURRENT_POSITION TO LEFTMOST STEP SCANNING_STEP PULSOUT Servo_pin, i CURRENT_POSITION = i PAUSE PAUSE_DURATION NEXT '---clockwise sweep--- FOR i = CURRENT_POSITION TO RIGHTMOST STEP SCANNING_STEP PULSOUT Servo_pin, i CURRENT_POSITION = i PAUSE PAUSE_DURATION NEXT SERIN 16, 16468, 1000, Scan, [STR command\1] ' Get 1-byte string IF command <> "4" THEN GOTO CheckCommand ENDIF GOTO Scan '*********************************

The additional arguments of the SERIN function are:
  • 1000—the timeout period in ms to wait for incoming data before control is transferred to the specified label (the next argument)
  • Scan—the label to jump to if timeout occurs
If incoming data is not received within one second, the servo continues its scanning. If a data is received and the value is not 4, then control is transferred to CheckCommand so that the appropriate action can be taken. Listing 1 lists the BS2 program in its entirety.

Building the Windows Application
You are now ready to build the Windows application to communicate with the BS2 program that you have written so that you can control the servo with the webcam mounted. Using Visual Studio 2005, create a new Windows application and name it C:\EnhancedSecurityWebcam.

In the default Form1, populate it with the following controls (see also Figure 5):

  • PictureBox
  • Button
Figure 5. Populate the default Form1 with the controls shown.
As I will be adapting the code that I have used for my earlier article ("Teach Your Old Web Cam New Tricks: Use Video Captures in Your .NET Applications"); I will not be explaining the code on how to integrate your Web cam into your Windows application. For that, please refer to the earlier article.

Switch to the code-behind of Form1 and import the following namespace:

Imports System.Runtime.InteropServices

Add the following constants to the form:

Public Class Form1 Const WM_CAP_START = &H400S Const WS_CHILD = &H40000000 Const WS_VISIBLE = &H10000000 Const WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10 Const WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11 Const WM_CAP_EDIT_COPY = WM_CAP_START + 30 Const WM_CAP_SEQUENCE = WM_CAP_START + 62 Const WM_CAP_FILE_SAVEAS = WM_CAP_START + 23 Const WM_CAP_SET_SCALE = WM_CAP_START + 53 Const WM_CAP_SET_PREVIEWRATE = WM_CAP_START + 52 Const WM_CAP_SET_PREVIEW = WM_CAP_START + 50 Const SWP_NOMOVE = &H2S Const SWP_NOSIZE = 1 Const SWP_NOZORDER = &H4S Const HWND_BOTTOM = 1

Also, declare the following functions so that you can use P/Invoke to display the video captured by your Web cam in your Windows application:

'--The capGetDriverDescription function retrieves the version ' description of the capture driver-- Declare Function capGetDriverDescriptionA Lib "avicap32.dll" _ (ByVal wDriverIndex As Short, _ ByVal lpszName As String, ByVal cbName As Integer, _ ByVal lpszVer As String, _ ByVal cbVer As Integer) As Boolean '--The capCreateCaptureWindow function creates a capture window-- Declare Function capCreateCaptureWindowA Lib "avicap32.dll" _ (ByVal lpszWindowName As String, ByVal dwStyle As Integer, _ ByVal x As Integer, ByVal y As Integer, ByVal nWidth As _ Integer, _ ByVal nHeight As Short, ByVal hWnd As Integer, _ ByVal nID As Integer) As Integer '--This function sends the specified message to a window or ' windows-- Declare Function SendMessage Lib "user32" Alias "SendMessageA" _ (ByVal hwnd As Integer, ByVal Msg As Integer, _ ByVal wParam As Integer, _ <MarshalAs(UnmanagedType.AsAny)> ByVal lParam As Object) As _ Integer '--Sets the position of the window relative to the screen buffer-- Declare Function SetWindowPos Lib "user32" Alias "SetWindowPos" _ (ByVal hwnd As Integer, _ ByVal hWndInsertAfter As Integer, ByVal x As Integer, _ ByVal y As Integer, _ ByVal cx As Integer, ByVal cy As Integer, _ ByVal wFlags As Integer) As Integer '--This function destroys the specified window-- Declare Function DestroyWindow Lib "user32" _ (ByVal hndw As Integer) As Boolean

Next, declare a variable to be used as the window handle (required for the Web cam):

'---used as a window handle--- Dim hWnd As Integer

Also declare a SerialPort variable so that you can communicate with the BS2 using serial port communication:

Private WithEvents serialPort As New IO.Ports.SerialPort

Define the PreviewVideo() subroutine so that the images from the Webcam can be bound to a PictureBox control:

'---preview the selected video source--- Private Sub PreviewVideo(ByVal pbCtrl As PictureBox) hWnd = capCreateCaptureWindowA(0, _ WS_VISIBLE Or WS_CHILD, 0, 0, 0, _ 0, pbCtrl.Handle.ToInt32, 0) If SendMessage( _ hWnd, WM_CAP_DRIVER_CONNECT, _ 0, 0) Then '---set the preview scale--- SendMessage(hWnd, WM_CAP_SET_SCALE, True, 0) '---set the preview rate (ms)--- SendMessage(hWnd, WM_CAP_SET_PREVIEWRATE, 30, 0) '---start previewing the image--- SendMessage(hWnd, WM_CAP_SET_PREVIEW, True, 0) '---resize window to fit in PictureBox control--- SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, _ pbCtrl.Width, pbCtrl.Height, _ SWP_NOMOVE Or SWP_NOZORDER) Else '--error connecting to video source--- DestroyWindow(hWnd) End If End Sub

When the form is loaded, load the images from the Web cam and then open a serial connection to the BS2 (assuming that the BoE is connected to your computer via COM port 3):

Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load '---preview the selected video source PreviewVideo(PictureBox1) If serialPort.IsOpen Then serialPort.Close() End If Try With serialPort .PortName = "COM3" .BaudRate = 9600 .Parity = IO.Ports.Parity.None .DataBits = 8 .StopBits = IO.Ports.StopBits.One .Handshake = IO.Ports.Handshake.None End With serialPort.Open() Catch ex As Exception MsgBox(ex.ToString) End Try End Sub

Finally, wire up all the Button controls so that you can send the appropriate command to the BS2:

Private Sub btnCentralized_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnCentralized.Click serialPort.Write("3") '---centralize the webcam--- End Sub Private Sub btnClockwise_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnClockwise.Click serialPort.Write("1") '---turn the webcam clockwise--- End Sub Private Sub btnAnticlockwise_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnAnticlockwise.Click serialPort.Write("2") '---turn the webcam anti-clockwise--- End Sub Private Sub btnScan_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnScan.Click serialPort.Write("4") '---scanning using the webcam End Sub

That's it! You are now ready to give the application a try. Press F5 to start the application. You should be able to see the images from the Web cam. You can also click on the various buttons to rotate the Webcam. Figures 6 and 7 are short 10-second videos that demonstrate the functionality built in this article. Figure 6 shows moving the camera clockwise and anti-colockwise while Figure 7 shows the scanning functionality.


Figure 6. This 10-second movie shows you how the buttons are used to turn the web cam left and right. Click the play button twice to start the movie.
 
Figure 7. This 10-second movie shows you how the scan button can be used to pan the camera steadily from one side to the other. Click the play button twice to start the movie.



Wei-Meng Lee is a Microsoft MVP and founder of Developer Learning Solutions, a technology company specializing in hands-on training on the latest Microsoft technologies. He is an established developer and trainer specializing in .NET and wireless technologies. Wei-Meng speaks regularly at international conferences and has authored and coauthored numerous books on .NET, XML, and wireless technologies. He writes extensively on topics ranging from .NET to Mac OS X. He is also the author of the .NET Compact Framework Pocket Guide, ASP.NET 2.0: A Developer's Notebook (both from O'Reilly Media, Inc.), and Programming Sudoku (Apress). Here is Wei-Meng's blog.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap