Combinando el enrutamiento manual y el enrutamiento automático en Eagle; ripup selectivo en un Eagle ULP

8

En Eagle, a menudo prefiero enrutar algunos cables yo mismo (power, xtal, UBS, etc.), y dejar el resto al autorouter. Cuando no estoy satisfecho con el resultado, encamino un poco más y dejo que el autorouter tenga otro intento.

Mi problema es deshacer el trabajo del autorouter, sin deshacer mi propio trabajo. La forma básica de hacer esto es simplemente no guardar la versión con enrutador automático y luego volver a cargar la placa. Pero una vez que cometo el error de guardar la versión con enrutamiento automático (y purgar las copias de seguridad), todavía quiero poder volver a la versión con pre-enrutamiento automático.

Un intento de hacer esto es identificar todos los cables de enrutamiento automático en un ULP y crear la cadena de comando para RIPUP estos segmentos. Puedo hacer arreglos para que el ULP identifique los cables con salida automática, por ejemplo, dándoles un ancho diferente. Pero el comando RIPUP parece romper el segmento de cable seleccionado Y SEGMENTOS DE AJUSTE. Hasta ahora no he encontrado un comando que rasgue solo el segmento de cable seleccionado.

Así que supongo que tengo dos preguntas: - ¿Cómo combina el enrutamiento manual y el enrutamiento automático de forma iterativa (prueba y error)? - ¿Hay alguna forma (probablemente usando ULP y comandos) de romper un subconjunto de segmentos de cable?

(actualizar) Intenté el enfoque opuesto: en un ULP, reúna todos los segmentos de cables que quiero mantener, realice una copia completa y luego restaure los segmentos de cables (mediante el comando ROUTE). Si no tiene éxito, los segmentos deben estar en un orden específico para los comandos de ruta (no el orden en que los encuentra el ULP :(), primero deben realizarse las vías y algunos problemas más.

GRRRR, debe haber una manera fácil de hacer esto, ¿o soy demasiado optimista?

    

3 respuestas

4

Odio responder a mi propia pregunta, pero aquí voy. Espero no obtener puntos por responder, ¿sería extraño, solo por aceptar una respuesta? (Por cierto, no obtuve ninguna respuesta en el foro Element14).

La solución es usar el comando DIBUJAR, no RUTA. DIBUJO colocará un segmento de cable, exactamente donde lo especifique (a diferencia de ROUTE, que intenta conectarse a un cable de aire sin enrutar. ROUTE es esencialmente inútil en un script). El siguiente problema es a través de: No puedo (o no quiero) distinguir entre una vía manual y una salida automática, por lo que mantengo todas las vías que conectan dos (o más) segmentos de cables manuales. Se eliminan otras vías.

Entonces, lo que hace mi guión final es:

prepare a ripup command
for all copper segments that are not 0.01 wide (the width I use for autorouting)
   check both endpoints for a via at that location
      prepare the via to be resurrected when it is visited the 2nd time
   prepare a command that resurrects the copper segment
execute the prepared commands

Tenga en cuenta que probablemente no funcionará para más de dos capas, ni para otras cosas que no sean segmentos de cable en la capa de cobre.

En mi humilde opinión, todo el concepto del águila ULP y los lenguajes de comando es problemático. Un ULP se ejecuta en un entorno de solo lectura, la única forma en que puede afectar el circuito, la placa o la biblioteca es mediante la creación de una lista de comandos. Esto elimina algunas técnicas de programación útiles, pero peor es que los comandos no fueron diseñados para ser creados fácilmente a partir de un ULP. Necesita todo tipo de transformaciones (en este caso: coordenadas, nombres de formas) para traducir del mundo ULP al mundo CMD.

(editar) Antes de ejecutar este ULP, configure la selección de 'doblado de alambre' para permitir ángulos arbitrarios, de lo contrario, Eagle intentará adaptar los cables resucitados a los ángulos permitidos, lo que puede resultar en un embarrado sangriento. En mi opinión, este es otro ejemplo del problema con ULP / SCR.

Este es el código ULP:

// gather the commands that must be run on exit
string RunOnExit = "";
void cmd( string s ) { RunOnExit += s + "\n"; }

// return an x or y position in the form that can be used in a command
real f( int x ){
   board( B ) switch( B.grid.unit ) {
      case 0: return u2mic(x);
      case 1: return u2mm(x);
      case 2: return u2mil(x);
      case 3: return u2inch(x);
   }
}   

// return the string form of the a via's shape
string sn( int x ){
   if( x == VIA_SHAPE_SQUARE )  return "square";
   if( x == VIA_SHAPE_ROUND )   return "round";
   if( x == VIA_SHAPE_OCTAGON   ) return "octagon";
   if( x == VIA_SHAPE_ANNULUS   ) return "annulus";
   if( x == VIA_SHAPE_THERMAL   ) return "thermal";
   return "unknown-via-shape";
}

// count the number of times x occurs in s
int n_ocurrences( string s, string x ){
   int i, n = 0;
   while( 1 ){
      i = strstr( s, x );
      if( i == -1 ) return n;
      s = strsub( s, i + strlen( x ));
      n++;
   }
}

// add a via, but only when it is visited the second time
string via_list = "";
void add_via( int a, int b ){

   // for all via's
   board( B ) B.signals( S ) S.vias( V ){

      // if the via is at the current location
      if(( V.x == a ) && ( V.y == b )){
         string s, coo;

         // the coordinates of the via are used as its identification
         sprintf( coo, "(%.6f %.6f)", f( V.x ), f( V.y ));         

         // if this is the second visit to this via
         via_list += coo;
         if( n_ocurrences( via_list, coo ) == 2 ){

            // resurrect this via
            sprintf( s, "VIA '%s' %f %s %s;", 
            S.name, f( V.drill ), sn( V.shape[ 1 ] ), coo );
            cmd( s );      
         }
      }
   }         
}

if( !board ){
   dlgMessageBox("start this ULP in Board", "OK");
   exit( 0 );
}

board( B ){ 

   // first delete all coper segments, 
   // later we will resurrect what we want to keep 
   cmd( "RIPUP;" );

   // for all wire segments in the top and bottom copper layers
   B.signals(S) S.wires(W) {
      if( ( W.layer == 1 ) || ( W.layer == 16 ) ){ 

         // that are not 0.01 width (that is what the autorouter uses)
         if( f( W.width ) != 0.01 ){
            string s;

            // resurrect via's adjacent to this wire segment
            add_via( W.x1, W.y1 );
            add_via( W.x2, W.y2 );

            sprintf( s, "CHANGE LAYER %d;", W.layer );
            cmd( s );      

            // resurrect this wire segment                 
            sprintf( 
               s, "WIRE '%s' %f (%.6f %.6f) (%.6f %.6f);", 
               S.name, f( W.width),
               f(W.x1), f(W.y1), f(W.x2), f(W.y2));
            cmd( s );   
         }   
      }
   }
   // dlgMessageBox( RunOnExit, "OK");
   exit( RunOnExit );
}
    
respondido por el Wouter van Ooijen
2

Wouter. No vi tu pregunta antes porque estuve en Masters la semana pasada.

La forma en que me ocupo de esto es guardar una copia de la pizarra con un nombre diferente justo antes de ejecutar el enrutador automático. Siempre lo nombro GUARDAR.BRD, que se puede eliminar de manera segura una vez hecho todo.

Mi flujo de trabajo de enrutamiento parece ser muy parecido al tuyo. Dirijo las partes críticas de forma manual, me aseguro de que las clases de red estén configuradas de manera razonable y luego ejecuten el enrutador automático. Luego busco problemas como donde el enrutador automático no pudo encontrar una solución, terminó haciendo algo inconveniente, etc. Vuelvo a la versión guardada (antes del enrutamiento automático) con algunos cambios manuales con la esperanza de que el enrutador automático no obtenga en problemas, a continuación, intente de nuevo. Esto podría repetirse 5-10 veces, dependiendo de la complejidad de la placa. Los primeros pasos automáticos son principalmente para ver si hay una solución y más o menos para encontrar los puntos problemáticos. Para eso ni siquiera utilizo pases de optimización. Los últimos programas automáticos son con optimización completa, que para mí suelen ser 8 pases y los costos cambian con respecto a esos pases para obtener las características que deseo.

Aunque hago un guardado en SAVE.BRD antes de cada paso de ruta automática (y luego vuelvo a abrir el archivo original para continuar con eso), trato de no guardar el resultado de la salida automática hasta que esté satisfecho con el toda la cosa. Guardar la instantánea en SAVE.BRD cada vez es un respaldo de seguridad en caso de que mis dedos accidentalmente hagan una copia antes de pensar en ello.

Sería bueno si Eagle tuviera una opción de ripup para el último pase de ruta automática, pero no existe tal cosa.

    
respondido por el Olin Lathrop
1

Si el archivo de datos de Eagle sigue el mismo enfoque que los anteriores con los que he jugado (p. ej., en su segundo Autotrax DOS), cada segmento de la pista tiene una línea para sí mismo. Las líneas son "independientes" y se pueden editar o eliminar sin afectar a nada más. Los sistemas "mejores" más nuevos pueden no tener una simplicidad tan poderosa.

Si las pistas son independientes, como se mencionó anteriormente, y si los anchos de pista son únicos, debería [tm] identificar los segmentos de la pista y eliminar las líneas correspondientes.

La memoria tenue me dice que en una etapa escribí una rutina para identificar las etiquetas de los componentes y cambiarles el tamaño, rotarlos y moverlos en relación con el cuerpo del componente. La identificación de la pista suena fácil en comparación. Guarda una copia antes de ejecutar el programa !!! :-).

    
respondido por el Russell McMahon

Lea otras preguntas en las etiquetas