| class HeunSimulation | |
| constructor: (args) -> | |
| @processing = false | |
| #robot properties | |
| @rolling_resistance = args['rolling_resistance'] * 4.448222 | |
| @rolling_resistance_prime = args['rolling_resistance_prime'] * 0.2248089*0.3048 | |
| @drivetrain_efficiency = args['drivetrain_efficiency'] | |
| #motor properties | |
| @motor_stall_torque = args['motor_stall_torque'] * 0.00706155 | |
| @motor_free_speed = args['motor_free_speed']/60*2*3.1415926536 | |
| #mechanical properties | |
| @number_of_motors = args['number_of_motors'] | |
| @gear_ratio = args['gear_ratio'] | |
| @wheel_radius = args['wheel_radius']*2.54/100 | |
| @mass = args['mass']*0.4535924 | |
| @uk = args['uk'] | |
| @us = args['us'] | |
| #simulation properties | |
| @dt = args['dt'] | |
| @duration = args['duration'] | |
| @Vfree = @motor_free_speed*@wheel_radius/@gear_ratio | |
| @mass_in_newtons = @mass*9.80665 | |
| @velocity = 0 | |
| @position = 0 | |
| @slipping = false | |
| @acceleration = 0 | |
| @data = [] | |
| accel: (vel) => | |
| @motor_torque = @motor_stall_torque*(1-vel/@Vfree) | |
| wheel_torque = @drivetrain_efficiency * @motor_torque * @gear_ratio | |
| rolling_resistance_losses = @rolling_resistance + @rolling_resistance_prime * vel | |
| @vehicle_force = wheel_torque/@wheel_radius * @number_of_motors - rolling_resistance_losses | |
| if @vehicle_force < 0 | |
| @vehicle_force = 0 | |
| if @vehicle_force > @mass_in_newtons * @us | |
| @slipping = true | |
| else if @vehicle_force < @mass_in_newtons * @uk | |
| @slipping = false | |
| if @slipping | |
| @vehicle_force = @mass_in_newtons*@uk | |
| @vehicle_force/@mass | |
| heun: () => | |
| for t in [@dt..@duration] by @dt | |
| @processing = true | |
| @temp_velocity = @velocity+@acceleration*@dt | |
| @temp_acceleration = @.accel(@temp_velocity) | |
| @temp_velocity = @velocity+(@acceleration+@temp_acceleration)/2*@dt | |
| @acceleration = @.accel(@temp_velocity) | |
| @position+=(@velocity+@temp_velocity)/2*@dt | |
| @velocity = @temp_velocity | |
| @data.push({t:t, position:@position*3.28083, velocity:@velocity*3.28083, acceleration:@acceleration*3.28083, slipping:@slipping, temp_acceleration:@temp_acceleration, temp_velocity:@temp_velocity, motor_torque:@motor_torque }) | |
| @max_position = @position | |
| @onmessage = (event) -> | |
| sim = new HeunSimulation(event.data) | |
| sim.heun() | |
| postMessage(JSON.stringify(sim)) | |
| // Generated by CoffeeScript 1.6.3 | |
| (function() { | |
| var HeunSimulation, | |
| __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; | |
| HeunSimulation = (function() { | |
| function HeunSimulation(args) { | |
| this.heun = __bind(this.heun, this); | |
| this.accel = __bind(this.accel, this); | |
| this.processing = false; | |
| this.rolling_resistance = args['rolling_resistance'] * 4.448222; | |
| this.rolling_resistance_prime = args['rolling_resistance_prime'] * 0.2248089 * 0.3048; | |
| this.drivetrain_efficiency = args['drivetrain_efficiency']; | |
| this.motor_stall_torque = args['motor_stall_torque'] * 0.00706155; | |
| this.motor_free_speed = args['motor_free_speed'] / 60 * 2 * 3.1415926536; | |
| this.number_of_motors = args['number_of_motors']; | |
| this.gear_ratio = args['gear_ratio']; | |
| this.wheel_radius = args['wheel_radius'] * 2.54 / 100; | |
| this.mass = args['mass'] * 0.4535924; | |
| this.uk = args['uk']; | |
| this.us = args['us']; | |
| this.dt = args['dt']; | |
| this.duration = args['duration']; | |
| this.Vfree = this.motor_free_speed * this.wheel_radius / this.gear_ratio; | |
| this.mass_in_newtons = this.mass * 9.80665; | |
| this.velocity = 0; | |
| this.position = 0; | |
| this.slipping = false; | |
| this.acceleration = 0; | |
| this.data = []; | |
| } | |
| HeunSimulation.prototype.accel = function(vel) { | |
| var rolling_resistance_losses, wheel_torque; | |
| this.motor_torque = this.motor_stall_torque * (1 - vel / this.Vfree); | |
| wheel_torque = this.drivetrain_efficiency * this.motor_torque * this.gear_ratio; | |
| rolling_resistance_losses = this.rolling_resistance + this.rolling_resistance_prime * vel; | |
| this.vehicle_force = wheel_torque / this.wheel_radius * this.number_of_motors - rolling_resistance_losses; | |
| if (this.vehicle_force < 0) { | |
| this.vehicle_force = 0; | |
| } | |
| if (this.vehicle_force > this.mass_in_newtons * this.us) { | |
| this.slipping = true; | |
| } else if (this.vehicle_force < this.mass_in_newtons * this.uk) { | |
| this.slipping = false; | |
| } | |
| if (this.slipping) { | |
| this.vehicle_force = this.mass_in_newtons * this.uk; | |
| } | |
| return this.vehicle_force / this.mass; | |
| }; | |
| HeunSimulation.prototype.heun = function() { | |
| var t, _i, _ref, _ref1, _ref2, _results; | |
| _results = []; | |
| for (t = _i = _ref = this.dt, _ref1 = this.duration, _ref2 = this.dt; _ref2 > 0 ? _i <= _ref1 : _i >= _ref1; t = _i += _ref2) { | |
| this.processing = true; | |
| this.temp_velocity = this.velocity + this.acceleration * this.dt; | |
| this.temp_acceleration = this.accel(this.temp_velocity); | |
| this.temp_velocity = this.velocity + (this.acceleration + this.temp_acceleration) / 2 * this.dt; | |
| this.acceleration = this.accel(this.temp_velocity); | |
| this.position += (this.velocity + this.temp_velocity) / 2 * this.dt; | |
| this.velocity = this.temp_velocity; | |
| this.data.push({ | |
| t: t, | |
| position: this.position * 3.28083, | |
| velocity: this.velocity * 3.28083, | |
| acceleration: this.acceleration * 3.28083, | |
| slipping: this.slipping, | |
| temp_acceleration: this.temp_acceleration, | |
| temp_velocity: this.temp_velocity, | |
| motor_torque: this.motor_torque | |
| }); | |
| _results.push(this.max_position = this.position); | |
| } | |
| return _results; | |
| }; | |
| return HeunSimulation; | |
| })(); | |
| this.onmessage = function(event) { | |
| var sim; | |
| sim = new HeunSimulation(event.data); | |
| sim.heun(); | |
| return postMessage(JSON.stringify(sim)); | |
| }; | |
| }).call(this); |
| <html> | |
| <head> | |
| <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> | |
| <script src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.3.3/d3.min.js" > </script> | |
| <script src="http://jashkenas.github.com/coffee-script/extras/coffee-script.js"> </script> | |
| <script type="text/coffeescript" src="simulation.coffee"></script> | |
| <link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"> | |
| <style type="text/css"> | |
| line{ | |
| shape-rendering: crispEdges; | |
| } | |
| .acceleration{ | |
| stroke:red; | |
| fill:none; | |
| } | |
| .velocity{ | |
| stroke:green; | |
| fill:none; | |
| } | |
| .position{ | |
| stroke:steelblue; | |
| fill:none; | |
| } | |
| .axis{ | |
| font-size: 9px; | |
| } | |
| .axis path, | |
| .axis line { | |
| fill: none; | |
| stroke: #000; | |
| shape-rendering: crispEdges; | |
| } | |
| .x.axis path { | |
| display: none; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="row"> | |
| <div id="canvas" class="col-md-6"> | |
| </div> | |
| <div class="col-md-2"> | |
| <h2>Data</h2> | |
| <form class="" roll="form"> | |
| <div class="form-group"> | |
| <label for="wheel_radius" class="control-label">Wheel Radius (inches)</label> | |
| <input type="wheel_radius" class="form-control input-sm" id="wheel_radius" placeholder="Wheel Radius (inches)" value="3"> | |
| </div> | |
| <div class="form-group"> | |
| <label for="number_of_motors" class="control-label">Number of Motors</label> | |
| <input type="number_of_motors" class="form-control input-sm" id="number_of_motors" placeholder="Number of Motors" value="4"> | |
| </div> | |
| <div class="form-group"> | |
| <label for="gear_reduction" class="control-label">Gear Reduction</label> | |
| <input type="gear_reduction" class="form-control input-sm" id="gear_reduction" placeholder="Gear Reduction" value="12.75"> | |
| </div> | |
| <div class="form-group"> | |
| <label for="duration" class="control-label">Duration</label> | |
| <input type="duration" class="form-control input-sm" id="duration" placeholder="Duration" value="1.0"> | |
| </div> | |
| <button type="button" class="btn btn-primary" onclick="window.recompute()">Recompute</button> | |
| </form> | |
| </div> | |
| </div> | |
| </body> | |
| </html> |
| width = 550 | |
| height = 350 | |
| window.acceleration_scale = d3.scale.linear() | |
| .range([height,50]) | |
| .domain([0,23]) | |
| window.velocity_scale = d3.scale.linear() | |
| .range([height,50]) | |
| .domain([0,12]) | |
| window.position_scale = d3.scale.linear() | |
| .range([height,50]) | |
| .domain([0,8]) | |
| window.time_scale = d3.scale.linear() | |
| .range([50,width]) | |
| .domain([0,1]) | |
| svg = d3.selectAll("#canvas").append("svg") | |
| .attr("width", width+50) | |
| .attr("height", height+50) | |
| window.values = [] | |
| time_axis = d3.svg.axis() | |
| .scale(time_scale) | |
| .orient("bottom") | |
| position_axis = d3.svg.axis() | |
| .scale(time_scale) | |
| .orient("left") | |
| svg.append("g") | |
| .attr("class", "x axis") | |
| .attr("transform", "translate(0," + height + ")") | |
| .attr("id", "time_axis") | |
| .call(time_axis); | |
| # svg.append("g") | |
| # .attr("class", "y axis position_axis") | |
| # .attr("id", "position_axis") | |
| # .attr("transform", "translate(50,0)") | |
| # .call(position_axis); | |
| window.update = () => | |
| svg.selectAll("path").remove() | |
| window.acceleration_scale.domain([0, d3.max(window.values, (d)->d.acceleration)]) | |
| window.velocity_scale.domain([0, d3.max(window.values, (d)->d.velocity)]) | |
| window.position_scale.domain([0, d3.max(window.values, (d)->d.position)]) | |
| window.time_scale.domain([0, d3.max(window.values, (d)->d.t)]) | |
| acceleration_line = d3.svg.line() | |
| .y((d)=> acceleration_scale(d.acceleration)) | |
| .x((d)=> time_scale(d.t)) | |
| velocity_line =d3.svg.line() | |
| .y((d)=> velocity_scale(d.velocity)) | |
| .x((d)=> time_scale(d.t)) | |
| position_line =d3.svg.line() | |
| .y((d)=> position_scale(d.position)) | |
| .x((d)=> time_scale(d.t)) | |
| t = svg.transition().duration(500) | |
| t.select("#time_axis").call(time_axis) | |
| t.select("#position_axis").call(position_axis) | |
| svg.append("path") | |
| .datum(window.values) | |
| .attr("class", "acceleration") | |
| .attr("d", acceleration_line) | |
| svg.append("path") | |
| .datum(window.values) | |
| .attr("class", "velocity") | |
| .attr("d", velocity_line) | |
| svg.append("path") | |
| .datum(window.values) | |
| .attr("class", "position") | |
| .attr("d", position_line) | |
| window.heun =new Worker("acceleration_heun.js") | |
| window.default_params = | |
| rolling_resistance: 10 | |
| rolling_resistance_prime: 1 | |
| drivetrain_efficiency: 0.9 | |
| motor_stall_torque: 343.4 | |
| motor_free_speed: 5310 | |
| number_of_motors: 4 | |
| gear_ratio: 12.75 | |
| wheel_radius: 3 | |
| mass: 150 | |
| us: 1 | |
| uk: .7 | |
| dt: .001 | |
| duration: 1.0 | |
| window.heun.postMessage(window.default_params) | |
| window.recompute = () => | |
| window.heun.postMessage({ | |
| rolling_resistance:10, | |
| rolling_resistance_prime:1, | |
| drivetrain_efficiency:0.9, | |
| motor_stall_torque: 343.4, | |
| motor_free_speed: 5310, | |
| number_of_motors: parseInt($('#number_of_motors').val()), | |
| gear_ratio: parseFloat($('#gear_reduction').val()), | |
| wheel_radius: parseFloat($('#wheel_radius').val()), | |
| mass: 150, | |
| us: 1, | |
| uk: .7, | |
| dt: .001, | |
| duration: parseFloat($('#duration').val()) | |
| }) | |
| window.heun.onmessage = (event) => | |
| console.log event.data | |
| window.values = JSON.parse(event.data).data | |
| window.update() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment