Jump to content

hugopeeters

Members
  • Posts

    55
  • Joined

  • Last visited

Everything posted by hugopeeters

  1. And for the people wanting to build a similar controller, here is my Arduino code for use with KSPSerialIO: https://github.com/hugopeeters/KerbalController
  2. For those interested, here's a list of the main parts I used. Parts Cost Used as/for Link LED bar graph $ 1,95 not used in final build https://www.sparkfun.com/products/9937 Arcade button $ 1,95 not used in final build https://www.sparkfun.com/products/9341 LED bar driver $ 2,45 not used in final build, only works with analog input, not PWM https://www.sparkfun.com/products/12694 Metal pushbutton $ 4,95 Stage button https://www.sparkfun.com/products/11968 LCD $ 24,95 LCD https://www.sparkfun.com/products/9395 Slide pot knob $ 0,95 Throttle https://www.sparkfun.com/products/9120 Slide pot $ 2,95 Throttle https://www.sparkfun.com/products/9119 Toggle switch $ 1,95 SAS and RCS https://www.sparkfun.com/products/9276 Safety switch $ 2,95 Abort and Stage Lock (Arm) https://www.sparkfun.com/products/11310 Screws and spacers, 4 boxes with different sizes (M2, M2.5, M3) € 17,00 Throttle, LCD and protoboards with LED bars https://nl.aliexpress.com/item/10pcs-Hex-nut-screw-M3-4-5-6-7-6mm-Hex-head-Brass-Threaded-Pillar-Female/32565388551.html?spm=a2g0s.9042311.0.0.Ri4DZM Shift registers € 0,54 Driving the LED bars (Fuel Gauges) https://nl.aliexpress.com/item/10pcs-free-shipping-SN74HC595N-SN74HC595-74HC595N-74HC595-DIP-16-Counter-Shift-Registers-Tri-State-8-Bit/32429190104.html?spm=a2g0s.9042311.0.0.Ri4DZM LED bars € 0,78 Fuel Gauges https://nl.aliexpress.com/item/2Pcs-10-Segment-LED-Bargraph-Light-Display-Module-Bar-Graph-Ultra-Bright-Red-Yellow-Green-Blue/32815306576.html?spm=a2g0s.9042311.0.0.Ri4DZM 4-axis joysticks € 14,72 Translation and rotation controls https://nl.aliexpress.com/item/4-axis-potentiometer-Joystick-400-series-Rocker-hall-joystick-dimensional-resistance-5K-sealed-with-button-joystick/32258450509.html?spm=a2g0s.9042311.0.0.Ri4DZM Buttons with LED (different colors) € 3,00 Action Groups https://www.tinytronics.nl/shop/nl/componenten/schakelaars/rode-drukknop-16mm-reset-met-6.3v-led-verlichting?search=AB6Y-M-6.3V-RED Rocker switch € 0,50 Power (not implemented (yet)) https://www.tinytronics.nl/shop/nl/componenten/schakelaars/standaard-inbouw-wipschakelaar-normaal?search=switchn Rocker switch small € 0,45 Debug mode https://www.tinytronics.nl/shop/nl/componenten/schakelaars/standaard-inbouw-wipschakelaar-klein?search=switchs protoboards € 0,80 LED bars and shift registers https://www.tinytronics.nl/shop/nl/prototyping/printplaten/experimenteer-printplaat-5cm*7cm-dubbelzijdig?search=PCB5x7DUB Toggle switch small € 0,60 X/Y/X toggles for LCD mode https://www.tinytronics.nl/shop/nl/componenten/schakelaars/standaard-inbouw-tuimelschakelaar-mts-102?search=MTS-102
  3. Thanks again @richfiles, your trick worked like a charm! I got the resistors bent out of the way and was able to mount the LED bars flush with the face plate. After soldering in the last 55 wires it was on to some hefty coding! The way I have the LEDs hooked up is efficient, but not very easy to code for. There are 7 shift registers with 8 outputs each. There are 5 LED bars with 10 LEDs each. When I soldered in the wires, I only took into account what would be easiest to route the wires. Everything else can be fixed in the code, I thought. Well, sure, but it takes a lot of testing and debugging. I first get the fuel levels from the game and calculate the percentage: //Fuel Gauges vSF = 100 * VData.SolidFuel / VData.SolidFuelTot; //percentage of solid fuel remaining vLF = 100 * VData.LiquidFuelS / VData.LiquidFuelTotS; //percentage of liquid fuel remaining in current stage vOX = 100 * VData.OxidizerS / VData.OxidizerTotS; //percentage of oxidized remaining in current stage vEL = 100 * VData.ECharge / VData.EChargeTot; //percentage of electric charge remaining vMP = 100 * VData.MonoProp / VData.MonoPropTot; //percentage of monopropellant remaining Next, I map them to values between 0 and 9. Note I correct for having one LED bar soldered in the wrong way around. //scale down to 0-9 for binary calculations SF = constrain(map(vSF, 100, 0, 0, 9), 0, 9); LF = constrain(map(vLF, 100, 0, 0, 9), 0, 9); OX = constrain(map(vOX, 100, 0, 0, 9), 0, 9); EL = constrain(map(vEL, 0, 100, 0, 9), 0, 9); //EL bar soldered wrong way around MP = constrain(map(vMP, 100, 0, 0, 9), 0, 9); Then, I calculate 2 to the power of those values. The pow() function works with floats, so you get some rounding issues. That's what the 0.1 is for. That doesn't work when the exponents get bigger, but for now it's fine. //calculate the power of 2. Now each value in binary is all zeroes an a single 1. we can use that to light one LED in each LED bar (dot mode) int powOX = 0.1+pow(2,OX); int powEL = 0.1+pow(2,EL); int powMP = 0.1+pow(2,MP); int powSF = 0.1+pow(2,SF); int powLF = 0.1+pow(2,LF); If you think about these values in binary, each one is a series of zeroes with a single 1 in there. The position of the 1 has a linear correlation to the initial input (% of fuel remaining). All I have to do now is get those bits shifted into the shift registers in the correct order. One issue with that is the shiftOut() function expects bytes (8 bits) at a time. I could write my own function, but I chose to map my 10-bit numbers into the proper 8-bit bytes. In hindsight maybe not the simplest way, but ah well. //map the 8-bit 595 shift registers to the 10-bit LED bars, specific to the way I wired them inputBytes[0] = powSF >> 6; inputBytes[1] = (powSF << 2) | (powLF >> 8); inputBytes[2] = powLF; inputBytes[3] = powEL >> 3; bitWrite(inputBytes[3], 0, bitRead(powEL, 4)); //fix the skipped 595 pin inputBytes[4] = (powEL << 4) | (powMP >> 6); inputBytes[5] = (powMP << 2) | (powOX >> 8); inputBytes[6] = powOX; Finally, those 7 bytes can be shifted out. //prepare the shift register digitalWrite(dataPin, LOW); digitalWrite(clockPin, LOW); digitalWrite(latchPin, LOW); //loop through the input bytes for (int j=0; j<=6; j++){ byte inputByte = inputBytes[j]; Serial.println(inputByte); shiftOut(dataPin, clockPin, MSBFIRST, inputByte); } //latch the values in when done shifting digitalWrite(latchPin, HIGH); And here's the result! Some vanity shots: All that remains is to find or build an enclosure. And I'll probably try to compile my own modified version of KSPSerialIO to add some improvements.
  4. LOL, every page is a different size Doesn't matter, it's a nice read. Looking forward to part 3.
  5. Yes! My neighbour was smart and dropped the package into my mailbox! That makes the mailman ever dumber, because why ring the doorbell if it fits in the mailbox? Well, whatever. Look at those sexy screws!
  6. I understand this niche is too small for a sub-forum, but why isn't this post at least a sticky like the other ones about cinematics and pics?
  7. Dude, that is awesome! That's a great skill to have for professional level hobby projects
  8. It's horrible! I live in an apartment building. I buzzed the mailman in and heard him use the elevator. But he never arrived on my floor! He apparently delivered the package on the wrong floor and I have no idea which one. At least it's only the bolts and not a crucial electrical component, so I can keep tinkering.
  9. There is so much I am learning by making these kinds of mistakes. I don't think you can learn these things beforehand. I guess knowledge comes from learning, but wisdom from experience All in all, I am very pleased with my results so far. Sometimes I imagine starting over and doing everything perfectly. But then I think: hey, it works and it looks fine, so why bother? Thank you for the compliment! I'll try your suggestion for bending the resistors while heating up the connections. Carefully! The last package of parts has already been delivered, but to one of my neighbors and I don't know which one! I'll go knocking on their doors tonight maybe. It's the M2, M2.5 and M3 nuts, bolts and spacers to fix the LCD and LED bars in place properly. Until then: duct (duck?) tape!
  10. Hey, now we have a working image. Great work, the first step has been taken! (a small step for man...) Note that you can always switch from using the arduino as a joystick to using KSPSerialIO or another method. All your inputs still need to be connected to the arduino in the same way. Good luck with your build. If you have any questions, just ask.
  11. Delivery from China! Best get soldering! Step 1: 50 wires to go from the shift registers to teh LED bars I put the wires on the back of the boards. You can see the copper leads looping back to be soldered in in the back. This way should help prevent breaking the solder points when I pull on the wires. Step 2: 50 current-limiting resistors to prevent the LEDs from burning out. I used larger value resistors on the green LEDs because they look brighter. Standing up at the back of the board because there is no room on the front on this board. The one on the right is nice and tidy. When I did the other two, I soldered them down before bending the resistors down and now they won't budge I broke 4 off while trying and had to desolder and replace them. Very frustrating! I guess they'll be recessed a mm more then I woud have liked. Ah well... Test fitting... You can tell the right ones are recessed. Last steps to be completed: connecting the 50 wires I attached to the shift registers to the LED bars and writing up the code.
  12. Nice! I love the visual style. It must be a lot of work getting all the pictures framed the way you want them. The captain saying "Let's go slow" while in orbit sounds weird to me...
  13. That's you?! Man, that's great! I love how everybody on here is creating something, be it in hardware or in software. To me, the process is more fun than the product. Ok, showing off the product is pretty cool too I guess the odds are pretty high I'll add a second module to the controller once it's done. With the controller working mostly as desired so far: it's time to add the final components: the fuel gauges! I am using these 10 LED bar modules. Some have all LEDs in one colour, others have a gradient of colours from green to red. On the former, I would like to light up all LEDs up to the current fuel level. On the latter, I want to light up only one LED at a time, so you get the visual cue of the level turning red. At first I was prototyping with a LM3914 driver chip. It's works fine when you connect it to a potentiometer. But then I found out it needs an analog input and won't work with a PWM signal from an Arduino. On to plan B: the shift register. In order to reduce 50 pins to only 3 we can string 7 HC595 chips together. All we have to do is convert the different fuel levels into the appropriate bytes to send into the chips. After the prototype on a breadboard seemed to work, it's on to planning the soldered boards: Work in progress: All done except for the 50 leads from the drivers to the LEDs and the LEDs, via resistors to ground: Now I'm waiting for the last 2 LED modules to arrive from China and I'll do the final soldering.
  14. That works as well. I'd prefer to be able to play vanilla. It's too bad I need the NavBall to fly, otherwise I'd play without UI altogether. I've seen some people build a hardware navball, but that's one step too far for me at the moment.
  15. Wow, great stuff! Thanks for sharing your code! It's too bad there is no vessel mass output by the plugin, to calculate remaining dV. Once I am able to compile the plugin myself I might do some digging in the API...
  16. @zitronen, I am digging around in your source code of KSPSerialIO to try and explain the behavior I am seeing. Take for example the lights. When a change in input is detected, you toggle the lights, like this: ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Light, KSPSerialPort.VControls.Lights); You basically keep track of the state of the lights with the boolean VesselControls.Lights. But you don't update that value based on what you get out of the game. You store that separately in KSPSerialPort.ControlStatus. I think that causes the unexpected behavior I am seeing. Is there any reason I am overlooking why you cannot stay in sync with the games (for example when the lights button in the GUI is pressed) by sending something like this upon button presses? ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Light, !(ActiveVessel.ActionGroups[KSPActionGroup.Light]));
  17. As you can see, I replaced the big arcade buttons with smaller, momentary push buttons with integrated LED's. I initially programmed some of them as toggles and others as momentary buttons. However, later I found out that Custom Action Groups are already handled as toggles. I am not sure whether that is native KSP behavior, or a feature of the KSPSerialIO plugin. Maybe @zitronen can shed some light on this? I also learned that the plugin already does a sort of edge detection to prevent unintentional repeated presses, so I could omit that from my own arduino code. Strange behavior still: if I toggle an Action group using my Controller, I cannot toggle it again from the game. Although my controller LED does follow the in-game status. Some more debugging to do there....
  18. Some KSP art my wife commissioned for our anniversary last year.
  19. My first mistake with the laser engraving was to include the KSP logo as a bitmap image. The laser shop requires everything to be vector based, so I should have traced the image in my vector drawing program to get it engraved. Ah well, I can stick on a sticker with a logo later. The second mistake was worse. When measuring the joysticks, I looked at the available screw holes and the room needed for the stick to move. I forgot to measure the size of the joystick handles and think about fitting them. The handle has to go through the hole, but I made the holes too small! The odd thing is that the base of the joysticks has 4 additional screw holes. Those are not required to fit the joystick to the faceplate. The outer holes are fine. You screw through the ring that masks off the rubber skirt straight into the base of the joystick, so it all becomes securely fastened. Luckily, the rubber skirt and the ring will cover the hole, so nobody will see the hack job of me enlarging the holes with totally inappropriate tools. It fits!
  20. Thank you! I like getting up learning curves. The view is great from up here Okay, I'll look into dtostrf(). I am also struggling a bit with converting the byte for maxoverheat. I added TAp and TPe. Here are the display modes I came up with: //LCD Display Modes // 0 xyz TakeOff Mode: Suface Velocity / Acceleration (G) // 1 Xyz Orbit Mode: Apoapsis + Time to Apoapsis / Periapsis + Time to Periapsis // 2 xYz Maneuver Mode: Time to next maneuver node / Remaining Delta-V for next maneuver node // 3 XYz Rendezvouz Mode: Distance to target / Velocity relative to target // 4 xyZ Re-Entry Mode: Percentage overheating (max) / Deceleration (G) // 5 XyZ Flying Mode: Altitude / Mach number // 6 xYZ Landing Mode: Radar Altitude / Vertical Velocity // 7 XYZ Extra Mode: not implemented (yet)
  21. Here's part two of the build process. After getting the inputs and outputs to work separately, I needed to think about integrating everything. I had used UnoJoy for the inputs and KSPSerialIO for the outputs. I realised using two Arduino's would not work very well, because I might want to make an output (LCD/LED) respond directly to an input (button press/toggle switch) or make the input depend on an output (crucial for using momentary buttons as toggles (if the lights are off, turn them on, if they are on, turn them off). So I really wanted to use a single Arduino. Because of the number of inputs and outputs required, I went with an Arduino Mega. Aside from the fact that I could not get MegaJoy running on the mega, that's only good for inputs anyway. So the next step was to get inputs working using KSPSerialIO. It's a bit more complex than UnoJoy/MegaJoy, but it is soooo powerful! After reverse engineering the demo code, I have reorganised the code in a way that makes sense to me and I started testing. Adding more and more code as I went along. At the same time, I felt it was time to move on from the shoebox model and move to something more final. I looked into a company that creates full production grade button boxes. The mass production costs were fine (around 50 buck per item), but the first prototype would have cost 600+ dollars! A bit too much for me. Then, I looked into laser cutting. Multiple companies offer this service in my region (The Netherlands), at a price of around 40 - 50 dollars. Great! The only hurdle was I had no experience creating a vector drawing. I played around with a trial of Adobe Illustrator, but didn't feel like spending 20 buck per month after that. Inkscape is free, but I ended up with Affinity Designer. At a one-time price of 50 euros (60-ish dollars?) I liked the product. I watched basically all their video tutorials and drew this: I'll add a mini-tutorial on how to draw for laser cutting / laser engraving later. Here's the product I received: I had only made two mistakes on this first try! No blocking issues however, so on with the build! The keep observer can spot the first mistake. Stay tuned for the rest of the build!
×
×
  • Create New...