Saturday, 10 June 2023

Chipmaster Gear Cutting

 

Calculate all the possible gear combinations for the gear selector to cut a 15TPI thread:

Imperial TPI C 5 24 20
Imperial TPI C 1 24 30
Imperial TPI B 1 24 60
Imperial TPI A 6 24 70
Imperial TPI B 1 28 70
Imperial TPI C 5 36 30
Imperial TPI B 5 36 60
Imperial TPI B 5 42 70
Imperial TPI C 1 48 60
Imperial TPI B 6 48 70
Imperial TPI C 1 56 70




Thursday, 2 July 2020

Golang quirks

I often pass a struct to a function, sometimes the structs contain pointers,
then on initialisation, the question is how to do it in the simplest possible way? 
The definition of transactionType is string

    
    purchaseRequest(&merchant.MerchantPurchaseRequest{
        TransactionType: &"21", // <-- want to do this
    })

// but have to do this
txT := merchant.TransactionType("21")
    purchaseRequest(&merchant.MerchantPurchaseRequest{
        TransactionType: &txT, 
    })


https://golang.org/ref/spec#Address_operators 
https://stackoverflow.com/questions/30716354/how-do-i-do-a-literal-int64-in-go/30716481

Tuesday, 25 February 2020

SAP NWRFCSDK Dockerfile with Golang

Here my working dockerfile for running a golang application depending on SAP/gorfc and the SAP Netweaver library

Compile with

GO111MODULE=on CGO_LDFLAGS_ALLOW=.* CGO_CFLAGS_ALLOW=.* CGO_CXXFLAGS_ALLOW=.*  \
CGO_CFLAGS='-I /usr/local/sap/nwrfcsdk/include' \
CGO_LDFLAGS='-L /usr/local/sap/nwrfcsdk/lib'  \
go build -a -o dist/myapp  cmd/main.go


Dockerfile

FROM debian:bullseye-slim

USER root
WORKDIR /app
EXPOSE 8080

COPY dist/myapp /bin
COPY .env /app
COPY nwrfcsdk.conf /etc/ld.so.conf.d/nwrfcsdk.conf
# unpack and install nwrfcsdk
ADD nwrfc750P_3-70002752.tar.gz /usr/local/sap/
RUN mkdir -p /usr/sap/ && ldconfig -v /usr/local/sap/nwrfcsdk/lib    

ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"/usr/local/sap/lib"
ENV LD_RUN_PATH=$LD_RUN_PATH:"/usr/local/sap/lib"
ENV SAPNWRFC_HOME="/usr/local/sap/nwrfcsdk"
ENV PATH="${PATH}:/usr/sap/nwrfcsdk/bin"

ENTRYPOINT [ "/bin/myapp" ]

Wednesday, 22 January 2020

My thoughts on using Apache Nifi for serious integration work



Over the years having implemented quite a few file interfaces, with similar goals but different design principles  (at the time best practice), of which the core is file based ETL with flow routing. With the recent project and juniors to train, I gave Nifi a try, partly because it sports a great UI and is fairly simple to hand over to system administrators, with build in authorisations and policy management.

To give some context to my use of the word serious, the recent integration required files to be interfaced from the logistics system to the financial system and then document management system. The weekly export process was running batch exports and produced approximately 2000 files within minutes with about 100k line items in total each line item translates to 3 financial transactions, which the interface had to generate and track until completed.

More about Nifi on the official site https://nifi.apache.org
    Due to the vast library of ready to use processors, it is a great tool for fast POC work or simple flows but.... perhaps my use case of XML file integration between systems supporting SOAP,REST and SAP RFC is an abuse of the intended use, but the user interface quickly became very crowded, with lots of groovy scrips on the operating system level. It soon reminded me of the reason why big business workflows are typically implemented in code, or eventually migrated to code. Point in case, Uber and AirBNB. To say the least, managing failures became a tedious task.

    The good:
    To extend the tool with custom processors java, was quite trivial. In my case I wrapped the JcoSon library to directly interface to SAP ERP. This solution works great.
    The not so great:
    Flows need error paths, a good thing, but handling the errors in a sane way with complex flows is a challenge in the UI.

    In the end I decided to take a micro service approach in gloang, with technologies like docker, minio, cadence, and kubernetes all running on premise, with a simple UI in Vue.js showing file interface status, and some additional data to enable a user to quickly spot failures. Golang is just a great systems language.


    Friday, 29 November 2019

    Golang ISO-88591-1 XML Decoder

    Recently I had to decode XML files in ISO-88591-1 charset, there are quite a few threads and blogs around, but none seemed to work, most present workarounds and then just the standard way from 2015 onward, but it does not work, at least not in my case. This simple implementation of CharsetReader works for me. // <?xml version="1.0" encoding="ISO-88591-1"?>



    func MyCharsetReader(charset string, input io.Reader) (io.Reader, error) {
        fmt.Printf("XML Charset: %s\n", charset)
        switch charset {
        case "ISO-88591-1":
            return transform.NewReader(input, charmap.ISO8859_1.NewDecoder()), nil     }
        return nil,nil
    }

    func main() {

        dec := xml.NewDecoder(os.Stdin)

        dec.CharsetReader = MyCharsetReader
        dec.Strict = false

     

    Saturday, 13 July 2019

    Decoding absolute reference marks on Heindenhain LS378C


    After a recent ebay find of affordable 0.001 glass scales, for my lathe cross slide, I now need a suitable DRO. Mixing scales with different reference mark standards, is a bad idea, but I like the challenge. Lets build a DRO capable of decoding Heidenhain reference marks.
     Although there are some DIY solutions out there, nothing I found was open source without custom hardware, thus not usable to extend.

    Dedicated chips like ls7366r have automatic decoding for index pulses, but do not support encoded reference marks.

    The idea is to use three HCTL2000 chips connected to an arduino, then feed the output to an ESP8266 for serving a simple web page.

    The document Linear scales by Heidenhain [1] ,gives the formulae to decode the absolute reference marks on their linear glass scales [page 9].

    Below a screenshot of the three tracks, the index pulses appear to be randomly spaced.

     After applying the formula to the input data, the result makes no sense.

    my $Mrr = 0; # Signal periods between two reference marks





    $B = (2*$Mrr)-$N;
    $D = +1; #direction
    # P1 Position of the first traversed reference mark in signal periods
    $P1 = (abs($B) - sgn($B) -1) * $N/2 + ( sgn($B) - sgn($D) ) * abs( $Mrr) /2;
    $N = 1000; #Nominal increment between two fixed reference marks in signal periods (see table below)


    References
    1 http://www.auto-met.com/heidenhain/08PDF/NC%20Linear.pdf

    Saturday, 16 March 2019

    Arduino based quadrature decoder experiments


    While looking for a very efficient method to decode quadrature signals directly on the Arduino Nano, I came up with this solution for 2 encoders. While not suitable for high resolution encoders, it is at least fast enough for 400 CPR running at 3000 rpm. Interesting finding was the lookup table method found else where on the internet, is about twice as slow. The  subroutine is called from a timer interrupt routine.




    
    // GPL, Hannes de Waal 2019 
    // Measured 97 KHz, 5.8us duration with lookup table 
    // 128.9 kHz with 3.36us using 2 case statements, instead of lookup
    
    void read_encoder() {
    
     
      static uint8_t enc1_ab = 0;
      static uint8_t enc1_idx = 0;
      static uint8_t enc2_ab = 0;
      static uint8_t enc3_ab = 0;
      
      /**/
      unsigned char port = PINC;
      enc1_ab <<= 2;               //remember previous state
      enc1_ab |=  ( port & 0x03 );  //add current state
      enc1_idx <<= 1;
      enc1_idx |= ( port & 0b00000100 );
      
      enc2_ab <<= 2; 
      enc2_ab |= ( port>>2 & 0x03 );
     // Pos1 +=  enc_states[( enc2_ab & 0x0f )];
     
    /* state transitions
      10 -> 11 +
      11 -> 01 +
      01 -> 00 +
      00 -> 10 +
      10 -> 00 -
      00 -> 01 -
      01 -> 11 -
      11 -> 10 -
      10 -> 01 e
      01 -> 10 e
      00 -> 11 e
      11 -> 00 e
      */
      switch( ( enc1_ab & 0x0f ) ) {
        
        case 0b00001011 : Pos += 1; break;
        case 0b00001101 : Pos += 1; break;
        case 0b00000100 : Pos += 1; break;
        case 0b00000010 : Pos += 1; break;
        
        case 0b00001000 : Pos -= 1; break;
        case 0b00000001 : Pos -= 1; break;
        case 0b00000111 : Pos -= 1; break;
        case 0b00001110 : Pos -= 1; break;
        
        case 0b00001001 : Err ++; break;
        case 0b00000110 : Err ++; break;
        case 0b00000011 : Err ++; break;
        case 0b00001100 : Err ++; break;
       // 0000 hold
       // 0101 hold
       // 1010 hold
       // 1111 hold
            
      }
      
    
     switch( ( enc2_ab & 0x0f ) ) {
        
        case 0b00001011 : Pos1 += 1; break;
        case 0b00001101 : Pos1 += 1; break;
        case 0b00000100 : Pos1 += 1; break;
        case 0b00000010 : Pos1 += 1; break;
        
        case 0b00001000 : Pos1 -= 1; break;
        case 0b00000001 : Pos1 -= 1; break;
        case 0b00000111 : Pos1 -= 1; break;
        case 0b00001110 : Pos1 -= 1; break;
        
        case 0b00001001 : Err1 ++; break;
        case 0b00000110 : Err1 ++; break;
        case 0b00000011 : Err1 ++; break;
        case 0b00001100 : Err1 ++; break;
            
      }
     
    }
    

    Saturday, 12 January 2019

    Surface Grinder CNC Notes


    Controlling the Z axis

    Option A - Stepper motor
    Using a stepper motor with 1.8 deg steps will give a resolution of 200 steps in full step mode per rotation. This would require a 46:1 reduction to achieve the desired 0.5um resolution on a 5mm lead screw.  Cons: discreet steps, not sure if this will be an issue, holding torque goes down with reducing step size.

    Option B - Servo
    With a servo motor using dual loop position feedback control will make more sense since steps are no longer discrete. The dunker motor I have had lying around for years, seems like a good fit. 23:1 gear ratio with a 100ppr encoder, without using the linear encoder as additional feedback this will give a resolution of 9200 steps or 0.543 um. Quick estimation with Bresenham algorithm, gave the following approximations for 0,001um increments. But i would like to hit them exactly...well in theory at least.

    1 0,000543
    2 0,001087 0,001
    3 0,00163
    4 0,002174 0,002
    5 0,002717
    6 0,003261 0,003
    7 0,003804 0,004
    8 0,004348
    9 0,004891 0,005
    10 0,005435
    11 0,005978 0,006
    12 0,006522
    13 0,007065 0,007
    14 0,007609
    15 0,008152 0,008
    16 0,008696
    17 0,009239 0,009
    18 0,009783 0,01
    19 0,010326
    20 0,01087 0,011
    21 0,011413
    22 0,011957 0,012
    23 0,0125

    This made me research the possibility of using dual loop feedback, seems common in commercial machines.
    LinuxCNC supports it out of the box
    http://wiki.linuxcnc.org/cgi-bin/wiki.pl?Combining_Two_Feedback_Devices_On_One_Axis
    http://linuxcnc.org/docs/2.7/html/man/man9/offset.9.html
    This great explanation https://granitedevices.com/wiki/Dual-loop_feedback_position_control
    Gave me another idea, just use Elm Chan SMC3 Velocity control mode with LinuxCNC, feeding position from Heidenhain encoder to LinuxCNC, which controls the SMC3 servo in velocity mode.
    http://elm-chan.org/works/smc/report_e.html

    Thursday, 3 January 2019

    Writing Software for CNC Applications

    Need to synchronise the spindle to the C axis? Or implement an electronic gearbox reduction for a lathe? Stepper on a rotary table? Or just plot a circle on XY planes? all of these implementations have a few common problems to solve, one of which is to coordinate the movement of two or more axis. Since each axis might have different resolution and or require fractional advance of that resolution to accomplish the desired motion. Most open and closed source implementations seem to make use of some sort of  Bresenham's line algorithm here, to deal with the resulting error.

    void main () {
       double y0 = 0.00;
       double dy = 0.0125; // 5mm / 100x4
       double dx = 23; // gear ratio
       double k = (double)dy / (double)dx;

        double y = (double)y0;
        double yi = 0.0000;

        for (int x=0; x<23; x++)
        {
            y += k;

            if ((y+0.0005) > yi) // error larger than 0.0005? increment yi
            //if ((int)(y+0.5) > yi)
            {
                yi=yi+0.0005;
            }
          printf("%02d %02f %02f\n", x, y, yi );
        }

    }

    Let us look at Gear ratios, the concept of accurate synchronized electronic reduction gears for the lathe made me think. Why not use closed loop phased locked control?

    1) decode position pulses to direction and 4x steps,
    2) Multiply step pules by M an then divide by N. 
    3) feed the resulting pules directly to a stepper which can act as the divider

    To implement this one would require a PLL for multiplication. Using this method should make it possible to implement any gear ratio without error.  I have implemented this on Arduino making use of the internal clocks and one external PLL 4046. The lock and capture range now determine the spindle speeds. The solution runs entirely on hardware no software is required once the counters have been set. It is abit more complex than this, since direction needs to be accounted for. But here is the gist of it. I then found commercial industrial solution doing exactly this at http://www.motrona.net/encoder_divider.html




    Sunday, 30 December 2018

    Eagle Surface Grinder MK3 Rebuild - Progress

    This will be the last post for 2018. It has been an exciting year with life happening.

    I finally managed to get some time to start the reassembling the Eagle Surface Grinder. All the surfaces have now been precision ground. All that is left to do is machine the oil grooves, match the dovetail surfaces, scrape the oil pockets, add the news spindle and ball screws, write some macros for the grbl g-code controller to behave like a surface grinder and the machine is ready for action.

    Spindle and Drive Motor
    After ordering and installing the new balls as described in a previous post, I am not satisfied with the resulting stiffness and pre-load design of the original spindle. The thinking now is to use a self contained spindle and machine an adapter sleeve. The new spindle axis diameter is 20mm compared to 25mm and the bearings considerably smaller, but for my needs this will be more accurate, even if I can only run 7" wheels. The motor in the base will drive a flat belt transmitting power to a love-joy style coupling in the "head stock" similar to old lathes with addition of the coupling if that makes any sense. Initially I wanted to go with poly V-Belts, but when I saw the very modern Schaublin 102 N-VM-CF still uses crown pulleys and flat belts. I started investigating the advantages of flat belts. The main advantages I could find was, better efficiency, less vibration, and higher speeds. not sure if any of this holds true, but worth a try. Here I will need to design the housing at the back of the spindle housing, which will hold the crown pulley and shaft coupling, for driving the spindle. A direct drive would be more efficient, economical with less vibration, but that would have the motor extend  at the back of the spindle housing, similar to the later eagle model shown below, in a small shop not an option.



    Knee Oil groves

    On the MK3 model the only the table sports oil groove. As discussed in a previous post, I have decided to go with the zig-zag oil grove pattern, it is more time consuming to machine, but should give better results. Below some images on the layout and machining process. The fixed dovetail had a ridge, where it meets the flat surface on the knee, this had me confused for some time as to why I do not get full bearing on the entire flat surface. a few head-scratches later I used a carbide ball nose end mill to machine some clearance in the corner, all this with a portable hand drill. The only straight edge I could find to fit the angled recess was a carpenters knife blade, this worked great!

    Ball Screws /Servo/Stepper Motor
    The ACME lead screw needs to be replaced, it has a lead of 10 TPI. I do not feel like cranking the hand wheel so installing a feed motor is a given. Sourcing an ACME 1-1/4" x 10TPI  or similar in my part of the world is not feasible. So I opted to go full CNC and use 5mm pitch ball screws.  After doing some calculations on THK ball screw specifications with a combined load of 100kg., a 20mm diameter screw will work within load ratings, if a maximum sliding speed of 38mm/s is not exceeded. For a 5mm pitch screw this will give maximum motor speed of 456 rpm. And 8NM motor would be required for https://www.nidec.com/en-EU/technology/calc/torque/ballscrew/ to drive this load.

    Sunday, 1 July 2018

    Deckel FP2 restoration Year 1966, Serial # 5151

    Almost two years since I got the machine, and many hours later, the restore is complete. Thanks to www.metalworker.eu, Bruce and some other helpful fellows at https://www.practicalmachinist.com/vb/deckel-maho-aciera-abene-mills/deckel-fp2-1966-restoration-321812/

    The machine runs incredibly quiet and is an absolute pleasure to use!



    Chipmaster Gear Cutting

      Calculate all the possible gear combinations for the gear selector to cut a 15TPI thread: Imperial TPI C 5 24 20 Imperial TPI ...