Create: Computing AgesDoc Brass
Périphériques

Machines de précision

La Bobineuse, la Chambre à vide, la Machine de photolithographie, l'Implanteur ionique, la Placeuse CMS et la Tireuse de cristaux : sur quoi elles travaillent, et pourquoi elles attendent.

Les machines de précision de Computing Ages fonctionnent comme une Presse mécanique de Create : elles sont suspendues au-dessus d'un tapis roulant ou d'un dépôt et descendent leur tête sur la pièce qui passe dessous, une étape de tube à vide ou de puce à la fois. Elles contiennent ce avec quoi elles travaillent (une bobine de fil, un dopant, un photomasque...) et demandent de la rotation, souvent rapide. Quand une machine attend, les Lunettes d'ingénieur disent pourquoi : trop lente, un ingrédient manquant... Un ordinateur lit la même chose, et peut agir : accélérer la ligne, réclamer du fil, vous prévenir.

Brass
local implanteur = peripheral.find("ion_implanter")
if implanteur.running() then
  print("au travail : " .. math.floor(implanteur.progress() * 100) .. " %")
else
  print("en attente : " .. (implanteur.problem() or "rien à corriger"))
end
Méthodes
machine.running()Si la machine travaille : du moment où sa tête commence à descendre sur une pièce jusqu'à ce qu'elle soit remontée.
machine.progress()Où en est le cycle en cours, de 0 (la tête quitte le haut) à 1 (elle est remontée), arrondi au millième. 0 tant que la machine est au repos. Un arbre plus rapide raccourcit le cycle.
machine.item()La pièce qui attend sous la machine, sous forme de table d'objet : celle du tapis roulant ou du dépôt deux blocs plus bas, ou sinon celle posée au sol juste en dessous. nil quand il n'y a rien. count est la taille de cette pile.
machine.recipe()La recette que la machine lancerait sur la pièce du dessous :
machine.problem()Ce qui empêche la machine de travailler la pièce du dessous, comme le montrent les lunettes. nil quand il n'y a rien dessous, ou quand la pièce peut être traitée maintenant.
machine.tier()Le niveau de la source lumineuse chargée dans une Machine de photolithographie : 1 pour une Lampe UV, 2 pour un Laser excimère (DUV), 3 pour une Source de lumière EUV. 0 quand il n'y en a pas, et toujours 0 sur les quatre autres machines.
tireuse.running()Si un cristal est en cours de tirage.
tireuse.progress()Où en est le tirage du cristal, de 0 (le germe touche le bain) à 1 (la boule est sortie), arrondi au millième. Les lunettes le montrent en pourcentage.
tireuse.max_speed()La vitesse limite de la tireuse, en tr/min : la configuration serveur crystalPullerMaxSpeed, 32 par défaut. Le tirage est le plus rapide à exactement cette vitesse.
tireuse.problem()Ce qui empêche la tireuse de travailler :

Installation

Cinq machines, les mêmes méthodes. Chaque machine a son propre type, celui que vous cherchez ; les cinq ont les méthodes de cette page, notées ici precision_machine.*.

typeblocce qu'elle contient (ses cases)
coil_winderBobineuse1 : la bobine de fil ou de feuille
vacuum_chamberChambre à vide1 : la cible de dépôt
lithography_machineMachine de photolithographie2 : le photomasque, puis la source lumineuse
ion_implanterImplanteur ionique1 : le dopant
pick_and_placePlaceuse CMS8 : les chargeurs de composants

precision_machine n'est pas un type : peripheral.find("precision_machine") renvoie nil. Demandez la machine que vous voulez, par exemple peripheral.find("coil_winder"). Sur un Câble de données (Mini-ordinateur et plus récents), une machine prend le nom de son type et de sa place : ion_implanter@120,64,-35.

Aussi cinétiques et inventaires. Une machine de précision tourne et contient des objets : c'est donc aussi un bloc cinétique et un inventaire, avec toutes leurs méthodes. machine.speed() lit sa vitesse en tr/min, machine.overstressed() dit si son réseau s'est arrêté, et machine.list() montre les cases du tableau ci-dessus (le fil qui reste sur une Bobineuse, par exemple). peripheral.find("inventory") les trouve aussi.

Où est la pièce. Une machine travaille sur la pièce posée sur le tapis roulant ou le dépôt deux blocs plus bas (avec un bloc d'air entre les deux, comme pour une Presse mécanique), ou, quand il n'y a là ni tapis ni dépôt, sur un objet posé au sol juste en dessous d'elle.

La Tireuse de cristaux travaille au-dessus d'un Bassin et a ses propres méthodes : voyez sa section à la fin de cette page.

Quand la machine a disparu, ses méthodes arrêtent le programme avec machine removed (crystal puller removed pour la Tireuse de cristaux) ; quand son chunk n'est pas chargé, avec peripheral is not loaded.

La tête

#

machine.running()

→ boolean

Si la machine travaille : du moment où sa tête commence à descendre sur une pièce jusqu'à ce qu'elle soit remontée.

Renvoie
boolean
true tant que la tête est dans un cycle

Un voyant « occupée » sur le dessus de l'ordinateur :

Brass
local bobineuse = peripheral.find("coil_winder")
while true do
  rs.set("top", bobineuse.running())
  sleep(0.5)
end

Voir aussi precision_machine.progress()

#

machine.progress()

→ number

Où en est le cycle en cours, de 0 (la tête quitte le haut) à 1 (elle est remontée), arrondi au millième. 0 tant que la machine est au repos. Un arbre plus rapide raccourcit le cycle.

Renvoie
number
l'avancement du cycle de la tête, de 0 à 1 ; 0 au repos
Brass
local chambre = peripheral.find("vacuum_chamber")
print("cycle sous vide : " .. math.floor(chambre.progress() * 100) .. " %")

Voir aussi precision_machine.running()

La pièce en dessous

#

machine.item()

→ table|nil⚙ coût 4

La pièce qui attend sous la machine, sous forme de table d'objet : celle du tapis roulant ou du dépôt deux blocs plus bas, ou sinon celle posée au sol juste en dessous. nil quand il n'y a rien. count est la taille de cette pile.

Renvoie
table|nil
la pièce sous la machine, {name =, count =, display =} ; nil quand il n'y en a pas
Brass
local litho = peripheral.find("lithography_machine")
local piece = litho.item()
if piece then
  print("sous la machine : " .. piece.display)
else
  print("pas de wafer dessous")
end

Voir aussi precision_machine.recipe()

#

machine.recipe()

→ table|nil⚙ coût 4

La recette que la machine lancerait sur la pièce du dessous :

Renvoie
table|nil
{id =, output =, min_speed =, tier =} ; nil sans pièce, ou quand on ne peut rien en faire
champcontenu
idl'identifiant de la recette
outputl'identifiant de l'objet qu'elle fabrique
min_speedla rotation la plus lente qu'accepte la recette, en tr/min ; 0 pour n'importe quelle vitesse
tierla source lumineuse qu'elle demande sur une Machine de photolithographie, de 1 à 3 ; 0 sur les autres machines

Plusieurs recettes peuvent partir de la même pièce : toute puce commence par le même wafer enduit sous la Machine de photolithographie. La machine prend celle pour laquelle elle est équipée : le photomasque, le dopant ou le fil que vous chargez décide donc du produit, et recipe() dit lequel ce sera. Dans un assemblage séquencé, output est la pièce inachevée que donne cette étape, jusqu'à la dernière.

Brass
local implanteur = peripheral.find("ion_implanter")
local r = implanteur.recipe()
if r then
  print("fabrique " .. r.output .. ", à " .. r.min_speed .. " tr/min ou plus")
end

Voir aussi precision_machine.item() precision_machine.problem()

Pourquoi elle attend

#

machine.problem()

→ string|nil⚙ coût 4

Ce qui empêche la machine de travailler la pièce du dessous, comme le montrent les lunettes. nil quand il n'y a rien dessous, ou quand la pièce peut être traitée maintenant.

Renvoie
string|nil
"no_recipe", "too_slow", "tier_too_low" ou "missing_ingredient" ; nil quand la pièce du dessous peut être traitée, ou quand il n'y a rien dessous
problèmepourquoique faire
"no_recipe"cette machine ne fait rien de la pièce du dessousenvoyer la pièce à la bonne machine
"too_slow"la machine ne tourne pas, ou moins vite que le min_speed de la recettel'accélérer, ou ajouter de la puissance si le réseau est surchargé
"tier_too_low"la source lumineuse de la Machine de photolithographie est trop faible pour le masque, ou absentecharger une source plus puissante
"missing_ingredient"la bobine, la cible, le dopant, le masque ou un composant que la recette prend dans la machine manquerecharger la machine

Un problème à la fois, dans cet ordre : une fois la vitesse réglée, il peut encore manquer le dopant. Redemandez après chaque correction.

Brass
local bobineuse = peripheral.find("coil_winder")
local probleme = bobineuse.problem()
if probleme == "missing_ingredient" then
  print("la Bobineuse a besoin d'une nouvelle bobine de fil")
elseif probleme == "too_slow" then
  print("la Bobineuse ne tourne pas assez vite")
end

Voir aussi precision_machine.recipe() precision_machine.tier()

#

machine.tier()

→ number

Le niveau de la source lumineuse chargée dans une Machine de photolithographie : 1 pour une Lampe UV, 2 pour un Laser excimère (DUV), 3 pour une Source de lumière EUV. 0 quand il n'y en a pas, et toujours 0 sur les quatre autres machines.

Renvoie
number
le niveau de la source lumineuse d'une Machine de photolithographie, de 1 à 3 ; 0 sans source, et sur les autres machines

Une recette tourne quand le niveau de la machine atteint au moins le tier de la recette : une lumière plus puissante sert aussi pour les masques plus anciens.

Brass
local litho = peripheral.find("lithography_machine")
local r = litho.recipe()
if r and litho.tier() < r.tier then
  print("ce masque demande une source lumineuse de niveau " .. r.tier)
end

Voir aussi precision_machine.recipe()

Tireuse de cristaux

La Tireuse de cristaux fait croître un monocristal dans le bain fondu du Bassin placé deux blocs plus bas, par le procédé Czochralski : une boule de silicium à partir de silicium fondu, ou du quartz synthétique. Son type est crystal_puller, et c'est aussi un bloc cinétique.

Elle veut un arbre lent. Au-delà de sa vitesse limite (32 tr/min par défaut), le cristal casserait : la tireuse ne démarre pas, et un tirage déjà commencé attend que l'arbre ralentisse. En dessous de la limite, plus elle tourne lentement, plus le tirage est long : deux fois plus long à la moitié de la limite, jusqu'à huit fois plus long. La durée est fixée au début du tirage : la meilleure vitesse est donc la limite elle-même, réglée avant que le tirage commence.

#

tireuse.running()

→ boolean

Si un cristal est en cours de tirage.

Renvoie
boolean
true tant qu'elle tire un cristal
Brass
local tireuse = peripheral.find("crystal_puller")
print(tireuse.running())

Voir aussi crystal_puller.progress()

#

tireuse.progress()

→ number

Où en est le tirage du cristal, de 0 (le germe touche le bain) à 1 (la boule est sortie), arrondi au millième. Les lunettes le montrent en pourcentage.

Renvoie
number
l'avancement du tirage, de 0 à 1 ; 0 quand elle ne tire pas
Brass
local tireuse = peripheral.find("crystal_puller")
if tireuse.running() then
  print("boule tirée à " .. math.floor(tireuse.progress() * 100) .. " %")
end

Voir aussi crystal_puller.running()

#

tireuse.max_speed()

→ number

La vitesse limite de la tireuse, en tr/min : la configuration serveur crystalPullerMaxSpeed, 32 par défaut. Le tirage est le plus rapide à exactement cette vitesse.

Renvoie
number
la rotation la plus rapide avant que le cristal casse, en tr/min

Avec la roue dentée d'un Contrôleur de vitesse de rotation qui entraîne directement la tireuse, ceci donne le tirage le plus rapide que permet le serveur (voir speed_controller.set_target_speed()) :

Brass
local tireuse = peripheral.find("crystal_puller")
local regulateur = peripheral.find("speed_controller")
regulateur.set_target_speed(tireuse.max_speed())

Voir aussi crystal_puller.problem()

#

tireuse.problem()

→ string|nil

Ce qui empêche la tireuse de travailler :

Renvoie
string|nil
"too_fast", "too_slow", "no_basin", ou nil
problèmepourquoi
"too_fast"elle tourne plus vite que max_speed() : le tirage attend
"too_slow"elle ne tourne pas
"no_basin"il n'y a pas de Bassin deux blocs plus bas

nil veut dire qu'aucun de ces problèmes ne se pose, pas qu'un tirage va commencer : le Bassin doit encore contenir le bon bain et être assez chaud (un Brûleur à blaze surchauffé pour une boule de silicium).

Brass
local tireuse = peripheral.find("crystal_puller")
if tireuse.problem() == "too_fast" then
  print("ralentissez : " .. tireuse.max_speed() .. " tr/min au plus")
end

Voir aussi crystal_puller.max_speed()

Exemples

Jamais trop lent

Les recettes de l'Implanteur ionique demandent 128 tr/min. Un Contrôleur de vitesse de rotation l'entraîne, et ce programme monte le contrôleur pas à pas tant que l'implanteur est trop lent, jusqu'à la limite de Create. Quand le réseau est surchargé, plus de vitesse ne ferait qu'empirer les choses : le programme le dit plutôt.

Brass
local implanteur = peripheral.find("ion_implanter")
local regulateur = peripheral.find("speed_controller")
local PAS = 16   -- tr/min ajoutés à chaque fois

while true do
  if implanteur.overstressed() then
    print("surcharge : ajoutez de la puissance, plus de vitesse n'aiderait pas")
  elseif implanteur.problem() == "too_slow" then
    local cible = regulateur.target_speed()
    if math.abs(cible) >= 256 then
      print("le contrôleur est déjà à pleine vitesse")
    else
      local tours = math.min(256, math.abs(cible) + PAS)
      if cible < 0 then
        tours = -tours   -- garde le sens de rotation
      end
      regulateur.set_target_speed(tours)
      print("trop lent : contrôleur réglé à " .. tours .. " tr/min")
    end
  end
  sleep(2)
end

Il fonctionne quels que soient les engrenages entre le contrôleur et l'implanteur, puisqu'il ne surveille que le problème de l'implanteur lui-même. overstressed() vient des méthodes cinétiques qu'a chaque machine.

Un tableau d'état de la ligne

Un Mini-ordinateur sur le Câble de données qui longe une ligne de puces affiche une ligne par machine qu'il atteint : au travail avec son avancement, en attente avec son problème, ou au repos. La Tireuse de cristaux a elle aussi running, progress et problem : elle trouve sa place sur le même tableau.

Brass
local NOMS = {
  coil_winder = "Bobineuse",
  vacuum_chamber = "Chambre à vide",
  lithography_machine = "Photolithographie",
  ion_implanter = "Implanteur ionique",
  pick_and_place = "Placeuse CMS",
  crystal_puller = "Tireuse",
}

local function etat(machine)
  if machine.running() then
    return "au travail, " .. math.floor(machine.progress() * 100) .. " %"
  end
  return machine.problem() or "au repos"
end

while true do
  term.clear()
  term.set_cursor(1, 1)
  for _, nom in ipairs(peripheral.list()) do
    local libelle = NOMS[peripheral.type(nom)]
    if libelle then
      print(string.format("%-18s %s", libelle, etat(peripheral.wrap(nom))))
    end
  end
  sleep(2)
end

peripheral.type donne le premier type de chaque nom, qui pour ces blocs est le leur (coil_winder...), et non kinetic ou inventory.