Coincidentally I've been working on a dummy load this last couple weekends trying to get it working satisfactorily.
So a few lessons and traps for young players I learned the hard way...
Because I wanted to make it from stuff in the drawer, I stuck with an AZ324 op amp (because I have a bunch from somewhere), and IRF610 mosfet (actually two of, but due to not being well balanced only one is probably doing most of the work, if I redesign the board I'd have two sense resistors and drive each mosfet separately, without a heatsink one very definitely is doing almost all the work). If I'd just got a better op amp much of this wouldn't have been a problem. The mosfets are not logic level, so everything is powered from 12v so they can hit 10Vgs if necessary.
After much filddling (MUCH fiddling) I've got it good-enough-for-my-purposes, there's some oscillation happening when scoping it if you purposefully forget you ever looked at it on a scope it still all works :-) It's hitting within a percent or so for most of the range 0 to about 1.5A (0 to about 12W), and much of the range is a spot on (depends exactly where I "cal" it).
I started out with a 0.01R 3W sense resistor, but that's just too small for the op amp and getting rid of errors was a problem (I might try again later now I have some corrective ability). So I moved to a 0.1R. In keeping with the bodged together nature, my 0.1R is a stack of 10 1R 1206 resistors of unknown (and probably very poor) quality which I further trimmed with another 1.18R (which is a stack of 4 resistors itself) - of course if I'd used better resistors I wouldn't have had to trim, but when using standard resistors careful trimming of your sense resistor(s) is essential especially down at these levels.
Don't underestimate the resistance of your wires and component legs, they can make for a substantial unexpected "error" depending on where you measure! For a while I had my stack of resistors hanging off about 10cm total of around 24AWG wire... and much head scratching about "wrong" gains ensued - if you're measuring across your sense resistor, make sure you're measuring as close to the same point as your op-amp is going to see!
I originally put in a small capacitance on the opamp output (to ground, from looking at other designs with regard to oscillation damping) but removed this as the oscillations were atrocious with it, this is of course very op-amp dependant. Similarly I tried with some various other cap suggestions already discussed here, but they were not really necessary, getting rid of the output capacitance cured the worst of the evils.
I anecdotally find that if the DUT is starting to sag that oscillations do increase a bit, but I havn't looked hard at that, but make sure you're "calibrating" at a current that you know your "DUT" can supply without any problem otherwise it's just a game of "guess which is bad, the DUT or the test equipment".
Like you are, to combat the terrible offset voltage induced errors I resorted to using a negative supply so they could be better nulled (well...). Slapped together with a 555 driving a voltage inverter at about 50kHz (because just that's the fastest I could get with the surface mount caps I had on hand) from the 12v input, and a zener regulator to give me about -3.6v which is supplied to the negative rail of the opamp (12v to the positive). A (biased so it's just a little above and below ground) potentiometer with 200k on the wiper feeds into the opamp I care about (the output voltage - eh, I'm amplifying the sense output by 10 to get 1A=1V, and feeding this into another amp on the 324 to do the compare to the set voltage which is also 1V=1A, just because it makes the numbers nicer) - see
http://www.ecircuitcenter.com/Circuits/op_voff/op_voff2.htmSimilarly I found that the bias current also must be compensated for, a 1k resistor between 0v and the non inverting input did the trick - see
http://www.ecircuitcenter.com/Circuits/op_ibias/op_ibias.htmBecause of my gain requirements (10x as mentioned to get 1V per A reported out of a 0.1V per A sense resistor) it does mean I have now 2 calibration points, the gain, and the offset null. I found the best way to calibrate it was to connect a supply (DUT) through a multimeter showing current, allow it to warm up, then disconnect the DUT and zero using the offset adjustment, reconnect the DUT and adjust the gain to synchronise what's "reported" and what it should be, check/adjust offset again, check/adjust gain again... after 2 or three cycles it gets "homed in" such that no more adjustment is necessary and hopefully you've got the offset killed (at that temperature, angle of tongue and phase of moon).
Attached annotated schematic (excuse the crudity), ignore the percentages on the resistors it's just the default. VNeg and VOff are not shown, they are respectively the negative supply and the wiper (with 200k in series) of the offset potentiometer which I made separately (after finding it was necessary). Ignore the 3 funny lookin' components not connected to anything bottom left, they are artifacts of some 0-Ohm jumpers I used routing the PCB.