Nazalassa Posted March 2, 2023 Share Posted March 2, 2023 (edited) The Kerbal KAL Logic & Computing Laboratory KerbalX hangar is here, git repo is here IMPORTANT NOTE: It is normal this project is going slowly. We're still working on it, but not very fast. +-----+ | LOG | +-----+ [ 230302.1751 ] Created thread. [ 230303.1542 ] Experiment 1: analog addition attempt (see log 23.1 and analysis 23.2) [ 230304.0937 ] Working bus (see log 23.3) [ 230305.1452 ] Working adder (see log 23.4) [ 230308.1649 ] Working instruction KALs (see log 23.5) [ 230319.1713 ] Thread got accidentally moved (see incident 23.6) [ 230330.1446 ] Experiment 2: KAL curves outside time range [0,1] attempt (see log 23.7) [ 230422.1602 ] Experiment 3: "Tape" memory idea + .craft file AG modification attempt (see log 23.8) [ 230506.1621 ] CFG File Parser (CFP) finished. [ 230714.1055 ] Bus with MOV instruction experiment (see log 23.9) [ 240118.1815 ] CFP 0.3 finished: now usable and finally good. (see log 24.1) [ 240121.1126 ] 256 register bank wiring finished, now all that's left is to implement the MOV instruction. (see log 24.2) +----------------+ | HARDWARE PACKS | +----------------+ Usable (and generaly more user-friendly) sets of hardware, packed together in a single contraption, like computers [ 256 Analog Early Computer Prototype ] An adder + registers pack, which also has instruction KALs you can run (TAB, ADD, etc.). Still not a computer. [I may redo this description] [] +-------------------------+ | BINARY HARDWARE LIBRARY | +-------------------------+ Hardware that operates on a single bit per KAL [ 1-bit AND Gate ] 1-bit AND Gate. [ 1-bit AND Gate Simplified ] Simplified version of the above 1-bit AND gate. [ 6-bit Adder ] A simple binary adder that adds two 6-bit numbers. Why 6-bit? Because there was only room for 6 KALs. [] +-----------------------------+ | I/O BINARY HARDWARE LIBRARY | +-----------------------------+ Hardware that handle I/O (Input/Output) with one bit per KAL [ 8-bit Triple 7-Segment Display ] Displays an 8-bit number. [] +-------------------------+ | ANALOG HARDWARE LIBRARY | +-------------------------+ Hardware that operate on KAL play positions, to represents larger numbers in a single KAL [ 256 Bus with 3 Registers ] 256 analog bus prototype, with 3 analog registers. [ 256 Analog Adder ] Adds two 256 analog numbers. It has a carry in and a carry out, allowing it to be stacked. [ Analog Subtraction ] Note: may require some investigations (to determine range etc.) [ 256 Analog Bus (3 Registers) + Adder ] 256 analog bus prototype, with 3 analog registers. It has an adder that can add two 256 analog numbers (A+B → A). [ MOV-256 Bus ] 256 analog bus prototype, featuring a MOV instruction. It can therefore have up to 256 registers. [ MOV-BUS-256 Register Pack ] A pack of 256 registers, with a working bus and MOV instruction. +-----------------------------+ | I/O ANALOG HARDWARE LIBRARY | +-----------------------------+ Hardware that handle analog I/O (Input/Output) with KAL play positions [ 256 Triple 7-Segment Display ] Displays a 256 analog number. [ Smoothed State Follower ] Note: may require some investigations (to determine range etc.) [] +------------------------+ | OTHER HARDWARE LIBRARY | +------------------------+ Hardware that convert between binary and analog, etc. [ 8-bit 256 Binary to Analog Converter ] Converts an 8-bit binary number into a 256 analog number. [ 256 8-bit Analog to Binary Converter ] (Not made yet, but that's a logical thing to do) [] +------------------+ | PYTHON UTILITIES | +------------------+ Python scripts that help using KALs, such as track generators, etc. [ CFP ] A craft file editor, which supports scripts. Comes with KAL-Utils script suite. [ Old CFG File Parser (CFP) ] A graphical program that uses Tk, to view and edit .craft files (and KSP cfgs in general). [ QnD Generate KAL Curve ] A quick-and-dirty python script that takes a list of values, and makes them a KAL curve. Can be used with CFP. [] For those who want to study KALs without having access to KSP, here's an extract of a .craft file, showing a KAL: Spoiler PART { part = controller1000_4294451462 partName = Part persistentId = 2563744445 pos = 0.663985729,10.0025492,-0.706833422 attPos = 0.699999988,-0.0166683197,-1.34075487 attPos0 = 0,0.0166683197,0.640754819 rot = 0,0.707106709,-0.707106829,0 attRot = 0,0,0,1 attRot0 = 0,0.707106709,-0.707106829,0 mir = 1,1,1 symMethod = Mirror autostrutMode = Off rigidAttachment = False istg = -1 resPri = 0 dstg = 0 sidx = -1 sqor = -1 sepI = -1 attm = 1 sameVesselCollision = False modCost = 0 modMass = 0 modSize = 0,0,0 srfN = srfAttach,structuralPanel2_4294458818,panel,0|0|0,0|0|-1,0|0|0 EVENTS { } ACTIONS { ToggleSameVesselInteraction { actionGroup = None wasActiveBeforePartWasAdjusted = False } SetSameVesselInteraction { actionGroup = None wasActiveBeforePartWasAdjusted = False } RemoveSameVesselInteraction { actionGroup = None wasActiveBeforePartWasAdjusted = False } } PARTDATA { } MODULE { name = ModuleRoboticController isEnabled = True persistentId = 2591903450 displayName = INPUT A5 sequencePosition = 10 sequencePlaySpeed = 0 sequenceLength = 10 controllerEnabled = True priorityField = 1 windowPosition = (246, -392) windowSize = (618, 419) stagingEnabled = True sequenceIsPlaying = False sequenceDirection = Forward sequenceLoopMode = Repeat EVENTS { } ACTIONS { TogglePlayAction { actionGroup = Custom10 wasActiveBeforePartWasAdjusted = False } ToggleLoopModeAction { actionGroup = None wasActiveBeforePartWasAdjusted = False } ToggleDirectionAction { actionGroup = None wasActiveBeforePartWasAdjusted = False } ToggleControllerEnabledAction { actionGroup = None wasActiveBeforePartWasAdjusted = False } ToggleControllerEnabledOn { actionGroup = None wasActiveBeforePartWasAdjusted = False } ToggleControllerEnabledOff { actionGroup = None wasActiveBeforePartWasAdjusted = False } PlaySequenceAction { actionGroup = None wasActiveBeforePartWasAdjusted = False } StopSequenceAction { actionGroup = None wasActiveBeforePartWasAdjusted = False } SequenceForwardAction { actionGroup = None wasActiveBeforePartWasAdjusted = False } SequenceReverseAction { actionGroup = None wasActiveBeforePartWasAdjusted = False } SequenceLoopOnceAction { actionGroup = None wasActiveBeforePartWasAdjusted = False } SequenceLoopRepeatAction { actionGroup = None wasActiveBeforePartWasAdjusted = False } SequenceLoopPingPongAction { actionGroup = None wasActiveBeforePartWasAdjusted = False } SequenceLoopOnceRestartAction { actionGroup = None wasActiveBeforePartWasAdjusted = False } SequencePlaySpeedZeroAction { actionGroup = None wasActiveBeforePartWasAdjusted = False } SequencePlaySpeedFullAction { actionGroup = None wasActiveBeforePartWasAdjusted = False } } AXISGROUPS { sequencePosition { axisGroup = None axisIncremental = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 axisSpeedMultiplier = 0 axisInverted = None overrideIncremental0 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 overrideIncremental1 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 overrideIncremental2 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 overrideIncremental3 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 } sequencePlaySpeed { axisGroup = None axisIncremental = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 axisSpeedMultiplier = 0 axisInverted = None overrideIncremental0 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 overrideIncremental1 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 overrideIncremental2 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 overrideIncremental3 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 } } CONTROLLEDAXES { AXIS { persistentId = 210973617 moduleId = 4023821551 partNickName = Spotlight Mk1 rowIndex = 0 axisName = lightR timeValueCurve { key = 0 0 0 0 key = 0.498 0 0 0 key = 0.5 1 0 0 key = 1 1 0 0 } } AXIS { persistentId = 210973617 moduleId = 4023821551 partNickName = Spotlight Mk1 rowIndex = 1 axisName = lightG timeValueCurve { key = 0 0 0 0 key = 0.498 0 0 0 key = 0.5 1 0 0 key = 1 1 0 0 } } AXIS { persistentId = 210973617 moduleId = 4023821551 partNickName = Spotlight Mk1 rowIndex = 2 axisName = lightB timeValueCurve { key = 0 0 0 0 key = 0.498 0 0 0 key = 0.5 1 0 0 key = 1 1 0 0 } } AXIS { persistentId = 3915516560 moduleId = 3186489012 partNickName = KAL-1000 Controller rowIndex = 3 axisName = sequencePosition timeValueCurve { key = 0 0 0 0 key = 0.5 0 0 0 key = 0.51 1 0 0 key = 1 1 0 0 } } } CONTROLLEDACTIONS { } UPGRADESAPPLIED { } } MODULE { name = ModuleCargoPart isEnabled = True beingAttached = False beingSettled = False reinitResourcesOnStoreInVessel = False stagingEnabled = True EVENTS { } ACTIONS { } UPGRADESAPPLIED { } } } Edited March 3, 2024 by Nazalassa Moved image to Codeberg and added link to git repo Quote Link to comment Share on other sites More sharing options...
HB Stratos Posted March 3, 2023 Share Posted March 3, 2023 Analog calculations will be fast and very KAL efficient, but as with real analog computers compounding errors will become a problem. This will be an issue for OP Codes and precise integer ops, but should be fine for most general purpose calculations. After all, this only runs on floats, and well floats even outside of KALs have their limits on precision. For OP Codes though we will need to have a stairstepped KAL to rule out any reading errors, cause if you're .1 off it doesn't matter much, but if you do ADD instead of POP STACK that will become a major issue. Quote Link to comment Share on other sites More sharing options...
Nazalassa Posted March 3, 2023 Author Share Posted March 3, 2023 (edited) Log 23.1 Analog logic gets too imprecise if the required precision (in this case 1/256, to represent 8-bit numbers) gets too small. All in the picture below: I entered at least 8 significant digits for all coordinates of all points in all curves, I made the curve between points segments (using the editor function), and the precision is like uuuh... If operations need to be chained, this will be an issue. A big issue. In the example I gave, chaining two additions will give wrong results. This is the fault of KSP's lack of precision on plenty of things. Don't worry, I double-checked my math. So yes it appears that we can store ROM as play positions, but operations, unless we want hundreds or even thousands of points, will likely be bitwise. Of course I can use the python script to give a specific value to each integer play position, but in this case the .craft will be veeeeery long, and even if I don't mind pasting 32768 lines in a .craft, we should find other ideas. Edited May 6, 2023 by Nazalassa Moved Experiment 1 log here Quote Link to comment Share on other sites More sharing options...
Nazalassa Posted March 3, 2023 Author Share Posted March 3, 2023 (edited) Analysis 23.2 On 3/3/2023 at 5:31 PM, HB Stratos said: Analog calculations will be fast and very KAL efficient, but as with real analog computers compounding errors will become a problem. This will be an issue for OP Codes and precise integer ops, but should be fine for most general purpose calculations. After all, this only runs on floats, and well floats even outside of KALs have their limits on precision. For OP Codes though we will need to have a stairstepped KAL to rule out any reading errors, cause if you're .1 off it doesn't matter much, but if you do ADD instead of POP STACK that will become a major issue. I think it would be fine if we made like 8-bit blocks (between 0 and 255) and stick two of them together when we need 16 bits etc., and hardcode very precise values with the help of the python script. As the script generates things like that: +---------------------+ | ___ | | _____| | | _____| | | ___| | +-0-----1-----2-----3-+ So if there's a tiny, tiny imprecision, it will be corrected. After analysing the way the analog adder I made works, I think that the issue is that I made something like tha instead: +------------------+ | _,-' | | _,-' | | _,-' | | _,-' | +-0----1----2----3-+ (Imagine the line is a straight line between start and stop) So the source of the imprecision is probably just the fact that I was lazy and didn't literally hardcode the values in the "flat" way I showed above (the first one). I'll try to use the first way and see if it works. On 3/3/2023 at 5:31 PM, HB Stratos said: Analog calculations will be fast and very KAL efficient, Also I noticed bitwise addition is like 1 physics tick or something, the lower that we can get. Edited May 6, 2023 by Nazalassa Moved Experiment 1 analysis here Quote Link to comment Share on other sites More sharing options...
Nazalassa Posted March 3, 2023 Author Share Posted March 3, 2023 (edited) OK I just copy-pasted around 2,000 lines of timestamps in the .craft. Time to see how it behaves. (cross your fingers :P) -- Oh great, 0 parts in 1 stage. I guess KSP doesn't like it. We have to find another way, I'll post the script in the OP rn (doc will follow) Edited May 6, 2023 by Nazalassa Quote Link to comment Share on other sites More sharing options...
darthgently Posted March 3, 2023 Share Posted March 3, 2023 (edited) Am I to understand you are looking at using the KAL as a l low level computer instead of a high level controller? If not what am I missing? Interesting exercise. Inspired by logic design courses while in college I made a fixed point basic op library for the Amiga 1000 blitter chip that could do add, subtract, and multiply on huge arrays of fixed point numbers (the blitter is for doing logical bit ops on entire bitplanes, mostly used for graphics). I got stumped on a division op that had decent precision and finals were coming up so let it fade away from my to-do list. Yes, years ago before FPUs and mega graphics cards were super common Edited March 3, 2023 by darthgently Quote Link to comment Share on other sites More sharing options...
HB Stratos Posted March 3, 2023 Share Posted March 3, 2023 4 hours ago, darthgently said: Am I to understand you are looking at using the KAL as a l low level computer instead of a high level controller? If not what am I missing? Interesting exercise. Inspired by logic design courses while in college I made a fixed point basic op library for the Amiga 1000 blitter chip that could do add, subtract, and multiply on huge arrays of fixed point numbers (the blitter is for doing logical bit ops on entire bitplanes, mostly used for graphics). I got stumped on a division op that had decent precision and finals were coming up so let it fade away from my to-do list. Yes, years ago before FPUs and mega graphics cards were super common Yes, we are looking at making a computer out of KALs. if you want to look at the basic writeups I did of the underlying things we can do with KALs, look here: https://kerbalx.com/HB_Stratos/Analog-Subtraction , https://kerbalx.com/HB_Stratos/Smoothed-State-Follower also @Nazalassa I am currently writing a parser for .craft files in python that will output nested dictionaries similar what the python json.loads() does. Might be of use to combine with your script once it's done, then you don't have to copy-paste into craft files anymore. Quote Link to comment Share on other sites More sharing options...
darthgently Posted March 3, 2023 Share Posted March 3, 2023 15 minutes ago, HB Stratos said: Yes, we are looking at making a computer out of KALs. if you want to look at the basic writeups I did of the underlying things we can do with KALs, look here: https://kerbalx.com/HB_Stratos/Analog-Subtraction , https://kerbalx.com/HB_Stratos/Smoothed-State-Follower also @Nazalassa I am currently writing a parser for .craft files in python that will output nested dictionaries similar what the python json.loads() does. Might be of use to combine with your script once it's done, then you don't have to copy-paste into craft files anymore. That is very cool. I've done smooth control of parts with kOS but overall have stopped using robotic parts as DockRotate + PicoPorts for joints works for most of what I want to do. But yours will work without mods from what I can tell Quote Link to comment Share on other sites More sharing options...
Nazalassa Posted March 4, 2023 Author Share Posted March 4, 2023 12 hours ago, HB Stratos said: also @Nazalassa I am currently writing a parser for .craft files in python that will output nested dictionaries similar what the python json.loads() does. Might be of use to combine with your script once it's done, then you don't have to copy-paste into craft files anymore. Nice! Then if we couple both scripts it'll be easier :) I think I have an idea for a 8-bit analog bus with 8-bit analog registers, it would use 1 KAL for the bus itself and 3 KALs per register. 17 hours ago, darthgently said: Am I to understand you are looking at using the KAL as a l low level computer instead of a high level controller? If not what am I missing? Interesting exercise. The main reason we do that is probably because it's fun and we may will learn things about how computers work. Quote Link to comment Share on other sites More sharing options...
HB Stratos Posted March 4, 2023 Share Posted March 4, 2023 11 hours ago, darthgently said: That is very cool. I've done smooth control of parts with kOS but overall have stopped using robotic parts as DockRotate + PicoPorts for joints works for most of what I want to do. But yours will work without mods from what I can tell Yeah that's the plan.. sadly Sensors (except for a single use collision sensor) are outside the range of possibility for now, so a PID controller would not be possible not because it can't be coded with KALs, but because we don't have any real world data we can use as input Quote Link to comment Share on other sites More sharing options...
Nazalassa Posted March 4, 2023 Author Share Posted March 4, 2023 (edited) On 3/4/2023 at 11:33 AM, HB Stratos said: Yeah that's the plan.. sadly Sensors (except for a single use collision sensor) are outside the range of possibility for now, so a PID controller would not be possible not because it can't be coded with KALs, but because we don't have any real world data we can use as input It would be totally possible to detect staging (at least when something decouples) or keyboard inputs that trigger either a specific action group, or pitch yaw that kind of things. -- [ MERGED WITH BELOW POST ] -- Log 23.3 OK the bus works! yeeeey Original state (I changed the values of the registers myself) Register A writes to the bus (AR A WRITE is enabled) and register B loads from the bus (AR B READ is enabled), effectively doing an A to B transfer. Now register C writes to the bus and register B reads, transfering data from C to B. Here's how it works! Each of the three lines is a register. Each register has 3 KALs, from left to right: read, store, write. Normally read and write are disabled, although store is always enabled. When write is enabled, it writes the contents of the register to the bus. When read is enabled, it stores the contents of the bus into the register. The thing works like that: Basically each KAL is a buffer, the bus writes into the read KALs, which each write into their register's store KAL, which does the same with the write KAL, which writes to the bus again. It's like this: R → S → W ]-- Register ↖ ↙ Bus ]-- Bus However, the read and write KALs of each register aren't always enabled, which means that we can decide when we want eachregister to read/write from/to the bus. Oh, by the way, here's how it looks in one KAL: Instead of having the sloped stuff from the adder, I used my script to generate a buffer, which basically sets the play position of the target KAL to the one of the current one. Download: https://kerbalx.com/Nazalassa/8-bit-bus-prototype Edited March 4, 2024 by Nazalassa Images to web.archive.org Quote Link to comment Share on other sites More sharing options...
Nazalassa Posted March 4, 2023 Author Share Posted March 4, 2023 (edited) [ WARNING | This post has been repurposed. It is roughly one day younger. ] I modified the OP and added a library to keep track of all the KAL logic & computing stuff we do :) Right now there are the crafts from @HB Stratos and me. If we want to make a CPU I suggest we first try to make an all-8-bit one, 256 bytes of total memory (maybe 192 program ROM, the rest is I/O, RAM, and possibly stack), with a small set of operations (LDA, LDB, STA, STB, LAV, LBV, JMP, ADD, NOP, maybe SUB and BNE-like things). Edited March 5, 2023 by Nazalassa Post repurposed. Quote Link to comment Share on other sites More sharing options...
Nazalassa Posted March 5, 2023 Author Share Posted March 5, 2023 (edited) Log 23.4 I finally got a 256 analog adder working! It's pretty straightforward. Two inputs, a carry in, a carry out, and the result. It can be stacked. I then connected it to the bus! So now we have a bus with three registers and some kind of simple ALU. How to operate it: well I already said how transferring stuff between registers work in a post above, so I won't repeat it. By default, the adder processor in enabled and the adder output is disabled. The result has the value of A+B. In order to transfer this result to the A register, here's how to proceed: Disable the adder processor, so that the result won't change; Enable, then disable, the adder output, to transfer the data from it to the A register (make sure the A register isn't reading from the bus); Finally, re-enable the adder processor. I also added the 'LDC' controller, which has the purpose of loading the C register with whatever's in it, when it's enabled (you'll need to set the value while it is enabled for the value to be actually loaded into C). This way you can load any register by transfering from C to it. By default the thing is disabled, but it can be left enabled (in fact, you should). Press '0', or whatever key is associated with AG 10, to toggle it. KerbalX: adder adder+bus After doing all of that I wonder how to actually execute opcodes. Maybe one KAL per opcode? That would play whenever needed and enable / disable KALs as needed. Edited March 4, 2024 by Nazalassa Moved log 23.4 here Quote Link to comment Share on other sites More sharing options...
HB Stratos Posted March 6, 2023 Share Posted March 6, 2023 Absolutely awesome work! I don't have much time rn, university exam season and all. but this is actually proving to be feasible. I was always wondering how a full loop of KALs would work. Usually there's the problem that a KAL cannot be disabled as when you set a KALs position from another KAL it skips around, never playing action groups. But in this case we can just have one single KAL that does actually play with a play speed above zero, essentially acting as our clock. And that one would be the only one allowed to use action groups to set a KAL playing or not for the bus to work. If that's not an option, the slightly messy workaround of having one KAL set the play speed of another KAL which is set to loop and will click an action group if play speed is increased would also work. A word of caution though, when playing with complex KAL mechanics on my 1k part concorde I have run into the issue of larger time skips causing issues with the averaging skipping around more. If we end up running into lag we may need to clock down the CPU beyond what the physics tick rate dropping would already do to ensure reliable function. Also, we cannot use axis groups as input, at least not without major filtering. Even when set to playing axis grouped KAL appear to be updating on a different clock cycle, therefore making the averaged output of that KAL and another one flutter between a real average and the value of the non-axis KAL. By the way, is your adder compatible with negative numbers with my method of just treating the middle of the play positon space as zero? Quote Link to comment Share on other sites More sharing options...
Nazalassa Posted March 6, 2023 Author Share Posted March 6, 2023 (edited) On 3/6/2023 at 2:37 AM, HB Stratos said: Absolutely awesome work! I don't have much time rn, university exam season and all. but this is actually proving to be feasible. I was always wondering how a full loop of KALs would work. Usually there's the problem that a KAL cannot be disabled as when you set a KALs position from another KAL it skips around, never playing action groups. But in this case we can just have one single KAL that does actually play with a play speed above zero, essentially acting as our clock. And that one would be the only one allowed to use action groups to set a KAL playing or not for the bus to work. If that's not an option, the slightly messy workaround of having one KAL set the play speed of another KAL which is set to loop and will click an action group if play speed is increased would also work. A word of caution though, when playing with complex KAL mechanics on my 1k part concorde I have run into the issue of larger time skips causing issues with the averaging skipping around more. If we end up running into lag we may need to clock down the CPU beyond what the physics tick rate dropping would already do to ensure reliable function. Also, we cannot use axis groups as input, at least not without major filtering. Even when set to playing axis grouped KAL appear to be updating on a different clock cycle, therefore making the averaged output of that KAL and another one flutter between a real average and the value of the non-axis KAL. By the way, is your adder compatible with negative numbers with my method of just treating the middle of the play positon space as zero? For the adder: unfortunately I guess it isn't. Oh well, if you do the 2's complement-plus-one thing yourself it will probably work, one more piece of hardware to do I think that for running actions we could like have all of them happen in less than 0.04 sec. (one phys-frame) in a single KAL. Like maybe we can have one KAL for each OPcode or something, that plays a sequence that basically enables/disables other KALs. I don't know if enabling then disabling a KAL in the same phys-frame would enable it for a bt, or not. More experiments to do I guess... I tried a 2-KAL-loop and oh well. The game doesn't seem to like it. EDIT from roughly one day later: I'll try extra-short KALs in the following days to see what we can do it the whole KAL plays in one phys-frame. Edited March 7, 2023 by Nazalassa One day later... Quote Link to comment Share on other sites More sharing options...
Nazalassa Posted March 8, 2023 Author Share Posted March 8, 2023 (edited) Log 23.5 Wheee! Through testing, I found some interesting stuff: It seems that, as long as we have 1 action or less for 0.04s the sequence is correctly executed. If there are more, some may go missing. An example is my try at a TAB operation (A->B), it works only if the length of the KAL is 0.08s or more. I don't know what it does if there's some lag. Needs testing I guess. So, I've added the six transfer instructions to the adder+bus thing, as well as ADD (A+B->A). One KAL is reserved for ADC (ADD with carry). I'll probably add a carry storage once I'll be done with that, should be soon. This "thing" (tell me if you have a better name) can be either active or inactive, the latter being the default state. It will only do meaningful operations when activated, and to switch between states press '0', or whatever key is associated with AG 10. The seven possible instructions have been packed in seven different KALs: TAB, TBA, TAC, TCA, TBC, TCB, ADD. Their location is shown in the picture above. To execute an instruction, simply play the associated KAL. Nothing more! OK, avoid executing two instructions simultaneously please... That'll break stuff - but otherwise it's safe. In order to be able to load stuff into the registers, I connected a KAL (labelled "C Register Loader") to the C register. If it is enabled and you write in it, whatever you write will be stored into the C register. You can then use one of the transfer instructions to put that data into another register. Instruction Set * TAB : Copies data from the A register into the B register. * TBA : Copies data from the B register into the A register. * TAC : Copies data from the A register into the C register. * TCA : Copies data from the C register into the A register. * TBC : Copies data from the B register into the C register. * TCB : Copies data from the C register into the B register. * ADD : Adds the values of registers A and B, then puts the result back in A. For the moment, there's no carry support. More pictures: Spoiler Also, if you want to check the 133.4 MiB gif where I add 42+71, it's here: https://imgur.com/vRdED09.gif [sorry, it has been cut by Imgur... ] Download: https://kerbalx.com/Nazalassa/256-Analog-Computer-Prototype Edited March 4, 2024 by Nazalassa Moved log 23.5 here Quote Link to comment Share on other sites More sharing options...
HB Stratos Posted March 10, 2023 Share Posted March 10, 2023 (edited) Super cool stuff, love to see it. I think by now we have proven that a full computer is possible, and I'm excited to see how far we can go. I in the meantime have made progress on the parser. It still is very janky, in desperate need of a re-write. It will break on stuff like the panther engine where one engine with two same moduleEngines exist, but otherwise it appears to be working, if very ugly (unused code, unreadable code, outdated comments, etc) . Since it is so heavily WIP I will not throw it on github yet, but if you're interested in using it already and maybe helping me fix stuff, here it is: Spoiler from pprint import pprint import re import collections.abc # for deep_update #from https://stackoverflow.com/questions/3232943/update-value-of-a-nested-dictionary-of-varying-depth def deep_update(target, update): for k, v in update.items(): if isinstance(v, collections.abc.Mapping): target[k] = deep_update(target.get(k, {}), v) else: target[k] = v return target """ def findFirstLineWithPattern(data:str, pattern:str) -> int : pattern:pattern = re.compile(pattern) match = re.search(pattern, data) if match: index = data[:match.start()].count("\n") else: raise ValueError("no match for pattern found in data") return index """ def parseCraftHeader(headerString:str) -> dict : headerDict = {} headerLines:list = headerString.split("\n") for line in headerLines: if " = " in line: key, value = line.split(" = ") headerDict[key] = value else: headerDict[line] = None return headerDict def splitStringByMODULE(string:str) -> list: outputList = [] index = string.find("{") if index == -1 : raise ValueError("No { defining a module could be found") else: previousLineIndex = string.rfind("\n", 0, index) outputList = [string[0:previousLineIndex], string[previousLineIndex:]] return outputList def splitIntoSections(string:str) -> list : outputList = [] i = 0 while True: i += 1 def _processLine(string:str) -> dict : try : key, value = string.split(" = ") except ValueError: return {string : None} else : return {key : value} def _recurseAddToPartDict(inputDict:dict, nameStack:list[str]) -> dict : if len(nameStack) <= 1 : return {nameStack[0] : inputDict} else : return {nameStack[0] : _recurseAddToPartDict(inputDict, nameStack[1:])} def recurseParseCraftPart(lineList:list[str]) -> dict: """ while True: if line = ALLCAPS, followed by { find matching closing brace throw content into recursion remove content from lineList """ partDict = {} tempDict = {} indexStack:list = [] nameStack:list = [] processedIndices:list = [] currentDepth = 0 previousDepth = 0 for i, line in enumerate(lineList) : if line == "{" : try: lineList[i-1] except IndexError: raise ValueError("open brace had no NAME, corruption?") indexStack.append(i-1) # do -1 because of NAME before { nameStack.append(lineList[i-1]) previousDepth = currentDepth currentDepth +=1 elif line == "}" : start = indexStack.pop() currentSection = lineList[start+1:i+1] #i+1 to truncate NAME and to make it inclusive currentNAME = nameStack.pop() currentDepth -= 1 for localIndex, line in enumerate(currentSection) : realIndex = localIndex + start + 1 #+1 needed as we start the currentSection at start+1, lovely off-by-one error if realIndex in processedIndices : continue if line == "{" or line == "}" : continue else: tempDict["#NAME"] = currentNAME #for line in currentSection: tempDict.update(_processLine(line)) for i in range(start, i+1): if i not in processedIndices: processedIndices.append(i) if nameStack != [] : updateDict = _recurseAddToPartDict({currentNAME : tempDict}, nameStack) partDict = deep_update(partDict, updateDict) print("\n-----\n") pprint(tempDict, sort_dicts=False) print("\n\n") pprint(updateDict, sort_dicts=False) print("\n\n") pprint(partDict, sort_dicts=False) tempDict.clear() pprint(partDict, sort_dicts=False) return partDict def parseCraftPart(partString:str) -> dict : partDict = {} #nestedList = re.findall(r"{(?:[^{}]|(?R))*}", partString) #build a nested list of all curly braces #loop over all curly braces, handle stuff partDict = recurseParseCraftPart(partString.split("\n")) return partDict def parseCraftParts(partsString:str) -> dict : partsDict = {} partsList:list = re.split(r"(?=PART\n)", partsString) #new_list = [expression for item in iterable if condition] partsList = [x for x in partsList if x != ""] for part in partsList: partsDict.update(parseCraftPart(part)) return partsDict def parseCraft(craftData:str) -> dict : craftDict = {} craftData = craftData.replace('\t', '') #create a string slice of craftData containing only the header so we don't have to split the entire string headerEnd = re.search("PART",craftData).start() headerString:str = craftData[0:headerEnd] partsString:str = craftData[headerEnd:] craftDict["header"] = parseCraftHeader(headerString) craftDict["parts"] = parseCraftParts(partsString) return craftDict craftFile = open('Kal Test.craft', 'r') print(craftFile) craftData = craftFile.read() #turns out craft files are not really json, but kinda close craftDict = parseCraft(craftData) pprint(craftDict, sort_dicts=False) print(len(craftDict)) Edited March 10, 2023 by HB Stratos Quote Link to comment Share on other sites More sharing options...
Nazalassa Posted March 10, 2023 Author Share Posted March 10, 2023 15 hours ago, HB Stratos said: Super cool stuff, love to see it. I think by now we have proven that a full computer is possible, and I'm excited to see how far we can go. Well ,I got working RAM -- the registers. Even if it won't be really usable in large clusters -- three KALs per byte... Er, no, that's too much. We need to find a way to put more RAM into less KALs, but concatenating two values into one KAL will be impossible, due to potentialprecision errors. Maybe some kind of... Grid? Data compression? I don't know. I think I'll start working on a python script with tk to have a "user-friendly" way to directly edit KAL sequences. I think. I may start working on it in some time. May. (sorry, not the month) Quote Link to comment Share on other sites More sharing options...
Nazalassa Posted March 10, 2023 Author Share Posted March 10, 2023 Also I think it's time to start thinking about sensors. Like, we can have single-use "same-ship" sensors (i.e sensors that can tell whether they're attached to the ship, or not, in which case they either exploded or were thrown away), but... Input sensors (Action groups) can be made, that's quite easy. As for output, anything that can be controlled by action groups can be made. Like wheel speed and turning, RCS thrusting, engines, ladders, or even science experiments. Maybe there is a way to trick the game into storing say, a pressure or temperature data into a KAL (with play position)? Maybe. Needs experiments. Quote Link to comment Share on other sites More sharing options...
HB Stratos Posted March 10, 2023 Share Posted March 10, 2023 I have done some research on sensors. as far as I know I invented the impact sensor, and make some torpedos with explosion triggers with that. But actual sensors that are more than single use have this far proven to be near impossible. I haven't found a way yet to have something - anything in the environment influence the play position of a KAL. Some theories that come to mind would be that we have proven that breaking links is detectable, so maybe breaking a docking port and redocking would be resettable, but I doubt the KAL would gain the curves it lost back. So I guess we need to look deeper, perhaps abuse changing tick rates or KAL update rates somehow. I don't know how yet, but that's the best I can think of so far. All my other sensors have been using purely mechanical systems. for example my full auto spoilers don't need a single KAL to function. Quote Link to comment Share on other sites More sharing options...
Nazalassa Posted March 10, 2023 Author Share Posted March 10, 2023 4 minutes ago, HB Stratos said: So I guess we need to look deeper, perhaps abuse changing tick rates or KAL update rates somehow. I don't know how yet, but that's the best I can think of so far. My guess on this is that we need to know how much events can happen in a single phys-tick, however it seems infinite... So um, I don't think we can "push" a KAL's update time by just putting a bunch of other things that add some "latency" (understand: generating enough events to make the KAL not update during this phys-frame). Now, I think a throttle sensor is possible. Just hook the KAL's play position to the "throttle" axis group (AG) and it will work (I hope). Also, sensors for player (ship control) input can be done the same way, just hooked to one of the rotate/translate AGs. Quote Link to comment Share on other sites More sharing options...
HB Stratos Posted March 10, 2023 Share Posted March 10, 2023 Axis group "sensors" aren't really sensors. They are more like a keyboard, player input. Also because axis groups only respond to player input, and sadly don't respond to SAS and the like. If they did we'd have a real-world sensor right there. Also worth noting is that the update rate for Axis groups affecting a KAL appears to be different to that of a KAL updating another KAL, which leads to a flickering input if a KAL and an Axis group affect another KAL simultaneously. That sort of tick rate flickering is what I was theorizing that it could be used for some sort of sensor, though I don't know how yet. Another thing, there's this section in the KALs craft file: Spoiler AXISGROUPS { sequencePosition { axisGroup = None axisIncremental = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 axisSpeedMultiplier = 0 axisInverted = None overrideIncremental0 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 overrideIncremental1 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 overrideIncremental2 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 overrideIncremental3 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 } sequencePlaySpeed { axisGroup = None axisIncremental = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 axisSpeedMultiplier = 0 axisInverted = None overrideIncremental0 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 overrideIncremental1 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 overrideIncremental2 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 overrideIncremental3 = Pitch, Yaw, Roll, TranslateX, TranslateY, TranslateZ, WheelSteer, WheelThrottle, Custom01, Custom02, Custom03, Custom04 } } I wonder whether it would be possible to hack this somehow so that e.g. the position of a sensor would affect the play position of a KAL. sounds near impossible... but maaaaybe.. Quote Link to comment Share on other sites More sharing options...
Jacob Kerman Posted March 10, 2023 Share Posted March 10, 2023 So let me get this straight. You two are building a computer out of modules of KAL-1000 controllers. It can only sense one type of event. And it is soon to reach basic 8-bit computer standards. Please tell me how this works, as I have no idea about how this works. I can tell you how to fix a car, how to build a rocket, and how to wire a house, but I know very little about coding. Quote Link to comment Share on other sites More sharing options...
HB Stratos Posted March 10, 2023 Share Posted March 10, 2023 2 hours ago, Jacob Kerman said: So let me get this straight. You two are building a computer out of modules of KAL-1000 controllers. It can only sense one type of event. And it is soon to reach basic 8-bit computer standards. Please tell me how this works, as I have no idea about how this works. I can tell you how to fix a car, how to build a rocket, and how to wire a house, but I know very little about coding. I can't fully explain everything, but you can read up on the basics of what you can do with KAls on my kerbalX posts: https://kerbalx.com/HB_Stratos/Analog-Subtraction , https://kerbalx.com/HB_Stratos/Smoothed-State-Follower @Nazalassa by the way in my research of craft files I discovered something: Look at that movementTransformName... You can enter any transform there. So far I have gotten it to work with model, light_08 and spotlight. The first two make the entire spotlight move including it's base, while the last one only makes the light move without even moving the lamp (It's the spotlight you can pitch and yaw around). I am currently trying to find out which unity function they are using to parse that string, and then try to do path traverse so I can modify parts outside of the current part to move around. Would you have any ideas how any of this could work? MODULE { name = ModuleLight isEnabled = True isOn = True uiWriteLock = False disableColorPicker = False lightR = 0.875 lightG = 0.875 lightB = 0.875 castLight = True movementTransformName = Lamp isBlinking = False rotationAngle = 0 pitchAngle = -22 blinkRate = 1 stagingEnabled = True EVENTS { Quote Link to comment Share on other sites More sharing options...
HB Stratos Posted March 10, 2023 Share Posted March 10, 2023 (edited) I had assumed that they likely use the unity transform.Find() function, which would allow path traverse with e.g. spotlight_08/Lamp/spotlight, but it doesn't appear to work. With said path traverse ./Lamp should equal Lamp, but only the latter actually works. So I am not entirely sure which function behind the scenes is evaluating this https://nodachisoft.com/common/en/article/en000181/ https://docs.unity3d.com/ScriptReference/Transform.Find.html Edited March 10, 2023 by HB Stratos Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.