{"id":18613590,"url":"https://github.com/aabbtree77/adast","last_synced_at":"2025-06-24T22:34:18.605Z","repository":{"id":167264273,"uuid":"413017770","full_name":"aabbtree77/adast","owner":"aabbtree77","description":"Replacing a busted Tesla chip of Adast Maxima MS80 with ATmega.","archived":false,"fork":false,"pushed_at":"2024-02-08T20:36:05.000Z","size":2130,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-17T00:37:27.437Z","etag":null,"topics":["adast","adast-maxima-ms80","atmega","avr-gcc","braking-distance","cutting","encoder","factory","guillotine","hacking","hardware","inverter","ls-m100","mechanics","paper","pd-04","precision","repairing","rotary-encoder"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aabbtree77.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-03T08:19:36.000Z","updated_at":"2023-12-06T19:23:40.000Z","dependencies_parsed_at":"2025-02-18T03:42:11.387Z","dependency_job_id":"b6d03dd1-cffc-4069-8082-b926a6036929","html_url":"https://github.com/aabbtree77/adast","commit_stats":null,"previous_names":["aabbtree77/adast"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/aabbtree77/adast","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aabbtree77%2Fadast","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aabbtree77%2Fadast/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aabbtree77%2Fadast/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aabbtree77%2Fadast/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aabbtree77","download_url":"https://codeload.github.com/aabbtree77/adast/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aabbtree77%2Fadast/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261767711,"owners_count":23206858,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adast","adast-maxima-ms80","atmega","avr-gcc","braking-distance","cutting","encoder","factory","guillotine","hacking","hardware","inverter","ls-m100","mechanics","paper","pd-04","precision","repairing","rotary-encoder"],"created_at":"2024-11-07T03:22:50.973Z","updated_at":"2025-06-24T22:34:18.586Z","avatar_url":"https://github.com/aabbtree77.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n## Introduction\n\nAdast Maxima MS80 is a paperboard cutting machine (guillotine) produced in the Czech Republic in the early 1990s. Still in operation in Vilnius, February 2024.\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align:center\"\u003e Adast Maxima MS80 under Repair\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\u003cimg src=\"./images/adastMain.jpg\"  alt=\"Adast Maxima MS80 under Repair\" width=\"100%\" \u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nThe repair was executed jointly by me and Saulius Rakauskas in about one week on February 2020. He got the client (the factory owner), disassembled the machine, located the problem, designed a new circuit board, did all the soldering and hardware testing. I only wrote the C program for the ATmega16/32 microcontroller with which we replaced the original Tesla chipset. \n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align:center\"\u003e Adast Maxima MS80 in Action\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\u003cimg src=\"./images/adastAction.jpg\"  alt=\"Adast Maxima MS80 in Action\" width=\"100%\" \u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n## Problem Setting\n\nAn accident due to the electric current overload in the factory burnt the main circuit board, see below. Its fusers went off, but the board died first.\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align:center\"\u003e Circuit Board: Front \u003c/th\u003e\n\u003cth style=\"text-align:center\"\u003e Circuit Board: Back \u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n\u003cimg src=\"./images/adastFront.jpg\"  alt=\"Adast electric circuit board burnt front\" width=\"100%\" \u003e\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n\u003cimg src=\"./images/adastBack.jpg\"  alt=\"Adast electric circuit board burnt back\" width=\"100%\" \u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nThe microcontroller did not survive, so we had to make a new circuit board from what was salvaged. The exact operating regimes and work flows were lost, but the main function, the precise electronic guillotine (knife) positioning and cutting, was retained.\n\nRemarkably, there exists a commercial solution/middleware designed to tackle this very specific problem, see i.e. [PD-04][1] which provides a rotary encoder along with the microcontroller based circuit board with the program designed for paper cutting machines. The PD-04 system is somewhat expensive for the replacements in these old machines. It costs [around 1220 euro (2023)](https://www.en.chip-elektronika.pl/readers-programmers-for-paper-cutters/control-system-pd-04/) for the hardware alone, and it takes two men (a mechanician and an electrical engineer) and several days to install it. This did not play well with the risks. Nobody knew for sure if PD04 would work on this particular old Adast Maxima, without the need to replace the motor and relays which would further increase the costs.\n\n## Adast Maxima MS80\n\nThe machine operation breaks into the three stages:\n\n1. The operator enters the distance value.\n2. The machine repositions its guillotine.\n3. The operator triggers the cutting.\n\nThere are a few other modes, but they are not essential. The position is sensed via a rotary encoder which, along with the guillotine, is shown in the photos below. The fourth picture shows a disk-like handle used to manually exit the emergency situations (e.g. lift the guillotine up if it gets stuck during the cutting as the electricity disappears).\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003e Guillotine \u003c/th\u003e\n\u003cth\u003e Rotary Encoder\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n\u003cimg src=\"./images/adastKnife.jpg\"  alt=\"Adast guillotine\" width=\"100%\" \u003e\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n\u003cimg src=\"./images/adastCounterZoom.jpg\"  alt=\"Adast encoder\" width=\"100%\" \u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003e Rotary Encoder \u003c/th\u003e\n\u003cth\u003e Deadlock Handling \u003c/th\u003e\n\u003cth\u003e Electrical Relays \u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n\u003cimg src=\"./images/adastCounterRemoved.jpg\"  alt=\"Adast Encoder\" width=\"100%\" \u003e\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n\u003cimg src=\"./images/adastDeadlockHandle.jpg\"  alt=\"Adast Deadlock Handle\" width=\"100%\" \u003e\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n\u003cimg src=\"./images/adastRelays.jpg\"  alt=\"Adast Electrical Relays\" width=\"100%\" \u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align:center\"\u003e Unsung Heroes: Saulius and Igor, May 2023\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\u003cimg src=\"./images/adastPeople.jpg\"  alt=\"Adast Heroes\" width=\"100%\" \u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n## Code\n\nThe code is written for the [ATmega16/32][4] microcontroller and the avr-gcc compiler. The chip has 32 IO pins which we considered plenty. This turned out to be a very tight choice. It would have been better to apply a ready-made array of 7-segment LED indicators with a keypad, both based on the 2 wire/I2C interfaces, in order to reduce soldering effort. However, we wanted to match the board with the specific digit indicators and the factory panel.\n\nThe code implements the three phases: (i) initial calibration, (ii) target distance setup, and (iii) knife motion/positioning. There are all sorts of minor complications that probably do not deserve a textual description here, one should simply see the code. \n  \nInitially, when turning the machine on, the guillotine's position is unknown and it is located where it has been left when the machine has been switched off. There is no distance value to read from the permanent memory, nor such a method would be viable. All we know is that: (i) the guillotine is somewhere in between the starting marker (approx. 20mm) and the end wall (approx. 810mm), (ii) there is a sensor located approximately at the 225mm from the starting marker, and (iii) the sensor sends the most precise signal only when the guillotine passes the sensor from the forward direction, that is when moving from the end towards the start.\n\nSince the position of the knife is unknown initially, and we do not know in which direction its only calibrating sensor will be reached, an operator needs to see a rough location of a knife and move it manually so that the knife passes the sensor. This is not as automatic or convenient as it should be, but it is the price we pay for having only a single distance-calibrating sensor.\n\nThe code may resync the distance value whenever the knife passes the sensor, but these parts are commented out. There are options to position the knife so that it first passes the target value by 5cm and then comes back, supposedly to always make the final stop from the forward direction.\n\n## Precision \n\nThe loss of precision can happen in two distinct ways: (i) in a cumulative/catastrophic loss, and (ii) as a constant bias which can be alleviated.\n\nThe first category includes the single most critical parameter of this system, i.e. the distance traveled per encoder impulse, in microns (MPS). This value must be known precisely, otherwise the error will accumulate in time. The encoder specification states that MPS=40mu, and we halve this value by reading the AB-states of the rotary encoder in a certain manner. However, we do not know the MPS deviation and whether the original system has not been corrected in code, via some precision/laser measurement.\n\nLet MPS = 40mu. After 10K impulses the distance becomes 40mu x 10000 = 40cm.\n\nSuppose that the real value MPS = 40.1mu. Then, 40.1mu x 10000 = 40.1cm. One tenth of a micron accumulates into the whole millimeter, and this is just a single 40cm. movement. After ten such movements, the error will be 1cm!\n\nThis example shows that a standard ruler with a millimeter scale and the movement of 10000 impulses can determine only the first decimal part of the micron. Given the millimeter scale, we need to measure longer distances, e.g. 100K-impulse motion leading to, say, 400.4cm would produce MPS = 400.4cm/1e5 = 40.04mu. This is not possible to do, unfortunately, since the maximal guillotine travel is about 80cm. We could use a more precise caliper, but typically its maximal range will only be 4cm and the accuracy of 0.1mm, which gives us nothing.\n\nAnother way towards a greater accuracy is to increase the number of impulses. The quadrature encoder outputs two binary signals A and B which produce four states per cycle. These states can be counted, increasing the number of impulses and hence resolution 4x. This is still insufficient, but consider how much the number of impulses matters with the following example. Suppose a guessed MPS=40mu and we measure the distance traveled with only 25 generated impulses. This is about 1mm of travel, which, when measured with a millimeter accuracy, leads to 100% error. Whereas in the example above with 10K impulses, the relative error will be (40.1-40.0)/40 = 0.25%.  \n\nTherefore, we cannot determine MPS with an adequate precision by means of a mm-ruler. We can only verify that the integral micron part is 40mu and see if the decimal part is close to zero, which seems to be the case.\n\nThe second group of errors add a constant bias to the distance value. For instance, the sensor position is known only approximately with a millimeter precision of a standard ruler which might introduce a mm/sub-mm bias in the real and displayed knife position. The bias is constant though, so it does not accumulate into the cascaded loss of precision with each knife movement; it can be measured and accounted for, in code. A similar case holds for the potentially imprecise stopping distance values. The only requirement/hope is that they are constant, which is the case only with a single speed and distances larger than a few centimeters. A stopping distance depends on the knife movement direction, which is accounted for in the code. \n\n## General Observations\n\n- The machine is a technological marvel of precision mechanics, hydraulics, electrical relay engineering, and the microcontroller logic. It is very heavy and experiences huge mechanical vibrations, yet it has been maintaining mm-precision and continuity throughout long working hours for years.\n\n- Repairing a microcontroller unit (MCU) based board will seldom be economically viable. \n  Rewriting a microcontroller program demands rediscovering bits of the original R\u0026D, which takes time, but the benefit of scaling is lost. \n  The result is just one repaired device, not many of them sold after the original R\u0026D.\n\n- The Polish PD04 \"middleware\" is a clever transformation of one such repairing process to a commercial product.\n\n- The machine is surprisingly long lasting. The motor brake system does start to give up under a heavy load, it occasionally refuses to move the knife. A hydraulic gear had once caught some sawdust and jammed the knife lifting mechanism. \n\n- The factory owner has bought another similar used Adast guillotine which is a newer model. Its electrical relays occasionally lose contact. Compared to the older model, they are less protected against the mechanical vibrations as the relays lack special jackets to keep them tight.\n\n## Update: December 2023\n\nThe knife motion exhibits discontinuities after dozens of minutes. Once the machine is cooled, it works again, initially. It is not clear if this is due to some burnt resistors that control some relays, or the motor.\n\nWe have begun work on a new system that will produce better motor control with a frequency inverter, enabling variable motor speed.\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align:center\"\u003e Saulius Rakauskas \u003c/th\u003e\n\u003cth style=\"text-align:center\"\u003e Custom Circuit + Inverter \u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n\u003cimg src=\"./images/adastLateEvening.jpg\"  alt=\"Saulius Rakauskas repairing Adast Maxima MS80. Late Evening\" width=\"100%\" \u003e\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n\u003cimg src=\"./images/adastInverter.jpg\"  alt=\"Installing a Frequency Inverter for a Smooth Motor Control.\" width=\"100%\" \u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nIt took us two days to test a modified ATmega16/32 program (the new main.c vs main_no_inverter.c). It now outputs 1V signal of 1KHz with a variable duty percentage. This signal is then fed to a custom (R, C, transistor) circuit which outputs the DC signal in the range of 0..60V whose value depends on the duty percentage. The program determines the duty automatically based on how far the knife is located from the specified target. This 0..60V signal controls [the LS M100 inverter](https://inverterdrive.com/group/AC-Inverter-Drives-230V/LS-LSLV-0008-M100-1EOFNS/) connected to the motor, and thus adjusts its speed. The inverter output is 220V, but its frequency varies depending on the 0..60V input signal.\n\nThe old motor braking system is now completely disabled. The stopping distances are now bigger, but we combat them with a variable motor speed. Initially, the duty percentage is 80%, and the motor runs fast enough. We reduce it to 20% duty when 5cm are left to the target, and the duty becomes 10% for the last centimeter.\n\nThe two braking distances become more like \"braking distance-related parameters\" as they are coupled with a now much shorter delay between the change of the direction at the 5cm overrreach. We determine the values experimentally:\n\n```\nvolatile int32_t BREAK_DIST_FORW_MU = 2400;\nvolatile int32_t BREAK_DIST_BACK_MU = 100;\n```\n\nVariable motor speed, the two parameters above, and \"_delay_ms(50);\" (our ATmega code lies here as it is 400ms-delay in reality) in the following code section provide a practical sub-mm precision:\n\n```\nvoid move_to_target_and_stop(int32_t target_val) {\n\n    int32_t diff_mu;\n    diff_mu = target_val - P_MU;\n    \n    //100mu = 0.1 mm is the smallest allowed target dist difference\n    if ( (diff_mu \u003c -90) || (diff_mu \u003e 90) ) {\n        if (diff_mu \u003e 0) {\n            if( (P_MAX_MU - target_val) \u003e OFFSET_MU ) {\n                submove_to_target(target_val + OFFSET_MU - BREAK_DIST_BACK_MU);\n                _delay_ms(50);\n                submove_to_target(target_val + BREAK_DIST_FORW_MU);          \n            } else {\n                submove_to_target(target_val - BREAK_DIST_BACK_MU);\n            }        \n        } else {\n            submove_to_target(target_val + BREAK_DIST_FORW_MU);\n        }\n    }\n    //Otherwise exit as diff_mu is too small.\n}    \n```\n\nIt is important to note that we have reached an acceptable precision for the knife positioning in the mode when it passes the target with a 5cm overreach and then goes back. It is still decent with the direct positioning when moving backwards, but not for small repeated displacements of few centimeters, or pure moving forward without an overreach. We were drastically saving time on the experiments that try to combat braking distances and were content with the final practical result. \n\nTo be more precise and exhaustive, one could make these three parameters depend on the target distance (big, medium, small, at least), and whether the knife is positioned directly, or with an overreach. This, however, would demand weeks of experiments, the results of which might be nullified if the new motor is installed sometime in the future.\n\nOddly, the new LS M100 inverter is not an ideal match for the old motor, but it does the job:\n\n* We cannot make it move the knife very fast in the 220V regime (the 380V option has been disabled in the past). This can be ignored.\n\n* At very low speeds (when the knife approaches the target), the motor occasionally halts, esp. under a load when the moving iron plate needs to push/adjust the paper stack.\n\n**A very slow knife movement is needed to combat the braking distance uncertainties, esp. after removal of the braking system. The major new pain point is getting enough motor power at these very slow speeds. A new motor needs to be installed.**\n\nThe new system depends on the inverter settings. Any non-factory value needs to be documented and stored somewhere in the case of an accidental reboot of the inverter.\n\nA minor note: \"_delay_ms\" is not a reliable function with ATmega16/32. Choosing fuse bits for the internal 8MHz oscillator, hinting the code with #define F_CPU 8000000UL does not guarantee proper delays. The program works fine until adding the timer1 code in main.c, which makes the program \"tick\" at 1MHz for some reason. \n\nOn the other hand, the default 1MHz fuse bit setup corrects \"_delay_ms\", but it also makes the timer1 tick 4x slower than expected (based on the new frequency and prescalings). These problems are easy to solve by measuring the ATmega output with an oscilloscope/oscillograph, followed by adjusted prescalings and delays. The patching solves the problem, but it does not reveal the true reason behind these mismatches. It also obfuscates the code (the actual values are 8x bigger than the ones shown in the code).\n\n## Update: February 2024\n\n**We have managed to get the new (inverter-based) system work without installing a new motor, although it would be a good idea to install it in the future as the old motor somewhat lacks power in the combo with the LS M100 inverter.** \n\nSaulius found a way to increase the inverter output voltage from 220V to 260V by adjusting these values in the ioV setting (LS M100). The old motor is now more lively.\n\nAmusingly, Igor found a mechanical way to adjust distance values (directly, without code). In the photo below, on the left, you can see a little \"black cube\" positioned between the impulse counter and the yellow disk. Rotating the cube enables the counting of impulses without moving the knife. \n\nThe edge detection and motion prevention sensor wirings got mingled in the previous work in December 2023. On the right, there is a panel with wires that had to be traced to the sensors, and then switched back.\n\nThe maximal physical knife distance is around 82cm, but the maximal precise positioning distance is now set to 75cm. The edge sensors reduce 82cm a bit, followed by a 5cm overreach motion needed for the precise positioning. This adjustment was also needed:\n\n```\nconst int32_t P_MAX_MU = ((int32_t)810000);\n```\n\nPreviously, it was 800000.\n\nOddly, after the removal of the brake system, we had to adjust the distance sensor position to\n\n```\nconst int32_t P_ST_MU = ((int32_t)222400);\n```\n\nThe old value was 222.5mm at first, then 230mm, and now it is 222.4mm. \n\nIgor also showed us that the experiments needed to be done with the actual paper cutting. It is not enough to measure the knife position with a ruler, which immensely slows down the process.\n\nLet us see how long it takes this time before some other problem emerges. The amazing thing is, the machine still works, and the printing factory uses it rather heavily.\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align:center\"\u003eAdast Maxima MS80: The Back Side, February 2024\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\u003cimg src=\"./images/adastBackSide.jpg\"  alt=\"Adast Maxima MS80 Back Side\" width=\"100%\" \u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e \n\n## References\n\n- [PD-04][1]\n- [rotary-encoder][2]\n- [vytassblog][3]\n- [ATmega16][4]\n- [A Tutorial on Portable Makefiles, 2017](https://nullprogram.com/blog/2017/08/20/)\n- [A Tutorial on Portable Makefiles, Comments on Hacker News](https://news.ycombinator.com/item?id=32303193)\n\n[1]: https://www.en.chip-elektronika.pl/readers-programmers-for-paper-cutters/control-system-pd-04/\n[2]: https://howtomechatronics.com/tutorials/arduino/rotary-encoder-works-use-arduino/\n[3]: http://blog.elektronika.lt/vytassblog/?page_id=113\n[4]: https://components101.com/microcontrollers/atmega16-pinout-features-datasheet\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faabbtree77%2Fadast","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faabbtree77%2Fadast","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faabbtree77%2Fadast/lists"}