Building an Enhanced Security System with a Web Cam and a Servo

n my previous article: “Teach Your Old Web Cam New Tricks: Use Video Captures in Your .NET Applications,” I showed you how to integrate your Webcam into your Windows application. And in my last couple of articles on DevX.com, I showed you a few ways to control external electronic devices from within your .NET applications. And so, equipped with this knowledge, I am next going to show you how you can build an enhanced security system using a Web cam mounted on a servo, which can be controlled to turn the Web cam in any direction you desire. The system I am building in this article can be deployed at home or at the office to monitor the surroundings.

In this application, you will:

  • learn how to control a servo using a microcontroller
  • learn to program a microcontroller using the PBASIC language
  • learn how to interface a .NET Windows application with a microcontroller so that it can control how the servo turns

What is a Servo?
A servo is basically a motor, except that it allows you to position the output shaft at any specific position you desire. Servos are very useful in robotics and are often found in toys such as remote controlled cars, airplanes, robots, etc.

There are two main types of servos you can use for this project?a standard servo or a continuous rotation servo. A standard servo only allows a limited angle of rotation, while a continuous rotation servo allows the servo to rotate continuously in either direction. For this article I chose a standard servo from vendor Parallax.

Connecting the Servo
Like the two sensors I discussed in my last article, the servo I used cannot be directly connected to the serial port of the PC. Hence, you need a microcontroller to serve as an adapter between the servo and the serial port of your PC. For this purpose, I used the BASIC Stamp 2 (BS2) Module ($49), also from Parallax. The BS2 is a microcontroller that runs at 20MHz and executes roughly 4000 instructions per second. You also need a board to house the BS2 module. I used Parallax’s USB Board of Education (BoE) Development Board ($65). You will control the servo directly by writing code that runs on the BS2. And in this case, the language for programming the BS2 is PBASIC (Parallax’s version of the BASIC programming language).

To connect the servo to the BoE, use three jumper wires and connect as follows (see Figure 1):

  • Connect the black cable (Ground) to the connector labeled Vss.
  • Connect the red cable (5V) to the connector labeled Vdd.
  • Connect the white cable (signal line) to the connector labeled P15.


Figure 1. Connec the servo to the BoE.
?
Figure 2. Mount your Web cam on top of the servo.

Author’s Note: Please refer to my previous article: ?Teach Your Old Web Cam New Tricks: Use Video Captures in Your .NET Applications? for more information on how to connect the BoE to the computer.

Not surprisingly, you also need to mount a Web cam on the horns of the servo. Figure 2 shows my Web cam mounted on the Parallax Standard Servo.

Understanding How Servo Works
A servo is controlled by pulsing its signal line. Pulsing means toggling the voltage of a device by setting it to high for a certain amount of time before setting it to low again. A standard servo can rotate both in the clockwise direction as well as in the anti-clockwise direction and my servo is capable of 180 degree rotation.

The duration of the pulse determines the direction that the servo turns. If the duration of the high pulse (also called the pulse width, see Figure 3) is about 1.5ms, the servo will stay in the middle of the 180 degrees rotation, that is, in the 90 degree position (also known as the neutral position). If it receives a pulse width of less than 1.5ms (such as 1.3ms), then it will turn slightly clockwise. Likewise, it turns slightly anti-clockwise if it receives a pulse width of more than 1.5ms (such as 2ms).

Figure 3. The length of the high point in the pulse train determines the direction of the servo’s rotation.

In order to use the BS2 to control the servo, the PBASIC language supports the PULSOUT function, which generates a pulse. The PULSOUT function has the following syntax:

PULSOUT Pin, Duration

The Pin parameter specifies the pin of the BS2 chip that is connected to the signal line of the servo. The Duration parameter specifies the pulse width. The pulse width is in multiples of 2?s (micro-seconds). Hence, to send a pulse width of 1.5ms (milliseconds) to pin 15, you would need the following arguments:

PULSOUT 15, 750

To get 1.5ms, you multiply 750 by 2?s (two micro-seconds), which is 750 x 2 x 10-6. This gives a total of 1.5ms (milliseconds). To turn the servo clockwise, you can issue something like the following:

PULSOUT 15, 550

To turn it anti-clockwise, the argument looks like this:

PULSOUT 15, 850

The “clockwise-most” duration is 190 and the “anticlockwise-most” position is 1180. So, to turn the web cam as far as possible to the right you would issue:

PULSOUT 15, 190

Likewise, to turn it all the way in the other direction, issue the arguments like this:

PULSOUT 15, 1180
Author’s Note: Actually, in real-life testing, the servo that I have uses a pulse duration of 685 (and not 750) for the neutral position. For discussion purposes, I am going to assume that 750 is the pulse duration for positioning the servo at the center. Check out your own servo for the pulse duration at the neutral position.

One important thing to note is that when you issue a single command like “PULSOUT 15, 190”, the servo does not turn all the way to the final position. Depending on where the current position of the servo is, it may take a few pulses to get to the final position. To do so, repeat the command in PBASIC using an infinite loop, like this:

Start:   PULSOUT 15, 190   PAUSE 20GOTO Start

Here, the PAUSE command simply inserts a delay of 20ms, between the pulses. This delay will affect how smoothly the servo turns. The smaller the delay, the smoother the servo turns. If the delay is too long, then the servo tends to jerk. However, the lower the delay, the more pulses are needed to turn the servo to its intended position. Typically, for a delay of 10ms (the lowest recommended), it does not take more than 40 pulses to move the servo from one end to the other. According to the specification of the Parallax Standard Servo, a pulse delay of 10 to 40ms works well. But the number of pulses needed to get the servo to reach its final destination is dependent on the pulse delay as well as its current position.

To summarize, here are two important points you need to know:

  • The pulse duration indicates the direction you want the servo to turn
  • The pulse delay affects how smoothly the servo turns

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 WordOnce the variables are defined, I'll initialize them:'**********init the values**********RIGHTMOST = 190LEFTMOST = 1180CENTER = 685PAUSE_DURATION = 40         ' the bigger the value, the slower it isCURRENT_POSITION = CENTER   ' always turn to the center pointROTATION_STEP = 20          ' the bigger the value, the more it turnsSCANNING_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   NEXTGOTO 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 = CENTERGOTO 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   ENDIFGOTO 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   ENDIFGOTO 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 = 190LEFTMOST = 1180CENTER = 685PAUSE_DURATION = 40         ' the bigger the value, the slower it isCURRENT_POSITION = CENTER   ' always turn to the center pointROTATION_STEP = 20          ' the bigger the value, the more it turnsSCANNING_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 isCURRENT_POSITION = CENTER   ' always turn to the center pointROTATION_STEP = 20          ' the bigger the value, the more it turnsSCANNING_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 = 190LEFTMOST = 1180CENTER = 685PAUSE_DURATION = 40         ' the bigger the value, the slower it isCURRENT_POSITION = CENTER   ' always turn to the center pointROTATION_STEP = 20          ' the bigger the value, the more it turnsSCANNING_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 command1]    ' Get 1-byte stringCheckCommand:  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  ENDIFGOTO 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 command1]?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 command1]   ' Get 1-byte string   IF command <> "4" THEN        GOTO CheckCommand   ENDIFGOTO 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, _        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.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

The Latest

iOS app development

The Future of iOS App Development: Trends to Watch

When it launched in 2008, the Apple App Store only had 500 apps available. By the first quarter of 2022, the store had about 2.18 million iOS-exclusive apps. Average monthly app releases for the platform reached 34,000 in the first half of 2022, indicating rapid growth in iOS app development.

microsoft careers

Top Careers at Microsoft

Microsoft has gained its position as one of the top companies in the world, and Microsoft careers are flourishing. This multinational company is efficiently developing popular software and computers with other consumer electronics. It is a dream come true for so many people to acquire a high paid, high-prestige job

your company's audio

4 Areas of Your Company Where Your Audio Really Matters

Your company probably relies on audio more than you realize. Whether you’re creating a spoken text message to a colleague or giving a speech, you want your audio to shine. Otherwise, you could cause avoidable friction points and potentially hurt your brand reputation. For example, let’s say you create a