Wanting to try some more advanced form of motor control, I started toying around a bit with airborne balancing platforms, that get their lift and control their movements solely using turbines or propellers. The result from the turbine experiments was in the previous blog post (the Hovercraft Lab). You can see the results from the new propeller version in the following video. The code controlling both this and the hovercraft is very similar for both and you can see it further below in this post.
There are some obvious TODO’s, like in the quadcopter adding a control panel to adjust height and the heading of the copter. Right now I have to turn around and fly it backwards, to fly in the opposite direction… kind of annoying 🙂
It would be possible to add some manipulators hanging below the platform, to clamp and pick up stuff from the ground. Maybe abducting animals could be the next big project here..
Controller code
For reference, here below is the complete quadcopter control code put in the computer (or brain if you will).
All in-game computer code is in Lua, a very simple script-like language.
If you want to insert it into the game without having to enter it, copy and paste it into a text file named for example “user.vbrain.quadcopter.lua” and drop in the world directory in your installation (where the other saves go). When you edit a computer in the game for the first time, it will ask if you want to create it as new, as a shared code or a copy. Select shared or copy and select the quadcopter code in the list that pops up.
-- Mekside Quadcopter demo code v1.0
-- By Realitylabs Game Studios
-- Use/adapt however you want.
-- First some constants:
---------------------------------
-- Starting target height
desired_height = 0.0
-- Target height that can be toggled to with the on/off switch
on_height = 0.45
-- Proportional coefficient of the height PD-regulator
-- (how much we try to reduce errors in height)
hP = 20.0
-- Derivative coefficient of the height PD-regulator
-- (how much we dampen quick height-changes)
hD = 4.0
-- Same PD coefficients for the tilt regulator
rotP = 4.0
rotD = 2.0
tiltcap = 0.05
-- Amount of tilt the control panel input can add
tiltcontrol = 0.2
-- I/O doc
------------------------------------------
-- Outputs (thrusters):
-- 1: left
-- 2: right
-- 3: front
-- 4: back
-- Inputs:
-- 1: Barometer (height)
-- 2: X tilt (positive if the ship tilts "to the left")
-- 3: Y tilt (positive if the ship tilts "backwards")
-- 4: Toggle button panel, on / off
-- 5: Primary control panel x
-- 6: Primary control panel y
-- 7: Secondary control panel rotation input (x)
-- main thrust to use for lift
collective = 0
-- extra thrust to compensate for tilt in the X and Y directions
xrot = 0
yrot = 0
-- Start with -200 so we know it's invalid below on the first iteration
last_height = -200
last_xtilt = -200
last_ytilt = -200
-- This function is called each physics tick, that is 100 times per second
-----------------------------------------------------------
function tick()
-- Check on/off control panel, just toggle the target height
-- (TODO: make another control input to adjust height)
if inputs[4] > 0.5 then
if desired_height > 0 then
desired_height = 0
else
desired_height = on_height
end
end
-- Copy some inputs into better named variables internally
height = inputs[1]
xtilt = inputs[2]
ytilt = inputs[3]
-- The first iteration we have to set some last-variables
if last_height < -100 then
last_height = height
end
if last_xtilt < -100 then
last_xtilt = xtilt
end
if last_ytilt < -100 then
last_ytilt = ytilt
end
-- Get the height-change per second (input is 0 to 1 for the world height)
zspeed = 100 * (height - last_height)
-- Tilt speeds
xtiltspeed = 100 * (xtilt - last_xtilt)
ytiltspeed = 100 * (ytilt - last_ytilt)
-- Deltas (velocities) in height and tilt
dh = desired_height - height
dxtilt = 0 - xtilt
dytilt = 0 - ytilt
-- Cap to sane values so we don't run away if the error is too large
if dh > 0.05 then
dh = 0.05
elseif dh < -0.05 then
dh = -0.05
end
if dxtilt > tiltcap then
dxtilt = tiltcap
elseif dxtilt < -tiltcap then
dxtilt = -tiltcap
end
if dytilt > tiltcap then
dytilt = tiltcap
elseif dytilt < -tiltcap then
dytilt = -tiltcap
end
-- PD regulator for height
collective = hP * dh - hD * zspeed
-- PD regulator for x tilt
xrot = rotP * dxtilt - rotD * xtiltspeed
if xrot < -0.2 then
xrot = -0.2
elseif xrot > 0.2 then
xrot = 0.2
end
-- PD regulator for y tilt
yrot = rotP * dytilt - rotD * ytiltspeed
if yrot < -0.2 then
yrot = -0.2
elseif yrot > 0.2 then
yrot = 0.2
end
-- Add in the control panel contribution, so we can tilt the vehicle a bit in each direction to
-- make it travel there
xrot = xrot - inputs[5] * tiltcontrol
yrot = yrot - inputs[6] * tiltcontrol
-- The secondary control panel x input controls the z-axis rotation
-- by adjusting the total rotational momentum imposed by the
-- counter-rotating rotors
-- TODO: this does not work. Think out why..
zrot = inputs[7] * 0.05
-- Calculate the actual motor speeds for the 4 engines
-- Positive xrot means we try to compensate for turing to the right,
-- so then we should increase the thrust on the right side, and vice versa.
left = math.min(1.0, math.max(0.0, collective - xrot))
right = math.min(1.0, math.max(0.0, collective + xrot))
front = math.min(1.0, math.max(0.0, collective + yrot))
back = math.min(1.0, math.max(0.0, collective - yrot))
-- Write to the outputs
outputs[1] = left + zrot
outputs[2] = -right + zrot
outputs[3] = front + zrot
outputs[4] = -back + zrot
-- Prepare for the next tick so we can calculate deltas
last_height = height
last_xtilt = xtilt
last_ytilt = ytilt
-- End of physics tick
end