En Eagle, a menudo prefiero enrutar algunos cables yo mismo (alimentación, xtal, UBS, etc.) y dejar el resto al enrutador automático. Cuando no estoy satisfecho con el resultado, ruteo un poco más yo mismo y dejo que el enrutador automático lo intente de nuevo.
Mi problema es deshacer el trabajo del enrutador automático, sin deshacer mi propio trabajo. La forma básica de hacer esto es simplemente no guardar la versión enrutada automáticamente y luego cargar la placa nuevamente. Pero una vez que cometo el error de guardar la versión autoenrutada (y purgar las copias de seguridad), aún quiero poder volver a la versión preautorrutada.
Un intento de hacer esto es identificar todos los cables enrutados automáticamente en un ULP y crear la cadena de comando para RIPAR estos segmentos. Puedo hacer que el ULP identifique los cables enrutados automáticamente, por ejemplo, dándoles un ancho diferente. Pero el comando RIPUP parece romper el segmento de cable seleccionado Y LOS SEGMENTOS ADYACENTES. Hasta ahora no he encontrado un comando que rasgue solo el segmento de cable seleccionado.
Así que supongo que tengo dos preguntas: - ¿Cómo se combinan el enrutamiento manual y el enrutamiento automático de forma iterativa (prueba y error)? - ¿Hay alguna manera (probablemente usando ULP y comandos) para romper un subconjunto de segmentos de cable?
(actualización) Intenté el enfoque opuesto: en un ULP, reúna todos los segmentos de cables que quiero conservar, realice una extracción completa y luego restaure los segmentos de cables (usando el comando ROUTE). Sin éxito, los segmentos deben estar en un orden específico para los comandos de ruta (no el orden en que los encuentra la ULP :( ), primero se deben hacer las vías, y algunos problemas más.
GRRRR, debe haber una manera fácil de hacer esto, ¿o soy demasiado optimista?
Odio responder a mi propia pregunta, pero aquí voy. Espero no obtener puntos por responder, eso sería raro, ¿solo por aceptar una respuesta? (Por cierto, no obtuve ninguna respuesta en el foro de Element14).
La solución es usar el comando DIBUJAR, no RUTA. DRAW colocará un segmento de cable, exactamente donde usted especifique (a diferencia de ROUTE, que intenta conectarse a un cable aéreo no enrutado. ROUTE es esencialmente inútil en un script). El siguiente problema son las vías: no puedo (o no quiero) distinguir entre una vía manual y una vía enrutada automáticamente, así que conservo todas las vías que conectan dos (o más) segmentos de cables manuales. Se eliminan otras vías.
Entonces, lo que hace mi script 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 alambre 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 lo peor es que los comandos no fueron diseñados para crearse fácilmente desde 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 'curva 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 desastre sangriento. En mi humilde 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 );
}
Wouter. No vi tu pregunta antes porque estuve en Masters la semana pasada.
La forma en que trato esto es guardar una copia de la placa con un nombre diferente justo antes de ejecutar el enrutador automático. Siempre lo llamo SAVE.BRD, que se puede eliminar de forma segura una vez que todo esté listo.
Mi flujo de trabajo de enrutamiento se parece mucho al suyo. Enruto las partes críticas manualmente, me aseguro de que las clases de red estén configuradas de manera razonable y luego ejecuto el enrutador automático. Luego busco problemas como cuando el enrutador automático no pudo encontrar una solución, terminó haciendo algo inconveniente, etc. Vuelvo a la versión guardada (antes de la ruta automática) hago algunos cambios manuales con suerte para que el enrutador automático no obtenga en problemas, luego inténtalo de nuevo. Esto puede repetirse de 5 a 10 veces, según la complejidad del tablero. Las primeras pasadas por la autopista son principalmente para ver si hay una solución y, más o menos, para encontrar los puntos problemáticos. Para eso ni siquiera uso ningún pase de optimización. Las rutas automáticas posteriores tienen una optimización completa, que para mí suele ser de 8 pases con costos que cambian entre esos pases para obtener las características que quiero.
Aunque guardo 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 ruta automática hasta que esté satisfecho con todo. Guardar la instantánea en SAVE.BRD cada vez es una copia de seguridad en caso de que mis dedos guarden accidentalmente antes de pensar en ello.
Sería bueno si Eagle tuviera una opción de ruptura para el último paso de la autopista, pero no existe tal cosa.
Si el archivo de datos de Eagle sigue el mismo enfoque que los más antiguos con los que he jugado (por ejemplo, el antiguo DOS Autotrax), entonces cada segmento de pista tiene una línea para sí mismo. Las líneas son "independientes" y se pueden editar o eliminar sin afectar nada más. Es posible que los sistemas "mejores" más nuevos no tengan una simplicidad tan poderosa.
Si las vías son independientes, como se indicó anteriormente, y si los anchos de vía son únicos, [tm] debería ser fácil identificar los segmentos de vía 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, girarlos y moverlos en relación con el cuerpo del componente. La identificación de pistas suena fácil en comparación. ¡Guarde una copia antes de ejecutar el programa! :-).
Russel McMahon
vicatcu
Wouter van Ooijen