Thursday, August 31, 2006
- a CNC machine
- a laser cutter
- a 3D printer
Wednesday, August 30, 2006
Things get a little complicated...
Pololu said that I should get mine by Saturday, so this weekend... :-)
The big change in the programming approach is that I'm not changing numbers to ASCII strings when I send them over any more. That cuts the length of the message that I have to transmit and receive way down. When I get to having to receiving Word and Long variables, though, I am going to have to write a bit of VB code to interpret them since as best as I can see the PIC chips don't understand what is meant by representing a negative integer by two's complementing it.
Step 1: Create a flash programmer
So I got a few Z8's yesterday. First step was to create a mess of wires and plug it into the computer to see if I could get it to work. A little bit of prototyping board, a LED to actually test if it was programmed (I created a short blinking Z8 program), and whoosh.. It worked. Well, okay, this was the second attempt. In the first attempt, I had a bit of a problem getting the voltage right. These chips are 3.6V max. It took me a bit to get the voltage regulator working, and in the process, I burned out one of the LED's. It is now putting out 3.3V solid from a 10V wall wart.
I think next step is to solder a board with DIP socket (I only have a 40pin socket, but oh well, it will just use a bit more real estate), and include some pins for the debug port (Only requires an extra 10K resistor, and 4 pins to plug into the Z8 smart cable.)
After that will probably be getting comms up. Probably a ways off though.
Okay, I decided to go ahead and get the soldering iron out. You can see the result here. Yeah, I did end up using the 40PIN dip socket, it actually doesn't look too bad. On the top left side of the board in this picture, you can see the pins to which the in circuit debugger/flash programmer attaches (It's easier to see in the full picture version). I decided to not add any LED's, since I plan on actually using this board to attach to try and get my serial link up. I've still got to do a little more research. I may want to add a buffer chip between the Z8 and the host computer. The dev board uses a MAX3222 chip between the serial inputs and the UART pins on the Z8.
Here what everything looks like when the Z8 smart cable in-circuit debugger/flash loader is attached. I went ahead and loaded the LED flash program, and checked to make sure it was running with a multi-meter. Tick-tock. Tick-tock went the multi-meter indicator. It appears to work. I am a bit concerned about the voltage. The resister tolerances on my protoboard put the voltage a bit lower than the resisters I used here. I measure the voltage going into the Z8 at 3.5V; the chip has an absolute max at 3.6V. I guess it should be okay. If not, ah well. I can probably add another 10K ohm resistor to reduce it just a little more if I blow this chip.
Tuesday, August 29, 2006
An ungrateful Plaas casts Cerberus back into the pit...
Once I had the 16F877A running at 4 MHz, it was obvious that I was still getting a ragged motor output. Something else had to be wrong.
At that point I started wondering what was different about the 877A board and the 628A board, because at 4 MHz the 628A board worked fine. I noticed two things different. First, on the 877A board I was feeding the 754410 H-bridge chip 12.4v instead of 5.4v. I had already adjusted the settings downward on the duty cycle to keep the GM4 gear motor within its 0-6v range.
The second thing was that I hadn't bothered to install a 100 nF ceramic disk capacitor across the power leads coming from the 754410 into the GM4. In theory, that little capacitor is supposed to keep backpropagated voltage spikes from coming back from the motor into the 754410. There has never been a lot of that sort of thing coming out of the GM4 so I hadn't got round to putting it in yet.
Just to be sure I slapped one across the power leads and... LO AND BEHOLD... the GM4 ran smoother, not perfectly, but smoother... a LOT smoother. It also ran a lot faster, indeed, it ran at speeds one might expect from it at the duty cycle I'd set for a change.
I've taught electrical installations for buildings at university but my feel for electronics work is pretty much pure thumb suck. I do know enough about capacitors to know that when you feed a variable signal into one they tend to smooth it out. Indeed, if you send a variable signal into a big enough capacitor when it finishes charging up you get an output that looks like the average of the incoming signal integrated over time.
Keeping that in mind, I remembered that back when I was building copies of Simon's stepper board he had had a fondness for polyester (green plastic) capacitors that were much bigger than the little ceramic disk capacitors that I had shifted over to when I went over to the GM4 a month or so ago. I still had several lying about.
I reasoned that the big polyester capacitor had a bigger time constant on it than the little ceramic disks so it should so a better job of turning the output from the 754410 into something the GM4 understood. The polyester capacitor had the same rating, 100 nF, as the ceramic disk so I figured that it couldn't hurt to try.
I slapped that green bad boy across the power output leads and cranked up the board and the GM4 ran as smooth as silk for Mode 7 at 977 Hz.
Never one to leave well enough alone, I went fishing for different PWM frequencies again. At 4 MHz for an 8 bit duty cycle resolution I had two other options, Mode 8 at 3906 Hz and Mode 9 at 15625 Hz. As Microchip had said in their literature the higher frequencies don't make as annoying a whine as the lower ones do. The GM4 ran just the same, save a little quieter, at those frequencies as well.
Just now I decided to REALLY push my luck and swapped out the 4 MHz resonator for a 20 MHz resonator and kept the same Mode 9 in the firmware, which was now going to be 15625 Hz x 5 = ~78 KHz.
IT RAN PERFECTLY!
All of the preconceptions I'd picked up over the past few days about the frequency response of the H-bridges were WRONG! :-)
Campers, running 2 motors for the x/y axes off of one 16F877A chip is back on the table! :-D
Monday, August 28, 2006
I grafted the second CPU on the XY controller board to handle 1 KHz PWM signals to run one of the plastic gearmotors. If I don't get some answers back from Microchip that give me some more elegant options the board will get another 16F628A CPU to run the other plastic gearmotor and we will have Cerberus. :-o
UPDATE: The bad news is that Microchip didn't have any good news for me.
The good news is that I've discovered that I have some three-post resonators rated at 4 and 10 MHz. I'm going to pull that 20 MHz crystal and try out the three-poster resonators and see if I can find a usuable PWM frequency. If I do I'm going to see if I can get the board running properly at the lower frequencies.
I hate losing the performance, but hey? What's the choice?
Sunday, August 27, 2006
It's Sunday night and NOOOOO fish. :-(
I did a LOT of fishing around. It appears that the 754410 is NOT a happy camper if you feed it much more than a 1 KHz signal. Ditto the L298N. You can get them to respond up to just under 4 KHz, but they're not happy about it. Not happy means you have a reduced range of speed control if any.
The problem is that timer 2, which generates the clock signal for the two PWM channels, only allows you a divisor of 1, 4 and 16 for prescaling. What that means is that when you slap a 20 MHz clock crystal on the 16F877A the nice little 977 Hz PWM signal that was running your GM4 and Frankenmotor jumps 5-fold to just under 5 KHz. You can fiddle that down to about 1.22 KHz, but your H-bridge chip efficiency and functionality goes south on you.
I went back to the Microchip PIC literature on PWM and those guys recommend that you try to run your PWM frequencies at over 20 KHz so that people won't hear the hum. That didn't square with what I was observing with the H-bridge chips that I was using so I did a literature search to see what I could find out about the frequency response of the H-bridge chips. I found several off-hand references that the 754410 wasn't good for much above 4 KHz, which squared with what I had observed.
I continued looking and discovered one H-bridge chip that was certified to work at over 1 MHz, Intersil HIP4081A. The data sheet had this little jewel in it...
For example, the HIP4081A can drive medium voltage brush motors, and two HIP4081As can be used to drive high performance stepper motors, since the short minimum “on-time” can provide fine micro-stepping capability.
Short propagation delays of approximately 55ns maximizes control loop crossover frequencies and dead-times which can be adjusted to near zero to minimize distortion, resulting in rapid, precise control of the driven load.
Interestingly, these chips work for 2.5 amps. I wonder if they had the NEMA 17's in mind. These bad boys cost $5.50/unit at mouser.
Anyhow, I'm hoping that the fine folks at Microchip know lots of stuff that I don't so I made out a nice trouble ticket on the issue and turned it in to them. Who knows, maybe this apparent frequency response problem is just a misunderstanding of some trivial detail and I'll wake up to an email from them with a nice message that starts out "Hey dummy! You forgot..."
I have some hope that that will be the case. I have two modes that I can get 977 Hz, Mode 2 and Mode 7. Mode 2 gets you 10 bits of speed control resolution while Mode 7 (which I am currently using) gets you 8. I redid the Frankenmotor control board to do Mode 2 and it didn't want to work right, so I'm hoping that there is something besides a H-bridge frequency response issue involved.
If that doesn't happen, though, I have a couple of options. The simplist and least happy option is to just put a 4 MHz clock crystal on the 16F877A and forget the problem. That guts any extra performance hopes I had with the 16F877A and leaves me with basically a big memory 16F628A. I'm not real happy about that.
The other approach is to simply use two 16F628A's to drive the PWM-driven motor speed channels on the 754410 and close couple them with the 16F877A which will keep track of the pulse counts and tell the 16F628A's what to do to the motors.
Anyway, it was a fairly frustrating weekend.
Saturday, August 26, 2006
Rotation direction and PWM speed control on the 16F877A
Cascading Spline Curve Accuracy
I decided to see how accurate I could get a cascading spline algorithm using 16.16 fixed point addition to run the spline cascade.
You can see the result of the spline here. You may need to look at the full size image to see the smaller details. The gray line shows the linear segments from spline endpoint to spline endpoint. The red line is the double floating point precision calculated spline, and the cyan colored curve is the cascading spline curve, calculated with 32 bit integer addition, with 128 samples per segment, where each coordinate sample is rounded to the most significant 16 bits, then plotted as a line to the next sample coordinate.
You can see the effect on precision at the end points at some of the curves -- They don't always connect 100%. However, assuming that 1 pixil = .02mm (Giving the motor position a range of 1 meter), the largest error for this specific curve is about 0.5mm. I did not implement full pre-processing of the spline curves, and the actual accuracy will be about double that (by distributing the error throughout the curve, rather than just at one endpoint.) The cascaded curve ends would also be joined together. Accuracy can also be improved by slowing down the motor and/or decreasing the number of steps/spline.
For this simulation, the motor was pretty much moving constantly at about 2mm - 4mm per second (each pixil is about .02mm - the entire shape is about 1cm across), except for one point at the bottom left where the motor is assumed to have started and stopped. I'm not sure the motors chosen would be able to accellerate to meet the demands of this particular spline path, but that will come later when I start experimenting with the hardware.
The motor would need to be able to position itself to each of the 128 sample point coordinates with good accuracy. I did not simulate velocity tracking yet, but each of the 128 points could also yield the desired motor velocity for that moment in time, which would minimize actual physical error as the motor tracks the spline curve with near lock step accuracy.
Friday, August 25, 2006
Serial Comms re-established on the 16F877A
Once I did that the serial comms VB.NET app started doing echoes like a champ.
I've got 2 separate PWM channels on this bad boy so I am going to see if I can run two different plastic gearmotors off of one 754410 dual darlington chip.
Simon quite rightly pointed out that synchronizing two shaft encoded feedback dc motors could be quite a technical challenge. Certainly, if we tried to do it with two synchronized control boards using 16F628A's communicating by serial comms it could well be.
I plan on running both out of one large, fast PIC chip like the 16F877A, or if that doesn't work one of the bigger, even faster 18F models. If I can get that to work I will have that X/Y controller board talk to the extruder board via dedicated software serial lines and save the hardware UART line for the token ring that talks to the PC. That way the PC app has administrative control over the individual boards while they can talk to each other over dedicated serial lines and not clutter up the comms line of the token ring.
I've got to order a couple of the plastic gearmotors out of Canada. I think that I am going to order those GM8's instead of the GM9's (equivalent of GM4).
They have a through-the-gearbox drive shaft. The top side of the drive shaft should seat the shaft encoder very nicely. They don't cost any more than the GM4's.
Oh yeah, here's the serial comms echo programme.
Dim i As Byte
It's really complicated.
Thursday, August 24, 2006
I had noticed that when I sent a query to the PIC controlling the GM4 motor that sometimes I didn't get anything back. It was easy enough to do workarounds for that situation and I didn't really think too much about it. I figured that it was just some sort of mismatch.
I was right and wrong. Apparently, when I sent out a query code to the board after I'd put to going somewhere on the axis at a given speed the CPU occasionally got from the line of .NET code where the query went out to the line of code where the answer was expected back faster than the PIC could respond.
While it was an occasional problem while the GM4 was being directed to go clockwise it was a constant problem when I told it to go counterclockwise. I'm not sure why that was so, but it was.
I cured up the .NET problem by putting a half-second pause between the query and the return string (57 bytes). Having to convert Long integers to an equivalent ASCII string is a non-trivial task for the 16F628A. I'd like to just send over the integers as integers, but the PIC integers don't do 2's complement maths to talk about negative numbers like .NET does so I'll have to sit down and write a 2's complement routine to convert what I get from the PIC over the serial port into something .NET can understand.
Anyhow, I have the serial comms control programme talking reliably with the PIC GM4 board regardless of the direction it's been told to go now, so I should be able to automate the calibration of the PWM/pulse and overshoot tables. I'm going to try to move those tables over to the EEPROM memory in that they take quite a bit of RAM and programme memory right now.
If I've read the manual correctly while I can't do a bootload with the 16F628A I may be able to reprogramme the EEPROM memory over the serial link if I am careful. That would let me update the tables without having to reprogramme the whole PIC chip. That would be nice.
Tuesday, August 22, 2006
Eat your heart out!
For a pulse count setting of 15 (0-18 scale) run over a 100,000 pulse test I got an average pulse count of 15.001421. That works out to a 0.0095% positive bias.
The average PWM setting turned out to be a shade over 212 (0-255 scale) . Interestingly, the longer the test ran the lower a PWM setting was required to keep on track with the required pulse count/unit time setting. It started out at a shade under 222. I guess when the gear box warms up it works better.
Oh yeah, it corrected for overshoot perfectly. :-D
BTW, I'm definitely going over to the 16F877A. I'm within 25 words of the upper limit of memory on the 16F628A and my code is fairly tight. :-(
I tightened it some more and got 200 words back, so I still have a little wiggle room left. :-)
Monday, August 21, 2006
Assuming the data that Forrest gave is typical, it appears the motor velocity vs PWM is anything but simple. I've tried a few expressions, and the one that came the closest is hard to explain (There isn't really enough data points or test runs to come to any conclusions; I'm going on what is available right now.)
The blue squares show the measured motor speed for a specified PWM value.
The red squares are: PWM = SPEED * 16 / 21 + 50
The green triangles are: PWM = SPEED^2 * 172 / 17 + 70
The yellow triangles are: PWM = SPEED^1.6 * 172 / 17 + 70
Very puzzling. In any case, it appears it won't be easy to try to get exact equations of this nature.
I have been considering using splines computed on the host being sent to the motor controllers, instead of linear segments. I believe this is possible, and the microcontroller code very straightforward (So far, compiled C methods consume 26 bytes of RAM, and take about 90 instructions to execute the spline logic, and to decode the next spline messages from the host. This code should have worst case spline sample positions on the order of .04mm for a head moving at 50mm/second in the extreme degenerate case. More typically, a head speed of 5mm/sec would be from 0.02mm to 0.04mm per sample, depending on the number of steps in the spline.
As such, I think that position can be tracked directly. At every pulse from the motor sensor, or whenever the computed spline position changes, simply send the appropriate Power Left, Power Right, or Coast command to the motor control, based on whether the current position is too far left, too far right, or spot on the spline desired position. I predict such a scheme will emulate exactly the pulse width modulations needed. I'm not certain whether you'd need to send the 'brake' command -- I guess it depends on how much better it is at stopping the motor than simply putting it in reverse? Anyone know if this would cause problems?
NOTE: I can increase spline resolution even further, but this might require doing greater than int32 additions; there isn't a lot of compiler support for 40, 48, or 56 bit integer arithmetic. If this was necessary, a few hand coded spline cascade addition methods would need to be created.
Automating PWM settings on the GM4 controller...
Not only will using a lookup table decrease the motor response time to changes, it will also allow me to greatly reduce the PWM adjustment step. That should make for smoother motor speeds.
Over lunch I put the PWM settings table into the firmware of the GM4 motor control board. I also reduced the adjustment factor for controlling PWM settings down from +/-4 to +/- 1.
Beagle was interested in how fast the GM4 could change speeds. I took a tentative look and it seems like now that I've put the PWM settings table in that the transition is faster than the sampling period. I'm going to have to go back and find in my notes what I set the sampling period to. It appears to be about 100 msec. I got that wrong before. Suffice it to say that the GM4 winds up to the speed I've set it to faster than I can punch the command button that sets the time and then punch the command button that checks the speed. That's probably about a half second.
I'll have to write in a check into the firmware to measure this and that will have to be for later, because lunch is over.
DC Motor Programming Madness
Example Computer output to Comms/PIC:
Each line here represents a 'job' in this program
(X movement, Y movement, Speed (in pulses per second)
All this data is in Pulses. Software translates positional data to # of pulses needed. On DC motors each pulse represents an encoder slit.
RepRap Variables in this example, mostly generated from original vector coords=
JobX=200 ' how far to move on X
JobY=50 'how far to move on Y
TotalTime=200 'Total pulses needed for the job. (Always equals largest absolute value of jobX or jobY)
Time=0 'current pulse # in job
dX=0 ' desired pulse position in job
dY=0 ' desired pulse position in job
X=0 ' actual position (in pulses)
Y=0 ' actual position (in pulses)
(Keep these in buffer so it knows what is up next. So it can prepare speed changes beforehand:)
RepRap Pseudo-IO in this example:
XmotorPWM, sends a 0-100% duty cycle for motor X
YmotorPWM, sends a 0-100% duty cycle for motor Y
Example Settings for the equations below:
Speed=100pps (speed in desired pulses per second)
MaxSpeedX=200pps (speed of motor at 100%PWM)
MaxSpeedY=200pps (speed of motor at 100%PWM)
Overshoot=9 (average overshoot in # of pulses at 100%PWM)
Correction=20 (1-100, represents rate of per-cycle motor speed corrections.)
Every Predicted Pulse (On PIC would be every (1/Speed) seconds. In example it is every 1/100th second)
dX=JobX * (Time/Totaltime)
dY=JobY * (Time/Totaltime)
XmotorPWM=(Speed*(JobX/Totaltime) /MaxSpeedX). Will return 0-100% for PWM speed. Needs to be modified in case it falls behind/ahead.
XmotorPWM=(Speed*(JobX/Totaltime) /MaxSpeedX)+ ( (dX-X)/100 * Correction ) Correction=10 will modify the motor by 1% per pulse
Now, to account for next-job-speed-prediction, you need to modify it further when it nears the end of it's job:
if Time >= Totaltime - ( Overshoot * (Speed/MaxSpeedX) ) then
Calibration needed to make it work:
MaxSpeedX,Y (total pulses measured after 1sec full-speed movement)
OvershootX,Y (overshoot measured in pulses, from going 100% to 0%
Correction (value from 0-255, sets the ferocity in which motor speeds are adjusted to keep it within its desired position. 10=1% correction, 100=10%, etc)
Programming note: The extra variables in memory like dX and dY can be trimmed out and replaced with more equations, I just used them to make it look nicer.
Other Programming note: Murphy's law dictates there is at least one malformed equation in a pseudoprogram this long.
I hope some of this makes sense. Again, I mostly wanted to show that it was possible to have PWM control with dynamic adjustment of speed to keep in-line with pulses just as a stepper motor would. That, and being able to change speed a few cycles early, using the difference in speeds and a set ratio to determine how early to change.
Sunday, August 20, 2006
Overshooting with the GM4...
As it was I had to use Long (4 Byte) integers. Those aren't seamlessly integrated into my compiler just yet. When I finally figured out how to handle them in my firmware programme I then discovered that I was having problems reading a number via the serial UART into a Long variable. THAT turned out to be an honest to gosh compiler bug and a very obscure one at that. Fortunately, while I was in the process of documenting the compiler bug for Vladimir at Oshonsoft in Serbia I discovered an easy workaround that let me avoid the invoking the bug.
Vladimir is a good man. He puts out a new cut of his compiler every few weeks and almost always addresses outstanding compiler bugs with that kind of quick turnaround time.
Anyhow, I did a test series to determine how much overshoot we were getting when we detected a stopping point. Here is the raw data.
I also did a 5-point smoothing on the raw data so that it was easier to see the curve.
Beagle! If you want to use this as input for your cubic splines fitting you can either get the data off of the Raw Data chart (the motor speed pulses are integers) or give me a shout with your email address and I'll shoot over the Excel file to you.
Oh yeah, the sampling period is 0.2 sec. That works out to about 42.5 rpm for a top speed of 17 pulses/sampling period. The reason that it isn't higher is that this board uses 5.45v to power the GM4.
The max voltage you are supposed to put to the GM4 is 6v which is supposed to get you 70 rpm. I didn't want to risk making a mistake and burning it out by using 12v input and then trying to limit the speed range to stay under 6v. I didn't know that H-bridges eat a few volts off the top of what you feed into them, so as a practical matter I'm really only getting about 3.65v to the motor after I run it through that 754410 dual Darlington chip. Now that I'm confident that what I've got works I'll build another board with 12v going into the 754410 and trim what gets into the GM4 in the firmware.
It's worth noting that even if I don't try to compensate for the overshoot that would get me a max error of 6/256 or 0.023 mm for a straight threaded rod positioning system. If I hook it to a pantograph linkage like I plan the error will multiply by whatever multiplying factor I set the pantograph to give me. Kicking it up to 6 mm/sec would give you an overshoot error of 0.2 mm at maximum speed. It's obvious that we have to compensate but it's also obvious that we don't have to have a very sophisticated compensation algorithm to hit our 0.1 mm accuracy target.
Supposing that I build up another GM4 controller that uses 12v instead of 5.45 I can expect to get a maximum rpm of 70. That would mean that the scaling factor to get 6 mm/sec with a pitch of 1 mm/turn gives you an overshoot error of 0.12 mm at a maximum translation speed of 6 mm/sec.
Saturday, August 19, 2006
A note on the JDM PIC programmer board...
I did a diagnostic rundown on the board and used one of the many checks that Simon thoughtfully included. This one was the problem...
Measure the voltage between pin 5 (-) and pin 4 (+). Tick the Enable MCLR box and it should go to +12V.
I got +7.53v. That low a voltage makes PIC programming a hit or miss affair. This sort of problem had been reported regularly with laptops trying to use the JDM programmer. I had it happen with desktops.
At first I thought that it might have been just a poor serial port design in my PC even though I had an Intel motherboard in it that the serial signal was coming from. I tried it again on my new top-of-the-line Dell workstation and had the same thing happen, though. At that point I decided that the JDM card was simply obsolescent.
I'd lost a month playing guessing games with the JDM by that time so was in no mood to try building up another kit or getting another plan off of the internet. I wound up paying about US$130 for a really good ME Labs USB PIC programmer with a 40 pin ZIF socket (that lets you program PIC chips without having to use a little screwdriver to get them out of the socket). It's a lot easier on the pins. The ME Labs PIC programmer also is very forgiving. If you put in a chip backwards it politely asks you what the hell you're playing at on your PC screen instead of staging an impromptu white smoke and burned electronics event on your worktable. I've never regretted the expense for a moment.
Now I can program every PIC chip made without worrying.
I know that there are a lot of PIC programmer board designs out there that you can get both as kits or ready-to-use boards that are a lot cheaper than what I bought. I've no doubt, as well, that there are PIC programmer boards out there that are a lot better value for money. My experience is currently limited to the JDM and the MELabs, however.
Serial Comms Board...
The instructions for building it are great, especially the pin voltage check diagnostics. Those really help you check to see if your soldering and wiring is right.
One thing I don't suggest that you do is try to...
Experienced hardware folk never trust their hardware. First make sure your serial port operates, which is easily done by shorting the Rx and Tx lines out on the serial lead from your PC. These are pins 2 & 3 and a small screwdriver will do the job.
Pay especial attention to that word Experienced and ask yourself honestly if you are. It is really easy to get a little dyslexic and count the pin counts from the wrong direction. As well, sticking a screwdriver, however small, into the cannon connector handling the serial port on the back of your PC to short two pins might be a good idea if you have good fine motor control and know what you're doing. For mere mortals, however, it doesn't address the reality of trying to find the right pins in the dark under your PC worktable with a little flashlight in your mouth while at the same time trying to tell your kid to type something on the keyboard and see if you get a response.
If you are a klutz like me I'd recommend that you take the cannon connector that you bought to connect your comms card to your PC and solder a jumper between pins 2 and 3 on it. I'd also recommend that if you're over 40 or wear contacts or glasses that you acquire a big magnifying glass and a bright light to help you read the tiny pin numbers on the back side of the connector to make sure you've connected the right pins. Reading tiny white numbers on a white plastic background is the pits.
Then, when you want to check to see if you have a live RS232 port plug that bad boy into your serial port. If you've got sensitive fingertips you can do that by feel without having to crawl under your worktable. You also don't have to put your kid through the trauma of trying to understand what dad is trying to get him or her to do while you're talking to them in the dark with a flashlight (torch) in your mouth and periodically hitting your head on the underside of your worktable. It's a family tranquility thing. :-s
After you've done the diagnostics if you've not got Linux installed you can use Hyperterminal. The instructions for using Hyperterminal are pretty straightforward.
If you're a Visual Studio afficinado, however, there is another possibility. A nice guy named Corrado Cavalli has a website. Therein he has quite a nice little VB.NET serial comms programme that works quite well to test your serial port. I've made a variation on it that is somewhat more useful. It's a good starting point if you have ambitions of writing a controller program independent of the Java one that Adrian has written, something that might be reasonable if you are a programmer with ideas but are not a Java coding god.
If you want mine you can download and use.
Plaas' magic VBNet serial comunications thingy
Have fun! :-)
Thursday, August 17, 2006
Dual Disk Sketch
Okay. Here is a sketch of a dual disk concept. I've left a lot of detail out (for example, how the extruder head might work -- it would need to be attached to something above the work space, or to a part that straddles the base with enough clearance to allow the inner disk to rotate the ~45 degree span.)
I'm not sure if it is an improvement or worse than a threaded model; but I thought I'd throw it out there anyway. Some of the problems that it might have:
- friction between the plates. What is the coefficient of friction for two plates of plexiglass split by a layer of vaseline?
- mounting the motor to the plates. I've sort of made this abstract, but I think it could be done.
- donut print area ; As you get closer to the centers, it becomes a lot harder to control (one motor has to be driven uber fast, the other, uber slow; it seems rather than trying to fix the singularity, just don't go there). I figure the ring form would allow a reasonably wide variety parts to be made.
- available resolution varies : the resolution at a point will be different for different angles. As you get closer to the center of the top disk, resolution in the direction of it's rotation will be higher
- It is a reasonably small footprint for the size of pieces it can make.
- It would be relatively easy to add a 2D motion sensor to monitor the top disk motion (Upside down optical mouse mounted beyond the radius of the inner disk.)
- It should be pretty easy to build the XY axis. The Z axis would probably still be a little more difficult.
Here are a two wireframe top down images that show the range of motion of the center disk (The top disk is allowed to rotate 360 fully.)
The extruder nozzle is the square/triangle pair near the top.
An outer disk with 30cm diameter would fit on a frame of about 40cm square, and could print solid cubes with a base about 10cm x 10cm, long rectangular pieces of about 2cm x 25cm, and of course, larger hollow pieces of up to about 30cm in diameter.
Oh, and here is how you would add a second print head (click for a larger image). This would not allow you print two parts at the same time (you'd need a second top disk for that), but could be used to fill with a second material
**** HOW IT WORKS ****
There was some confusion as to how this XY axis would work. In the drawing here, I hope you can see how you could move any point in the ring under the extruder head. Look at just the green lines for a moment. If motor A were the only motor turning, you would form the arc of a circle between the two darker green lines radiating out of the center of that circle. If motor B were the only motor turning, you would get an arc of a circle between the two darker green lines radiating from that circle. If both motors were running, you would get some curve (or line, if you controlled the motor speeds accurately) that represents the sum of two circular arc vectors.
The same would happen when moving along the blue line, and the red line. I think it might be easy to visualize if you turn the two disks into lines, put the extruder head out on the tip of the line, and pretend that this is above a working surface --> You get a robot arm. If you reverse the concept, and put a working surface on the robot arm instead of putting the extruder on it, this is what you get.
Here you go...
Attach your xy threaded rod positioning stage to the rightmost red knobbed node, put in a longer slide threaded vertical axis and put a Mk II in place of the leftmost red knobbed node and you should be good to go. :-D
Microbric's Viper Robotics Development Kit
Wednesday, August 16, 2006
Just for fun...
I've made a rack and pinion script but a reprap will have a hard time making a gear tooth much smaller than about 2 mm according to Adrian. That means that you need something like a 25 mm radius gear to engage the rack and then you have to get a 12-15:1 ratio for your gear motor to slow it down enough to give you a translation rate in the 4-10 mm/sec range. That's either a lot of little gears or a few really big ones.
Looking at Kiplinger's linkages page got me to thinking about Joseph Whitworth and his genius for precision machinery during the 19th century.
Sure enough, Kiplinger had one of Whitworth's linkages. That one wasn't as interesting as Peaucelliers straight line generating linkage, though. I thought for a while of using a threaded rod to push that linkage to generate longer straight line movement. The only problem with the idea is that whereas a threaded rod gives a very linear input vis a vis rotation, Peaucellier's linkage wouldn't use it like that. Then I thought... why not use a bloody pantograph to multiply the translation speed of a threaded rod?
We'll lose force and resolution by the same proportions as we increase the travel distance, but it should be easy enough to build and test. We've also got resolution on the threaded rod to burn.
With a pitch of 1 thread/mm, a very common one, we get a resolution with a 256 pulse encoder of 0.0039 mm/pulse. Pushing that up to six times that will still give us just over 0.02 mm/pulse which is a factor of 4-5 better than our target.
It's not like others haven't done similar things before, but it might solve our problem with wanting to use threaded rods with slow gear motors. :-)
You know what? If we hooked Peaucellier linkages on the short and long stroke nodes of the pantograph we'd have a hell of a stable motion amplifier. Wowzie!
Hmmm... If we looked at the pantograph as not being basically a stick linkages but rather extended those sticks on the vertical axis and made them planes and then slid the Mk II up and down on the vertical edge of the long stroke node plane you'd have a very different kind of reprap machine.
That's enough creativity for one evening... or morning, I see. :-s I need to catch a little sleep.
Nite all! :-D
Polygons and CSG
1. Compute the convex hull of the polygons you've got.
2. Let A = intersection of all hull edges that are also polygon edges.
3. Compute the convex hull of the edges that are left.
4. Let B = the union of all those hull edges that are also polygon edges.
5. Object = A . B
In fact you have to do it recursively as there may be bits left over after step 4 (the union and intersection operations alternate as you go down the recursion), and also step 4 can give more than one disjoint shape. If you start with multiple disjoint objects and nested polygons things are a bit more complicated too, but that's the essence of it.
For the red object below that gives
object = A . E . F . (B + C + D)
I think that's the simplest expression for the shape, and it's what the algorithm makes automatically. I think it also offsets correctly.
To turn the CSG representation back into a polygon I use an algorithm called MEG (model edge generator) devised by my old chum John Woodwark.
One of the nice things about CSG is that quad-tree division gives you a real handle on it. Imagine a complicated CSG expression and a rectangle. Classify all the half-planes against the rectangle into three categories:
1. All solid
2. All null
You can now massively simplify the expression inside the rectangle: 1 is the universal set, 2 is the null set, and 3 stays as it is; when you make this substitution the CSG expression collapses right down to unions and intersections of just those half-planes in category 3. This is called pruning the CSG expression to the rectangle.
You recursively divide a quad tree of rectangles over your object, pruning as you go, and stop when a quad has two or fewer half-planes in it. Those quads with two in may be a corner (it's easy to work out if they really are or not from the position of their intersection point). You join those corners up in the right order and you've got your polygons.
Tuesday, August 15, 2006
Offsetting and Sharp Points, part 2
I'm going to go ahead and post what I believe is a summary of the CSG algorithm coded in Java, the algorithm that I was working on, and some thoughts on how to adapt the existing algorithm to have the same qualities as my approach would have given. The image thumbnail to the left shows a slice of my 'widget' example used recently. The goal of the algorithm is to turn this into a perimiter trace. It can also be adapted to return the region that must be in-filled.
Here, I show an image that would be gotten using the CSG algorithm. I do a poor job illustrating this with my program, but Adrian added a blog earlier that details this more clearly. I'm not sure exactly how the boolean region expressions are determined; I would guess some kind of binary partition line algorithm is used? It's not too important, as long as it works and is reasonably fast.
Here, you can see how my algorithm would have accomplished the same task. The red inset line segments are calculated by intersecting each adjacent edge, offset thru an angle 90 degrees counter clockwise to the edge direction. The edges terminate at intersection points. The result can be a self-intersecting polygon; this is easily remedied by turning it into a collection of simple polygons and removing the simple polygons that turn the wrong way (They form negative areas that should not contain any thread).
This demonstrates that the two algorithms are actually doing the same mathematical operation. The only difference is how the data is organized and abstracted, and the algorithm used to process it.
This perimiter seems to me to be a weaker bond than could be possible. It introduces defects on the sides opposite an inner angle that wanders too close (Hard to see here, but the pointy angle is actually a divet). It also appears the area shown in red has quite a bit of material extruded into it twice (on separate passes with the extruder head.)
What I thought might be better approach is to clip the interior angles; in effect, it tries to 'circle' around the inner angles rather than wander too far away. Though a circle is the ideal case, a line approximation is good enough.
The perimeter extrusion should be a lot stronger, you avoid the seam, and you aren't trying to squish so much material inside while tracing the perimeter.
To solve this, I came up with a vector equation that could be used to clip these degenerate inner angles so that the thread, as closely as possible, forms a path that circles around the inner angle.
So, the question is, can the CSG algorithm be adapted (if necessary) to clip inner angles? I think the answer is yes. If an extremly tiny triangle is added to round out every inner acute angle, it would seem this would grow to the size necessary to fill in the gaps. It can even start out as an infintesimal triangle, if the boolean region partitioning algorithm doesn't choke on it.
When this triangle is included in the final inset area, it gets amplified and bridges all the separate regions, if it is reasonably possible to do so.
I don't know if my algorithm is better/faster/easier to understand, etc. To me, calculating the boolean expression in the CSG solution would appear to complicate factors a lot. If existing libraries could be used, this might reduce complexity, but I believe there are probably also libraries for polygon manipulation and decomposition (They are, after all, attacking almost identical problems.) In any case, it does appear that whatever algorithm used for perimeter and infill calculations, there is a solution for the acute angle defect if problems begin to occur because of defects in the printed parts.
*** UPDATE ***
After thinking about the boolean expression Adrian posted, I think the half plane combination can lead to problems unless you are very careful about how you compose the half plane boolean expressions. It is best if I illustrate with pictures:
The full sum of products expression for this is image's region, where '.' is an intersection, '+' is a union, and '^' is complement, for half planes that are solid in the downward direction, is:
A . B.^C .^D . E .^F 
+ A .^B. C .^D . E .^F 
+ A .^B.^C . D . E .^F 
+ A .^B. C . D . E .^F 
+ A . B. C . D . E .^F 
+ A . B. C .^D . E .^F 
Normal boolean algebra allows you to simplify this to:
A . B . ^F [Red]
+ D . E . ^F [Green]
+ ^B . ^D . C [Blue]
The yellow region represents overlap between the red and green region.
If you offset each half-plane in the away from the outer edge of the polygon, the simplified form starts to have problems:
The BDC product term is not truncated by the F half plane (It doesn't need to be in the non-offset region), and the result is a triangle that blows out past the F plane.
I could not see what form of boolean expressions would be created by the Java code, but test cases like this would expose whether it is working correctly.
In any case, special care would need to be taken before assuming applying a valid boolean combination on offset planes will result in a usable inset area. The full sum of product representation doesn't have the problem I describe here (The 'bad' triangle at the bottom gets clipped off by the F plane in this case), so it is still a valid approach, assuming you take into account every clipping half plane for every region included.
Offsetting and sharp points
Ignore the inner offset triangle and quadrilateral for the moment; just stick with the outside edges. We have six lines A...F that are infinitely long and are considered half-planes solid on their sides with the black dots. Using . for intersection and + for union, the boolean expression that describes the outer shape is
This is exactly how the RepRap Java code (subversion repository - start here) solves the offset problem.
Direct to PCB InkJet Resist Printing
Sunday, August 13, 2006
Acute Inner Angle Clipping
So I didn't get a lot of time to work on this during the weekend. After thinking about this problem more, I think the mathematically 'correct' way to create the perimeters, the infill material, and the support material would be to operate on the model while it is still in 3D rather than to slice it and then attempt to maniplate it for wall perimeter. Trying to solve the problem in 2D planes will reduce the tolerances in the Z direction. If you, for example, are attempt to print as perfect a sphere as possible, you'll end up making an ellipsoid that is slightly taller than it is wide (by up to whatever the thread width happens to be? Not sure on this, it probably also depends on how the thread squishes around once it leaves the nozzle.)
One idea to get the mathematically exact solution would be to create an algorithm to generate 3 separate 3D models: one to defines a surface containing the center of the perimeter thread, one to define the surface interior inside the perimeter threads, and one to define the surface of the support material. Turning these three models into a set of extruder paths is almost trivial -- just trace the Z-Plane intersections of the perimeter model, add alternating scans using the infill model, and add support material scans using the third model.
In any case, I thought I'd finish up with where I've stopped on the 2D slicing; I started working on line intersection clipping, and decided to give it up for now. Since it isn't the mathematically perfect solution afterall, it lost much of it's appeal. Using a simple model pictured at the start of the blog, I created 2 Z-Plane slices, and added the perimeter path. The red line is extruder head center, and the blue line shows an approximation of how the thread fills the space. (The sphere with a square knocked out and a wavy/fiddly bit added required too much accuracy and exposed too many bugs with my code -- as indicated in other messages, points and segments need to be removed to reduce the amplification of small errors.)
These are the traces without the acute inner angle clipping turned off.
And here are the traces with the acute inner angle clipping turned on, set to clip any interior angle that is less than 90 degrees.
It seems pretty obvious to me that the second perimeter traces would create a stronger object, even if intersection clipping was added to resolve the the degenerate case where the thread pierces the opposite side of the object.
Thursday, August 10, 2006
Modeling and Slicing
Since Forrest switched over to using a grid view for his model decomposition technique (and has been making really good progress on it), I decided to see if I could get my ideas in a geometric slicing algorithm working. It also let me wet my feet working with the 3D data. Here are some of the images for the progress I've made. I've talked a little about the current limitations on the message board -- there are two degenerate cases on the inset algorithm that need to be handled 1. Clipping off tips in acute inner angles, and 2. clipping off intersections.) To exersize the code, I created this little widget model. It has some wavy fiddly bits in the middle of a sphere with a square hole knocked out of it. I modeled it around the concept that Forrest started with on his explorations.
Here is a wire frame image of the same model, hopefully, the little wavy fiddly bits make more sense with this.
The images that follow are screen captures of a Z Plane explorer I wrote to visualize the algorithm. I think it should demonstrate that the geometric approach should work well. You can see the degenerate cases pretty clearly here. I can zoom the Z plane around real time -- each layer is recalculated every time the scrollbar changes, and I'd guess it takes about .2 seconds to calculate and draw -- including slicing the model, and then performing the inset algorithm. The model is approximately 11000 triangles.
The black lines represent the triangles from the model (I got an STL import from blender to work, so it's not a problem like I originally thought. I did have to write an STL loader in C#, though.)
The red lines represent the inset algorithm operating on the black edges.
Here you can start to see the interior angle degenerate case. The interior angle 'horn' is extending a bit further than it needs to here. It should be capped to prevent it from growing even longer as the angle becomes more acute.
This is pretty close to dead center. Note the little horns. This is another the interior angle degenerate case for some really tiny triangles. My current idea for solving the degenerate case would probably leave bumps instead of horns for this particular situation.
All the remaining layers are mirror images of the above, so I won't bore you by posting them (And I seem to be having problems uploading images, anyway. I'm still a blogger newbie.)
Tuesday, August 01, 2006
I whipped out a 3d model of my imagined 'wire on/off' switch on the mechanical pencil tip extruder. All theoretical at this stage, but I think it shows the idea a bit more clearly than just text alone.
First time posting images, so not sure if this will come out or not.
The purple stuff was my attempt to wrap the model with an insulation, since the heat will be spread thru a larger portion of the extruder. The idea is that air pressure drives the liquid plastic thru the tip, as has been suggested in other comments.