VibrationController.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. using System;
  2. using System.Threading.Tasks;
  3. using Sensors;
  4. using UnityEngine;
  5. namespace SicknessReduction.Haptic
  6. {
  7. public enum VibrationControllerMode
  8. {
  9. Continuous,
  10. AlternatingFixed,
  11. AlternatingCadenceBased
  12. }
  13. [RequireComponent(typeof(DynamicReductionSource))]
  14. public class VibrationController : EspController
  15. {
  16. private const string TOPIC_CYCLE = "Vibration/Control/Cycle";
  17. private const string TOPIC_CADENCE = "Vibration/Control/Cadence";
  18. private const int THRES_CADENCE_CHANGE = 4;
  19. public int minCycle = 100;
  20. public int maxCycle = 178; //vibro motor specs: 11000 ± 3,000rpm = 133.33 - 183.33 Hz
  21. public float reductionValueThreshold = 0.05f;
  22. public VibrationControllerMode mode;
  23. public int fixedCycleRpm;
  24. private int currentCycle;
  25. private bool stopped = false;
  26. private bool initialCyclePublished;
  27. private int previousCadence = -1;
  28. private DynamicReductionSource reductionSource;
  29. protected override void Start()
  30. {
  31. base.Start();
  32. reductionSource = GetComponent<DynamicReductionSource>();
  33. }
  34. protected override async void Update()
  35. {
  36. base.Update();
  37. // > 0 while cornering
  38. var reductionValue = reductionSource.CurrentValue;
  39. var cycleValue = reductionValue < reductionValueThreshold
  40. ? 0
  41. : (int) Mathf.Lerp(minCycle, maxCycle, reductionValue);
  42. if (!DoUpdate || PreviousUpdateActive) return;
  43. if (reductionValue > 0)
  44. switch (mode)
  45. {
  46. case VibrationControllerMode.Continuous:
  47. await VibrateContinuous(cycleValue);
  48. break;
  49. case VibrationControllerMode.AlternatingFixed:
  50. await VibrateAlternatingFixed(cycleValue);
  51. break;
  52. case VibrationControllerMode.AlternatingCadenceBased:
  53. await VibrateAlternatingCadenceBased();
  54. break;
  55. default:
  56. throw new ArgumentOutOfRangeException();
  57. }
  58. else
  59. await StopVibrating();
  60. PreviousUpdateActive = false;
  61. }
  62. private async Task StopVibrating()
  63. {
  64. if (stopped) return;
  65. await Broker.Publish(TOPIC_CYCLE, "0");
  66. currentCycle = 0;
  67. stopped = true;
  68. }
  69. private async Task VibrateAlternatingCadenceBased()
  70. {
  71. var cadence = BikeSensorData.Instance.PowermeterData?.InstantaneousCadence;
  72. if (!cadence.HasValue) return;
  73. var c = cadence.Value;
  74. stopped = false;
  75. PreviousUpdateActive = true; //flag to avoid concurrent updates
  76. //as soon as we have a cadence, we want the motors to vibrate
  77. if (!initialCyclePublished)
  78. {
  79. await Broker.Publish(TOPIC_CYCLE, $"{maxCycle}");
  80. initialCyclePublished = true;
  81. }
  82. //if the cadence changes to 0, we have to switch off vibration
  83. if (c == 0)
  84. {
  85. await Broker.Publish(TOPIC_CYCLE, "0");
  86. previousCadence = c;
  87. }
  88. //as soon as we have cadence again, we want to switch on vibration again, and then immediately set cadence again
  89. else if (previousCadence == 0)
  90. {
  91. await Broker.Publish(TOPIC_CYCLE, $"{maxCycle}");
  92. await PublishCadence(c);
  93. }
  94. //if we have never set cadence, or the change of cadence is high enough, we tell the ESP to change cadence
  95. else if (previousCadence < 0 || c - previousCadence > THRES_CADENCE_CHANGE)
  96. {
  97. await PublishCadence(c);
  98. }
  99. }
  100. private async Task VibrateAlternatingFixed(int cycleValue)
  101. {
  102. if (Math.Abs(cycleValue - currentCycle) > 0)
  103. {
  104. await Broker.Publish(TOPIC_CYCLE, $"{cycleValue}");
  105. await PublishCadence(fixedCycleRpm);
  106. }
  107. }
  108. private async Task VibrateContinuous(int cycleValue)
  109. {
  110. if (Math.Abs(cycleValue - currentCycle) > 2)
  111. {
  112. stopped = false;
  113. //Debug.Log($"Sending Cycle {cycleValue}");
  114. await Broker.Publish(TOPIC_CYCLE, $"{cycleValue}");
  115. currentCycle = cycleValue;
  116. }
  117. }
  118. private async Task PublishCadence(int cadence)
  119. {
  120. //Debug.Log($"Sending Cadence {cadence}");
  121. await Broker.Publish(TOPIC_CADENCE, $"{cadence}");
  122. previousCadence = cadence;
  123. }
  124. }
  125. }