
vehicle
Où se trouve le véhicule Create Aeronautics qui porte l'ordinateur, et à quelle vitesse il va.
La bibliothèque vehicle indique à un ordinateur où il se trouve dans le monde et comment il se déplace. Elle est faite pour les ordinateurs embarqués sur un véhicule Create Aeronautics (un dirigeable, un ballon, une plateforme volante) : grâce à elle, un Microcontrôleur devient compteur de vitesse, enregistreur de vol, pilote automatique ou balise qui signale la position du navire à la base.
local p = vehicle.position()
print("Position : " .. p.x .. " " .. p.y .. " " .. p.z)
print("Vitesse : " .. vehicle.speed() .. " blocs/s")À savoir avant de commencer :
- Quels ordinateurs. Le Micro-ordinateur, le Microcontrôleur et l'Ordinateur moderne l'ont. Sur les plus anciens,
vehiclevautnil. - Positions réelles. Create Aeronautics range les blocs d'un véhicule à part du monde, à des coordonnées très éloignées de l'endroit où il vole vraiment.
vehicle.position()répond toujours avec la vraie place dans le monde, celle que vous lisez avec F3 en vous tenant à côté du navire. Les portées radio utilisent ces mêmes positions réelles (voirRéseaux). - Au sol aussi. Un ordinateur qui n'est pas sur un véhicule est son propre véhicule, à l'arrêt :
vehicle.position()donne la place de l'ordinateur,vehicle.velocity()donne zéro,vehicle.name()donnenil. Sans Create Aeronautics installé, tous les ordinateurs sont dans ce cas. Une tour de contrôle peut donc se servir des mêmes fonctions que ses navires. - Unités et arrondis. Les positions sont en blocs, les vitesses en blocs par seconde, le tout arrondi à 0,01. Un bloc fait un mètre : des blocs par seconde fois 3,6 donnent des km/h.
- Valeurs fraîches. Chaque appel lit le monde à cet instant : rappelez-le dans une boucle pour suivre le véhicule.
vehicle.position() | L'endroit où se trouve l'ordinateur dans le monde : une table avec x, y et z. Le point est le centre du bloc de l'ordinateur : un ordinateur posé en 120 70 -45 (les nombres que F3 affiche pour ce bloc) répond {x = 120.5, y = 70.5, z = -44.5}. |
vehicle.velocity() | La vitesse de l'ordinateur le long de chaque axe, en blocs par seconde : x vers l'est, y vers le haut, z vers le sud. Les valeurs négatives vont dans l'autre sens (ouest, bas, nord). Au sol, les trois valent 0. |
vehicle.speed() | La vitesse de l'ordinateur, en blocs par seconde, quelle que soit la direction (la montée et la descente comptent). C'est la longueur de vehicle.velocity(). Au sol, 0. |
vehicle.name() | Le nom du véhicule Create Aeronautics qui porte l'ordinateur, ou nil au sol (et toujours nil sans Create Aeronautics). |
vehicle.on_vehicle() | true quand l'ordinateur est à bord d'un véhicule. C'est la même chose que vehicle.name() ~= nil. |
Position
L'endroit où se trouve l'ordinateur dans le monde : une table avec x, y et z. Le point est le centre du bloc de l'ordinateur : un ordinateur posé en 120 70 -45 (les nombres que F3 affiche pour ce bloc) répond {x = 120.5, y = 70.5, z = -44.5}.
- table
{x, y, z}, le centre du bloc de l'ordinateur dans le monde, en blocs
local p = vehicle.position()
print("X " .. p.x .. " Y " .. p.y .. " Z " .. p.z)À quelle distance est la base ? La distance entre deux points, avec Pythagore (la position est ici écrite à la main, un vrai programme utilise vehicle.position()) :
local BASE = {x = 250.5, y = 72.5, z = -1199.5}
local function distance_vers(a, b)
local dx, dy, dz = b.x - a.x, b.y - a.y, b.z - a.z
return math.sqrt(dx * dx + dy * dy + dz * dz)
end
local ici = {x = 130.5, y = 112.5, z = -1109.5} -- vehicle.position() à bord
print("base à " .. math.floor(distance_vers(ici, BASE)) .. " blocs")base à 155 blocs
Un enregistreur de vol. Un Microcontrôleur à bord écrit une ligne par seconde dans un fichier : le temps, la position et la vitesse, au format CSV qu'ouvre un tableur. Il s'arrête quand sa mémoire est presque pleine :
local FICHIER = "vol.csv"
if not fs.exists(FICHIER) then
fs.write(FICHIER, "temps,x,y,z,vitesse\n")
end
local debut = os.clock()
while fs.free() > 100 do
local p = vehicle.position()
local secondes = math.floor(os.clock() - debut)
fs.append(FICHIER, string.format("%d,%.2f,%.2f,%.2f,%.2f\n", secondes, p.x, p.y, p.z, vehicle.speed()))
sleep(1)
end
print("Enregistreur plein : copiez vol.csv puis effacez-le")Une ligne prend de 30 à 40 octets : les 16 Ko d'un Microcontrôleur tiennent environ 7 minutes de vol. De retour à la base, un programme lit le fichier et calcule la distance parcourue, point après point :
local journal = "temps,x,y,z,vitesse\n0,100.5,80.5,20.5,0\n1,112.5,80.5,25.5,13\n2,124.5,81.5,30.5,13.04\n"
-- dans un vrai programme : local journal = fs.read("vol.csv")
local total, precedent = 0, nil
for i, ligne in ipairs(string.split(journal, "\n")) do
local c = string.split(ligne, ",")
if i > 1 and #c == 5 then
local p = {x = tonumber(c[2]), y = tonumber(c[3]), z = tonumber(c[4])}
if precedent then
local dx, dy, dz = p.x - precedent.x, p.y - precedent.y, p.z - precedent.z
total = total + math.sqrt(dx * dx + dy * dy + dz * dz)
end
precedent = p
end
end
print("Distance parcourue : " .. math.round(total) .. " blocs")Distance parcourue : 26 blocs
Voir aussi vehicle.velocity() math.sqrt()
Mouvement
La vitesse de l'ordinateur le long de chaque axe, en blocs par seconde : x vers l'est, y vers le haut, z vers le sud. Les valeurs négatives vont dans l'autre sens (ouest, bas, nord). Au sol, les trois valent 0.
- table
{x, y, z}, la vitesse en blocs par seconde
y seul dit si le navire monte ou descend :
local v = vehicle.velocity()
if v.y > 0.1 then
print("Monte à " .. v.y .. " blocs/s")
elseif v.y < -0.1 then
print("Descend à " .. -v.y .. " blocs/s")
else
print("Vol en palier")
endx et z donnent le cap, la direction dans laquelle avance le navire, sous forme de relèvement au compas avec math.atan2 : 0 au nord, 90 à l'est, 180 au sud, 270 à l'ouest. Une autre fonction dit de combien tourner pour faire face à une cible, de -180 (tout à gauche) à 180 (tout à droite) :
local function relevement(dx, dz)
local degres = math.atan2(dx, -dz) * 180 / math.pi
return (degres + 360) % 360
end
local function virage(cap, cible)
return (cible - cap + 540) % 360 - 180
end
print(math.round(relevement(0, -100))) -- nord
print(math.round(relevement(100, 0))) -- est
print(math.round(relevement(-50, 50))) -- sud-ouest
print(virage(350, 10)) -- 20 degrés à droite
print(virage(10, 350)) -- 20 degrés à gauche0 90 225 20 -20
À bord, relevement(v.x, v.z) est le cap du navire. Un navire immobile n'a pas de cap : vérifiez d'abord sa vitesse. Le programme complet qui ramène à la base se trouve dans les motifs plus bas.
Voir aussi vehicle.speed() math.atan2()
La vitesse de l'ordinateur, en blocs par seconde, quelle que soit la direction (la montée et la descente comptent). C'est la longueur de vehicle.velocity(). Au sol, 0.
- number
- la vitesse en blocs par seconde
local vitesse = 18.42 -- ce qu'a renvoyé vehicle.speed()
print(vitesse .. " blocs/s")
print(math.round(vitesse * 3.6) .. " km/h")
print(math.round(vitesse * 60) .. " blocs par minute")18.42 blocs/s 66 km/h 1105 blocs par minute
Un compteur de vitesse sur un Moniteur LCD. Un Microcontrôleur à bord du dirigeable, un Moniteur LCD contre lui : le moniteur affiche l'écran de l'ordinateur. Le dessin est une fonction, montrée ici avec des valeurs d'exemple :
local function afficher(nom, vitesse, montee, hauteur)
term.set_bg(term.colors.black)
term.clear()
term.set_fg(term.colors.yellow)
term.set_cursor(2, 1)
term.write(nom or "Au sol")
term.set_fg(term.colors.white)
term.set_cursor(2, 3)
term.write(string.format("Vitesse %6.1f blocs/s", vitesse))
term.set_cursor(2, 4)
term.write(string.format(" %6.1f km/h", vitesse * 3.6))
-- une barre de 38 cases pour 0 à 40 blocs/s
local cases = math.min(38, math.floor(vitesse / 40 * 38))
term.set_cursor(2, 6)
term.set_bg(term.colors.lime)
term.write(string.rep(" ", cases))
term.set_bg(term.colors.gray)
term.write(string.rep(" ", 38 - cases))
term.set_bg(term.colors.black)
term.set_cursor(2, 8)
if montee > 0.1 then
term.set_fg(term.colors.lime)
term.write(string.format("Monte %5.1f blocs/s", montee))
elseif montee < -0.1 then
term.set_fg(term.colors.orange)
term.write(string.format("Descend %5.1f blocs/s", -montee))
else
term.set_fg(term.colors.light_gray)
term.write("Vol en palier")
end
term.set_fg(term.colors.white)
term.set_cursor(2, 10)
term.write("Altitude " .. math.floor(hauteur))
end
afficher("Albatros", 18.42, 1.25, 143.5)
À bord, la même fonction est appelée quatre fois par seconde avec les vraies valeurs (placez cette boucle sous la fonction, dans le même fichier) :
while true do
local v = vehicle.velocity()
afficher(vehicle.name(), vehicle.speed(), v.y, vehicle.position().y)
sleep(0.25)
endVoir aussi vehicle.velocity()
Le véhicule
Le nom du véhicule Create Aeronautics qui porte l'ordinateur, ou nil au sol (et toujours nil sans Create Aeronautics).
- string|nil
- le nom du véhicule, ou
nilsi l'ordinateur n'est pas sur un véhicule
local nom = vehicle.name()
if nom then
print("À bord de " .. nom)
else
print("Pas sur un véhicule")
endUn nom est bien pratique dans les messages : un navire qui fait son rapport à la base dit qui il est. nil ne peut pas être la valeur d'un champ de table, alors prévoyez un nom de secours :
local moi = vehicle.name() or os.label() or ("n°" .. net.id())Voir aussi vehicle.on_vehicle()
true quand l'ordinateur est à bord d'un véhicule. C'est la même chose que vehicle.name() ~= nil.
- boolean
truesi l'ordinateur est sur un véhicule Create Aeronautics
Un pilote automatique n'a rien à piloter au sol : il peut refuser de démarrer.
if not vehicle.on_vehicle() then
print("Posez-moi d'abord sur un dirigeable.")
return
end
print("Pilote automatique prêt")Elle dit aussi à un programme qui passe du navire au sol quoi faire : l'écran de vol à bord, la liste du chargement une fois le navire déchargé au quai.
Motifs courants
Rentrer à la base. Chaque seconde, le programme compare le relèvement de la base au cap du navire et dit au pilote de quel côté tourner. Les deux fonctions d'aide sont celles de vehicle.velocity :
local BASE = {x = 250, z = -1200} -- l'aire d'atterrissage, lue avec F3
local function relevement(dx, dz)
local degres = math.atan2(dx, -dz) * 180 / math.pi
return (degres + 360) % 360
end
local function virage(cap, cible)
return (cible - cap + 540) % 360 - 180
end
while true do
local p = vehicle.position()
local dx, dz = BASE.x - p.x, BASE.z - p.z
local distance = math.sqrt(dx * dx + dz * dz)
term.clear()
term.set_cursor(1, 1)
if distance < 8 then
print("Au-dessus de l'aire : posez-vous !")
else
local cible = relevement(dx, dz)
print(string.format("Base : %d blocs, relèvement %d", math.floor(distance), math.floor(cible)))
local v = vehicle.velocity()
if math.sqrt(v.x * v.x + v.z * v.z) < 1 then
print("Avancez pour connaître votre cap")
else
local t = virage(relevement(v.x, v.z), cible)
if t > 10 then
print(string.format("Tournez à droite de %d degrés", math.floor(t)))
elseif t < -10 then
print(string.format("Tournez à gauche de %d degrés", math.floor(-t)))
else
print("Tout droit")
end
end
end
sleep(1)
endLe cap du navire vient de son mouvement, pas de la direction de sa proue. Une table de navigation (Navigation Table) sur le câble donne directement l'angle vers une cible (navigation_table.angle()).
Un suivi de flotte. Chaque navire diffuse sa position toutes les 2 secondes sur le canal "flotte". Avec un Routeur Wi-Fi sur chaque navire et dans la tour, tous réglés une fois sur le même SSID avec radio.set_ssid(), les routeurs forment un seul réseau dans toute la dimension : la tour entend des navires bien au-delà des 256 blocs d'un routeur seul (voir Réseaux).
-- sur chaque navire : un Microcontrôleur avec un Routeur Wi-Fi sur son câble
local moi = vehicle.name() or os.label() or ("n°" .. net.id())
while true do
local p = vehicle.position()
net.broadcast({type = "position", nom = moi, x = p.x, y = p.y, z = p.z, vitesse = vehicle.speed()}, "flotte")
sleep(2)
endLa tour garde le dernier rapport de chaque navire. Au sol, vehicle.position() donne la place de la tour elle-même, le centre de la carte. Une ligne du tableau, construite à partir de rapports d'exemple :
local function ligne(n, ici)
local dx, dz = n.x - ici.x, n.z - ici.z
return string.format("%-12.12s %5d %4d %5.1f", n.nom, math.floor(math.sqrt(dx * dx + dz * dz)), math.floor(n.y), n.vitesse)
end
local ici = {x = 0.5, y = 70.5, z = 0.5} -- vehicle.position() de la tour
print(string.format("%-12s %5s %4s %5s", "NAVIRE", "DIST", "ALT", "VIT."))
print(ligne({nom = "Albatros", x = 300.5, y = 142.5, z = -399.5, vitesse = 18.4}, ici))
print(ligne({nom = "Monte-charge", x = -59.5, y = 96.5, z = 80.5, vitesse = 0}, ici))NAVIRE DIST ALT VIT. Albatros 500 142 18.4 Monte-charge 100 96 0.0
La boucle de la tour (placez-la sous ligne, dans le même fichier) redessine chaque seconde, et signale un navire muet depuis 10 secondes :
local ici = vehicle.position()
local navires = {}
while true do
local m = net.receive(1)
if m and m.channel == "flotte" and type(m.data) == "table" and m.data.type == "position" then
m.data.quand = os.clock()
navires[m.sender] = m.data
end
term.clear()
term.set_cursor(1, 1)
print(string.format("%-12s %5s %4s %5s", "NAVIRE", "DIST", "ALT", "VIT."))
for _, n in pairs(navires) do
local texte = ligne(n, ici)
if os.clock() - n.quand > 10 then texte = texte .. " perdu" end
print(texte)
end
endPour un pilote automatique qui tient l'altitude d'un ballon avec les brûleurs à air chaud, voyez Maintien d'altitude d'un dirigeable et le programme intégré balloon.
Voir aussi vehicle.name()