IP camera for video and control

Control Boards, Controllers, Tethers, Ect.
rossrov
Posts: 383
Joined: Feb 28th, 2013, 5:01 pm
Location: Australia

IP camera for video and control

Post by rossrov »

Hello fellow enthusiasts. First time poster here. There may already be details of a similar set-up on the forum, if so forgive me for repetition and ignorance. Hopefully this approach may help some of us get over the control and video hurdle and into the fun stuff such as thrusters, tether and housings, and then develop a better control system over time

New Toy
I started looking at the DIY ROV and robotics forums and commercial sites a few months ago after buying a $60 IP camera as an educational project (new toy for me) with the view of using the pan and tilt motor signals as a means of controlling thrusters over ethernet. Minimal hardware with video and control over 2 pairs.

The Great "Discovery"
Searching the net for more information on said camera while waiting for it to arrive, I found other people had identified a logic-level serial port on the camera's main PCB. These guys were into changing the firmware through this port - that sort of programming a bit beyond me - but there was another who was sending his data out of the serial port by using a command sent down the ethernet cable. Turned out that my camera was a copy of these commonly hacked ones, and that the command codes I was interested in were the same. Much easier and way more elegant than trying to interpret the stepper motor signals!

Edited - credit where credit is due. Found the post that alerted me to the TXD port and how to access it from the browser
ipcgirobot.png
ipcgirobot.png (93.35 KiB) Viewed 12891 times
Thanks Mickey!
http://letsmakerobots.com/node/22674


Three items needed for viewing and control:
1. IP camera ($60 purchased from large online retailer in Australia), warranty voided and two wires soldered on.
2. Microcontroller board with VERY simple program (Atmel M32 programmed in BASCOM, alternatively use Arduino or any similar) to receive serial out from the cam board and convert it to thruster speed control PWM signals.
3. PC running browser to view camera, and to send ROV commands from a simple HTML file on the PC ($200 ASUS netbook works well)

Typical command structure http://169.254.233.196/comm_write.cgi?port=0&baud=13&bytes=6&data=%ff%ff%ff%0f

Note that with this setup the only feedback I have at present is video, with the possibility of encoding very low speed data onto the alarm and mic inputs. Compass bearing etc could be displayed on LCD in edge of camera view. The camera's built-in webserver lets your PC record video, so you could have at least a visual log.

I stopped work on the ROV several months ago due to other commitments and the desire develop better thrusters instead of making another 2 mag-coupled units. So have a housing, electronics, speed control, 1 thruster and a bit of cable but no wet feet yet.


The Experimental User Interface:
After trying to see what was involved in writing a Javascript or some other control window, I decided to just use a mouse-over command in HTML to send the motor commands out of the camera's port. Pretty clunky, a joystick much better, but good as a start and very simple to implement. The test webpage I created is only controlling one motor. In practice you would be sending commands to 3 motors simultaneously. Mixing, as the RC folks call it. Anyway, when mouse-ing over a circular array of "buttons" (actually table cells) the motors speed and direction commands are sent, as if you were clicking an a link in any other webpage. The camera replies and these replies are sent to a junk frame and not used for anything.

I first open the camera's standard display/ control window, then open the HTML file with the table/commands in it in another so it overlays the unwanted part of the "normal" camera control. If you like, you can impress your friends and colleagues by adding your ROV's name to the control page.


Microcontroller:
The camera's serial port sends status messages every once in a while that need to be ignored or "filtered out" by the microcontroller. These are at a higher baud rate, but the camera is forced to send at lower baud that the micro can receive properly each time you want to send something. Some dummy characters (the FFs) are sent by the control webpage to indicate the start of valid data. The program reads and discards these, then reads and uses the motor speed data. Program can be easily changed to control more than 1 motor.

Language Suggestions
If someone has suggestions for an easyish-to-learn Windows PC compatible language that could produce a simple GUI and send data to the camera's address on the network from analog joysticks, then I would be keen to hear. If too complex, then my next step could be a stand-alone controller connected to the network, working alongside the camera's standard display

Cheers,

Ross
Last edited by rossrov on Nov 24th, 2013, 10:40 pm, edited 2 times in total.
rossrov
Posts: 383
Joined: Feb 28th, 2013, 5:01 pm
Location: Australia

Re: IP camera for video and control

Post by rossrov »

Further to previous post.

Camera link below. I had to change its IP address using the software that came with the camera so could connect cat5 patch lead direct to the PC and not through router. Router easier, but I did not have one handy. Very slight but insignificant time delay with commands to motor and video returned

http://www.kogan.com/au/buy/wireless-ip-security-camera/

Document I got the decoder control and comm write details from. Some other functions will probably work also. Do not know what camera the document is specifically for:

http://secomvn.com/Download/IPCAM/QUESTEK%20MJPEG%20IP%20Camera%20CGI%20-English%20Version.pdf




Microcontroller Code in BASCOM BASIC. Size-limited BASCOM compiler for Atmel micros can be downloaded free from MCS electronics. Although limited to 2k, can still do this code and should cope with a few more lines for extra motors. Lots of examples with download, very easy to learn by following examples


'400hz.bas rossrov 5-8-2013

$regfile = "M32def.dat"

Mcusr = &H80 'disables jtag
Mcusr = &H80
$crystal = 4000000
$baud = 9600

Config Timer0 = Timer , Prescale = 1
On Timer0 Count
Enable Timer0
Enable Interrupts
Config Portb.0 = Output
Config Portb.1 = Output
Config Portb.2 = Output
Dim Intcount As Byte
Dim Eport As Byte
Dim Estar As Byte
Dim Evert As Byte
Dim Character As Byte
Dim Portontime As Byte
Dim Starontime As Byte
Dim Vertontime As Byte
Timer0 = 0

Portontime = 19 ' 19=ESC neutral
Starontime = 19
Vertontime = 19

Wait 1


Readserialfromcam:

Character = Waitkey()
If Character <> 254 Then Goto Skip
Character = Waitkey()
If Character <> 254 Then Goto Skip

Eport = Waitkey()
If Eport > 45 Then Goto Skip
If Eport < 29 Then Goto Skip

Estar = Waitkey()
If Estar > 45 Then Goto Skip
If Estar < 29 Then Goto Skip

Evert = Waitkey()
If Evert > 45 Then Goto Skip
If Evert < 29 Then Goto Skip

If Eport = 37 Then Portontime = Eport - 18 'esc neutral
If Eport > 37 Then Portontime = Eport - 16 'forward
If Eport < 37 Then Portontime = Eport - 20 'reverse

If Estar = 37 Then Starontime = Estar - 18
If Estar > 37 Then Starontime = Estar - 16
If Estar < 37 Then Starontime = Estar - 20

If Evert = 37 Then Vertontime = Evert - 18
If Evert > 37 Then Vertontime = Evert - 16
If Evert < 37 Then Vertontime = Evert - 20

Skip:
Goto Readserialfromcam


Count:
Timer0 = 0 'reloads counter

If Intcount = 0 Then Set Portb.2
If Intcount = Vertontime Then Reset Portb.2

If Intcount = 0 Then Set Portb.1
If Intcount = Starontime Then Reset Portb.1

If Intcount = 0 Then Set Portb.0
If Intcount = Portontime Then Reset Portb.0

Incr Intcount

If Intcount = 32 Then Intcount = 0 'interrupts per 400Hz PWM cycle

Return


End
Last edited by rossrov on Aug 4th, 2013, 5:25 pm, edited 1 time in total.
rossrov
Posts: 383
Joined: Feb 28th, 2013, 5:01 pm
Location: Australia

Re: IP camera for video and control

Post by rossrov »

Answering my own question I decided to have a go at learning some Javascript, as plain HTML wouldn't support the mouse wheel for the vertical thruster. So far so good, I will develop further if using the mouse is a usable alternative to joystick.
Probably the biggest test will be how the Ethernet cable works underwater. Working on the "electronics bottle" and getting the ESCs/motors behaving properly for now.
For anyone interested in the IP camera approach you can copy the code below into a new notepad document and save it as cam.html and have a look by opening the document with Internet Explorer. Works in IE8, don't know about others.
Pic attached is the bench test rig. camera still works with the pan and tilt motors simply disconnected. Under the timber is an ATMEGA32 micro in a board with RS232 out that helps when getting things without an LCD going. Gets it's power from same 5V source as the camera. The micro only picks up data coming out of the camera's auxilliary port and turns that into PWM for the ESCs, nothing else.

<!DOCTYPE html>
<html>
<head>
<script>
var y = 0;
var x = 0;
var portmotor = 0;
var starmotor = 0;
var oldportr = 0;
var oldstarr = 0;
var oldvertr=0;
var vertmotor = 37;// 21 (motor off) plus 16 (nibble fix)
var vertindicator = 101;
var portindicator=0;
var starindicator=0;

var hstar = 0;
var hport = 0;
var hvert = 0;
var xold = 0;

var mb = 1
var positionlogged=0
var ob = 1;

var xactual=0;
var yactual=0;
var xoffset=0;
var yoffset=0;

var portr=0;
var starr=0;
var vertr=0;

var fwdbs=44;
var revbs=30;

var vbs=1;
var pbs=1;
var sbs=1;

var vbscompleted=0;
var pbscompleted=0;
var sbscompleted=0;

var powerscale=30;
var allowmousemove=0;





function mymousewheel(e)
{
delta=event.wheelDelta;
if (delta>0)
{
vertmotor= vertmotor+1;
}
else if (delta<0)
{
vertmotor=vertmotor-1;
}
else
{
vertmotor=vertmotor;
}

if (vertmotor>45)//16 added

{
vertmotor=45;
}
else if (vertmotor<29)
{
vertmotor=29;
}
else
{
vertmotor=vertmotor;
}

vertr=vertmotor;
sendtorov();
}


function sendtorov()
{

if(portr!=oldportr)
{
oldportr=portr;
hport=(portr.toString(16));
hstar=(starr.toString(16));
hvert=(vertr.toString(16));
var a="http://169.254.233.196/comm_write.cgi?port=0&;baud=13&;bytes=5&;data=%fe%fe"+"%"+hport+"%"+hstar+"%"+hvert;
window.urltarget.location=a;
portindicator=250+((portmotor-37)*-30);
starindicator=250+((starmotor-37)*-30);
document.getElementById("portdiv").innerHTML=portr;
document.getElementById("stardiv").innerHTML=starr;
}

else if(starr!=oldstarr)
{
oldstarr=starr;
hport=(portr.toString(16));
hstar=(starr.toString(16));
hvert=(vertr.toString(16));
var a="http://169.254.233.196/comm_write.cgi?port=0&;baud=13&;bytes=5&;data=%fe%fe"+"%"+hport+"%"+hstar+"%"+hvert;
window.urltarget.location=a;
portindicator=250+((portmotor-37)*-30);
starindicator=250+((starmotor-37)*-30);
document.getElementById("portdiv").innerHTML=portr;
document.getElementById("stardiv").innerHTML=starr;
}

if(vertr!=oldvertr)
{
oldvertr=vertr;
hport=(portr.toString(16));
hstar=(starr.toString(16));
hvert=(vertr.toString(16));
var a="http://169.254.233.196/comm_write.cgi?port=0&;baud=13&;bytes=5&;data=%fe%fe"+"%"+hport+"%"+hstar+"%"+hvert;
window.urltarget.location=a;

document.getElementById("vertdiv").style.position = "absolute";
document.getElementById("vertdiv").style.left= "140";
document.getElementById("vertdiv").style.fontSize="xx-large";
document.getElementById("vertdiv").innerHTML=vertr-37;
}

}


function mousedown()
{
mb=0;
ob=1;
return;
}




function mouseup() //e

{
mb=1;
positionlogged=0;


//centres divs and stops p and s motors
x=100;
y=100;
ym=(y - 100) *-1;
xm=x -100;


if (y>0)
{
portmotor=(Math.round((ym+xm)/12.5))+21+16;
starmotor=(Math.round((ym-xm)/12.5))+21+16;//add 16 to fix upper nibble problem subtract 16 at micro
}
else
{
portmotor= (Math.round((ym-xm)/12.5))+21+16;
starmotor=(Math.round((ym+xm)/12.5))+21+16;
}


if (portmotor>45)//16 added
{
portmotor=45;
}
else if (portmotor<29)
{
portmotor=29;
}
else
{
portmotor=portmotor;
}
if (starmotor>45)//16 added
{
starmotor=45;
}
else if (starmotor<29)
{
starmotor=29;
}
else
{
starmotor=starmotor;
}

portindicator=250+((portmotor-37)*-30);// 101 div locates from div bottom edge
starindicator=250+((starmotor-37)*-30);// 101 div locates from div bottom edge




document.getElementById("portdiv").style.position = "absolute";
document.getElementById("portdiv").style.left= "0";
document.getElementById("portdiv").style.top= portindicator;


document.getElementById("stardiv").style.position = "absolute";
document.getElementById("stardiv").style.left= "320";
document.getElementById("stardiv").style.top= starindicator;


portr=37
starr=37
sendtorov();
return;
}


function mousemove()

{


if (mb>0)
{
return;
}
else

{
xactual=event.clientX;
yactual=event.clientY;


if (positionlogged<1)
{

xoffset=xactual-100;
yoffset=yactual-100;
positionlogged=1;
}
else
{
x = (xactual-xoffset);
y=yactual-yoffset;
}



ym=(y - 100) *-1;
xm=(x -100)/3;

portmotor=(Math.round((ym+xm)/powerscale))+21+16;
starmotor=(Math.round((ym-xm)/powerscale))+21+16;


if (portmotor>45)//16 added
{
portmotor=45;
}
else if (portmotor<29)
{
portmotor=29;
}
else
{
portmotor=portmotor;
}
if (starmotor>45)//16 added
{
starmotor=45;
}
else if (starmotor<29)
{
starmotor=29;
}
else
{
starmotor=starmotor;
}

portr=portmotor;
starr=starmotor;
sendtorov();


document.getElementById("portdiv").style.position = "absolute";
document.getElementById("portdiv").style.left= "0";
document.getElementById("portdiv").style.top= portindicator;

document.getElementById("stardiv").style.position = "absolute";
document.getElementById("stardiv").style.left= "320";
document.getElementById("stardiv").style.top= starindicator;

}

}


</script>
</head>

<body bgcolor="#000000">

<div id="vertdiv" style="background-color: #ffffff;position:absolute; left:140; top:5;width:60px;height:40px"></div>

<div id="portdiv" style="background-color: #ffffff;position:absolute; left:2; top:101;width:20px;height:20px"></div>
<div id="stardiv" style="background-color: #ffffff;position:absolute; left:320; top:300;width:20px;height:20px"></div>

<div id="bottom" style="color:#000000;position:absolute; left:0; top:0;width:340px;height:510px;border:1px solid" onMouseUp="mouseup()" onMouseMove="mousemove();return false;" onMouseDown="mousedown()" onMouseWheel="mymousewheel()"></div>
<p id="port"></p>
<p id="star"></p>
<p id="vert"></p>

<iframe name="urltarget" width="50" height="50" frameborder="1"></iframe>

</body>

</html>
Attachments
rov bench test rig.jpg
rov bench test rig.jpg (137.27 KiB) Viewed 13880 times
Last edited by rossrov on Aug 16th, 2013, 4:29 pm, edited 1 time in total.
rossrov
Posts: 383
Joined: Feb 28th, 2013, 5:01 pm
Location: Australia

GUI video from ROV

Post by rossrov »

Early days. In future I want to incorporate mouse button press and hold or toggle click to enable motors, and button release or second click to centre the "virtual joystick" and so stop the motors.
Left indicator shows commands sent to port thruster, down is reverse, up forward. Right indicator shows commands sent to starboard thruster, unsuprisingly.
Centre indicator is showing commands sent to vertical thruster from the mouse wheel.
I added the 3 mouseover cells at the bottom to make programming the ESCs easier.
In the returned video to the right of the picture you can see a delay in the movement of the port indicator. The true delay is actually half this because the system is videoing itself so 2 trips through the system.

rossrov
Posts: 383
Joined: Feb 28th, 2013, 5:01 pm
Location: Australia

Re: IP camera for video and control

Post by rossrov »

After altering the micro's code to send 400Hz PWM to the thruster ESCs instead of 50Hz PWM, control is much improved. Also changed the Javascript on the PC so the left mouse button needs to be held down and mouse dragged to command the port and starboard thrusters. Releasing the button resets throttles to neutral. Previous posts edited to show current code.
Limited footage below. Unfortunately the water where I am testing is very cloudy. Stuff grows like crazy in it.




rossrov
Posts: 383
Joined: Feb 28th, 2013, 5:01 pm
Location: Australia

Re: IP camera for video and control

Post by rossrov »

Diagram of the electronics.
Attachments
ip cam rov diagram.jpg
ip cam rov diagram.jpg (243.91 KiB) Viewed 13450 times
CLYON
Posts: 35
Joined: Dec 2nd, 2012, 8:52 am

Re: IP camera for video and control

Post by CLYON »

I love it when people go old school and draw schematics, it takes me back. Do you know how to change the PWM on an Arduino Uno?

Chuck
rossrov
Posts: 383
Joined: Feb 28th, 2013, 5:01 pm
Location: Australia

Re: IP camera for video and control

Post by rossrov »

Thanks Chuck. After over 600 views on this thread nice to get a comment! Short answer is no, I don't know how to do it in Arduino - never done any C programming.
Just did a quick search a moment ago and saw people using 400Hz for their Arduino-based quadcopter ESCs, though for different reasons. There's also a fair bit on how to use timer interrupts for the Arduino too. I have only used the Trackstar 18A ESCs so far, so can't comment on whether other ESCs will be helped or indeed work at all by changing PWM to 400Hz.
fryslan76
Posts: 290
Joined: Dec 18th, 2012, 4:52 pm
Location: Netherlands

Re: IP camera for video and control

Post by fryslan76 »

Hi Rosrov,

Through a post in which you linked to this it came to my attention. You are using the same cam as I am planning on buying for the control. Gonna mount my underwater camera in video modus below the rov later to get good quality video on a SD card.
But how is the delay now working out for you in the water? Do you might have some video or impression of how the camera is holding up in even deeper/ darker water?

Thanks,

Fryslan76
rossrov
Posts: 383
Joined: Feb 28th, 2013, 5:01 pm
Location: Australia

Re: IP camera for video and control

Post by rossrov »

Thanks Fryslan76. Delay is no more than 0.3 second. I have not been more than 4 metres deep but water was very cloudy and as yet have not used any lighting. Images above the water are better than what I expected from a cheap camera like this one. Next ROV project I plan using the same camera...

Surface footage to give idea of camera quality in good conditions
Post Reply