I have converted a Shizuoka AN-S vertical milling machine from the original bandit controls to being controlled by the linuxCNC software package.
I have removed and sold off the original Bandit controller. It had a single failed motor driver board, but everything was ancient and I like open source software. I have been using linuxCNC on another mill for several years and I am happy with what the software can do. Documented below are updates and my notes on getting it going.
2Current Pictures of the Mill
2018-07-20 PYVCP MANUAL TOOL CHANGE AND TOOL LENGTH OFFSETS
I've operated the mill for about a year without using tool length offsets. I didn't have an easy way to issue tool change commands, so if I ever forgot to do it things went really badly. If one doesn't issue the tool change command and then check zeros, zero might be in the wrong place. Too low and things get destroyed. I swore off them for year. Now that I have more experience, and I am working around not having the offsets stored, it seemed to make sense to enable easy use of them.
The first thing I did was modify the PYVCP control panel file I use to have additional controls for picking the tool number and sending a tool change command. It looks like this:
The code to add these buttons was added to custompanel.xml:
<hbox>
<label>
<text>"Tool Now "</text>
<font>("Helvetica",18)</font>
</label>
<s32>
<halpin>"tool-now"</halpin>
<font>("Helvetica",18)</font>
</s32>
<label>
<text>" "</text>
<font>("Helvetica",18)</font>
</label>
<button>
<halpin>"force-tool-change"</halpin>
<text>"CHANGE TO TOOL"</text>
<font>("Helvetica",18)</font>
</button>
<spinbox>
<halpin>"tool-number"</halpin>
<min_>0</min_>
<max_>54</max_>
<initval>0</initval>
<increment>1</increment>
<format>"2.0f"</format>
<justify>CENTER</justify>
<font>("Helvetica",18)</font>
<width>2</width>
</spinbox>
</hbox>
Then I added some new hal lines to hook up the new controls:
# Tool Change Routines to add to the Main HAL file
net tool-change-button halui.mdi-command-01
net next-tool motion.analog-in-00
net now-tool iocontrol.0.tool-number
# Add to the postgui script for the pyvcp
net now-tool pyvcp.tool-now
net next-tool pyvcp.tool-number
net tool-change-button pyvcp.force-tool-change
I also modified theshiz.ini to have an extra MDI line so that it could issue an MDI command to make the tool change actually happen with gcode:
MDI_COMMAND = M66 E0 M61 Q[#5399] G43
The way it works is that the spinbox sets the number of the tool we want next and sends it to motion.analog-in-00. This input get read by M66 and stuffed into #5399. The button is connected to the halui.mdi-command-01 and kicks off the MDI command for doing an instant tool change AND sets G43 so that tool length offsets are being used.
2018-01-14 Max Velocity Knob Working, Tool Change Position Button
The "Max Speed" potentiometer has been wired for 9 months and I just took the time required to integrate it. This was done in this github pull request. o Highlights are that it uses a memory efficient bitshift based averaging algorithm to average out as much noise on the analog input from the potentiometer as possible. The result is passed from the arduino over modbus. A new file was added to my configuration for just this purpose called
maxVelocityControl.hal I learned that setting halui.max-velocity.direct-value TRUE would force it to accept the value from the pot constantly.
I have also added a "tool change" button that submits an MDI command to rapid move to the home position for the Z axis. This allows me to send the quill up to the top where the impact can get at it without holding the Z up button. IIt is REALLY nice. While it is cranking up the quill I can turn off the disconnect and be ready to safely remove the ttool as soon as it is ready.
I have also gotten the RUN button to cause programs to run consistently. I had to add
net run-button halui.mode.auto
to my configuration. This forces the mill into auto mode when the run button is pressed. Once in auto, the program can be started with a pulse on halui.program.run.
2017-03-25 Doh! Librecad->DXF2GCODE->LinuxCNC Inside Pocket Folly
I got a humbling reminder that I am still learning this pleasant Saturday morning. I have been making a yoke so that I can attach a laminate trimmer to my mill for things best done on a router. I have been using DXF2GCODE as my path planner and until this morning, it went great.
I tried to mill a simple rectangular pocket. It was intended to be 0.825 x 0.625 inches. I had a 0.375" diameter cutter. The entry to the pocket went fine. The milling of the pocket went fine. When the pocket was done, Y axis move went outside the pocket before the Z retract. This gouged the edge of the pocket. The part will still work fine, but it was a reminder to me that I am a beginner, and I should double check my toolpaths. Does anyone have advice on what I should have done instead? Files for the DOH are in the file drawer under Laminate Trimmer Bracket.
2017-03-20 Making LinuxCNC think it is A 3D Printer
This isn't really for the shiz. I'm learning how to remap the MCodes that are spat out by Slic3r when it makes gcode for LinuxCNC.
2017-03-20 UDEV Rule Didn't Work
Declaration of victory for the UDEV rule was premature. I am unable to use the /dev/arduino-hwpanel as a link to the device in my mb2hal.ini file. Not sure why -- probably some sort of file permission thing I need to sort out.
2017-03-19 Fans, Filters, and USB Enumeration
This week I added a pair of fans to the cabinet. I put some "vent filter" media inside the cover after wrapping it in a layer of welded wire hardware cloth to keep it from getting sucked into the fans. I spliced the fan power off the 12V line feeding devices inside the PC. Nothing really needs cooling if the PC is off. I added a fuse for the 5V and 12V lines before pulling them out through a grommet in the back of the PC case. A substantial amount of current is available on those lines and things would go pretty poorly if they got short circuited.
I have been struggling to keep my USB devices enumerating at the same place/name when they get plugged in. I had to create a custom UDEV rule to make the hardware button panel consistently show up in /dev. Sometimes when the PC would boot, it would be /dev/ttyUSB0. At other times, it would be /dev/ttyUSB1. As root, I created a new file:
/etc/udev/rules.d/99-usb-serial-custom.rules
Its content currently is:
#CUSTOM UDEV RULE BY YELTROW TO MAKE SURE THE Hardware Button Panel ALWAYS gets linked to a device ID we can find
#This is specific to the 4th USB bus chip, 2nd port. If the arduino gets plugged in someplace else, it will not
#get the symlink assigned to it.
KERNELS=="4-2", SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="arduino-hwpanel"
I am unsure if Bus 4, port 2 will appear consistently. Since more CH341 based Arduinos may end up showing up my system, I added this port dependency. It may have to go away.
I have also figured out how to get my momentary buttons on my hardware panel to select which axis the jogwheel effects. The hwpanel button lines get tied to the halui.joint.NN.select lines. The halui.joint.NN.is-selected then goes to the axis.NN.jog-enable line to tell it to pay attention to the jogwheel counts. The jogwheel counts are tied into all of the axes at the same time.
net x-jog-select-but halui.joint.0.select
net y-jog-select-but halui.joint.1.select
net z-jog-select-but halui.joint.2.select
net a-jog-select-but halui.joint.3.select
net x-jog-select-but hwpanel.0.XBUT
net y-jog-select-but hwpanel.0.YBUT
net z-jog-select-but hwpanel.0.ZBUT
net a-jog-select-but hwpanel.0.ABUT
net jogwheel axis.0.jog-counts
net jogwheel axis.1.jog-counts
net jogwheel axis.2.jog-counts
net jogwheel axis.3.jog-counts
net x-jog-select halui.joint.0.is-selected
net y-jog-select halui.joint.1.is-selected
net z-jog-select halui.joint.2.is-selected
net a-jog-select halui.joint.3.is-selected
net x-jog-select axis.0.jog-enable
net y-jog-select axis.1.jog-enable
net z-jog-select axis.2.jog-enable
net a-jog-select axis.3.jog-enable
net jog-scale axis.0.jog-scale
net jog-scale axis.1.jog-scale
net jog-scale axis.2.jog-scale
net jog-scale axis.3.jog-scale
sets jog-scale 0.00025
setp axis.0.jog-vel-mode 1
setp axis.1.jog-vel-mode 1
setp axis.2.jog-vel-mode 1
setp axis.3.jog-vel-mode 1
sets jog-scale .0005
Below are images of how I chose to ventilate my enclosure: One fan blows in and one fan blows out to keep the differential pressure across the fans lower. I bought two "vent filrers" from Home Depot and wrapped them with .25" grid hardware cloth on both sides so they wouldn't get sucked into the fans. I put foam tape around the inside to seal against the filters. Then I installed a return vent cover from Home Depot that I painted and then allowed to float around the workshop for a year from bench to bench.
2017-03-13 The Control Panel Is Installed
Over the end of the week last week, I started to find making modifications with everything crowded around the mill getting cumbersome. Wiring modifications have slowed and the remainder of them to be done should be accomplished readily even with the panel in a tub. Thursday I removed all the cables. The rest of the weekend was burned putting them back in properly. A disconnect has been added for the spindle so tool changes won't be creepy anymore. I found that the G201 drives that I have are pulling up my e-stop loop detection pin so that it doesn't reliably detect the machine is off. This prevents it from being able to provide a reset pulse to the rest of the system. I have added some resistors to pull the line down when I remove the 5V feed to the common line on the drives, and that has made the machine workable; however, I think I will need to come up with something else.
2017-03-04 Heartbeats and Watchdogs
This morning I have been working to add a watchdog. The watchdog will monitor the heartbeat from the button panel to make sure it is still alive. Here is what I have learned this morning
The functions watch.process AND watchdog.set-timeouts BOTH need to be added to a thread or the watchdog won't run.
mb2hal uses LESS cpu when querrying the arduino with a higher maximum update rate. It was using 20% to talk to it at ~18Hz update rate, and it only uses 3% at 33Hz with my maximum update rate set to 55Hz. Not sure why that is, but if it works...
The rotary table I have weighs 198lbs. I am not sure if it will be suitable for operating on its side because it appeared there was some oil on the floor after it sat that way for a day. It could just be that I sat it in oil, or it ran out of the t-slots. I will have to keep an eye on it.
The solution I came up with for monitoring the communication health of the Arduino on modbus is to output a bit to the Arduino and have it echo the bit back. The hwpanel.comp component that separates out the bits that come packed as a 16 bit integer does the dirty work of inverting the bit and sending it back to the Arduino again. This causes the bit to become inverted every pass through the Arduino. If the loop fails, the oscillations stop. The oscillations are monitored by the hal watchdog component. If the component does not see an oscillation every 600ms, it triggers a message and the halui.machine.off bit. This will cause the machine to stop immediately and will prevent it from operating if the machine powers up and can't communicate with the front panel.
loadrt watchdog num_inputs=1
loadrt not names=not-estop,not-watchdogok
loadrt message names=msgwatchdog messages="Button_Control_Panel_Watchdog_Timout "
addf watchdog.set-timeouts servo-thread
addf watchdog.process servo-thread
# HARDWARE BUTTON PANEL WATCHDOG
setp msgwatchdog.edge 0
setp watchdog.timeout-0 0.600
net hwpanel-heartbeat hwpanel.0.HEARTBEAT watchdog.input-0
net msg-hw-panel-wd watchdog.ok-out msgwatchdog.trigger
net estopreset not-estop.in
net estopreset-not not-estop.out watchdog.enable-in
net mb2hwpanel8 hwpanel.0.reg8 => mb2hal.RegOut.00
net msg-hw-panel-wd not-watchdogok.in
net watchdogfault not-watchdogok.out => halui.machine.off
addf not-estop servo-thread
addf not-watchdogok servo-thread
addf msgwatchdog servo-thread
2017-03-03 Button, Knobs, and Jog Wheels...
My current setup consist of all the buttons connected to an Arduino Mega 2560. The Mega 2560 is connected currently via USB (as ttyACM0). mb2hal communicates to over the USB connection and makes pins for hal. I pass the packed bytes into a component I wrote called hwpanel.comp. It just remaps the 16 bit groups into 32 bit groups for the encoders and breaks out the individual button lines so hal can get at them easily. The arduino code, theshiz.hal, theshiz.ini, and hwpanel.comp are all in the github repo.
My current issues are:
1) Pause/Step/Run/Stop/Feed Hold work kind of weird right now because of the pins they are mapped to and how I thought they worked. I'm going to get them straightened out, but for the time being, the feed hold does stop the feed, stop stops the machine, and after that things get weird... I working through it.
2) I am attempting to use acceleration on the jog wheel. It can surprise me from time to time and needs work.
3) The momentary buttons for selecting different axes to jog haven't been connected in hal yet. Feed override works fine.
4) Spindle Override is yet to be done.
5) I have no idea how the direct entry input stuff works to connect the potentiometer for max speed into halui....
6) Coolant and spindle control buttons aren't wired into hal yet.
2017-02-27 Successful 1800 Hole Drill Job Test
Since the drilling job was able to produce the error in Z-axis steps, I re-ran the job tonight as a test. With the changes I made it appears the Z-axis is now reliable. I improved the latency of the box improved by getting rid of my ATI video card. I also adjusted the stepgen parameters and base thread time so that everything should be satisfying the timing requirements of the Gecko stepper drives. The oiler appears to be operating properly on its 25% duty cycle, although I am considering adjusting it to be 8 minutes of runtime every 22 minutes. It should net out the same, but with less time between oilings. Even at 25% it still could empty the reservoir in two 40 hour work weeks, so it is probably still excessive. Some of the Bijur pumps have an adjustable shot volume, so I may see if I can turn that down.
2017-02-26 New Oilerctl Userspace Python Component for the Oiler and Stepper Configuration
Per the plan below, I focused today on checking the latency in the system. It was terrible. It appears the cool, dual monitor video card I had was trashing my latencies to the tune of 300 milliseconds. That could explain everything. Occasionally I have heard thunks while jogging that I couldn't really explain. A lack of pulses for any significant period of time could explain them. It could even even have limited my maximum slide velocity during my testing. It is possible that might mean I can turn up the maximum velocity after some more testing.
In order to continue using the hole drilling program as a test, I needed to reduce the machine's consumption of way oil by putting a duty cycle on the oiler. To that end, I created a new python component. It is still in a testing branch as of tonight, but will pull it in some time this week. It is uploaded to github. The component really cleans up the hal file and was much easier to write in python than a bunch of hal statements. It triggers off table movement. If the table is moving, it advances the duty cycle counter. I have mine configured for 15 minutes of oiling time per hour with no less than 60 seconds of runtime before it quits just to keep the relay from clattering too much. It also has persistence and saves the count to the drive of the computer that is being used so it doesn't over-oil if you keep shutting down linuxcnc.
2017-02-26 Physical Button Panel and Z-axis Mayhem
On the good-news front: The physical button panel is now installed and mostly operational. See github for the commits. The control panel consists lots of switches and encoders wired to an Arduino Mega 2560. The Mega is connected to the PC via USB. Hal talks to it via the mb2hal module using modbus. The halui userspace component is used to poke hal with button presses when something happens on the physical button panel. I have yet to add the encoder reading code into the Arduino and put the counts into the array that mb2hal reads.
On the bad-new front: I wrote a gcode program to poke holes into a vacuum box for holding down parts. It consisted of drilling about 1800 holes at 0.5 inch spacing. The machine plugged away for about 90 minutes and then a bunch of Z-up steps got missed or something jammed or slipped. I was making the Arduino mount and heard atypical noises from the machine, ran over, and stopped the job. The chuck made three good dents in the workpiece before I got it stopped. I changed the bit and ran the remainder of the job, but it did it again during the last 30 minutes of the job. I don't know if the geckodrive G201, the motor, or something mechanical are to blame. It does appear to be time related. The longer the machine runs, the more likely it appears that it will mess up. It appears to lose a large number of steps all at once and not gradually over the whole job. I ran the same job with the countersink installed to make the vacuum ports cover a larger surface area of the part being held. It got about 60% of the way through the 1800 hole job and the Z axis again lost "up" steps. I have several theories that I am working through:
Mechanical slippage of the pulley on the motor when it gets hot: I verified there is a key in the shaft, the setscrew that holds it is tight, and I can't slide the pulley up off the end of the motor. It seems this is not the smoking gun.
Mechanical slippage of the pulley INSIDE the head that drives the ballscrew: I have not checked this yet.
The Z-axis motor heated up. This caused the winding resistance to increase. This causes a loss of some torque. The accelerations for the Z-axis haven't really be examined in detail for a hot motor. The motor feeds slowly down and then does a rapid move up. The change in direction requires high acceleration. This high demand causes the missed steps. Lowering the acceleration allowed for Z should fix it. This has been done and tested for 1800 holes. I marked the travel limits for the Z-axis and ran the machine without the spindle on. It appears that it might have lost 0.100 inches during the run. I need to make sure my test procedure reproduces the situation AND can measure smaller numbers of lost steps. Perhaps an encoder of some sort needs fitted either temporarily or permanently.
The Z-axis motor heated up->lower torque... Add in timing jitter. I have not gone through and checked the Linux box for timing deviations and optimized its performance for those. Perhaps some crazy timing in combination with some loss of torque causes some missed steps. I have gotten some warnings from LinuxCNC regarding latency. This neglected step will be addressed.
Timing jitter may be more important when going fast: It is possible that a loss of steps when performing the rapid move upward is more harmful than when moving downward. If a 100ms timing deviation occurs while moving up, perhaps it causes the motor to stall. Step timing during the rapid move is about 53in/min * 10000 steps/in / 60s/min = 8833steps/second (113us/step). At the 12in/min feedrate, the step pulses come in at 2000 steps/sec (500us/step). It is possible the machine hangs for 100ms, loses position and synchronization with the rotor, and the hiccup causes the axis to stall during the fast move. I should be able to test this situation and even make it worse to verify it. This assumes the weight of the quill is a negligible influence. Again, checking and addressing timing jitter is a key step. [ UPDATE: Found timing jitter of up to 300,000ns, so I am following the steps HERE to setup isolcpus and other options in /etc/grub.d/07_rtai. That is the most timing jitter I have ever seen. It could mean I have made a terrible choice on video cards or something...]
The parallel port driver chip has gotten hot and weaker: It is possible that sinking 16mA across eight outputs on the parallel port is too much. It is also possible that the "up" direction for the Z-axis is the straw that breaks the camel's back. I have checked the outputs with a scope and it appears the lines pull down to about 0.7V or so during normal operation, so they are loaded, but I'm not sure that they are overloaded. They pop crisply back up to 5V through the optocoupler inputs on the stepper drives. I can put some interposing transistors on a board to test this. It will be time consuming, and many of the other possible causes are just good practice items I have neglected to check, so this is probably lower on the priority list.
Drive and parallel port driver chip get warmer and pulse timing has become marginal: I have just started to dig into providing "proper" timing for the pulses to the drive. I measured the step pulses to the drive and saw they were right around 5ms and I couldn't influence them. This didn't make sense to me because my base period is 30us. I hypothesized that the parallel port driver must be in some sort of special "fast pulse" mode. It is. The step pins for each motor are set to reset themselves when parport.0.reset is called. My machine can only really reliably travel on the Y axis at about 60ipm with carefully managed acceleration, so I think I will change this to use base-thread managed pulses which limit everything to 120ipm. This should produce VERY generous pulse lengths of 25us if I speed up the base thread to 25us. This also seems like good practice and housekeeping.
Before any of the rest of this gets done, I need to get the oiler tamed. Running all of these "long running" tests will cause excessive way oil consumption if I don't change something. Right now the machine runs the oiler constantly when the table is moving. That is fine for short jobs. This long test causes it to over-lubricate the machine such that oil drips from the quill on my workpiece periodically. The table also rains oil down the cardboard on the floor below it. I am going to try to make my oiler run on a hour-meter basis. I plan to have a counter run continuously that resets after an hour. If the time is in the first 15 minutes of the hour, it will run the oiler. I think the 25% duty cycle should be about right. The machine is capable of emptying the pint reservoir in about 48 hours if it is left on. I might even want to dial back the duty cycle more if it is a long-running job. I have discovered there is a userspace component "Parameter Saver" that I can probably use to store the runtime of the oiler. It could be useful for storing the runtime of the spindle and other stuff for maintenance reasons, too. A dedicated custom python userspace component could used for this purpose too like in the example at http://linuxcnc.org/docs/html/hal/halmodule.html.
2017-02-22 A Current Photo of The Machine
2017-02-20 VESA Monior Mounts and Mounts for the Physical Button Panel
The monitors I have been using have been vise-gripped to the old bandit mount for weeks. They seem out of the way enough that I am ready to make it permanent. I also need bracket to hold up the physical button panel. The monitors each have VESA mounts on the backs of them with 100mm x 100mm hole spacing. I have some reclaimed aluminum extrusion that I am going to mount them with. I made the VESA mounts from 0.450" thick lexan. In the file drawer are the dxf files for the mounts and the NC files I used to make them.
Below you can see the button panel in the "service position." It has a hinge so that only one bolt has to be removed for the panel to swing down. This makes it much easier to get at the guts of it and make wiring changes.
Here you can see the visa mount installed on the extrusion and the first monitor bolted on. I learned that the viewing angle of the LCD's isn't great from lower than monitor and I needed to tilt them formward with a shim to get the angle I wanted (not shown).
2017-02-20 CNC Tool Holder Rack
I was beginning to lose my mind digging through a bucket of nmtb40 tool holders every time I needed to change a tool. One of my kids expressed interest in learning to use the CNC mill so this was a perfect project to learn on. It is wood, so it is a forgiving material to learn on. I explained what was needed and taught them how to use librecad to draw it up, DXF2GCODE to teach the machine how to make it, and then how to operate linuxcnc to cut it out. It was a great success. The files are in my public file drawer linked HERE. I reused the program two more times to create a total of three shelves to organize my holders. The shop is still a mess, but I am really beginning to like how quickly the power drawbar and dedicated holders make changing tools compared to my manual drawbar and R8 collets on my Rong-Fu. Perhaps an electric impact upgrade for the Rong-Fu is in the future.
2017-02-15 Physical Buttons Saga Continues
2017-02-12 Physical Button Interface
I have been kicking around the design of the button layout of the physical user interface while making as many parts of it as I can on the mill. The discussion of the design is occurring on the linuxcnc forum, and I have received a lot of great input from the community. I have spent much of the past week assessing the performance of the Arduino as input and figuring out what the panel should look like. I am making the front panel in segments to make it easier to reconfigure if needed. I might have to take out only 4 controls instead of 15 to add a button or indicator. I am also unsure that I can bend a 20" wide piece of 1/8" thick aluminum on my little harbor freight brake. I have proven out if I really need it, I can get input updates every 20ms. MB2HAL does eat the CPU alive on the machine to do it: about 78% of all the CPU cores were used when I told it to go as fast as possible. I haven't tried it yet, but i purchased this 8CH dc 12V Modbus RTU RS485 Relay Module Switch Board for PLC Lamp LED Camera. It could be a simple way to add some relay outputs using the same serial network I control the drive with. It does have the drawback of being 12V instead of 24, so I need to add that supply voltage to my machine. There is a lot of "Modbus RTU" stuff on ebay very cheap, so it seems worthwhile to learn how to use it and create some documentation for its use under linuxcnc.