Skip to content

Commit

Permalink
Feature: Implement Haptic Feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
Relys committed Aug 28, 2024
1 parent 7777d33 commit 85ae6ac
Show file tree
Hide file tree
Showing 5 changed files with 346 additions and 3 deletions.
15 changes: 15 additions & 0 deletions src/conf/datatypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
#include <stdbool.h>
#include <stdint.h>

typedef enum {
HAPTIC_FEEDBACK_NONE = 0,
HAPTIC_FEEDBACK_AUDIBLE,
HAPTIC_FEEDBACK_RUMBLE,
HAPTIC_FEEDBACK_ALTERNATING
} HAPTIC_FEEDBACK_TYPE;

typedef enum {
INPUTTILT_NONE = 0,
INPUTTILT_UART,
Expand Down Expand Up @@ -185,6 +192,14 @@ typedef struct {
float tiltback_lv;
float tiltback_return_speed;
float tiltback_constant;
HAPTIC_FEEDBACK_TYPE haptic_feedback_duty;
HAPTIC_FEEDBACK_TYPE haptic_feedback_error;
float haptic_feedback_voltage;
int haptic_feedback_duty_freq;
int haptic_feedback_error_freq;
float haptic_feedback_rumble_voltage;
int haptic_feedback_rumble_freq;
int haptic_feedback_alt_delay;
uint16_t tiltback_constant_erpm;
float tiltback_variable;
float tiltback_variable_max;
Expand Down
173 changes: 173 additions & 0 deletions src/conf/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,162 @@ p, li { white-space: pre-wrap; }
<suffix> ERPM</suffix>
<vTx>3</vTx>
</tiltback_variable_erpm>
<haptic_feedback_duty>
<longName>Haptic Feedback Duty Cycle</longName>
<type>4</type>
<transmittable>1</transmittable>
<description>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Roboto'; ; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Type of haptic feedback for duty cycle.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</description>
<cDefine>CFG_DFLT_HAPTIC_FEEDBACK_DUTY</cDefine>
<valInt>0</valInt>
<enumNames>HAPTIC_FEEDBACK_NONE</enumNames>
<enumNames>HAPTIC_FEEDBACK_AUDIBLE</enumNames>
<enumNames>HAPTIC_FEEDBACK_RUMBLE</enumNames>
<enumNames>HAPTIC_FEEDBACK_ALTERNATING</enumNames>
</haptic_feedback_duty>
<haptic_feedback_error>
<longName>Haptic Feedback Error</longName>
<type>4</type>
<transmittable>1</transmittable>
<description>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Roboto'; ; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Type of haptic feedback for error.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</description>
<cDefine>CFG_DFLT_HAPTIC_FEEDBACK_ERROR</cDefine>
<valInt>0</valInt>
<enumNames>HAPTIC_FEEDBACK_NONE</enumNames>
<enumNames>HAPTIC_FEEDBACK_AUDIBLE</enumNames>
<enumNames>HAPTIC_FEEDBACK_RUMBLE</enumNames>
<enumNames>HAPTIC_FEEDBACK_ALTERNATING</enumNames>
</haptic_feedback_error>
<haptic_feedback_voltage>
<longName>Haptic Feedback Strength</longName>
<type>1</type>
<transmittable>1</transmittable>
<description>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Roboto'; ; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Strength for haptic feedback audible tone.&lt;span style=&quot; font-style:italic;&quot;&gt;&lt;br /&gt;&lt;br /&gt;Recommended Values: 0.0 - 6.0 (Caution with higher values!)&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</description>
<cDefine>CFG_DFLT_HAPTIC_FEEDBACK_VOLTAGE</cDefine>
<editorDecimalsDouble>1</editorDecimalsDouble>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxDouble>6</maxDouble>
<minDouble>0</minDouble>
<showDisplay>0</showDisplay>
<stepDouble>0.1</stepDouble>
<valDouble>3</valDouble>
<vTxDoubleScale>10</vTxDoubleScale>
<suffix> v</suffix>
<vTx>7</vTx>
</haptic_feedback_voltage>
<haptic_feedback_duty_freq>
<longName>Haptic Feedback Duty Tone</longName>
<type>2</type>
<transmittable>1</transmittable>
<description>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Roboto'; ; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Recommended Values: 0 - 1000&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</description>
<cDefine>CFG_DFLT_HAPTIC_FEEDBACK_DUTY_FREQ</cDefine>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxInt>1000</maxInt>
<minInt>0</minInt>
<showDisplay>0</showDisplay>
<stepInt>1</stepInt>
<valInt>495</valInt>
<suffix> Hz</suffix>
<vTx>3</vTx>
</haptic_feedback_duty_freq>
<haptic_feedback_error_freq>
<longName>Haptic Feedback Error Tone</longName>
<type>2</type>
<transmittable>1</transmittable>
<description>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Roboto'; ; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Recommended Values: 0 - 1000&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</description>
<cDefine>CFG_DFLT_HAPTIC_FEEDBACK_ERROR_FREQ</cDefine>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxInt>1000</maxInt>
<minInt>0</minInt>
<showDisplay>0</showDisplay>
<stepInt>1</stepInt>
<valInt>495</valInt>
<suffix> Hz</suffix>
<vTx>3</vTx>
</haptic_feedback_error_freq>
<haptic_feedback_rumble_voltage>
<longName>Haptic Feedback Rumble Strength</longName>
<type>1</type>
<transmittable>1</transmittable>
<description>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Roboto'; ; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Strength for haptic feedback rumble.&lt;span style=&quot; font-style:italic;&quot;&gt;&lt;br /&gt;&lt;br /&gt;Recommended Values: 0.0 - 6.0 (Caution with higher values!)&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</description>
<cDefine>CFG_DFLT_HAPTIC_FEEDBACK_RUMBLE_VOLTAGE</cDefine>
<editorDecimalsDouble>1</editorDecimalsDouble>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxDouble>6</maxDouble>
<minDouble>0</minDouble>
<showDisplay>0</showDisplay>
<stepDouble>0.1</stepDouble>
<valDouble>0</valDouble>
<vTxDoubleScale>10</vTxDoubleScale>
<suffix> v</suffix>
<vTx>7</vTx>
</haptic_feedback_rumble_voltage>
<haptic_feedback_rumble_freq>
<longName>Haptic Feedback Rumble Frequency</longName>
<type>2</type>
<transmittable>1</transmittable>
<description>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Roboto'; ; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Recommended Values: 0 - 1000&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</description>
<cDefine>CFG_DFLT_HAPTIC_FEEDBACK_RUMBLE_FREQ</cDefine>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxInt>1000</maxInt>
<minInt>0</minInt>
<showDisplay>0</showDisplay>
<stepInt>1</stepInt>
<valInt>0</valInt>
<suffix> Hz</suffix>
<vTx>3</vTx>
</haptic_feedback_rumble_freq>
<haptic_feedback_alt_delay>
<longName>Haptic Feedback Alternating Delay</longName>
<type>2</type>
<transmittable>1</transmittable>
<description>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Roboto'; ; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Delay for switching between audible tone and rumble.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</description>
<cDefine>CFG_DFLT_HAPTIC_FEEDBACK_ALT_DELAY</cDefine>
<editorScale>1</editorScale>
<editAsPercentage>0</editAsPercentage>
<maxInt>1000</maxInt>
<minInt>0</minInt>
<showDisplay>0</showDisplay>
<stepInt>1</stepInt>
<valInt>500</valInt>
<suffix> ms</suffix>
<vTx>3</vTx>
</haptic_feedback_alt_delay>
<noseangling_speed>
<longName>Nose Angling Speed</longName>
<type>1</type>
Expand Down Expand Up @@ -3564,6 +3720,14 @@ p, li { white-space: pre-wrap; }
<ser>dark_pitch_offset</ser>
<ser>is_beeper_enabled</ser>
<ser>disabled</ser>
<ser>haptic_feedback_duty</ser>
<ser>haptic_feedback_error</ser>
<ser>haptic_feedback_voltage</ser>
<ser>haptic_feedback_duty_freq</ser>
<ser>haptic_feedback_error_freq</ser>
<ser>haptic_feedback_rumble_voltage</ser>
<ser>haptic_feedback_rumble_freq</ser>
<ser>haptic_feedback_alt_delay</ser>
</SerOrder>
<Grouping>
<group>
Expand Down Expand Up @@ -3701,6 +3865,15 @@ p, li { white-space: pre-wrap; }
<param>::sep::Low Voltage Alert Pushback</param>
<param>tiltback_lv_angle</param>
<param>tiltback_lv_speed</param>
<param>::sep::Haptic Feedback (6.05+)</param>
<param>haptic_feedback_duty</param>
<param>haptic_feedback_error</param>
<param>haptic_feedback_voltage</param>
<param>haptic_feedback_duty_freq</param>
<param>haptic_feedback_error_freq</param>
<param>haptic_feedback_rumble_voltage</param>
<param>haptic_feedback_rumble_freq</param>
<param>haptic_feedback_alt_delay</param>
</subgroupParams>
</subgroup>
<subgroup>
Expand Down
99 changes: 99 additions & 0 deletions src/haptic_feedback.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2024 Syler Clayton
//
// This file is part of the Refloat VESC package.
//
// Refloat VESC package is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// Refloat VESC package is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <http://www.gnu.org/licenses/>.

#include "haptic_feedback.h"

void haptic_feedback_configure(HapticFeedback *haptic_feedback, RefloatConfig *float_conf) {
haptic_feedback->duty.type = float_conf->haptic_feedback_duty;
haptic_feedback->duty.voltage = float_conf->haptic_feedback_voltage;
haptic_feedback->duty.freq = float_conf->haptic_feedback_duty_freq;
haptic_feedback->error.type = float_conf->haptic_feedback_error;
haptic_feedback->error.voltage = float_conf->haptic_feedback_voltage;
haptic_feedback->error.freq = float_conf->haptic_feedback_error_freq;
haptic_feedback->rumble_voltage = float_conf->haptic_feedback_rumble_voltage;
haptic_feedback->rumble_freq = float_conf->haptic_feedback_rumble_freq;
haptic_feedback->alt_delay = float_conf->haptic_feedback_alt_delay;
}

void haptic_feedback_reset(HapticFeedback *haptic_feedback, float current_time) {
if (haptic_feedback->tone_in_progress) {
VESC_IF->foc_stop_audio(true);
}
haptic_feedback->tone_in_progress = false;
haptic_feedback->timer = current_time;
haptic_feedback->alt_timer = current_time;
haptic_feedback->alt_state = false;
}

void haptic_feedback_update(
HapticFeedback *haptic_feedback, State *state, float current_time, float note_duration
) {
if (state->mode == MODE_FLYWHEEL || !(VESC_IF->foc_play_tone && VESC_IF->foc_stop_audio)) {
return;
}
HapticFeedbackConfig haptic_feedback_state;
if (state->state == STATE_RUNNING && state->sat >= SAT_PB_DUTY) {
if (state->sat == SAT_PB_DUTY) {
haptic_feedback_state = haptic_feedback->duty;
} else if (state->sat > SAT_PB_DUTY) {
haptic_feedback_state = haptic_feedback->error;
}
if ((haptic_feedback_state.type > HAPTIC_FEEDBACK_NONE)) {
if (!haptic_feedback->tone_in_progress) {
if ((haptic_feedback_state.type == HAPTIC_FEEDBACK_RUMBLE ||
(haptic_feedback_state.type == HAPTIC_FEEDBACK_ALTERNATING &&
(haptic_feedback_state.voltage == 0.0 || haptic_feedback_state.freq == 0)))) {
haptic_feedback_state.freq = haptic_feedback->rumble_freq;
haptic_feedback_state.voltage = haptic_feedback->rumble_voltage;
haptic_feedback->alt_state = !haptic_feedback->alt_state;
}
if ((haptic_feedback_state.freq > 0) && (haptic_feedback_state.voltage > 0.0)) {
VESC_IF->foc_play_tone(
0, haptic_feedback_state.freq, haptic_feedback_state.voltage
);
haptic_feedback->alt_timer = current_time;
haptic_feedback->tone_in_progress = true;
}
}
haptic_feedback->timer = current_time;
}
}

if (haptic_feedback->tone_in_progress) {
if (fabsf(haptic_feedback->timer - current_time) > note_duration) {
VESC_IF->foc_stop_audio(true);
haptic_feedback->tone_in_progress = false;
} else if ((haptic_feedback_state.type == HAPTIC_FEEDBACK_ALTERNATING) && (haptic_feedback->alt_delay > 0) && (fabsf(haptic_feedback->alt_timer - current_time) > haptic_feedback->alt_delay/1000.0))
{
haptic_feedback->alt_timer = current_time;
haptic_feedback->alt_state = !haptic_feedback->alt_state;
// change tone based on state
haptic_feedback_state.voltage = haptic_feedback->alt_state
? haptic_feedback->rumble_voltage
: haptic_feedback_state.voltage;
haptic_feedback_state.freq = haptic_feedback->alt_state ? haptic_feedback->rumble_freq
: haptic_feedback_state.freq;
if (haptic_feedback_state.voltage > 0.0 && haptic_feedback_state.freq > 0) {
VESC_IF->foc_play_tone(
0, haptic_feedback_state.freq, haptic_feedback_state.voltage
);
} else {
VESC_IF->foc_stop_audio(false);
}
}
}
}
44 changes: 44 additions & 0 deletions src/haptic_feedback.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2024 Syler Clayton
//
// This file is part of the Refloat VESC package.
//
// Refloat VESC package is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// Refloat VESC package is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <http://www.gnu.org/licenses/>.

#pragma once
#include "conf/datatypes.h"
#include "state.h"
#include "utils.h"
#include <math.h>

typedef struct {
HAPTIC_FEEDBACK_TYPE type;
float voltage;
int freq;
} HapticFeedbackConfig;

typedef struct {
float timer, alt_timer;
bool alt_state, tone_in_progress;
HapticFeedbackConfig duty, error;
float rumble_voltage;
int rumble_freq, alt_delay;
} HapticFeedback;

void haptic_feedback_configure(HapticFeedback *haptic_feedback, RefloatConfig *float_conf);

void haptic_feedback_reset(HapticFeedback *haptic_feedback, float current_time);

void haptic_feedback_update(
HapticFeedback *haptic_feedback, State *state, float current_time, float note_duration
);
Loading

0 comments on commit 85ae6ac

Please sign in to comment.