# Combining hand-routing and auto-routing in Eagle; selective ripup in an Eagle ULP

In Eagle I often prefer to route some wires myself (power, xtal, UBS, etc), and leave the rest to the autorouter. When I am not pleased with the result I route some more myself, and let the autorouter have another try.

My problem is undoing the work of the autorouter, without undoing my own work. The basic way to do this is simply not saving the autoroutered version, and then loading the board again. But once I make the mistake of saving the autorouted version (and purging the backups) I still want to be able to go back to the pre-autorouted version.

One attempt to do this is to identify all autorouted wires in an ULP and create the command string to RIPUP these segments. I can arrange for the ULP to identify the autorouted wires, for instance by giving them a different width. But the RIPUP command seems to ripup the selected wire segment AND ADJACENT SEGMENTS. So far I have not found a command that rips just the selected wire segment.

So I guess I have two questions: - How do you combine hand-routing and auto-routing in an iterative (trial-and-error) way? - Is there a way (probably using ULP and commands) to ripup a subset of wire segments?

(update) I tried the opposite approach: in an ULP, gather all wire segments I want to keep, do a full ripup, and then restore the wires segments (using the ROUTE command). No success, the segments must be in a specific order for the route commands (not the order in which the ULP finds them :( ), the via's must be made first, and some more problems.

GRRRR, there must be an easy way to do this, or am I overly optimistic?

• If Eagle's data file follows the same approach as older ones that I have played with (eg ye olde DOS Autotrax) then each track segment has a line to itself. If the track widths are unique it should [tm] be easy to identify track segments and delete the lines concerned. Dim memory tells me that at one stage I wrote a routine to identify component labels and resize, rotate and move them relative to the component body. Track identification sounds easy compared. Save a copy before running program !!! :-). – Russell McMahon Aug 25 '11 at 4:48
• this is a terrific question, might I suggest you also post it to the Element14 expert on Eagle element14.com/community/message/5177. If you do and you find anything please do post back to here! – vicatcu Aug 26 '11 at 19:56
• Ok, done. If that fails I can try the eagle forums. – Wouter van Ooijen Aug 27 '11 at 19:49

I hate answering my own question, but here I go. I hope I don't get get points for answering, that would be weird, only for accepting an answer? (BTW, I did not get any response on the Element14 forum.)

The solution is to use the DRAW command, not ROUTE. DRAW will place a wire segment, exactly where you specify (unlike ROUTE, which tries to connect to an unrouted airwire. ROUTE is essentially useless in a script.). The next issue is via's: I can't (or don't want to) distinguish between a manual via and an autorouted via, so I keep all via's that connect two (or more) manual wire segments. Other via's are deleted.

So what my final script does is:

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


Note that it will probably not work for more than two layers, nor for other things than wire segments at the copper layer.

IMHO the whole concept of the eagle ULP and command languages is troublesome. An ULP runs in a read-only environment, the only way it can affect the circuit, board or library is by creating a list of commands. This eliminates some useful programming techniques, but worse is that the commands were not designed to be easily created from an ULP. You need all kinds of transformations (in this case: coordinates, shape names) to translate from the ULP world to the CMD world.

(edit) Before you run this ULP, set the 'wire bend' selection to allow arbitrary angles, otherwise eagle will try to adapt the resurrected wires to the allowed angles, which can result in a bloody mess. IMHO this is another example of the problem with ULP/SCR.

This is the ULP code:

// 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 );
}

• Eagle's ULP/SCR are one of its most powerful features. As you've found, ULPs are used to query the board and write scripts which can be absolutely anything you can do yourself. That's its power. Having said that I wish that it was in a 'normal' language, perhaps Python or even Lua, but even you must admit that being able to do something that the authors of the software didn't think of is a good feeling. – akohlsmith Feb 15 '13 at 11:57
• Sure, but their power must be wielded in an arcane way: ULPs are powerful, but can not change the schematic/bord, SCR is a crippled variation of the GUI. Together they can do useful work, but things could have been made much easier! And for my particular problem it would have been be nice if the things added by the autorouter were somehow identifiable. – Wouter van Ooijen Feb 15 '13 at 12:13
• In EAGLE v6.3, the command is WIRE not DRAW (there is no DRAW command). – user40475 Apr 17 '14 at 6:50

Wouter. I didn't see your question earlier because I was at Masters last week.

The way I deal with this is to save a copy of the board to a different name right before running the autorouter. I always name it SAVE.BRD, which can be safely deleted once all done.

My routing workflow seems to be a lot like yours. I route the critical parts manually, make sure the net classes are set up reasonably, then run the autorouter. Then I look for problems like where the autorouter couldn't find a solution, it ended up doing something inconvenient, etc. I go back to the saved version (before autoroute) make a few manual changes hopefully so that the autorouter won't get in trouble, then try again. This might be repeated 5-10 times, depending on the board complexity. The first few autoroute passes are mostly to see if there is a solution and roughly to find the trouble spots. For that I don't even use any optimization passes. The later autoroutes are with full optimization, which for me is usually 8 passes with costs changing over those passes to get the characteristics I want.

Even though I do a save to SAVE.BRD before each autoroute pass (and then re-open the original file to proceed with that), I try not to do a save on the autorouted result until I'm happy with the whole thing. Saving the snapshot to SAVE.BRD each time is a safety backup in case my fingers accidentally do a save before I think about it.

It would be nice if Eagle had a ripup option for the last autoroute pass, but there is no such thing.

• You discipline will work for a person that is always disciplined. You might guess that I am not. Once I autorouted, then made some changes to the circuit, then deleted the brd and tried to switch back to the pre-autorouted version. Not a good idea... So now I more-or-less have a way to un-autoroute, provided that I can distinguish the autorouted traces by width. It would be nice if autorouted traces had some attribute that identified them as such. – Wouter van Ooijen Sep 2 '11 at 14:27
• Strange, I had written "Hi, Wouter" at the beginning of my post, but the "Hi, " part seems to have gotten stripped off. – Olin Lathrop Sep 2 '11 at 14:31
• I believe that is a "feature" that stack exchange has. They think saying "Hi" at the beginning of a post is not needed and should be removed to keep things "clean". Similar to them stripping off @username in some cases... and just like this case where I couldn't type @ Olin (with no space) and @ username in the same comment. – Kellenjb Sep 2 '11 at 18:09
• – Kellenjb Sep 2 '11 at 18:14

If Eagle's data file follows the same approach as older ones that I have played with (eg ye olde DOS Autotrax) then each track segment has a line to itself. Lines are "stand alone" and can be edited or deleted without impact on anything else. Newer "better" systems may not have such powerful simplicity.

If tracks are independent, as above, and if the track widths are unique it should [tm] be easy to identify track segments and delete the lines concerned.

Dim memory tells me that at one stage I wrote a routine to identify component labels and resize, rotate and move them relative to the component body. Track identification sounds easy compared. Save a copy before running program !!! :-).

• Which file format are you talking about? The eagle .brd file is not a text file. My problem with the track segments is not that I can't identify them, but that the only command I am aware of that I can use will do too much: RIPUP rips not just the segment but (some) adjacent segments too. – Wouter van Ooijen Aug 25 '11 at 6:07
• @Wouter van Ouijen - YMMV :-). Not being text per se does not mean it can't be hacked - but it may. I do not know what the Eagle .brd file looks like inside and I do not know if you can tear out whole track segments and concatenate the remainder safely - probably not. Worth a look though. You may be able to write a file reader and rewriter which intelligently rebuilds the file less the undesired parts. It would depend on how well known or knowable the file format is. – Russell McMahon Aug 25 '11 at 7:06
• I realize that at the time of writing the question this was true, but Eagle's file formats now are straightforward XML text files. – akohlsmith Feb 15 '13 at 11:58