Skip to content

Instantly share code, notes, and snippets.

@schreiaj
Last active December 23, 2015 07:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save schreiaj/6604718 to your computer and use it in GitHub Desktop.
Save schreiaj/6604718 to your computer and use it in GitHub Desktop.
FRC Drivetrain Heun
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