MK1 VSSS Torpedo

VSSS - video scanning sonar seeker

This is a torpedo made using Wiremod’s e2, that uses a complex image processing technique to find, designate and target submarines and surface vessels in Gmod. The “sonar video feed”, is supplied by a ranger scanner which is realistically limited to only see below the waterline.

This seemingly needless complexity combines to make this by far the most realistic torpedo ever made in Gmod to my knowledge.

It is realistically susceptible to loosing target lock on fast or small targets, countermeasures, and requires rough initial aiming.

Inputs and outputs

WaterLevel: the world z coordinate of the waterline

AttackMode: 1 for surface, 2 for submerged.

InitialDir: optional direction vector input which the torpedo will aim for until it finds a target

Screen[wirelink]: optional visual output of the seeker camera, with overlaid target point and target priority colour coding.

Where to use it

The torpedo is approx 2:1 scale, in order to be most useful in gmod’s small waters. It can be dropped by air, or launched by a surface ship or submerged vessel.

Uses the phx svn and wiremod svn addons.

Go to http://www.wiremod.com/forum/finished-contraptions/21664-mk1-vsss-torpedo.html to download, or read a more in depth description.

you got the ranger scan FAST enough? wow

Yep. Next project will be an air to air missile. Now that is going to be a challenge. :wink:

give it proper interception

The nature of the seeker means interception is not possible without loosing target lock. I don’t feel the low speeds at which ship and submarines travel really warrants the need for velocity interception anyway.

When I make the air to air missile version of this seeker, it will have a (virtual) movable seeker eye, in order to be able to track the target whilst flying on an intercept course.

This whole seeker thing is pretty epic. I reccomend making submarine high frequancy sonar. Can you detail how the stystem works? I’ve done all sorts of things in e2, but nothing with rangerscans

Reasonably hi-speed ranger traces aren’t really all that new, I’ve built a few drone eyes using them. In this case it’s a loop in the E2 that runs a set sequence of local vectors (infront of the torpedo) to built-in ranger traces and retrieves the data from them to compile an image.

Well the ranger scanner works like any other really, with the addition of a chain of code to assign target priority to every pixel scanned(and ignore ones above water). And also modifications to allow two different aspect ratios for the two different attack modes.

Each frame from the video feed is then fed through the seeker algorithm and a target direction vector is outputted.

The whole operation is completed in a fraction of a second, so that the target direction vector is only out of date by a very small amount before the guidance system attempts to follow it. This allows the torpedo to target moving targets and also targets smaller than the resolution of its seeker would otherwise allow.

The applyTorque guidance system then guides the torpedo towards that direction vector.

Edit: Lying, are you saying you’ve just made video scanners before, or you have actually processed the video feed to get to a machine readable output like my seeker does?

Machine readable output.

Cool, I’m interested. Other than Josef’s pathfinder I don’t really recall seeing anything like it. Link to your contraption using it?

No link as I’ve not released anything using it, but here’s a quick commented-out code to demonstrate:


@name Drone grid eye
@persist E:entity Data:table
@persist Bl B

if(first()){
    E=entity()
    
    Bl=3
        #Grid checked is Bl x Bl
        #Tends to redchip at 5+, due mostly to the holograms
    
    B=floor(Bl/2)
    
    for(N=1,Bl^2){
        holoCreate(N)
        holoScaleUnits(N,vec(1,1,1)*10)
    }
    runOnTick(1)
}
V=vec(100,-B*10,B*10)
for(N=1,Bl^2){
        #Target point the trace aims for
    Vec=round(E:toWorld(V)/10)*10
    
    R=rangerOffset(E:pos(),Vec)
        #Point where the trace actually hit
    Land=round(R:position()/10)*10
        #Actually hitting our point is immaterial as
        #the objective is to gain information about 
        #the visible surroundings.
        #If the target is never achieved, it is never 
        #rated and remains unknown. A point surrounded 
        #by world is inaccessible by this method.
    
    H=R:hit() #Did the trace to here hit anything?
    if(H){
            Ent=R:entity()
        M=(Ent ? Ent:id() : 0)
            #Is there an entity here?
                #At its root, this helps navigate player bases 
                #and clutter.
                #As it keeps a record of encountered entities 
                #and their last known location, it can also be
                #used for tracking specific ones.
        P=(Ent:isPlayer()|Ent:isNPC() ? 1 : 0)
            #Is there a player or NPC here?
                #Both can serve as distinctly different hazards
                #compared to the environment
    }
    
    Vector=vec(H,M,P)
    Data[Land:toString(),vector]=Vector
        #Vector value records:
            #Was there something there?
                #As a consequence, empty "air" spaces are never
                #given values, and as zeroes in tables are 
                #dropped, this saves a lot of space.
            #Was it an entity? If so, what ID number?
                #The ID number later helps discern un/frozen state
                #of props, among other things.
            #Was it a player or NPC?
                #Perhaps notably, this eye is blind to *which*
                #when it's recalling the data, though the 
                #entity ID (Vector:y()) can help find out
    
    #Hologram visual controls
    Val=(H ? (!M ? 1 : (P ? 0.75 : 0.5)) : 0)
    holoPos(N,Land) holoAlpha(N,255*Val)
    
    V+=(V:y()>=B*10 ? -vec(0,B*20,10) : vec(0,10,0))
}

Using the Data table, you can use a fairly simple sequential algorithm to find a path through the world based on the values stored in the table.

In this case, the world is divided into 10x10x10 cubes with vector values assigned to them (if indeed there’s anything but air occupying them), so a path can be achieved by looking at the 26 surrounding cubes by working out their world vectors and looking them up in the table, finding the easiest path among them, and just repeating. Using the vector values, you can have the code discern that the order of difficult would be something like:[ol]
[li]Unfrozen, unconstrained prop[ul][/li][li][1,N,0] plus entity(N), E:isFrozen() and E:hasConstraints()[/ul][/li][li]NPC[ul][/li][li][1,N,1] plus entity(N) and E:isNPC()[/ul][/li][li]Unfrozen, constrained prop[ul][/li][li]See #1[/ul][/li][li]Player[ul][/li][li][1,N,1] plus entity(N) and E:isPlayer()[/ul][/li][li]Frozen, unconstrained prop[ul][/li][li]See #1[/ul][/li][li]Frozen & constrained prop[ul][/li][li]See #1[/ul][/li][li]World[ul][/li][*][1,0,0][/ul][/ol]I’ve been testing drones like Cronus with this sort of system, since it doesn’t really need a base entity to work from, just a point in space and a local-to-world conversion.

The “finding the easiest path among them” bit is the interesting bit imo, but I guess that’s what the A* algorithm and others do. I need to learn about path-finding, I am hoping to someday get it real-time enough to use on a cruise missile :smiley:

Awesome i love guided shit.

Well here’s a very simple pathfinder, doesn’t always work (and it really likes to fly) because it doesn’t really think ahead at all, it just chooses the available point with the least distance to the ground and to the owner and goes from there. With 26 possible directions from a given point it is pretty agile though.


@name 
@inputs 
@outputs 
@persist [Dis Open Vecs]:array Box:vector Deg
@trigger 

if(first()){
    E=entity()
    Deg=5
    
    Vecs[1,vector]=vec(1,-1,1)
    Vecs[2,vector]=vec(1,0,1)
    Vecs[3,vector]=vec(1,1,1)
    Vecs[4,vector]=vec(1,-1,0)
    Vecs[5,vector]=vec(1,0,0)
    Vecs[6,vector]=vec(1,1,0)
    Vecs[7,vector]=vec(1,-1,-1)
    Vecs[8,vector]=vec(1,0,-1)
    Vecs[9,vector]=vec(1,1,-1)
    Vecs[10,vector]=vec(0,-1,1)
    Vecs[11,vector]=vec(0,0,1)
    Vecs[12,vector]=vec(0,1,1)
    Vecs[13,vector]=vec(0,-1,0)
    Vecs[14,vector]=vec(0,1,0)
    Vecs[15,vector]=vec(0,-1,-1)
    Vecs[16,vector]=vec(0,0,-1)
    Vecs[17,vector]=vec(0,1,-1)
    Vecs[18,vector]=vec(-1,-1,1)
    Vecs[19,vector]=vec(-1,0,1)
    Vecs[20,vector]=vec(-1,1,1)
    Vecs[21,vector]=vec(-1,-1,0)
    Vecs[22,vector]=vec(-1,0,0)
    Vecs[23,vector]=vec(-1,1,0)
    Vecs[24,vector]=vec(-1,-1,-1)
    Vecs[25,vector]=vec(-1,0,-1)
    Vecs[26,vector]=vec(-1,1,-1)
    
    for(N=1,26){
        holoCreate(N)
        holoScaleUnits(N,vec(1,1,1)*Deg)
        holoAlpha(N,170)
        holoAng(N,ang())
    }
    
    runOnTick(1)
    Box=E:toWorld(E:boxCenter())
}
Own=owner():toWorld(owner():boxCenter())

Dis=array()
Open=array()
for(N=1,26){
    Vec=Box+(Vecs[N,vector]*Deg)
    Vec=round(Vec/Deg)*Deg
    
    R=rangerOffset(Box,Vec)
    
    if(!R:hit()){
        D=Vec:distance(Own)
        
        Dis[N,number]=D
        Open[D,vector]=Vec
    }
    holoColor(N,vec(1,1,1)*255)
    holoPos(N,Vec)
}

if(Dis:count()){
    Box=Open[Dis:min(),vector]
    holoColor(Dis:minIndex(),vec(0,1,0)*255)
}

This is fantastic! Do you mind if I use your ranger code? I have been trying forever to get a good viewscreen for my enterprise and I finally was going to learn GPU, but now I can use this!

That ranger code is far from what you want. If you really can’t just use a cam controller, you’d be better off using a simple depth greyscale video scanner like this;

try this with a 32x32 screen;

Edit: like Lying said, ranger scanners capable of video have been around since before hiSpeed rangers even, I’m surprised so many people here have never seen them (and the similar comments of amazement in multiplayer). They are frikkin simple.

awesome shit. I’ve been trying to make a locking-by-target-speed ranger-based focal pane array for radar and homing, but i’m trying to get a balance between quality and laglessness.
You should make AA missile and SAM missile variants of the same general concept. Always loved realistic guided missiles, but so far I’ve only gotten beam-riding and a SARH guidance to work past the usual “hurp entity vector” crap everyone does.

I think the reason I’ve managed the torpedo is because of its relatively slow speed, so the seeker doesn’t have to be as high performance as an AA missile. I’ve also probably made a few too many ranger scanners in my time lol. Like I said before though, missiles are in the works. I’ve got quite a few ideas of how to optimise seeker performance (basically making it a shitload more complex :p) without actually increasing the number of traces I do.

:smile: My thoughts exactly. Beam riding and SARH are still quite impressive though, just wiki’d them ;).

Thanks a lot! I have tried more than a few systems and I don’t know why I didnt try this. My best try was:


@name Forwards Scanner
@inputs R:entity Update
@outputs X Y Contraption:array I Clk G
@persist Vec2:vector2
@trigger 
interval(100)
if(first()){Contraption = array()}
if(R){Contraption = R:getConstraints()
    Contraption[0,entity] = R}
X = round(entity():toLocal(Contraption[I,entity]:pos()):x()/100)+16
Y = round(entity():toLocal(Contraption[I,entity]:pos()):y()/100)+16
#G = ((Contraption[I,entity]:pos():distance(entity():pos())/3)*-1)+255
G = 255
if(Update){I += 1
    if(I > Contraption:count()){I = 0}
    Clk = 1
}
else{Clk = 0}


I think the real thing was I didn’t try wirelinks, which I only have had experience with on Console Screens. I didn’t need a ranger scanner, per se, but I just needed a way of displaying contraptions on a digital screen. But I like the idea of a scanner better anyways, because it feels more realistic with the slightly low draw rate. This also solves the problem of trying to avoid the map! Anyways, thanks for the help, threadjack over.

AA missile and SAM are the exact same, except AA missile don’t exist SAM = Surface to Air
AA = anti aircraft