diff --git a/src/livetankdemo.jl b/src/livetankdemo.jl index ba74c63ae1e58a6e5b10eeb891b42f1d24b2d63d..acf4ea5376ce596a62a653a5109f54ef3d10d999 100644 --- a/src/livetankdemo.jl +++ b/src/livetankdemo.jl @@ -1,6 +1,6 @@ using InteractNext, Mux, Plots, LabProcesses, LabConnections, LabGUI include("tankgraphic.jl") -include("doubletank.jl") +include("DoubleTank.jl") include("tanklabgui.jl") diff --git a/src/tankdemo.jl b/src/tankdemo.jl index 927098b313227f9466a7ac949f99a1878fd924ac..037138203a5427dcc9972c7dafd373217a8604fa 100644 --- a/src/tankdemo.jl +++ b/src/tankdemo.jl @@ -1,6 +1,6 @@ using InteractNext, Mux, Plots, LabProcesses, LabGUI include("tankgraphic.jl") -include("doubletank.jl") +include("DoubleTank.jl") include("tanklabgui.jl") R = DoubleTankSimulator(σ = 0.001) diff --git a/src/tankgraphic.jl b/src/tankgraphic.jl new file mode 100644 index 0000000000000000000000000000000000000000..bbe687bcd4edb4c5e07c87830c4409338f3c8aff --- /dev/null +++ b/src/tankgraphic.jl @@ -0,0 +1,164 @@ +using InteractNext, Mux, Plots, LabGUI + +const lightblue = (150, 150, 255) +const wall_thickness = 5 +const mouth_width = 20 +const animationspeed = 1500 + +inspectdr(show=false) + + +function stream(width, height, x, y) + bigstyle = Dict(:fill => "rgb$s_blue") + smallstyle = Dict(:fill => "rgb$lightblue") + lines = 10 + sp = "$(height/animationspeed)s" + thickness = 10 + speed = 10 + ht = height - thickness + attr_small = Dict("width"=> "$(width)", "height" => "$(thickness)", "x" => "$(x)", "y"=>"$(y)") + + #we may want to rethink this a little bit + animate1 = Dict("attributeType" => "XML", "attributeName" => "y", "from" => "$(y)", + "to" => "$(y+ht/2)", "dur" => sp, "repeatCount" => "indefinite") + animate2 = Dict("attributeType" => "XML", "attributeName" => "y", "from" => "$(y+ht/2)", + "to" => "$(y+ht)", "dur" => sp, "repeatCount" => "indefinite") + anim1 = dom"svg:animate"(attributes=animate1) + anim2 = dom"svg:animate"(attributes=animate2) + stline1 = Node(instanceof(dom"svg:rect"()), anim1, style = smallstyle, attributes = attr_small) + stline2 = Node(instanceof(dom"svg:rect"()), anim2, style = smallstyle, attributes = attr_small) + #stlines = (svg_rect(width, thickness, x, y+(speed*time() + i)%ht, smallstyle) + #for i in 0:ht/lines:ht) + #(svg_rect(width, height, x, y, bigstyle), stlines...) + (svg_rect(width, height, x, y, bigstyle), stline1, stline2) +end + + +function water_container(width, height, fill, x=0, y=0) + #Produces an SVG water container of size height, width, filled from the + #bottom to the height fill (as a proportion of height + #fill_level = fill*height + fill_level = fill*height + water_style = Dict(:fill => "rgb$s_blue") + wall_style = Dict(:fill => "rgb$s_black") + container_attr = Dict("x" => "$x", + "y" => "$y", + "width" => "$width", + "height" => "$height") + #svg_rect(width, fill_level, height-fill_level, water_style) + Node(svgsvg_symb, + svg_rect(width, fill_level, 0, height-fill_level, water_style), + svg_rect(wall_thickness, height, 0, 0, wall_style), + svg_rect(wall_thickness, height, width-wall_thickness, 0, wall_style), + svg_rect((width-mouth_width)/2, wall_thickness, 0, height-wall_thickness, wall_style), + svg_rect((width-mouth_width)/2, wall_thickness, (width+mouth_width)/2, height-wall_thickness, wall_style), + attributes = container_attr) +end + + +function tank_construct(upper, lower, pump_speed = 1, tnum = 0, r = -1) + height = 250 + width = 200 + + arrowwidth = 0 + arrowheight= 20 + arrowtext = "" + #level_upper = height*upper + #level_lower = height*lower + upper_x = 75 + upper_y = 100 + lower_x = 75 + lower_y = upper_y + height+50 + + tank_x = 0 + tank_y = upper_y + height*2 + 100 + tank_width = 2*lower_x+width + tank_height = 50 + pipe_thickness = 25 + pd = (pipe_thickness-mouth_width)/2 + pt = pipe_thickness/2 + + if r>=0 && r<=1 + arrowwidth = 20 + end + redarrow = svg_polygon([(upper_x+width, 50+tnum*(height+50)-r*height), + (upper_x+width+arrowwidth, 50+tnum*(height+50)-r*height-arrowheight), + (upper_x+width+arrowwidth, 50+tnum*(height+50)-r*height+arrowheight)], s_red) + pipe = svg_polyline([(pipe_thickness/2, height*2+250), (pt,pt), (tank_width/2, pt), (tank_width/2, 50-pt)], + pipe_thickness, s_black) + funnel = svg_polygon([(tank_width/2, 2*pt), (tank_width/2-pipe_thickness*2, 4*pt), + (tank_width/2+pipe_thickness*2, 4*pt)], s_black) + + + #remove constraints later when controller is bug free + w1 = mouth_width*sqrt(max(0,pump_speed)) + w2 = mouth_width*sqrt(max(0, upper)) + w3 = mouth_width*sqrt(max(0, lower)) + + container1 = water_container(width, height, upper, upper_x, upper_y) + container2 = water_container(width, height, lower, lower_x, lower_y) + + + #The order of svg objects is important, latter elements are laid on top of existing ones + Node(svgsvg_symb, + stream(w1, height+50, upper_x+(width-w1)/2, 50)..., + stream(w2, height+50, upper_x+(width-w2)/2, height+100)..., + stream(w3, 100, upper_x+(width-w3)/2, 2*height+150)..., + container1, container2, redarrow, + #water_container(width, height, upper, upper_x, upper_y), + #water_container(width, height, lower, lower_x, lower_y), + svg_rect(tank_width, tank_height, tank_x, tank_y), + pipe, + funnel, + id = "tank", + attributes = stdattr) +end + +#= +gui = GUI() +widgets, garbage = @construct for upper in 0:16, + lower in 0:16 + Node(:div, "", id = "blarf") +end + +set!(gui, widgets) + +dummy, graphic = @construct for tankvar in 0:1 + tank_construct(gui[:upper]/16, gui[:lower]/16) +end + +add!(gui, dummy) + +widgets2, graphic2 = @construct for t in 0:0.1:10 + plot(linspace(0,2pi), sin.(gui[:lower]*linspace(0,2pi))) + plot!(linspace(0,2pi), cos.(gui[:upper]*linspace(0,2pi))) +end + +add!(gui, widgets2) + +layout = make_grid(2,2) +options_grid = make_grid(2,1) +options_grid = setindex_(options_grid, widgets[1], 1, 1) +options_grid = setindex_(options_grid, widgets[2], 2, 1) +layout = setindex_(layout, options_grid, 1, 1) +layout = setindex_(layout, graphic, 1, 2) +layout = setindex_(layout, garbage, 2, 1) +layout = setindex_(layout, graphic2, 2, 2) + +set!(gui, layout) + + +function initialize() + print("Initializing...\n") + #WebIO.newid() + LabGUI.animate(gui, [:tankvar, :t], [:upper, :lower]) + #animate(gui, :tankvar, 1) +end + +function responder(req) + initialize() + gui.dom +end + +webio_serve(page("/", responder), 8004) +=# diff --git a/src/tanklabgui.jl b/src/tanklabgui.jl new file mode 100644 index 0000000000000000000000000000000000000000..d21a2cfe067abfc121fc704208768c776d97c528 --- /dev/null +++ b/src/tanklabgui.jl @@ -0,0 +1,114 @@ +function makegui(P, plottingframerate = 10, guiframerate = 10) + #tankpid = PID(1.0, 1.0, R.h, 1.0, 1.0, 0.51, 10, P) + tankpid = PID() + scale = 100/16 + boundsupper = (0,1) + boundslower = (-2,2) + maxplotlength = 800 + gui = GUI() + #ptfr = P.α/(P.a1*sqrt(2*P.g*(outputrange(P)[1][2]))) #pump to flow ratio + ptfr = 3.8 #the accuracy here isn't very important + + widgets, graphic1 = @construct for + u in slider(0:0.01:1, label=" u"), + run in button("Run"), #This should only exist in the simulated version + K in slider(0:50, label="K"), + Ti in slider(0:50, label="Ti"), + Td in slider(0:50, label="Td"), + r in slider(0:0.01:1.0, label=" r"), + mode in togglebuttons(["Manual", "Automatic"], label=""), + tankno in togglebuttons(["Upper", "Lower"], label=""), + pOn in togglebuttons(["On", "Off"], label="P"), + iOn in togglebuttons(["On", "Off"], label="I"), + dOn in togglebuttons(["On", "Off"], label="D") + + tankpid.K = K + tankpid.Ti = Ti + tankpid.Td = Td + if tankno=="Upper" + tankg = tank_construct(measure(P)..., u*ptfr, 1, r) + elseif tankno=="Lower" + tankg = tank_construct(measure(P)..., u*ptfr, 2, r) + else + tankg = tank_construct(measure(P)..., u*ptfr) + end + Node(:div, tankg, id="tanks") + end + + w2, graphic2 = @construct for + dummy in checkbox(false, label="This button does nothing") + if length(gui.data[1])>maxplotlength + start = length(gui.data[1])-maxplotlength + else + start=1 + end + p = plot(layout=(2,1), size=(700, 600)) + plot!(p[1], gui.data[1][start:end], label="y", ylim = boundsupper) + plot!(p[1], gui.data[2][start:end], label="r") + plot!(p[2], gui.data[3][start:end], label="P", ylim = boundslower) + plot!(p[2], gui.data[4][start:end], label="I") + plot!(p[2], gui.data[5][start:end], label="D") + plot!(p[2], gui.data[6][start:end], label="Tot", color=:black) + end + + #-----------------------------------------------# + #This should only exist in the simulated version# + on(obs(run)) do val + if val==1 + @async prbs_experiment(P, gui, tankpid) + else + obs(run).listeners[end] = x ->() + end + end + #-----------------------------------------------# + + layout = make_grid(1, 2) + left_element = make_grid(2,1) + settings_element = make_grid(5,1) + corner_element = make_grid(1,4) + + + p_element = make_grid(2,1) + p_element = setindex_(p_element, dom"div"(widgets[:pOn]), 1, 1) + p_element = setindex_(p_element, dom"div"(widgets[:K]), 2, 1) + + i_element = make_grid(2,1) + i_element = setindex_(i_element, dom"div"(widgets[:iOn]), 1, 1) + i_element = setindex_(i_element, dom"div"(widgets[:Ti]), 2, 1) + + d_element = make_grid(2,1) + d_element = setindex_(d_element, dom"div"(widgets[:dOn]), 1, 1) + d_element = setindex_(d_element, dom"div"(widgets[:Td]), 2, 1) + + + settings_element = setindex_(settings_element, dom"div"(widgets[:run]), 1, 1) + #settings_element = setindex_(settings_element, runbutton, 1, 1) + settings_element = setindex_(settings_element, dom"div"(widgets[:tankno]), 2, 1) + settings_element = setindex_(settings_element, dom"div"(widgets[:mode]), 3, 1) + settings_element = setindex_(settings_element, dom"div"(widgets[:r]), 4, 1) + settings_element = setindex_(settings_element, dom"div"(widgets[:u]), 5, 1) + + + corner_element = setindex_(corner_element, settings_element, 1, 1) + corner_element = setindex_(corner_element, p_element, 1, 2) + corner_element = setindex_(corner_element, i_element, 1, 3) + corner_element = setindex_(corner_element, d_element, 1, 4) + + left_element = setindex_(left_element, corner_element, 1, 1) + left_element = setindex_(left_element, graphic2, 2, 1) + layout = setindex_(layout, left_element, 1, 1) + layout = setindex_(layout, graphic1, 1, 2) + + + + LabGUI.set!(gui, widgets) + LabGUI.set!(gui, layout) + add!(gui, w2) + + LabGUI.animate(gui, :u, 1/guiframerate) + LabGUI.animate(gui, :dummy, 1/plottingframerate) + function responder(req) + gui() #With Mux + end + return (gui, responder, tankpid) +end