Joystick/5-position switch to replicate PTZ Controller
Im planning to build a camera controller from either the Parallax joystick or 5-position switch. I dont have the servos yet but am combing through code from forum posts to get an idea of how this will work compared to the security system I currently have. It will eventually be wireless via XBee, but I want to get a hard-wired mock-up working first.
My security system includes a Prosumer-grade PTZ (Pan/Tilt/Zoom) camera that is controlled by a Joystick-equipped controller via RS485. The joystick is spring-loaded to the center position. The cameras Pan and Tilt movements occur while the joystick is not in the center position. The speed of the movement is based on the displacement from the center (neutral) position, i.e. it barely creeps if the joystick is only a few mm from the center but is quite fast when the joystick is at its limit. If the joystick is held at one position, the camera continues to move but at the (steady) speed determined by the displacement from center. When the joystick is released and returns to center, the camera remains at the same position until the joystick is again moved away from the center position. The distance from this center position only determines the speed at which the camera moves:
Since the Parallax joysticks and 5-position switches are spring-loaded to the center (neutral) position, the code examples Ive seen seem like the servos will follow the knob and return to the neutral position when the joystick is released, and not remain at their last positions.
What would be the approach to mimic the PTZ controller described above? The key parameters are:
Servos move anytime joystick is not at center (mandatory)
Servo speed depends on displacement from center (nice to have)
Servo speed remains steady if joystick held stationary away from center
Servos remain stationary when joystick is released. (mandatory)
Thoughts?
falcon
My security system includes a Prosumer-grade PTZ (Pan/Tilt/Zoom) camera that is controlled by a Joystick-equipped controller via RS485. The joystick is spring-loaded to the center position. The cameras Pan and Tilt movements occur while the joystick is not in the center position. The speed of the movement is based on the displacement from the center (neutral) position, i.e. it barely creeps if the joystick is only a few mm from the center but is quite fast when the joystick is at its limit. If the joystick is held at one position, the camera continues to move but at the (steady) speed determined by the displacement from center. When the joystick is released and returns to center, the camera remains at the same position until the joystick is again moved away from the center position. The distance from this center position only determines the speed at which the camera moves:
Since the Parallax joysticks and 5-position switches are spring-loaded to the center (neutral) position, the code examples Ive seen seem like the servos will follow the knob and return to the neutral position when the joystick is released, and not remain at their last positions.
What would be the approach to mimic the PTZ controller described above? The key parameters are:
Servos move anytime joystick is not at center (mandatory)
Servo speed depends on displacement from center (nice to have)
Servo speed remains steady if joystick held stationary away from center
Servos remain stationary when joystick is released. (mandatory)
Thoughts?
falcon

Comments
5-position switch might be a bit harder to implement your second and 3-rd requirements as they seem to be mutually exclusive and require some more states than just the 2 provided by a simple ON-OFF switch.
You have a PTZ camera with a joystick. Does the PT mount not come with servos already?
Do you want to mimic the signal on the RS485 line with your own joystick?
Whatever controller you are using to read the joystick and control the servos can certainly not return to center if that's what you want. It's just a small matter of programming.
Do you have a microcontroller in mind? Reading joystick values (or 5-position switch values) and moving servos are pretty easy stuff for any microcontroller. Mimicking the RS485 joystick controller might be a problem for some microcontrollers.
I mentioned the PTZ controller and camera just as an example of the camera movements I want to mimic with either a BSp or a Prop and two servos. The camera will be mounted to a wheeled robot. All of my experience so far is with the BS2 line, but I will begin the Prop EK soon so that is also an option.
I'm trying to do this with two servos (and eventually XBees) to avoid using a commercial PTZ camera on the robot and having to generate and send the necessary RS-485 signals wirelessly.
kwinn,
The PTZ controller uses a joystick so that was my first thought. But the 5-position switch would be fine if it will work. I understand that the 5-position switch will not allow variable servo speed but that is not a strict requirement. The ability to move the servos and have them remain at a stationary position when the joystick or switch is released is the most important aspect.
falcon
The joystick/servo interaction you're looking for isn't an issue for either the Propeller or a BS2.
One option with the 5-position switch is to have the camera move faster the longer the swich is held in one position.
Depending on your enclosure requirements, there are lots of options to chose from as input devices. One inexpensive input device I really like is the Wii Nunchuck. It would only require two IO pins on a Prop (which could be shared with other I2C devices).
I'd strongly suggest using a some sort of analog input like a joystick instead of a 5-position switch. An analog input (such as joystick or Nunchuck) would allow a lot more control than just on or off inputs.
What camera did you have in mind?
A joystick will be easy enough to use and give you better control, especially if your camera does any kind of zoom.
xanadu,
I have several composite-output bullet video cameras now but all are non-zoom. I'm searching for one that has a zoom function that can be manipulated with a 3rd servo. I have a 1500 mW 900 MHz TX/RX that I plan to use to get that video to my base unit..
I would certainly consider an IP camera if I could get a reliable signal over a 200 yd range through a wooded area. That may require a repeater though.
Do you have a thread on this project, or code and a schematic that you could share?
I appreciate your help.
falcon
If I stay with the BS2 I was planning to use a ServoPal to offload any servo functions. However, it looks more and more like I should use the Propeller for this project.
In that regard, the joystick does seem to be the better choice. I have the Parallax joystick to test with but have just discovered that many use a Playstation controller. With that I could integrate the robot drive control and the PTZ camera function into one controller with buttons left to activate lights and the TX only when required.
I appreciate you taking the time to reply.
falcon
The PlayStation 2 controller is pretty cool. Did you know 12 of the buttons are pressure sensitive? You could use a button to control a servo and control its speed by how hard you're pressing the button. (I need to try this myself soon.)
I haven't added control of the Dual Shock motors yet, but it's on my todo list. If you want to try use the Dual Shock feature before I add it, let me know, and I'll try to move it up on my priority list.
I updated one of the objects for the PS2 to read the analog values of the buttons. My object also automatically updates the joystick and button data from a separate cog. If you try it and have any trouble let me know. I want to make the object easy to use so I'd appreciate the feedback from someone new to the Propeller.
XBees are very nice wirless devices. I have a bunch myself. The problem is they are kind of expensive. I use a lot of Nordic nRF24L01+ modules in my projects. These things are very inexpensive (less than $2.50). You could get 10 of the Nordic modules for the price of one XBee. In some ways the Nordic modules are better than XBees. The Nordic modules have a faster communication rate than XBees partially do to using SPI to communicate rather than asychronous serial. The SPI communication protocol is also what makes the Nordic modules harder to use. I have an object for the Nordic modules and again, if you use it and have any trouble, let me know, and I'll try to help.
As much as I like XBees, it pains me to see how much of the cost of a robot can be increased by price of a couple of XBees.
The servo object that comes with the Propeller tool does a great job. I have a bunch of servo projects myself including my QuickStart servo tester. There's a very simple servo demo in post #15 of that thread. The servo demo in the Prop Tool's "_demo" folder is also fine.
If you have questions about any of the objects I just linked to feel free to ask a question in the object's thread (or start a new thread if you want). I bet you wont be the only one to have those same questions.
The Prop is harder to learn than the BS2, but it's really just about as perfect a microcontroller for robotic projects as you could ask for. It is well worth the effort to learn how to use. People in the Propeller Forum are very helpful. If you get stuck, just ask a question there.
Wouldn't robotics be fun without having to worry if your program loop is short enough to refresh the servos every 20ms?
Pan Tilt action- http://www.youtube.com/watch?v=j_TYHeeWPJ8
Here's my current code - http://dl.dropbox.com/u/79058769/xbee_robot%20w%20ptz%20v9.spin (thanks to the help of this forum)
In my code there is no provision for moving it with an analog joystick, but I'm also controlling it from my PC, not another microcontroller. So basically my project is only good for your camera side.
One thing I noticed off the bat, standard servos only turn 180 degrees. Regular servos can be used with limit switches to give you more viewing options.
1177115618
' {$STAMP BS2} ' {$PBASIC 2.5} ' Running 2 servos with a joystick using RCTIME to record the pot's values. ' Make sure that the JoyStickRCTimeRecorder.bs2 has been run and you have recorded ' the Values for the Max and Min Pot on the Joystick. ' ' Calculate the RCUDMin and RCUDMax scaling using your numbers that you got ' Use this formula to insert it into the Variables settings for TimeUDMin, TimeUDMax, TimeRlMin, TimeRLMax ' TimeMax: YourMaxReadng x (500 / YourMaxReading)= YourMaxReading x YourMinReading ' TimeMin: YourMinReading x (500 / YourMaxReading) scaling and Offset ' Do this for each Pot to start your Sc ' by GWJax '================================================================================= '-------------------------------- Set variables and Pins ------------------------- '================================================================================= RTS PIN 14 ' For Right Servo LTS PIN 15 ' Set Left Servo RCUD PIN 7 ' Set Up Down Pot to pin 7 RCRL PIN 8 ' Set Right Left Pot to pin 8 ScaleUD CON 1100 ' Scale by 0.724 (X 256 for */) 0.724 is from your calculations for Scale Right ' Change 185 to your correct calculation ScaleRL CON 1100 ' Scale for left servo Offset CON 200 ' Offset by 500 TimeUD VAR Word ' Records value for UD RC results TimeRL VAR Word ' Records value for RL RC results CenterUD VAR Word ' Records Center Value CenterRL VAR Word ' Records Center Value '================================================================================= '------------------------------ Main Routine ------------------------------------- '================================================================================= LOW RCUD ' Discharge Cap LOW RCRL ' Discharge Cap 'IF TimeUD = 1 OR TimeUD = 0 THEN GOTO Bug ' Stop program POT failed 'IF TimeRL = 1 OR TimeRL = 0 THEN GOTO Bug ' Stop program POT failed Main: DO GOSUB PotRCTime TimeUD = TimeUD */ ScaleUD TimeUD = TimeUD + Offset TimeRL = TimeRL */ ScaleRL TimeRL = TimeRL + Offset PULSOUT RTS, TimeUD ' Send pulses to servo. PULSOUT LTS, TimeRL PAUSE 18 LOOP '================================================================================= '-------------------------- Get Joystick Center Values --------------------------- '================================================================================= JoyStickCenter: HIGH RCUD PAUSE 1 ' Charge Cap RCTIME RCUD, 1, CenterUD ' Get Recording for TimeUD LOW RCUD ' Discharge UD Cap HIGH RCRL PAUSE 1 ' Charge Cap RCTIME RCRL, 1, CenterRL ' Get Recording for TimeRL LOW RCRL ' Discharge RL Cap RETURN '================================================================================= '------------------------------ Record Pot Values -------------------------------- '================================================================================= PotRCTime: HIGH RCUD PAUSE 1 ' Charge Cap RCTIME RCUD, 1, TimeUD ' Get Recording for TimeUD LOW RCUD ' Discharge UD Cap HIGH RCRL PAUSE 1 ' Charge Cap RCTIME RCRL, 1, TimeRL ' Get Recording for TimeRL LOW RCRL ' Discharge RL Cap RETURN '================================================================================== '------------------------------ Pot Failure --------------------------------------- '================================================================================== Bug: DEBUG "BUG", cr STOWhile going through the WAM text Ver 3.0, page 158 has me record the RC time variables for the pots. I get the following readings:
Left Center Right
L/R 0 30 247
Down Center Down
U/P 0 24 233
After loading the code I see that 95% of the servo travel occur when moving the joystick from the center poisition to either the Right or Up positions. I suppose this is related to the Center time variables of 30 and 24 being now where near the center points. If these values were closer to the center of the range (247/2=124 and 233/2=117) I would see the servo movement more evenly divided.
I under stand the the Endpoints can be scaled and offset to adjust for the actual servo travel. I don't see any mechanical ajustment on the Joystick. Is there any way to compensate for the lopsided center point time values?
falcon
I started, as many do, with some good 'ole Jon Williams code and added the subroutine to move the two servos:
' {$STAMP BS2} ' {$PBASIC 2.5} ' ' ========================================================================= ' -----[ Program Description ]--------------------------------------------- ' This program demonstrates the essential interface between the BASIC ' Stamp and a Sony PlayStation (or compatible) game controller. This ' code assumes that the clock signal is inverted between the Stamp and ' the controller to allow simpler [less sophisticated] interface with ' SHIFTOUT and SHIFTIN. ' ' -----[ Revision History ]------------------------------------------------ ' -----[ I/O Definitions ]------------------------------------------------- PsxAtt PIN 7 ' PSX joystick interface Yellow Wire PsxClk PIN 6 ' PSX joystick interface Blue Wire PsxCmd PIN 5 ' PSX joystick interface Orange Wire PsxDat PIN 4 ' PSX joystick interface Brown Wire UDServo PIN 8 ' Right Servo RLServo PIN 9 ' Left Servo ' -----[ Constants ]------------------------------------------------------- Inverted CON 1 ' inverted clock signal ClockMode CON Inverted ' -----[ Variables ]------------------------------------------------------- idx VAR Byte ' loop counter psxOut VAR Byte ' byte to controller psxIn VAR Byte ' byte from controller psxID VAR Byte ' controller ID psxThumbL VAR Byte ' left thumb buttons psxThumbR VAR Byte ' right thumb buttons psxStatus VAR Byte ' status ($5A) psxJoyRX VAR Byte ' r joystick - X axis psxJoyRY VAR Byte ' r joystick - Y axis psxJoyLX VAR Byte ' l joystick - X axis psxJoyLY VAR Byte ' l joystick - Y axis TimeUD VAR Word ' Records value for UD RC results TimeRL VAR Word ' Records value for RL RC results CenterUD VAR Word ' Records Center Value CenterRL VAR Word ' Records Center Value ScaleY CON 883 ' Scale by 3.52 ScaleX CON 883 ' Scale for left servo Offset CON 210 ' Offset ' -----[ EEPROM Data ]----------------------------------------------------- ' -----[ Initialization PSX Controller]------------------------------------ Setup: HIGH PsxAtt ' deselect PSX controller OUTPUT PsxCmd PsxClk = ~ClockMode ' release clock OUTPUT PsxClk ' make clock an output ' -----[ Program Code ]---------------------------------------------------- Main: DO GOSUB Get_PSX_Packet_Fast ' type and packet DEBUG HOME, "Type = " IF (psxStatus = $5A) THEN DEBUG IHEX2 psxId, " (", IHEX2 psxStatus, ")", CLREOL, CR, CR, BIN8 psxThumbL, " ", BIN8 psxThumbR, " " IF (psxId <> $41) THEN DEBUG DEC3 psxJoyLX, " ", DEC3 psxJoyLY, " ", DEC3 psxJoyRX, " ", DEC3 psxJoyRY, CR, CR ELSE DEBUG CLREOL ENDIF ELSE DEBUG "Unknown. No response.", CR, CLRDN 'PAUSE 1000 ENDIF GOSUB Move_Servos LOOP END ' Transmit psxOut to, and receive psxIn from the ' PSX controller PSX_TxRx: FOR idx = 0 TO 7 PsxCmd = psxOut.LOWBIT(idx) ' setup command bit PsxClk = ClockMode ' clock the bit psxIn.LOWBIT(idx) = PsxDat ' get data bit PsxClk = ~ClockMode ' release clock NEXT RETURN ' This routine combines manual and built-in shifting ' routines to get the best speed and all valid data. ' ' Execution time on BS2 is ~40 ms. Get_PSX_Packet_Fast: 'IF (ClockMode = Direct) THEN Get_PSX_Packet ' redirect if not inverted LOW PsxAtt ' select controller SHIFTOUT PsxCmd, PsxClk, LSBFIRST, [$01] ' send "start" psxOut = $42 : GOSUB PSX_TxRx ' send "get data" psxId = psxIn ' save controller type SHIFTIN PsxDat, PsxClk, LSBPOST, [psxStatus] ' should be $5A ("ready") SHIFTIN PsxDat, PsxClk, LSBPOST, [psxThumbL] SHIFTIN PsxDat, PsxClk, LSBPOST, [psxThumbR] SHIFTIN PsxDat, PsxClk, LSBPOST, [psxJoyRX] SHIFTIN PsxDat, PsxClk, LSBPOST, [psxJoyRY] SHIFTIN PsxDat, PsxClk, LSBPOST, [psxJoyLX] GOSUB PSX_TxRx : psxJoyLY = psxIn HIGH PsxAtt ' deselect controller RETURN Move_Servos: '================Move Servos================= TimeUD = psxJoyRY */ ScaleY 'psxJoyRY = right joystick - Y axis = Up-Down TimeUD = TimeUD + Offset 'psxJoyRY = right joystick - Y axis = Up-Down TimeRL = psxJoyRX */ ScaleX 'psxJoyRX = right joystick - X axis = Left-right TimeRL = TimeRL + Offset 'psxJoyRX = right joystick - X axis = Left-right SELECT TimeUD 'Deadzone to calm servos at neutral position CASE 113 TO 142 GOTO Skip ENDSELECT PULSOUT UDServo, TimeUD ' Send pulses to servo. PULSOUT RLServo, TimeRL PAUSE 18 Skip: RETURNI added the Select-Case statement to introduce a Deadzone since the sticks do not return to the same value when released. This is an old controller so I will source a new one in the near future.
I have servo movement that follows the two joysticks but it very jerky. The servos seems to overshoot the "target" and wiggle back and forth until they settle down to the intended location. I suppose that some of this is due to the nature of having to execute a lot of other code during the loop.
Would the ServoPal be the ticket for eliminating this jittery servo movement by off-loading the servo control from the BS2 code loop? I've read the datasheet but am not quite sure how to implement the nlnp statementy. Is it as easy as adding the Initialization code and replacing the Move_Servos subroutine with the following to include the nInp code?
Move_Servos: '================Move Servos================= TimeUD = psxJoyRY */ ScaleY 'psxJoyRY = right joystick - Y axis = Up-Down TimeUD = TimeUD + Offset 'psxJoyRY = right joystick - Y axis = Up-Down TimeRL = psxJoyRX */ ScaleX 'psxJoyRX = right joystick - X axis = Left-right TimeRL = TimeRL + Offset 'psxJoyRX = right joystick - X axis = Left-right SELECT TimeUD 'Deadzone to calm servos at neutral position CASE 113 TO 142 GOTO Skip ENDSELECT PULSOUT nInp, TimeUD ' Send pulses to servo. PULSOUT nInp, TimeRL ' Send pulses to servo. PAUSE 18 Skip: RETURNfalcon