Advertisement
Guest User

Edit to NimbleTCode.h

a guest
May 26th, 2024
270
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.41 KB | Source Code | 0 0
  1. #include <Arduino.h>
  2. #include <TCode.h>
  3. #include "nimbleConModule.h"
  4.  
  5. #define MAX_POSITION_DELTA 100
  6. #define VIBRATION_MAX_AMP 50
  7. #define VIBRATION_MAX_SPEED 30.0 // hz
  8.  
  9. struct nimbleFrameState {
  10.     int16_t targetPos = 0; // target position from tcode commands
  11.     int16_t position = 0; // next position to send to actuator (-1000 to 1000)
  12.     int16_t lastPos = 0; // previous frame's position
  13.     int16_t force = IDLE_FORCE; // next force value to send to actuator (0 to 1023)
  14.     int8_t air = 0; // next air state to send to actuator (-1 = air out, 0 = stop, 1 = air in)
  15.     int16_t vibrationPos = 0; // next vibration position
  16. };
  17.  
  18. class NimbleTCode {
  19.     public:
  20.         NimbleTCode(const String &firmware) { tcode = new TCode<3>(firmware); }
  21.         ~NimbleTCode() { delete tcode; }
  22.         void init();
  23.         void resetState();
  24.         void start() { running = true; }
  25.         void stop() { tcode->stop(); running = false; }
  26.         void toggle() { if (running) stop(); else start(); }
  27.         void inputByte(byte input) { tcode->inputByte(input); }
  28.         void updateActuator();
  29.         void updateEncoderLEDs(bool isOn = true);
  30.         void updateHardwareLEDs();
  31.         void updateNetworkLEDs(uint32_t bluetooth, uint32_t wifi);
  32.         void setVibrationSpeed(float v) { vibrationSpeed = min(max(v, (float)0), (float)VIBRATION_MAX_SPEED); }
  33.         void setVibrationAmplitude(uint16_t v) { vibrationAmplitude = min(max(v, (uint16_t)0), (uint16_t)VIBRATION_MAX_AMP); }
  34.         void printFrameState(Print& out = Serial);
  35.         bool isRunning() { return running; }
  36.         void setMessageCallback(TCODE_FUNCTION_PTR_T function) { tcode->setMessageCallback(function); }
  37.  
  38.     private:
  39.         TCode<3> *tcode;
  40.         bool running = true;
  41.         float vibrationSpeed = VIBRATION_MAX_SPEED; // hz
  42.         uint16_t vibrationAmplitude = 0; // amplitude in position units (0 to 25)
  43.         uint16_t vibrationAmplitudePend = 0; // amplitude calculated from pendant input
  44.         nimbleFrameState frame;
  45.  
  46.         void handleAxisChanges();
  47.         void handleVibrationSpeedChanges();
  48.         void handlePositionChanges();
  49.         void handleAirChanges();
  50.         void handleForceChanges();
  51.         int16_t clampPositionDelta();
  52.         void calculatePendVibe();
  53. };
  54.  
  55. void NimbleTCode::init()
  56. {
  57.     initNimbleConModule();
  58.     resetState();
  59.  
  60.     tcode->init();
  61.  
  62.     tcode->axisRegister("L0", F("Up")); // Up stroke position
  63.     tcode->axisWrite("L0", 5000, ' ', 0); // 5000: midpoint
  64.     tcode->axisEasingType("L0", EasingType::EASEINOUT);
  65.  
  66.     tcode->axisRegister("V0", F("Vibe")); // Vibration Amplitude
  67.     tcode->axisWrite("V0", 0, ' ', 0);    // 0: vibration off
  68.     tcode->axisEasingType("V0", EasingType::EASEINOUT);
  69.  
  70.     tcode->axisRegister("A0", F("Air")); // Air in/out valve
  71.     tcode->axisWrite("A0", 5000, ' ', 0); // 0: air out, 5000: stop, 9999: air in
  72.  
  73.     tcode->axisRegister("A1", F("Force"));
  74.     tcode->axisWrite("A1", 9999, ' ', 0); // 9999: max force
  75.  
  76.     tcode->axisRegister("A2", F("VibeSpeed"));
  77.     tcode->axisWrite("A2", 9999, ' ', 0); // 9999: max vibration speed
  78. }
  79.  
  80. void NimbleTCode::resetState() {
  81.     frame.targetPos = 0;
  82.     frame.force = MAX_FORCE;
  83.     frame.air = 0;
  84.     vibrationSpeed = VIBRATION_MAX_SPEED;
  85.     vibrationAmplitude = 0;
  86.     vibrationAmplitudePend = 0;
  87. }
  88.  
  89. void NimbleTCode::handleAxisChanges()
  90. {
  91.     handleVibrationSpeedChanges();
  92.     handlePositionChanges();
  93.     handleAirChanges();
  94.     handleForceChanges();
  95.     calculatePendVibe();
  96. }
  97.  
  98. void NimbleTCode::handleVibrationSpeedChanges()
  99. {
  100.     if (!tcode->axisChanged("A2")) return;
  101.     int val = tcode->axisRead("A2");
  102.     int maxSpeed = VIBRATION_MAX_SPEED * 100;
  103.     int newSpeed = map(val, 0, 9999, 0, maxSpeed);
  104.     vibrationSpeed = float(newSpeed) / 100;
  105. }
  106.  
  107. void NimbleTCode::handlePositionChanges()
  108. {
  109.     if (!tcode->axisChanged("L0")) {
  110.         int val = tcode->axisRead("L0");
  111.         frame.targetPos = map(val, 0, 9999, -ACTUATOR_MAX_POS, ACTUATOR_MAX_POS);
  112.     }
  113.    
  114.     if (this->tcode->axisChanged("V0")) {
  115.         int val = tcode->axisRead("V0");
  116.         vibrationAmplitude = map(val, 0, 9999, 0, VIBRATION_MAX_AMP);
  117.     }
  118.  
  119.     // Set vibrations to pendant value if it's active
  120.     if(pendant.activated) {
  121.         vibrationAmplitude = vibrationAmplitudePend;
  122.     }
  123.  
  124.     if (vibrationAmplitude > 0 && vibrationSpeed > 0) {
  125.         int vibSpeedMillis = 1000 / vibrationSpeed;
  126.         int vibModMillis = millis() % vibSpeedMillis;
  127.         float tempPos = float(vibModMillis) / vibSpeedMillis;
  128.         int vibWaveDeg = tempPos * 360;
  129.         frame.vibrationPos = round(sin(radians(vibWaveDeg)) * vibrationAmplitude);
  130.     } else {
  131.         frame.vibrationPos = 0;
  132.     }
  133.     // Serial.printf("A:%5d S:%0.2f P:%5d\n",
  134.     //     vibrationAmplitude,
  135.     //     vibrationSpeed,
  136.     //     vibrationPos
  137.     // );
  138.  
  139.     int targetPosTmp = frame.targetPos;
  140.     if (frame.targetPos - vibrationAmplitude < -ACTUATOR_MAX_POS) {
  141.         targetPosTmp = frame.targetPos + vibrationAmplitude;
  142.     } else if (frame.targetPos + vibrationAmplitude > ACTUATOR_MAX_POS) {
  143.         targetPosTmp = frame.targetPos - vibrationAmplitude;
  144.     }
  145.     frame.position = targetPosTmp + frame.vibrationPos;
  146. }
  147.  
  148. void NimbleTCode::handleAirChanges()
  149. {
  150.     if (!tcode->axisChanged("A0")) return;
  151.     int val = tcode->axisRead("A0");
  152.  
  153.     //    0-3333 = air out
  154.     // 3334-6666 = valve off
  155.     // 6667-9999 = air in
  156.     if (val < 3334) {
  157.         frame.air = -1;
  158.     } else if (val > 6666) {
  159.         frame.air = 1;
  160.     } else {
  161.         frame.air = 0;
  162.     }
  163. }
  164.  
  165. void NimbleTCode::handleForceChanges()
  166. {
  167.     if (!tcode->axisChanged("A1")) return;
  168.     int val = tcode->axisRead("A1");
  169.     frame.force = map(val, 0, 9999, 0, MAX_FORCE);
  170. }
  171.  
  172. void NimbleTCode::updateActuator()
  173. {
  174.     handleAxisChanges();
  175.     // Send packet of values to the actuator when time is ready
  176.     if (checkTimer())
  177.     {
  178.         if (isRunning()) {
  179.             frame.lastPos = clampPositionDelta();
  180.             actuator.positionCommand = frame.lastPos;
  181.             actuator.forceCommand = frame.force;
  182.             // Read air commands from pendant, probably don't need the present check but it makes me feel safe
  183.             if (pendant.present) {
  184.                 actuator.airIn = (pendant.airIn ? true : frame.air > 0);
  185.                 actuator.airOut = (pendant.airOut ? true : frame.air < 0);
  186.             } else {
  187.                 actuator.airIn = (frame.air > 0);
  188.                 actuator.airOut = (frame.air < 0);
  189.             }
  190.            
  191.         } else {
  192.             actuator.airIn = false;
  193.             actuator.airOut = false;
  194.             actuator.forceCommand = IDLE_FORCE;
  195.         }
  196.         sendToAct();
  197.     }
  198.  
  199.     if (readFromAct()) // Read current state from actuator.
  200.     { // If the function returns true, the values were updated.
  201.  
  202.         // Unclear yet if any action is required when tempLimiting is occurring.
  203.         // A comparison is needed with the Pendant behavior.
  204.         // if (actuator.tempLimiting) {
  205.         //     setRunMode(RUN_MODE_OFF);
  206.         // }
  207.  
  208.         // Serial.printf("A P:%4d F:%4d T:%s\n",
  209.         //     actuator.positionFeedback,
  210.         //     actuator.forceFeedback,
  211.         //     actuator.tempLimiting ? "true" : "false"
  212.         // );
  213.     }
  214.     if (readFromPend()) // Read current state from pendant. Adding this call allows the pendant values to start being read!
  215.     {
  216.  
  217.     }
  218. }
  219.  
  220. void NimbleTCode::updateEncoderLEDs(bool isOn)
  221. {
  222.     int16_t pos = frame.lastPos;
  223.     int16_t vibPos = frame.vibrationPos;
  224.  
  225.     byte ledScale = map(abs(pos), 0, ACTUATOR_MAX_POS, 1, LED_MAX_DUTY);
  226.     byte ledState1 = 0;
  227.     byte ledState2 = 0;
  228.     byte vibScale = map(abs(vibPos), 0, VIBRATION_MAX_AMP, 1, LED_MAX_DUTY);
  229.     byte vibState1 = 0;
  230.     byte vibState2 = 0;
  231.  
  232.     if (isOn)
  233.     {
  234.         if (pos < 0) {
  235.             ledState1 = ledScale;
  236.         } else if (pos > 0) {
  237.             ledState2 = ledScale;
  238.         }
  239.  
  240.         if (vibPos < 0) {
  241.             vibState1 = vibScale;
  242.         } else if (vibPos > 0) {
  243.             vibState2 = vibScale;
  244.         }
  245.     }
  246.  
  247.     ledcWrite(ENC_LED_N,  ledState1);
  248.     ledcWrite(ENC_LED_SE, ledState1);
  249.     ledcWrite(ENC_LED_SW, ledState1);
  250.  
  251.     ledcWrite(ENC_LED_NE, ledState2);
  252.     ledcWrite(ENC_LED_NW, ledState2);
  253.     ledcWrite(ENC_LED_S,  ledState2);
  254.  
  255.     ledcWrite(ENC_LED_W, vibState1);
  256.     ledcWrite(ENC_LED_E, vibState2);
  257. }
  258.  
  259. void NimbleTCode::updateHardwareLEDs()
  260. {
  261.     ledcWrite(PEND_LED, (pendant.present) ? 50 : 0);
  262.     ledcWrite(ACT_LED, (actuator.present) ? 50 : 0);
  263. }
  264.  
  265. void NimbleTCode::updateNetworkLEDs(uint32_t bluetooth, uint32_t wifi)
  266. {
  267.     ledcWrite(BT_LED, bluetooth);
  268.     ledcWrite(WIFI_LED, wifi);
  269. }
  270.  
  271. int16_t NimbleTCode::clampPositionDelta()
  272. {
  273.     int16_t delta = frame.position - frame.lastPos;
  274.     if (delta >= 0) {
  275.         return (delta > MAX_POSITION_DELTA) ? frame.lastPos + MAX_POSITION_DELTA : frame.position;
  276.     } else {
  277.         return (delta < -MAX_POSITION_DELTA) ? frame.lastPos - MAX_POSITION_DELTA : frame.position;
  278.     }
  279. }
  280.  
  281. void NimbleTCode::calculatePendVibe()
  282. {
  283.     // This code's stupid, sets the vibe to fixed value if there is any position input
  284.     // set the position input to 0 to turn off the vibe, couldn't figure how to read the actual vibration setting
  285.     if(pendant.positionCommand != 0) {
  286.         vibrationAmplitudePend = 24;
  287.     } else {
  288.         vibrationAmplitudePend = 0;
  289.     }
  290. }
  291.  
  292.  
  293.  
  294. void NimbleTCode::printFrameState(Print& out)
  295. {
  296.     out.printf("------------------\n");
  297.     out.printf("   VibAmp: %5d\n", vibrationAmplitude);
  298.     out.printf(" VibSpeed: %0.2f (hz)\n", vibrationSpeed);
  299.     out.printf("   TarPos: %5d\n", frame.targetPos);
  300.     out.printf("      Pos: %5d\n", frame.position);
  301.     out.printf("    Force: %5d\n", actuator.forceCommand);
  302.     out.printf("    AirIn: %s\n", actuator.airIn ? "true" : "false");
  303.     out.printf("   AirOut: %s\n", actuator.airOut ? "true" : "false");
  304.     out.printf("TempLimit: %s\n", actuator.tempLimiting ? "true" : "false");
  305.     // Extra pendant values I added for debugging
  306.     out.printf("Pendant AirIn: %s\n", pendant.airIn ? "true" : "false");
  307.     out.printf("Pendant AirOut: %s\n", pendant.airOut ? "true" : "false");
  308.     out.printf("Pendant Position: %5d\n", pendant.positionCommand);
  309.     out.printf("Pendant Vibration: %5d\n", vibrationAmplitudePend);
  310.     out.printf("Pendant Present: %s\n", pendant.present ? "true" : "false");
  311.  
  312. }
  313.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement