Laboratorio 1 · Semáforos

Célula FMS: prensa, CNC y robot

Una célula de fabricación flexible: las piezas llegan a la posición de entrada, un robot las lleva a la prensa (estampado), luego al CNC (mecanizado) y finalmente a la salida. Cuatro hilos gobiernan las cuatro posiciones y el robot es región crítica. Es el ejercicio ej24 del cuaderno SCTR, ejecutable.

Qué observar

Pulsa Ejecutar y usa Paso para avanzar instrucción a instrucción.

Mapa semáforo → significado

SemáforoInicialUna unidad significa…
spEntradaPrensa1la prensa tiene su hueco libre
scEntradaPrensa0hay pieza esperando en la prensa
spPrensaCNC1el CNC tiene su hueco libre
scPrensaCNC0hay pieza esperando en el CNC
spCNCSalida1la posición de salida está libre
scCNCSalida0hay pieza terminada en la salida
sRobot1el robot está disponible

Qué línea produce qué efecto

LíneaEfecto en la planta
hEntrada:4 wait(spEntradaPrensa)La entrada se detiene si la prensa está ocupada.
hEntrada:5 wait(sRobot)Solicita el robot; si otro hilo lo usa, espera.
hEntrada:6–7 coge/dejaEl brazo gira de la entrada a la prensa con la pieza.
hEntrada:9 signal(scEntradaPrensa)Despierta a hPrensa: empieza el estampado.
hPrensa:4 estampa()La prensa trabaja durante varios ticks.
hPrensa:10 signal(spEntradaPrensa)Libera la prensa: hEntrada puede traer la siguiente pieza.
hCNC:4 mecaniza()El CNC trabaja la pieza.
hSalida:4 while(barrera_salida())Espera a que el operario retire la pieza terminada.

Código C++20 equivalente

#include <semaphore>
#include <thread>
#include <mutex>

std::binary_semaphore spEntradaPrensa(1), scEntradaPrensa(0);
std::binary_semaphore spPrensaCNC(1),     scPrensaCNC(0);
std::binary_semaphore spCNCSalida(1),     scCNCSalida(0);
std::binary_semaphore sRobot(1);          // robot: región crítica

void hEntrada() {
    while (true) {
        esperarPiezaEnEntrada();          // sensor / barrera óptica
        spEntradaPrensa.acquire();
        sRobot.acquire();
        coge(100, 0); deja(0, 100);
        sRobot.release();
        scEntradaPrensa.release();
    }
}

void hPrensa() {
    while (true) {
        scEntradaPrensa.acquire();
        estampa();
        spPrensaCNC.acquire();
        sRobot.acquire();
        coge(0, 100); deja(-100, 0);
        sRobot.release();
        spEntradaPrensa.release();
        scPrensaCNC.release();
    }
}

void hCNC() {
    while (true) {
        scPrensaCNC.acquire();
        mecaniza();
        spCNCSalida.acquire();
        sRobot.acquire();
        coge(-100, 0); deja(0, -100);
        sRobot.release();
        spPrensaCNC.release();
        scCNCSalida.release();
    }
}

void hSalida() {
    while (true) {
        scCNCSalida.acquire();
        while (piezaEnSalida())           // el operario debe retirarla
            std::this_thread::yield();
        spCNCSalida.release();
    }
}

int main() {
    std::jthread t1(hEntrada), t2(hPrensa), t3(hCNC), t4(hSalida);
}

Experimentos propuestos

  1. Elimina mentalmente spPrensaCNC: ¿qué intentaría hacer hPrensa mientras el CNC mecaniza? (Respuesta: esperar el robot, mover la pieza… y el código de la simulación bloquearía la entrega; en hardware real habría colisión.)
  2. Haz que estampa() dure mucho más que mecaniza() y observa dónde se acumulan las esperas: ese es el cuello de botella.
  3. Cuenta en el registro cuántos wait(sRobot) quedan bloqueados por ciclo: ¿cuánto tiempo está el robot retenido?